├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Cross.toml ├── README.md ├── benches ├── cap_handle.rs └── packet_cnt.rs ├── bind_src ├── packets.h └── structures.h ├── cap ├── perf_data ├── latency.log └── release_build_flamegraph.svg ├── scripts ├── gst_play.sh ├── gst_save.sh ├── gst_save_play.sh ├── gst_stream.sh └── set_netcard.sh ├── src ├── device.rs ├── inject.rs ├── lib.rs ├── main.rs ├── packet.rs └── packet_h_bind.rs └── tests ├── send_a_frame.rs └── test.sdp /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.vscode 3 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anstream" 16 | version = "0.6.13" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" 19 | dependencies = [ 20 | "anstyle", 21 | "anstyle-parse", 22 | "anstyle-query", 23 | "anstyle-wincon", 24 | "colorchoice", 25 | "utf8parse", 26 | ] 27 | 28 | [[package]] 29 | name = "anstyle" 30 | version = "1.0.6" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" 33 | 34 | [[package]] 35 | name = "anstyle-parse" 36 | version = "0.2.3" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" 39 | dependencies = [ 40 | "utf8parse", 41 | ] 42 | 43 | [[package]] 44 | name = "anstyle-query" 45 | version = "1.0.2" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" 48 | dependencies = [ 49 | "windows-sys 0.52.0", 50 | ] 51 | 52 | [[package]] 53 | name = "anstyle-wincon" 54 | version = "3.0.2" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" 57 | dependencies = [ 58 | "anstyle", 59 | "windows-sys 0.52.0", 60 | ] 61 | 62 | [[package]] 63 | name = "autocfg" 64 | version = "1.2.0" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" 67 | 68 | [[package]] 69 | name = "bitfield" 70 | version = "0.14.0" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" 73 | 74 | [[package]] 75 | name = "bitflags" 76 | version = "1.3.2" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 79 | 80 | [[package]] 81 | name = "bitops" 82 | version = "0.1.0" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "f41a723cb1fba322fe1bc95dd28dc7e7aadd8d3f81db31511df86c64c2d4a57e" 85 | dependencies = [ 86 | "num-integer", 87 | ] 88 | 89 | [[package]] 90 | name = "byteorder" 91 | version = "1.5.0" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 94 | 95 | [[package]] 96 | name = "cc" 97 | version = "1.0.90" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" 100 | 101 | [[package]] 102 | name = "cfg-if" 103 | version = "1.0.0" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 106 | 107 | [[package]] 108 | name = "clap" 109 | version = "4.5.4" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" 112 | dependencies = [ 113 | "clap_builder", 114 | "clap_derive", 115 | ] 116 | 117 | [[package]] 118 | name = "clap_builder" 119 | version = "4.5.2" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" 122 | dependencies = [ 123 | "anstream", 124 | "anstyle", 125 | "clap_lex", 126 | "strsim", 127 | ] 128 | 129 | [[package]] 130 | name = "clap_derive" 131 | version = "4.5.4" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" 134 | dependencies = [ 135 | "heck", 136 | "proc-macro2", 137 | "quote", 138 | "syn", 139 | ] 140 | 141 | [[package]] 142 | name = "clap_lex" 143 | version = "0.7.0" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" 146 | 147 | [[package]] 148 | name = "colorchoice" 149 | version = "1.0.0" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" 152 | 153 | [[package]] 154 | name = "crc" 155 | version = "3.0.1" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" 158 | dependencies = [ 159 | "crc-catalog", 160 | ] 161 | 162 | [[package]] 163 | name = "crc-catalog" 164 | version = "2.4.0" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" 167 | 168 | [[package]] 169 | name = "errno" 170 | version = "0.2.8" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" 173 | dependencies = [ 174 | "errno-dragonfly", 175 | "libc", 176 | "winapi", 177 | ] 178 | 179 | [[package]] 180 | name = "errno-dragonfly" 181 | version = "0.1.2" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 184 | dependencies = [ 185 | "cc", 186 | "libc", 187 | ] 188 | 189 | [[package]] 190 | name = "esp-vtx-gs-rs" 191 | version = "0.1.0" 192 | dependencies = [ 193 | "bitfield", 194 | "clap", 195 | "crc", 196 | "pcap", 197 | "radiotap", 198 | "zfec-rs", 199 | ] 200 | 201 | [[package]] 202 | name = "heck" 203 | version = "0.5.0" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 206 | 207 | [[package]] 208 | name = "libc" 209 | version = "0.2.153" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 212 | 213 | [[package]] 214 | name = "libloading" 215 | version = "0.6.7" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" 218 | dependencies = [ 219 | "cfg-if", 220 | "winapi", 221 | ] 222 | 223 | [[package]] 224 | name = "memchr" 225 | version = "2.7.1" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" 228 | 229 | [[package]] 230 | name = "num-integer" 231 | version = "0.1.46" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 234 | dependencies = [ 235 | "num-traits", 236 | ] 237 | 238 | [[package]] 239 | name = "num-traits" 240 | version = "0.2.18" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" 243 | dependencies = [ 244 | "autocfg", 245 | ] 246 | 247 | [[package]] 248 | name = "pcap" 249 | version = "1.3.0" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "99e935fc73d54a89fff576526c2ccd42bbf8247aae05b358693475b14fd4ff79" 252 | dependencies = [ 253 | "bitflags", 254 | "errno", 255 | "libc", 256 | "libloading", 257 | "pkg-config", 258 | "regex", 259 | "windows-sys 0.36.1", 260 | ] 261 | 262 | [[package]] 263 | name = "pkg-config" 264 | version = "0.3.30" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 267 | 268 | [[package]] 269 | name = "proc-macro2" 270 | version = "1.0.79" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" 273 | dependencies = [ 274 | "unicode-ident", 275 | ] 276 | 277 | [[package]] 278 | name = "quick-error" 279 | version = "1.2.3" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 282 | 283 | [[package]] 284 | name = "quote" 285 | version = "1.0.35" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" 288 | dependencies = [ 289 | "proc-macro2", 290 | ] 291 | 292 | [[package]] 293 | name = "radiotap" 294 | version = "1.3.0" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "e50757032799a2a41ed705169a87efea63fb0babfe69f418b3f5630df4c8394a" 297 | dependencies = [ 298 | "bitops", 299 | "byteorder", 300 | "quick-error", 301 | ] 302 | 303 | [[package]] 304 | name = "regex" 305 | version = "1.10.4" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" 308 | dependencies = [ 309 | "aho-corasick", 310 | "memchr", 311 | "regex-automata", 312 | "regex-syntax", 313 | ] 314 | 315 | [[package]] 316 | name = "regex-automata" 317 | version = "0.4.6" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" 320 | dependencies = [ 321 | "aho-corasick", 322 | "memchr", 323 | "regex-syntax", 324 | ] 325 | 326 | [[package]] 327 | name = "regex-syntax" 328 | version = "0.8.2" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" 331 | 332 | [[package]] 333 | name = "strsim" 334 | version = "0.11.1" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 337 | 338 | [[package]] 339 | name = "syn" 340 | version = "2.0.55" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" 343 | dependencies = [ 344 | "proc-macro2", 345 | "quote", 346 | "unicode-ident", 347 | ] 348 | 349 | [[package]] 350 | name = "unicode-ident" 351 | version = "1.0.12" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 354 | 355 | [[package]] 356 | name = "utf8parse" 357 | version = "0.2.1" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 360 | 361 | [[package]] 362 | name = "winapi" 363 | version = "0.3.9" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 366 | dependencies = [ 367 | "winapi-i686-pc-windows-gnu", 368 | "winapi-x86_64-pc-windows-gnu", 369 | ] 370 | 371 | [[package]] 372 | name = "winapi-i686-pc-windows-gnu" 373 | version = "0.4.0" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 376 | 377 | [[package]] 378 | name = "winapi-x86_64-pc-windows-gnu" 379 | version = "0.4.0" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 382 | 383 | [[package]] 384 | name = "windows-sys" 385 | version = "0.36.1" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" 388 | dependencies = [ 389 | "windows_aarch64_msvc 0.36.1", 390 | "windows_i686_gnu 0.36.1", 391 | "windows_i686_msvc 0.36.1", 392 | "windows_x86_64_gnu 0.36.1", 393 | "windows_x86_64_msvc 0.36.1", 394 | ] 395 | 396 | [[package]] 397 | name = "windows-sys" 398 | version = "0.52.0" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 401 | dependencies = [ 402 | "windows-targets", 403 | ] 404 | 405 | [[package]] 406 | name = "windows-targets" 407 | version = "0.52.4" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" 410 | dependencies = [ 411 | "windows_aarch64_gnullvm", 412 | "windows_aarch64_msvc 0.52.4", 413 | "windows_i686_gnu 0.52.4", 414 | "windows_i686_msvc 0.52.4", 415 | "windows_x86_64_gnu 0.52.4", 416 | "windows_x86_64_gnullvm", 417 | "windows_x86_64_msvc 0.52.4", 418 | ] 419 | 420 | [[package]] 421 | name = "windows_aarch64_gnullvm" 422 | version = "0.52.4" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" 425 | 426 | [[package]] 427 | name = "windows_aarch64_msvc" 428 | version = "0.36.1" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" 431 | 432 | [[package]] 433 | name = "windows_aarch64_msvc" 434 | version = "0.52.4" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" 437 | 438 | [[package]] 439 | name = "windows_i686_gnu" 440 | version = "0.36.1" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" 443 | 444 | [[package]] 445 | name = "windows_i686_gnu" 446 | version = "0.52.4" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" 449 | 450 | [[package]] 451 | name = "windows_i686_msvc" 452 | version = "0.36.1" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" 455 | 456 | [[package]] 457 | name = "windows_i686_msvc" 458 | version = "0.52.4" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" 461 | 462 | [[package]] 463 | name = "windows_x86_64_gnu" 464 | version = "0.36.1" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" 467 | 468 | [[package]] 469 | name = "windows_x86_64_gnu" 470 | version = "0.52.4" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" 473 | 474 | [[package]] 475 | name = "windows_x86_64_gnullvm" 476 | version = "0.52.4" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" 479 | 480 | [[package]] 481 | name = "windows_x86_64_msvc" 482 | version = "0.36.1" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" 485 | 486 | [[package]] 487 | name = "windows_x86_64_msvc" 488 | version = "0.52.4" 489 | source = "registry+https://github.com/rust-lang/crates.io-index" 490 | checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" 491 | 492 | [[package]] 493 | name = "zfec-rs" 494 | version = "0.1.0" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "3056bc66f085fdd156a145a90636aa7ff0d590f4ecd03a6b065f44e2dc93afab" 497 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "esp-vtx-gs-rs" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | bitfield = "0.14.0" 10 | clap = {version = "4.5.4", features = ["derive"]} 11 | crc = "3.0.1" 12 | pcap = "1.3.0" 13 | radiotap = "1.3.0" 14 | zfec-rs = "0.1.0" 15 | 16 | [[test]] 17 | name = "send_a_frame" 18 | harness = false 19 | 20 | [[bench]] 21 | name = "cap_handle" 22 | harness = false 23 | 24 | [[bench]] 25 | name = "packet_cnt" 26 | harness = false -------------------------------------------------------------------------------- /Cross.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | build-std = true # do not build the std library. has precedence over xargo 3 | xargo = false # enable the use of xargo by default 4 | zig = false # do not use zig cc for the builds 5 | default-target = "armv7-unknown-linux-gnueabihf" # or aarch64-unknown-linux-gnu 6 | pre-build = [ # additional commands to run prior to building the package 7 | "dpkg --add-architecture $CROSS_DEB_ARCH", 8 | "apt-get update && apt-get --assume-yes install libpcap0.8-dev:$CROSS_DEB_ARCH" 9 | ] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ESP-VTX-GS 2 | 3 | Ground Station of ESP-VTX. Rewrite from the c++ origin project: https://github.com/jeanlemotan/esp32-cam-fpv/tree/main/gs. 4 | 5 | Why rewrite it? The main reason is that I don't like cpp, and I felt difficult and worried when I want to add some new features or do some refactoring, 6 | so at last, I try using rust rewrite it. Not for performance or latency consideration, just for more easily maintain the project. 7 | 8 | The new project will not inherit all features from origin project, actually I remove many of them (like GUI/JPEG decode etc. these may be added in the feture, 9 | but for now, I prefer doing these work on Mobile platform.) 10 | 11 | ## Features 12 | - receieve the jpeg parts packets and do FEC 13 | - send data out through udp 14 | - ground2air packets 15 | - multi card support[ongoing] 16 | 17 | ### Send Data Through Udp 18 | you can set the target ip by setting option argument:--target_ip 19 | 20 | for example: 21 | ``` 22 | ./esp-vtx-gs-rs -d DEVICE_NAME --target_ip 192.168.2.101 23 | ``` 24 | 25 | if you want to send jpeg data to mobile phone to work with: 26 | https://github.com/Ncerzzk/ESPVTxAndroid 27 | 28 | - connect mobile phone with the ground station board(PC or some other boards) 29 | - mobile phone share internnet with ground station by usb 30 | - check the mobile phone ip in ground station: `netstat -rn` 31 | - set target_ip to the ip of mobile 32 | 33 | ## Development related 34 | ### bind generate 35 | this project rely on some struct defined in c headers(packet.h and structures.h) as it's not a good way to redefine them in Rust. 36 | 37 | so we use bindgen to generate the bind file: 38 | 39 | ``` 40 | bindgen packets.h -- -x c++ > bind_packet.rs 41 | ``` 42 | 43 | this file should be update and regenerated if c headers are edited in air sied. 44 | -------------------------------------------------------------------------------- /benches/cap_handle.rs: -------------------------------------------------------------------------------- 1 | use std::net::Ipv4Addr; 2 | use std::net::SocketAddr; 3 | use std::net::UdpSocket; 4 | use std::str::FromStr; 5 | use std::time::Duration; 6 | use std::time::SystemTime; 7 | 8 | use esp_vtx_gs_rs::CapHandler; 9 | use esp_vtx_gs_rs::tests::*; 10 | fn main(){ 11 | let mut time_sum:Duration = Duration::default(); 12 | let mut time_sum_process_cap_packet = Duration::default(); 13 | let mut time_sum_process_block_air2ground_packets = Duration::default(); 14 | let mut time_sum_get_jpegout= Duration::default(); 15 | let mut time_sum_udpsend= Duration::default(); 16 | let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); 17 | 18 | let target_ip = Ipv4Addr::from_str("127.0.0.1").unwrap(); 19 | let target = SocketAddr::new(target_ip.into(), 5000); 20 | 21 | for i in 0..1000 { 22 | let mut cap = pcap::Capture::from_file("./cap").unwrap(); 23 | let mut cap_handler = CapHandler::new(FEC_K as u32, FEC_N as u32); 24 | let start_time = SystemTime::now(); 25 | 26 | for _ in 0..10{ 27 | let packet = cap.next_packet().unwrap(); 28 | cap_handler.process_cap_packets(packet); 29 | } 30 | 31 | 32 | time_sum_process_cap_packet += start_time.elapsed().unwrap() / 10; 33 | 34 | let start_time = SystemTime::now(); 35 | for blocks in cap_handler.blocks.keys().cloned().collect::>(){ 36 | if let Some(ret) = cap_handler.process_block(blocks){ 37 | cap_handler.process_air2ground_packets(ret); 38 | } 39 | } 40 | 41 | time_sum_process_block_air2ground_packets += start_time.elapsed().unwrap() / cap_handler.blocks.len() as u32; 42 | 43 | 44 | assert!(cap_handler.finish_frame_index != 0); 45 | let start_time = SystemTime::now(); 46 | let data = cap_handler.frames.get(&cap_handler.finish_frame_index).unwrap().get_jpegdata(); 47 | time_sum_get_jpegout += start_time.elapsed().unwrap(); 48 | 49 | let start_time = SystemTime::now(); 50 | socket.send_to(&data, target).unwrap(); 51 | time_sum_udpsend += start_time.elapsed().unwrap(); 52 | 53 | } 54 | 55 | let get_avg_time = |mut x:Duration,str:&str| { 56 | println!("{} escape avg:{} us",str,x.as_micros() as f32 / 1000.0); 57 | }; 58 | 59 | get_avg_time(time_sum_process_cap_packet,"process_cap_packet"); 60 | get_avg_time(time_sum_process_block_air2ground_packets,"process block and air2ground packet"); 61 | get_avg_time(time_sum_get_jpegout,"get jpeg"); 62 | get_avg_time(time_sum_udpsend,"udp send"); 63 | 64 | } -------------------------------------------------------------------------------- /benches/packet_cnt.rs: -------------------------------------------------------------------------------- 1 | use std::time::SystemTime; 2 | 3 | use clap::{Command, Parser}; 4 | use esp_vtx_gs_rs::device::Device; 5 | 6 | #[derive(Parser)] 7 | #[command(author, version, about, long_about = None, arg_required_else_help(true))] 8 | struct Cli { 9 | #[arg(short, long)] 10 | dev: String, 11 | } 12 | 13 | fn main(){ 14 | let args = Cli::parse(); 15 | let mut wlan_dev = Device::new(args.dev); 16 | 17 | let start_time = SystemTime::now(); 18 | let mut cnt = 0; 19 | while start_time.elapsed().unwrap().as_millis() <= 10* 1000{ 20 | let packet = wlan_dev.cap.next_packet(); 21 | cnt +=1; 22 | } 23 | 24 | println!("recv {} packets in 10s",cnt); 25 | println!("{:?}",wlan_dev.cap.stats()); 26 | } -------------------------------------------------------------------------------- /bind_src/packets.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "structures.h" 4 | 5 | #pragma pack(push, 1) // exact fit - no padding 6 | 7 | enum class WIFI_Rate : uint8_t 8 | { 9 | /* 0 */ RATE_B_2M_CCK, 10 | /* 1 */ RATE_B_2M_CCK_S, 11 | /* 2 */ RATE_B_5_5M_CCK, 12 | /* 3 */ RATE_B_5_5M_CCK_S, 13 | /* 4 */ RATE_B_11M_CCK, 14 | /* 5 */ RATE_B_11M_CCK_S, 15 | 16 | /* 6 */ RATE_G_6M_ODFM, 17 | /* 7 */ RATE_G_9M_ODFM, 18 | /* 8 */ RATE_G_12M_ODFM, 19 | /* 9 */ RATE_G_18M_ODFM, 20 | /* 10 */ RATE_G_24M_ODFM, 21 | /* 11 */ RATE_G_36M_ODFM, 22 | /* 12 */ RATE_G_48M_ODFM, 23 | /* 13 */ RATE_G_54M_ODFM, 24 | 25 | /* 14 */ RATE_N_6_5M_MCS0, 26 | /* 15 */ RATE_N_7_2M_MCS0_S, 27 | /* 16 */ RATE_N_13M_MCS1, 28 | /* 17 */ RATE_N_14_4M_MCS1_S, 29 | /* 18 */ RATE_N_19_5M_MCS2, 30 | /* 19 */ RATE_N_21_7M_MCS2_S, 31 | /* 20 */ RATE_N_26M_MCS3, 32 | /* 21 */ RATE_N_28_9M_MCS3_S, 33 | /* 22 */ RATE_N_39M_MCS4, 34 | /* 23 */ RATE_N_43_3M_MCS4_S, 35 | /* 24 */ RATE_N_52M_MCS5, 36 | /* 25 */ RATE_N_57_8M_MCS5_S, 37 | /* 26 */ RATE_N_58M_MCS6, 38 | /* 27 */ RATE_N_65M_MCS6_S, 39 | /* 28 */ RATE_N_65M_MCS7, 40 | /* 29 */ RATE_N_72M_MCS7_S, 41 | }; 42 | 43 | static constexpr size_t AIR2GROUND_MTU = WLAN_MAX_PAYLOAD_SIZE - 6; //6 is the fec header size 44 | 45 | /////////////////////////////////////////////////////////////////////////////////////// 46 | 47 | constexpr size_t GROUND2AIR_DATA_MAX_SIZE = 64; 48 | 49 | struct Ground2Air_Header 50 | { 51 | enum class Type : uint8_t 52 | { 53 | Data, 54 | Config, 55 | }; 56 | 57 | Type type = Type::Data; 58 | uint32_t size = 0; 59 | uint8_t crc = 0; 60 | }; 61 | 62 | struct Ground2Air_Data_Packet : Ground2Air_Header 63 | { 64 | }; 65 | static_assert(sizeof(Ground2Air_Data_Packet) <= GROUND2AIR_DATA_MAX_SIZE, ""); 66 | 67 | enum class Resolution : uint8_t 68 | { 69 | QVGA, //320x240 70 | CIF, //400x296 71 | HVGA, //480x320 72 | VGA, //640x480 73 | SVGA, //800x600 74 | XGA, //1024x768 75 | SXGA, //1280x1024 76 | UXGA, //1600x1200 77 | }; 78 | 79 | struct Ground2Air_Config_Packet : Ground2Air_Header 80 | { 81 | uint8_t ping = 0; //used for latency measurement 82 | int8_t wifi_power = 20;//dBm 83 | WIFI_Rate wifi_rate = WIFI_Rate::RATE_G_48M_ODFM; 84 | uint8_t fec_codec_k = 2; 85 | uint8_t fec_codec_n = 3; 86 | uint16_t fec_codec_mtu = AIR2GROUND_MTU; 87 | bool dvr_record = false; 88 | 89 | struct Camera 90 | { 91 | Resolution resolution = Resolution::VGA; 92 | uint8_t fps_limit = 30; 93 | uint8_t quality = 8;//0 - 63 94 | int8_t brightness = 0;//-2 - 2 95 | int8_t contrast = 0;//-2 - 2 96 | int8_t saturation = 0;//-2 - 2 97 | int8_t sharpness = -1;//-1 - 6 98 | uint8_t denoise = 0; 99 | uint8_t special_effect = 0;//0 - 6 100 | bool awb = true; 101 | bool awb_gain = true; 102 | uint8_t wb_mode = 0;//0 - 4 103 | bool aec = true; 104 | bool aec2 = true; 105 | int8_t ae_level = 0;//-2 - 2 106 | uint16_t aec_value = 0;//0 - 1200 107 | bool agc = true; 108 | uint8_t agc_gain = 0;//0 - 30 109 | uint8_t gainceiling = 0;//0 - 6 110 | bool bpc = true; 111 | bool wpc = true; 112 | bool raw_gma = false; 113 | bool lenc = true; 114 | bool hmirror = false; 115 | bool vflip = false; 116 | bool dcw = true; 117 | }; 118 | Camera camera; 119 | }; 120 | static_assert(sizeof(Ground2Air_Config_Packet) <= GROUND2AIR_DATA_MAX_SIZE, ""); 121 | 122 | /////////////////////////////////////////////////////////////////////////////////////// 123 | 124 | struct Air2Ground_Header 125 | { 126 | enum class Type : uint8_t 127 | { 128 | Video, 129 | Telemetry 130 | }; 131 | 132 | Type type = Type::Video; 133 | uint32_t size = 0; 134 | uint8_t pong = 0; //used for latency measurement 135 | uint8_t crc = 0; 136 | }; 137 | 138 | struct Air2Ground_Video_Packet : Air2Ground_Header 139 | { 140 | Resolution resolution; 141 | uint8_t part_index : 7; 142 | uint8_t last_part : 1; 143 | uint32_t frame_index = 0; 144 | //data follows 145 | }; 146 | 147 | static_assert(sizeof(Air2Ground_Video_Packet) == 13, ""); 148 | 149 | /////////////////////////////////////////////////////////////////////////////////////// 150 | 151 | #pragma pack(pop) 152 | 153 | -------------------------------------------------------------------------------- /bind_src/structures.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | constexpr uint8_t WLAN_IEEE_HEADER_AIR2GROUND[] = 8 | { 9 | 0x08, 0x01, 0x00, 0x00, 10 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 11 | 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 12 | 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 13 | 0x10, 0x86 14 | }; 15 | constexpr uint8_t WLAN_IEEE_HEADER_GROUND2AIR[] = 16 | { 17 | 0x08, 0x01, 0x00, 0x00, 18 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 19 | 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 20 | 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 21 | 0x10, 0x86 22 | }; 23 | 24 | constexpr size_t WLAN_IEEE_HEADER_SIZE = sizeof(WLAN_IEEE_HEADER_AIR2GROUND); 25 | constexpr size_t WLAN_MAX_PACKET_SIZE = 1500; 26 | constexpr size_t WLAN_MAX_PAYLOAD_SIZE = WLAN_MAX_PACKET_SIZE - WLAN_IEEE_HEADER_SIZE; 27 | 28 | static_assert(WLAN_IEEE_HEADER_SIZE == 24, ""); 29 | 30 | struct Wlan_Outgoing_Packet 31 | { 32 | uint8_t* ptr = nullptr; 33 | uint8_t* payload_ptr = nullptr; 34 | uint16_t size = 0; 35 | uint16_t offset = 0; 36 | }; 37 | 38 | struct Wlan_Incoming_Packet 39 | { 40 | uint8_t* ptr = nullptr; 41 | uint16_t size = 0; 42 | uint16_t offset = 0; 43 | }; 44 | 45 | //////////////////////////////////////////////////////////////////////////////////// 46 | 47 | 48 | -------------------------------------------------------------------------------- /cap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ncerzzk/esp-vtx-gs-rs/72170447d2b58d3256db476d0466cbe2a12983bc/cap -------------------------------------------------------------------------------- /perf_data/release_build_flamegraph.svg: -------------------------------------------------------------------------------- 1 | Flame Graph Reset ZoomSearch <alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter (1 samples, 0.25%)__GI___libc_malloc (1 samples, 0.25%)tcache_get (1 samples, 0.25%)__x64_sys_sendto (4 samples, 0.99%)__sys_sendto (4 samples, 0.99%)inet_sendmsg (3 samples, 0.74%)udp_sendmsg (3 samples, 0.74%)udp_send_skb (3 samples, 0.74%)ip_send_skb (3 samples, 0.74%)ip_output (3 samples, 0.74%)ip_finish_output (3 samples, 0.74%)__ip_finish_output (3 samples, 0.74%)ip_finish_output2 (3 samples, 0.74%)neigh_hh_output (3 samples, 0.74%)__dev_queue_xmit (3 samples, 0.74%)__local_bh_enable_ip (3 samples, 0.74%)do_softirq.part.0 (3 samples, 0.74%)__do_softirq (2 samples, 0.50%)net_rx_action (2 samples, 0.50%)__napi_poll (2 samples, 0.50%)process_backlog (2 samples, 0.50%)__netif_receive_skb (2 samples, 0.50%)__netif_receive_skb_one_core (2 samples, 0.50%)ip_rcv (2 samples, 0.50%)ip_local_deliver (2 samples, 0.50%)ip_local_deliver_finish (2 samples, 0.50%)ip_protocol_deliver_rcu (2 samples, 0.50%)udp_rcv (2 samples, 0.50%)__udp4_lib_rcv (2 samples, 0.50%)__icmp_send (1 samples, 0.25%)_ZN13esp_vtx_gs_rs4main28_$u7b$$u7b$closure$u7d$$u7d$17hfaaabb2cecc5196aE.llvm.5485522086393543559 (5 samples, 1.24%)std::sys_common::net::UdpSocket::send_to (5 samples, 1.24%)__libc_sendto (5 samples, 1.24%)entry_SYSCALL_64_after_hwframe (5 samples, 1.24%)do_syscall_64 (5 samples, 1.24%)syscall_exit_to_user_mode (1 samples, 0.25%)exit_to_user_mode_prepare (1 samples, 0.25%)exit_to_user_mode_loop (1 samples, 0.25%)schedule (1 samples, 0.25%)__schedule (1 samples, 0.25%)prepare_task_switch (1 samples, 0.25%)__perf_event_task_sched_out (1 samples, 0.25%)perf_event_context_sched_out (1 samples, 0.25%)perf_ctx_disable (1 samples, 0.25%)x86_pmu_disable (1 samples, 0.25%)amd_pmu_disable_all (1 samples, 0.25%)amd_pmu_check_overflow (1 samples, 0.25%)amd_pmu_test_overflow_topbit (1 samples, 0.25%)native_read_msr (1 samples, 0.25%)alloc::collections::btree::map::entry::VacantEntry<K,V,A>::insert (1 samples, 0.25%)alloc::collections::btree::node::Handle<alloc::collections::btree::node::NodeRef<alloc::collections::btree::node::marker::Mut,K,V,alloc::collections::btree::node::marker::Leaf>,alloc::collections::btree::node::marker::Edge>::insert_recursing (1 samples, 0.25%)__memcpy_avx_unaligned_erms (1 samples, 0.25%)esp_vtx_gs_rs::CapHandler::process_air2ground_packets (9 samples, 2.23%)e..esp_vtx_gs_rs::Frame::get_jpegdata (2 samples, 0.50%)alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle (1 samples, 0.25%)_ZN5alloc7raw_vec11finish_grow17hde5956d82760e928E.llvm.840880353876214762 (1 samples, 0.25%)__GI___libc_realloc (1 samples, 0.25%)_int_realloc (1 samples, 0.25%)_int_free (1 samples, 0.25%)__GI___libc_free (1 samples, 0.25%)_int_free (1 samples, 0.25%)__memcpy_avx_unaligned_erms (1 samples, 0.25%)alloc::collections::btree::map::entry::OccupiedEntry<K,V,A>::remove_kv (3 samples, 0.74%)alloc::collections::btree::remove::<impl alloc::collections::btree::node::Handle<alloc::collections::btree::node::NodeRef<alloc::collections::btree::node::marker::Mut,K,V,alloc::collections::btree::node::marker::LeafOrInternal>,alloc::collections::btree::node::marker::KV>>::remove_kv_tracking (3 samples, 0.74%)__libc_calloc (1 samples, 0.25%)esp_vtx_gs_rs::CapHandler::process_block_with_fix_buffer (12 samples, 2.98%)esp..zfec_rs::Fec::decode (3 samples, 0.74%)__memset_avx2_unaligned_erms (1 samples, 0.25%)mpt_interrupt (1 samples, 0.25%)asm_common_interrupt (2 samples, 0.50%)common_interrupt (2 samples, 0.50%)__common_interrupt (2 samples, 0.50%)handle_fasteoi_irq (2 samples, 0.50%)handle_irq_event (2 samples, 0.50%)__handle_irq_event_percpu (2 samples, 0.50%)usb_hcd_irq (1 samples, 0.25%)ehci_irq (1 samples, 0.25%)_int_malloc (7 samples, 1.74%)malloc_consolidate (4 samples, 0.99%)__GI___libc_malloc (8 samples, 1.99%)_..tcache_get (1 samples, 0.25%)alloc::collections::btree::map::entry::VacantEntry<K,V,A>::insert (2 samples, 0.50%)hashbrown::map::HashMap<K,V,S,A>::contains_key (1 samples, 0.25%)hashbrown::map::HashMap<K,V,S,A>::insert (3 samples, 0.74%)_ZN9hashbrown3raw21RawTable$LT$T$C$A$GT$14reserve_rehash17hf53c192d430d9694E.llvm.18066530080999219783 (2 samples, 0.50%)__memset_avx2_unaligned_erms (1 samples, 0.25%)<radiotap::RadiotapIteratorIntoIter as core::iter::traits::iterator::Iterator>::next (1 samples, 0.25%)__GI___libc_malloc (2 samples, 0.50%)<radiotap::field::Header as radiotap::field::Field>::from_bytes (6 samples, 1.49%)alloc::raw_vec::RawVec<T,A>::grow_one (6 samples, 1.49%)alloc::raw_vec::finish_grow (6 samples, 1.49%)__GI___libc_realloc (4 samples, 0.99%)_int_realloc (2 samples, 0.50%)__memcpy_avx_unaligned_erms (1 samples, 0.25%)esp_vtx_gs_rs::CapHandler::process_cap_packets (36 samples, 8.93%)esp_vtx_gs_rs..radiotap::Radiotap::from_bytes (16 samples, 3.97%)radi..radiotap::Radiotap::parse (9 samples, 2.23%)r..__GI___libc_malloc (1 samples, 0.25%)tcache_get (1 samples, 0.25%)[libpcap.so.1.10.1] (1 samples, 0.25%)__memcpy_avx_unaligned_erms (1 samples, 0.25%)_copy_from_user (2 samples, 0.50%)eventfd_poll (1 samples, 0.25%)packet_poll (1 samples, 0.25%)__irqentry_text_start (1 samples, 0.25%)update_cfs_group (1 samples, 0.25%)dequeue_task (2 samples, 0.50%)dequeue_task_fair (2 samples, 0.50%)dequeue_entity (2 samples, 0.50%)update_load_avg (1 samples, 0.25%)__update_load_avg_se (1 samples, 0.25%)__perf_event_task_sched_in (20 samples, 4.96%)__perf..perf_ctx_enable (20 samples, 4.96%)perf_c..x86_pmu_enable (20 samples, 4.96%)x86_pm..amd_pmu_enable_all (20 samples, 4.96%)amd_pm..native_write_msr (20 samples, 4.96%)native..asm_common_interrupt (4 samples, 0.99%)common_interrupt (4 samples, 0.99%)__common_interrupt (4 samples, 0.99%)handle_fasteoi_irq (4 samples, 0.99%)handle_irq_event (4 samples, 0.99%)__handle_irq_event_percpu (4 samples, 0.99%)usb_hcd_irq (4 samples, 0.99%)ehci_irq (4 samples, 0.99%)__hrtimer_run_queues (1 samples, 0.25%)tick_sched_timer (1 samples, 0.25%)tick_sched_handle (1 samples, 0.25%)update_process_times (1 samples, 0.25%)scheduler_tick (1 samples, 0.25%)perf_event_task_tick (1 samples, 0.25%)perf_adjust_freq_unthr_context (1 samples, 0.25%)x86_pmu_stop (1 samples, 0.25%)amd_pmu_disable_event (1 samples, 0.25%)amd_pmu_test_overflow_topbit (1 samples, 0.25%)native_read_msr (1 samples, 0.25%)asm_sysvec_apic_timer_interrupt (2 samples, 0.50%)sysvec_apic_timer_interrupt (2 samples, 0.50%)__sysvec_apic_timer_interrupt (2 samples, 0.50%)hrtimer_interrupt (2 samples, 0.50%)tick_program_event (1 samples, 0.25%)clockevents_program_event (1 samples, 0.25%)lapic_next_event (1 samples, 0.25%)native_write_msr (1 samples, 0.25%)finish_task_switch.isra.0 (28 samples, 6.95%)finish_ta..asm_sysvec_call_function_single (1 samples, 0.25%)sysvec_call_function_single (1 samples, 0.25%)native_apic_msr_eoi_write (1 samples, 0.25%)newidle_balance (4 samples, 0.99%)pick_next_task (6 samples, 1.49%)pick_next_task_fair (2 samples, 0.50%)newidle_balance (2 samples, 0.50%)load_balance (1 samples, 0.25%)activate_task (1 samples, 0.25%)enqueue_task (1 samples, 0.25%)enqueue_task_fair (1 samples, 0.25%)enqueue_entity (1 samples, 0.25%)__const_udelay (2 samples, 0.50%)delay_tsc (2 samples, 0.50%)ctx_sched_out (84 samples, 20.84%)ctx_sched_out__pmu_ctx_sched_out (84 samples, 20.84%)__pmu_ctx_sched_outgroup_sched_out (84 samples, 20.84%)group_sched_outevent_sched_out (84 samples, 20.84%)event_sched_outx86_pmu_del (84 samples, 20.84%)x86_pmu_delx86_pmu_stop (84 samples, 20.84%)x86_pmu_stopamd_pmu_disable_event (84 samples, 20.84%)amd_pmu_disable_eventamd_pmu_test_overflow_topbit (82 samples, 20.35%)amd_pmu_test_overflow_topbitnative_read_msr (82 samples, 20.35%)native_read_msr__const_udelay (1 samples, 0.25%)__const_udelay (6 samples, 1.49%)delay_tsc (6 samples, 1.49%)amd_pmu_check_overflow (182 samples, 45.16%)amd_pmu_check_overflowamd_pmu_test_overflow_topbit (176 samples, 43.67%)amd_pmu_test_overflow_topbitnative_read_msr (175 samples, 43.42%)native_read_msrnative_write_msr (7 samples, 1.74%)prepare_task_switch (288 samples, 71.46%)prepare_task_switch__perf_event_task_sched_out (288 samples, 71.46%)__perf_event_task_sched_outperf_event_context_sched_out (288 samples, 71.46%)perf_event_context_sched_outperf_ctx_disable (204 samples, 50.62%)perf_ctx_disablex86_pmu_disable (204 samples, 50.62%)x86_pmu_disableamd_pmu_disable_all (204 samples, 50.62%)amd_pmu_disable_allx86_pmu_disable_all (14 samples, 3.47%)x86..native_read_msr (14 samples, 3.47%)nat..__schedule (327 samples, 81.14%)__schedulepsi_task_switch (1 samples, 0.25%)psi_group_change (1 samples, 0.25%)schedule_hrtimeout_range (328 samples, 81.39%)schedule_hrtimeout_rangeschedule_hrtimeout_range_clock (328 samples, 81.39%)schedule_hrtimeout_range_clockschedule (328 samples, 81.39%)scheduledequeue_task (1 samples, 0.25%)schedule_hrtimeout_range_clock (1 samples, 0.25%)sock_poll (1 samples, 0.25%)packet_poll (1 samples, 0.25%)entry_SYSCALL_64_after_hwframe (337 samples, 83.62%)entry_SYSCALL_64_after_hwframedo_syscall_64 (337 samples, 83.62%)do_syscall_64__x64_sys_poll (337 samples, 83.62%)__x64_sys_polldo_sys_poll (337 samples, 83.62%)do_sys_polldo_poll.constprop.0 (335 samples, 83.13%)do_poll.constprop.0srso_alias_safe_ret (1 samples, 0.25%)pcap::capture::activated::<impl pcap::capture::Capture<T>>::next_packet (341 samples, 84.62%)pcap::capture::activated::<impl pcap::capture::Capture<T>>::next_packetpcap_next_ex (341 samples, 84.62%)pcap_next_ex[libpcap.so.1.10.1] (341 samples, 84.62%)[libpcap.so.1.10.1][libpcap.so.1.10.1] (340 samples, 84.37%)[libpcap.so.1.10.1]__GI___poll (339 samples, 84.12%)__GI___pollsrso_alias_untrain_ret (2 samples, 0.50%)[unknown] (402 samples, 99.75%)[unknown]esp_vtx_gs_rs::main (402 samples, 99.75%)esp_vtx_gs_rs::mainstd::time::SystemTime::elapsed (1 samples, 0.25%)std::sys::pal::unix::time::Timespec::now (1 samples, 0.25%)__GI___clock_gettime (1 samples, 0.25%)all (403 samples, 100%)esp-vtx-gs-rs (403 samples, 100.00%)esp-vtx-gs-rsentry_SYSCALL_64_after_hwframe (1 samples, 0.25%)do_syscall_64 (1 samples, 0.25%)syscall_exit_to_user_mode (1 samples, 0.25%)exit_to_user_mode_prepare (1 samples, 0.25%)exit_to_user_mode_loop (1 samples, 0.25%)arch_do_signal_or_restart (1 samples, 0.25%)get_signal (1 samples, 0.25%)do_group_exit (1 samples, 0.25%)do_exit (1 samples, 0.25%)exit_mm (1 samples, 0.25%)mmput (1 samples, 0.25%)__mmput (1 samples, 0.25%)exit_mmap (1 samples, 0.25%)unmap_vmas (1 samples, 0.25%)unmap_single_vma (1 samples, 0.25%)unmap_page_range (1 samples, 0.25%)zap_pmd_range.isra.0 (1 samples, 0.25%)zap_pte_range (1 samples, 0.25%) -------------------------------------------------------------------------------- /scripts/gst_play.sh: -------------------------------------------------------------------------------- 1 | gst-launch-1.0 udpsrc port=5600 ! application/x-rtp, payload=26 ! rtpjpegdepay ! jpegdec ! videoconvert ! autovideosink -------------------------------------------------------------------------------- /scripts/gst_save.sh: -------------------------------------------------------------------------------- 1 | gst-launch-1.0 udpsrc port=5600 ! application/x-rtp, payload=26 ! rtpjpegdepay ! jpegdec ! videoscale ! videoconvert ! videorate ! video/x-raw,framerate=30/1 ! x264enc tune=zerolatency ! qtmux ! filesink location=video.mp4 -e -------------------------------------------------------------------------------- /scripts/gst_save_play.sh: -------------------------------------------------------------------------------- 1 | gst-launch-1.0 udpsrc port=5600 ! application/x-rtp, payload=26 ! rtpjpegdepay ! jpegdec ! \ 2 | videoscale ! videoconvert ! videorate ! video/x-raw,framerate=30/1 ! tee name=t \ 3 | t. ! queue ! x264enc tune=zerolatency ! qtmux ! filesink location=video.mp4 -e \ 4 | t. ! queue ! autovideosink sync=false 5 | -------------------------------------------------------------------------------- /scripts/gst_stream.sh: -------------------------------------------------------------------------------- 1 | gst-launch-1.0 udpsrc port=12345 ! image/jpeg,width=200,height=200,framerate=30/1 ! rtpjpegpay ! udpsink sync=false host=127.0.0.1 port=5600 2 | -------------------------------------------------------------------------------- /scripts/set_netcard.sh: -------------------------------------------------------------------------------- 1 | 2 | dev_name=$1 3 | 4 | nmcli device set $dev_name managed no 5 | ifconfig $dev_name down 6 | iw dev $dev_name set monitor otherbss 7 | ifconfig $dev_name up 8 | iw dev $dev_name set channel 11 9 | 10 | -------------------------------------------------------------------------------- /src/device.rs: -------------------------------------------------------------------------------- 1 | 2 | use pcap::{Active, Capture, Inactive}; 3 | 4 | pub struct Device { 5 | dev_name: String, 6 | pub cap: Capture, 7 | } 8 | 9 | unsafe impl Sync for Device{} 10 | unsafe impl Send for Device{} 11 | 12 | /* 13 | change channel of device: 14 | refer scripts/set_netcard.sh 15 | */ 16 | impl Device { 17 | pub fn new(dev_name: String) -> Self { 18 | let mut cap: Option> = None; 19 | for i in pcap::Device::list().unwrap() { 20 | if i.name == dev_name { 21 | cap = Some(Capture::from_device(i).unwrap()); 22 | break; 23 | } 24 | } 25 | 26 | if cap.is_none() { 27 | panic!( 28 | "could not find the device:{} or could not open it!", 29 | dev_name 30 | ); 31 | } 32 | 33 | let cap = cap 34 | .unwrap() 35 | .snaplen(1800) 36 | .promisc(true) 37 | .rfmon(true) 38 | .immediate_mode(true) 39 | .buffer_size(16000000); 40 | 41 | let mut active_cap = cap.open().unwrap(); 42 | 43 | active_cap.filter("ether[0x0a:4]==0x11223344 && ether[0x0e:2] == 0x5566", true).unwrap(); 44 | Device { 45 | dev_name, 46 | cap: active_cap, 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/inject.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | net::{Ipv4Addr, SocketAddr, UdpSocket}, 3 | slice, 4 | }; 5 | 6 | use zfec_rs::Fec; 7 | 8 | use crate::{packet_h_bind::Ground2Air_Config_Packet, VtxPacketHeader, VTX_PACKET_HEADER_SIZE}; 9 | 10 | /* 11 | To prevent misunderstanding, "send data to air frame" would be named as inject here. 12 | */ 13 | pub struct InjectHandler { 14 | pub fec_k: u32, 15 | pub fec_n: u32, 16 | fec: Fec, 17 | cur_block_index: u32, 18 | packet_cnt: u32, 19 | raw_data: Vec, 20 | } 21 | 22 | type VtxPacketHeaderRaw = Vec; 23 | type VtxPacketRaw = Vec; 24 | 25 | #[derive(Default)] 26 | #[repr(C, packed)] 27 | struct RadiotapHeader { 28 | version: u8, 29 | pad: u8, 30 | it_len: u16, 31 | it_present: u32, 32 | } 33 | 34 | const WLAN_IEEE_HEADER_GROUND2AIR: [u8; 24] = [ 35 | 0x08, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 36 | 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x10, 0x86, 37 | ]; 38 | 39 | unsafe fn to_u8_slice(origin: &T) -> &[u8] { 40 | let ptr = origin as *const T as *const u8; 41 | slice::from_raw_parts(ptr, std::mem::size_of::()) 42 | } 43 | 44 | impl InjectHandler { 45 | pub fn new(fec_k: u32, fec_n: u32) -> Self { 46 | InjectHandler { 47 | fec_k, 48 | fec_n, 49 | fec: Fec::new(fec_k as usize, fec_n as usize).unwrap(), 50 | cur_block_index: 0, 51 | packet_cnt: 0, 52 | raw_data: Vec::new(), 53 | } 54 | } 55 | 56 | fn new_raw_vtx_packet_header( 57 | block_index: u32, 58 | packet_index: u32, 59 | size: u16, 60 | ) -> VtxPacketHeaderRaw { 61 | let mut header = VtxPacketHeader(vec![0 as u8; VTX_PACKET_HEADER_SIZE]); 62 | header.set_block_index(block_index); 63 | header.set_packet_index(packet_index); 64 | header.set_size(size); 65 | header.0 66 | } 67 | 68 | fn new_raw_radiotap() -> Vec { 69 | let mut ret = Vec::new(); 70 | let mut header = RadiotapHeader::default(); 71 | header.it_present = (1 << 15) | (1 << 17); // IEEE80211_RADIOTAP_DATA_RETRIES and IEEE80211_RADIOTAP_TX_FLAGS 72 | header.it_len = (std::mem::size_of::() + 3) as u16; // cal the len here, after we add header into vec, we could not edit it easily 73 | 74 | ret.extend_from_slice(unsafe { to_u8_slice(&header) }); 75 | let f_t_no_ack = 0x08 as u16; 76 | ret.extend_from_slice(unsafe { to_u8_slice(&f_t_no_ack) }); // IEEE80211_RADIOTAP_TX_FLAGS 77 | ret.push(0x0); // IEEE80211_RADIOTAP_DATA_RETRIES 78 | 79 | ret 80 | } 81 | 82 | fn new_inject_packet() -> VtxPacketRaw { 83 | let mut ret = Vec::new(); 84 | ret.append(&mut Self::new_raw_radiotap()); 85 | ret.extend_from_slice(&WLAN_IEEE_HEADER_GROUND2AIR); 86 | 87 | ret 88 | } 89 | 90 | pub fn push_ground2air_config_packet( 91 | &mut self, 92 | packet: &Ground2Air_Config_Packet, 93 | ) -> Vec { 94 | let mut data = unsafe { 95 | let ptr = packet as *const Ground2Air_Config_Packet as *const u8; 96 | slice::from_raw_parts(ptr, std::mem::size_of::()).to_vec() 97 | }; 98 | data.resize(64, 0); 99 | self.push_data(&data) 100 | } 101 | pub fn push_data(&mut self, data: &[u8]) -> Vec { 102 | assert_eq!( 103 | self.packet_cnt * data.len() as u32, 104 | self.raw_data.len() as u32 105 | ); // to make sure all the packet size is the same 106 | self.raw_data.extend_from_slice(data); 107 | 108 | if self.packet_cnt == self.fec_k - 1 { 109 | // we can start doing fec encode when recv fec_k packets 110 | // handle packet id [fec_k - 1 , fec_n) 111 | // we will get fec packets + 1 normal packet 112 | let fec_ret = self.fec.encode(&self.raw_data).unwrap(); 113 | let mut ret: Vec = Vec::new(); 114 | for mut chunk in fec_ret.0 { 115 | if chunk.index < self.fec_k as usize - 1 { 116 | continue; 117 | } 118 | let mut packet = Self::new_inject_packet(); 119 | let mut header = Self::new_raw_vtx_packet_header( 120 | self.cur_block_index, 121 | chunk.index as u32, 122 | chunk.data.len() as u16, 123 | ); 124 | 125 | packet.append(&mut header); 126 | packet.append(&mut chunk.data); 127 | ret.push(packet); 128 | } 129 | self.cur_block_index += 1; 130 | self.packet_cnt = 0; 131 | self.raw_data.clear(); 132 | return ret; 133 | } else { 134 | // we cannot do fec encode now 135 | // while we can directly return the packet out and inject it 136 | // just need to make sure the packet afterwards will be the same size. 137 | let mut packet: VtxPacketRaw = Self::new_inject_packet(); 138 | let mut header = Self::new_raw_vtx_packet_header( 139 | self.cur_block_index, 140 | self.packet_cnt, 141 | (data.len() + VTX_PACKET_HEADER_SIZE) as u16, 142 | ); 143 | packet.append(&mut header); 144 | packet.extend_from_slice(data); 145 | self.packet_cnt += 1; 146 | vec![packet] 147 | } 148 | } 149 | } 150 | 151 | #[cfg(test)] 152 | mod tests { 153 | mod unittest { 154 | use zfec_rs::Fec; 155 | 156 | #[test] 157 | fn test_fec_encode() { 158 | let a = [ 159 | 1, 41, 0, 0, 0, 182, 0, 20, 12, 2, 3, 190, 5, 0, 0, 0, 8, 0, 0, 0, 255, 0, 0, 1, 1, 160 | 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 161 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 41, 0, 0, 0, 182, 0, 20, 12, 2, 3, 190, 5, 0, 162 | 0, 0, 8, 0, 0, 0, 255, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 163 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164 | ]; 165 | 166 | let fec = Fec::new(2, 6).unwrap(); 167 | let (mut chunks, pad) = fec.encode(&a).unwrap(); 168 | chunks.remove(2); 169 | chunks.remove(4); 170 | chunks.remove(1); 171 | chunks.remove(0); 172 | 173 | let decode = fec.decode(&chunks, pad).unwrap(); 174 | for i in 0..decode.len() { 175 | assert_eq!(a[i], decode[i]); 176 | } 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::{BTreeMap, HashMap}, 3 | fmt::Debug, 4 | mem::{size_of, MaybeUninit}, 5 | time::SystemTime, 6 | }; 7 | 8 | use bitfield::bitfield; 9 | use packet::Air2GroundFramePacket; 10 | use packet_h_bind::WLAN_IEEE_HEADER_SIZE; 11 | use pcap::{Packet}; 12 | use radiotap::Radiotap; 13 | use zfec_rs::{Chunk, Fec}; 14 | pub mod device; 15 | 16 | pub mod inject; 17 | mod packet; 18 | pub mod packet_h_bind; 19 | 20 | pub const VTX_PACKET_HEADER_SIZE:usize = 6; 21 | bitfield! { 22 | #[derive(Clone)] 23 | pub struct VtxPacketHeader([u8]); 24 | impl Debug; 25 | u32; 26 | pub block_index, set_block_index: 23, 0; 27 | pub packet_index, set_packet_index: 31, 24; 28 | u16; 29 | pub size,set_size: 47,32; 30 | } 31 | 32 | // const WLAN_IEEE_HEADER_LEN: usize = 24; // only when the cap linktype is IEEE802_11_RADIOTAP 33 | // use WLAN_IEEE_HEADER_SIZE in packet_h_bind instead. 34 | 35 | #[derive(Clone)] 36 | pub struct VtxPacket { 37 | pub data: Vec, 38 | pub header: VtxPacketHeader>, 39 | } 40 | 41 | impl VtxPacket { 42 | fn from(payload: &[u8], fcs_enable: bool, fec_n: u32) -> Option { 43 | let header = VtxPacketHeader(payload[..VTX_PACKET_HEADER_SIZE].to_vec()); 44 | 45 | if header.packet_index() >= fec_n { 46 | return None; 47 | } 48 | let size = if fcs_enable { 49 | payload.len() - 4 50 | } else { 51 | payload.len() 52 | } as usize; 53 | 54 | Some(VtxPacket { 55 | data: payload[VTX_PACKET_HEADER_SIZE..size].to_vec(), 56 | header, 57 | }) 58 | } 59 | } 60 | 61 | #[derive(Clone)] 62 | pub struct Block { 63 | pub packets: HashMap, 64 | pub fec_packets: Vec, 65 | pub index: u32, 66 | } 67 | 68 | impl Block { 69 | fn new(index: u32) -> Self { 70 | Block { 71 | packets: HashMap::new(), 72 | fec_packets: Vec::new(), 73 | index, 74 | } 75 | } 76 | } 77 | 78 | pub struct Frame { 79 | parts: BTreeMap, 80 | frame_index: u32, 81 | parts_count: u8, 82 | } 83 | 84 | impl Frame { 85 | fn new(frame_index: u32) -> Self { 86 | Frame { 87 | parts: BTreeMap::new(), 88 | frame_index, 89 | parts_count: 0, 90 | } 91 | } 92 | 93 | pub fn get_jpegdata(&self) -> Vec { 94 | let mut ret = Vec::new(); 95 | for (_, air2ground_frame_packet) in &self.parts { 96 | ret.append(&mut air2ground_frame_packet.data.clone()); 97 | } 98 | ret 99 | } 100 | } 101 | pub struct CapHandler { 102 | pub blocks: BTreeMap, 103 | pub frames: BTreeMap, 104 | pub fec_k: u32, 105 | pub fec_n: u32, 106 | fec: Fec, 107 | pub finish_frame_index: u32, 108 | pub current_process_block_index: u32, 109 | callback: Option>, 110 | pub stats:ConnectStats 111 | } 112 | 113 | pub struct ConnectStats { 114 | pub start_time: SystemTime, 115 | pub broken_block_count: u32, 116 | } 117 | 118 | impl ConnectStats { 119 | fn new() -> Self { 120 | ConnectStats { 121 | start_time: SystemTime::now(), 122 | broken_block_count: 0, 123 | } 124 | } 125 | } 126 | 127 | impl CapHandler { 128 | pub fn new(fec_k: u32, fec_n: u32) -> Self { 129 | CapHandler { 130 | blocks: BTreeMap::new(), 131 | frames: BTreeMap::new(), 132 | fec_k, 133 | fec_n, 134 | fec: Fec::new(fec_k as usize, fec_n as usize).unwrap(), 135 | finish_frame_index: 0, 136 | current_process_block_index: 0, 137 | callback: None, 138 | stats:ConnectStats::new(), 139 | } 140 | } 141 | 142 | pub fn do_when_recv_new_frame(&mut self, func: F) 143 | where 144 | F: FnMut(Frame) + Send + 'static, 145 | { 146 | self.callback = Some(Box::new(func)) 147 | } 148 | 149 | pub fn process_cap_packets(&mut self, packet: Packet) { 150 | let radiotap = Radiotap::from_bytes(&packet.data).unwrap(); 151 | if radiotap.flags.unwrap().bad_fcs { 152 | panic!("bad fcs!"); 153 | } 154 | let payload = &packet.data[radiotap.header.length + WLAN_IEEE_HEADER_SIZE..]; 155 | /* 156 | let payload_valid_len = packet.header.len // 1540 157 | - radiotap.header.length as u32 // 36 158 | - WLAN_IEEE_HEADER_LEN as u32 // 24 159 | - if radiotap.flags.unwrap().fcs { 4 } else { 0 }; 160 | */ 161 | 162 | let vtx_packet = VtxPacket::from(payload, radiotap.flags.unwrap().fcs, self.fec_n); 163 | if vtx_packet.is_none() { 164 | return; 165 | } 166 | let vtx_packet = vtx_packet.unwrap(); 167 | 168 | if !self.blocks.contains_key(&vtx_packet.header.block_index()) { 169 | self.blocks.insert( 170 | vtx_packet.header.block_index(), 171 | Block::new(vtx_packet.header.block_index()), 172 | ); 173 | } 174 | let block = self 175 | .blocks 176 | .get_mut(&vtx_packet.header.block_index()) 177 | .unwrap(); 178 | 179 | if vtx_packet.header.packet_index() >= self.fec_k { 180 | if !block 181 | .fec_packets 182 | .iter() 183 | .any(|x| x.header.packet_index() == vtx_packet.header.packet_index()) 184 | { 185 | block.fec_packets.push(vtx_packet); 186 | } 187 | } else { 188 | if !block 189 | .packets 190 | .contains_key(&vtx_packet.header.packet_index()) 191 | { 192 | block 193 | .packets 194 | .insert(vtx_packet.header.packet_index(), vtx_packet); 195 | } 196 | } 197 | } 198 | 199 | /* 200 | process the block by index. 201 | remove this block from blocks hashmap if it could be processed. 202 | */ 203 | #[inline(always)] 204 | pub fn process_block(&mut self, block_index: u32) -> Option> { 205 | let block_ret = self.blocks.get_mut(&block_index); 206 | if block_ret.is_none() { 207 | return None; 208 | } 209 | 210 | let block = block_ret.unwrap(); 211 | let out; 212 | if block.packets.len() == self.fec_k as usize { 213 | let mut entie_out = Vec::::with_capacity(1470 * self.fec_k as usize); 214 | for i in 0..self.fec_k { 215 | let mut packet = block.packets.remove(&i).unwrap(); 216 | entie_out.append(&mut packet.data); 217 | } 218 | out = entie_out; 219 | } else if block.packets.len() + block.fec_packets.len() >= self.fec_k as usize { 220 | let mut chunks = Vec::::new(); 221 | for i in 0..self.fec_k { 222 | let mut packet; 223 | if block.packets.contains_key(&i) { 224 | packet = block.packets.remove(&i).unwrap(); 225 | } else { 226 | packet = block.fec_packets.pop().unwrap(); 227 | } 228 | packet.data.resize(1470, 0); 229 | chunks.push(Chunk::new( 230 | packet.data, 231 | packet.header.packet_index() as usize, 232 | )); 233 | chunks.sort_by(|a, b| a.index.cmp(&b.index)); 234 | } 235 | let fec_out = self.fec.decode(&chunks, 0).unwrap(); 236 | out = fec_out; 237 | } else { 238 | return None; 239 | } 240 | self.current_process_block_index = block_index; 241 | self.blocks.remove(&block_index); 242 | 243 | Some(out) 244 | } 245 | 246 | 247 | pub fn process_air2ground_packets(&mut self, data: Vec) { 248 | assert_eq!(data.len() % 1470, 0); 249 | let mut rest_data = data; 250 | while rest_data.len() >= 1470 { 251 | let tmp = rest_data.split_off(1470); 252 | let packet = Air2GroundFramePacket::from_bytes(rest_data); 253 | rest_data = tmp; 254 | 255 | let frame_index = packet.header.frame_index; 256 | if frame_index < self.finish_frame_index { 257 | // the air side may be restart, so clear blocks and restart 258 | self.blocks.clear(); 259 | self.finish_frame_index = 0; 260 | return ; 261 | } 262 | 263 | if !self.frames.contains_key(&frame_index) { 264 | self.frames.insert(frame_index, Frame::new(frame_index)); 265 | } 266 | 267 | let frame = self.frames.get_mut(&frame_index).unwrap(); 268 | let real_part_index = packet.header.part_index(); 269 | let last_part = packet.header.last_part(); 270 | frame.parts.insert(real_part_index, packet); 271 | 272 | if last_part != 0 { 273 | frame.parts_count = real_part_index + 1; // update the parts_count when recv last part 274 | } 275 | if frame.parts_count != 0 && frame.parts.len() == frame.parts_count as usize { 276 | self.finish_frame_index = frame_index; 277 | if self.callback.is_some() { 278 | (self.callback.as_mut().unwrap())(self.frames.remove(&self.finish_frame_index).unwrap()); 279 | self.frames.clear(); 280 | } 281 | // if self.callback is None, then the frame will not be poped out 282 | // let's keep all the frame when no callback apply 283 | 284 | while let Some(x) = self.blocks.first_key_value(){ 285 | if *x.0 <= self.current_process_block_index { 286 | self.blocks.pop_first().unwrap(); 287 | }else{ 288 | break 289 | } 290 | } 291 | // pop the old and useless blocks 292 | 293 | } 294 | } 295 | } 296 | } 297 | 298 | /* 299 | How the data construct: 300 | CapPacketHeader | RadiotapHeader | WLAN_IEEE_HEADER | VtxPacketHeader | Air2GroundPacketHeader | FramePayload 301 | A jpeg frame could be split to several air2ground packets. 302 | */ 303 | 304 | pub mod tests { 305 | use super::*; 306 | 307 | pub const FEC_K: usize = 2; 308 | pub const FEC_N: usize = 3; 309 | 310 | pub fn init_cap_and_recv_packets(num: usize) -> CapHandler { 311 | let mut cap = pcap::Capture::from_file("/home/ncer/esp-vtx-gs-rs/cap").unwrap(); 312 | let mut cap_handler = CapHandler::new(FEC_K as u32, FEC_N as u32); 313 | for _ in 0..num { 314 | let packet = cap.next_packet().unwrap(); 315 | cap_handler.process_cap_packets(packet); 316 | } 317 | cap_handler 318 | } 319 | 320 | pub fn find_block( 321 | cap_handler: &CapHandler, 322 | packet_len: Option, 323 | fec_packet_len: Option, 324 | ) -> Option<(u32, &Block)> { 325 | let ret = cap_handler.blocks.iter().find(|(_, block)| { 326 | // if no condition provided, return one block 327 | let mut ret = true; 328 | if let Some(p_len) = packet_len { 329 | ret &= block.packets.len() == p_len as usize; 330 | } 331 | if let Some(fec_len) = fec_packet_len { 332 | ret &= block.fec_packets.len() == fec_len as usize; 333 | } 334 | ret 335 | }); 336 | if ret.is_none() { 337 | return None; 338 | } else { 339 | Some((ret.unwrap().0.clone(), ret.unwrap().1)) 340 | } 341 | } 342 | 343 | #[cfg(test)] 344 | mod unittest { 345 | use std::sync::{Arc, RwLock}; 346 | 347 | use super::*; 348 | #[test] 349 | fn test_process_air2ground_packet() { 350 | let mut cap_handler = init_cap_and_recv_packets(40); 351 | let mut keys: Vec = cap_handler.blocks.keys().cloned().collect(); 352 | keys.sort(); 353 | for block_index in keys { 354 | println!("{}", block_index); 355 | if let Some(out) = cap_handler.process_block(block_index) { 356 | cap_handler.process_air2ground_packets(out); 357 | } 358 | } 359 | assert_ne!(cap_handler.finish_frame_index, 0); 360 | } 361 | 362 | #[test] 363 | fn test_call_back() { 364 | let mut cap_handler = init_cap_and_recv_packets(40); 365 | let test_cnt = Arc::new(RwLock::new(0)); 366 | let test_cnt_copy = test_cnt.clone(); 367 | cap_handler.do_when_recv_new_frame(move |_| { 368 | let mut copy = test_cnt_copy.write().unwrap(); 369 | *copy += 1; 370 | println!("frame cnt:{}", *copy); 371 | }); 372 | let keys: Vec = cap_handler.blocks.keys().cloned().collect(); 373 | for idx in keys { 374 | if let Some(out) = cap_handler.process_block(idx) { 375 | cap_handler.process_air2ground_packets(out); 376 | } 377 | } 378 | assert_ne!(cap_handler.frames.len(), *test_cnt.read().unwrap()); 379 | assert!(*test_cnt.read().unwrap() != 0); 380 | } 381 | 382 | #[test] 383 | fn test_process_block_with_buffer() { 384 | let mut cap_hander = init_cap_and_recv_packets(40); 385 | let mut keys: Vec = cap_hander.blocks.keys().cloned().collect(); 386 | keys.sort(); 387 | keys.reverse(); 388 | 389 | assert!(cap_hander.blocks.len() > 5); 390 | cap_hander.process_block_with_fix_buffer(keys[0]); 391 | assert!(cap_hander.blocks.len() == 2); 392 | } 393 | 394 | #[test] 395 | fn test_air2ground_packets_parse() { 396 | let cap_handler = init_cap_and_recv_packets(20); 397 | let (_, block) = cap_handler 398 | .blocks 399 | .iter() 400 | .find(|(_, x)| x.packets.len() == 2) 401 | .unwrap(); 402 | 403 | let packet = block.packets.get(&0).unwrap().clone(); 404 | let d = Air2GroundFramePacket::from_bytes(packet.data); 405 | println!("{:?}", d.header); 406 | } 407 | 408 | #[test] 409 | fn test_process_block() { 410 | let mut cap_handler = init_cap_and_recv_packets(20); 411 | let (idx, _) = find_block(&cap_handler, Some(2), None).unwrap(); 412 | assert!(cap_handler.process_block(idx).is_some()); 413 | 414 | let (idx, _) = find_block(&cap_handler, Some(1), Some(1)).unwrap(); 415 | assert!(cap_handler.process_block(idx).is_some()); 416 | assert!(!cap_handler.blocks.contains_key(&idx)); 417 | 418 | let (idx, _) = find_block(&cap_handler, Some(1), Some(0)).unwrap(); 419 | assert!(cap_handler.process_block(idx).is_none()); 420 | } 421 | 422 | #[test] 423 | fn test_fec_decode() { 424 | let mut cap_handler = init_cap_and_recv_packets(20); 425 | 426 | let (target_idx, target_block) = cap_handler 427 | .blocks 428 | .iter() 429 | .find(|(_, block)| { 430 | block.packets.len() == FEC_K as usize 431 | && block.fec_packets.len() == (FEC_N - FEC_K) as usize 432 | }) 433 | .unwrap(); 434 | 435 | let mut block_copy = target_block.clone(); 436 | let mut block_copy2 = target_block.clone(); 437 | 438 | let origin_out = cap_handler.process_block(target_idx.clone()).unwrap(); 439 | 440 | block_copy.packets.remove(&0).unwrap(); 441 | block_copy2.packets.remove(&1).unwrap(); 442 | 443 | cap_handler.blocks.insert(0, block_copy); 444 | cap_handler.blocks.insert(1, block_copy2); 445 | 446 | let new_out = cap_handler.process_block(0).unwrap(); 447 | let new_out2 = cap_handler.process_block(1).unwrap(); 448 | 449 | assert_eq!(origin_out.len(), new_out.len()); 450 | assert_eq!(origin_out.len(), new_out2.len()); 451 | println!("{:?}", &origin_out[..20]); 452 | println!("{:?}", &new_out[..20]); 453 | println!("{:?}", &origin_out[origin_out.len() - 20..]); 454 | println!("{:?}", &new_out[new_out.len() - 20..]); 455 | for i in 0..origin_out.len() { 456 | assert_eq!(origin_out[i], new_out[i]); 457 | assert_eq!(origin_out[i], new_out2[i]); 458 | } 459 | } 460 | } 461 | } 462 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | net::{Ipv4Addr, SocketAddr, UdpSocket}, 3 | sync::{Arc, RwLock, Condvar, Mutex}, 4 | time::SystemTime, str::FromStr, collections::VecDeque, 5 | }; 6 | 7 | use clap::Parser; 8 | use esp_vtx_gs_rs::{device::Device, packet_h_bind::Ground2Air_Config_Packet, inject::InjectHandler, Frame}; 9 | use esp_vtx_gs_rs::CapHandler; 10 | use pcap::Linktype; 11 | 12 | #[derive(Parser)] 13 | #[command(author, version, about, long_about = None, arg_required_else_help(true))] 14 | struct Cli { 15 | #[arg(short, long)] 16 | dev: Option, 17 | 18 | // output port 19 | #[arg(long, default_value_t = 12345)] 20 | port: u32, 21 | 22 | // control port 23 | #[arg(long)] 24 | control_port: Option, 25 | 26 | // target ip 27 | #[arg(long,default_value = "127.0.0.1")] 28 | target_ip: String, 29 | 30 | } 31 | 32 | /* 33 | How the data construct: 34 | CapPacketHeader | RadiotapHeader | WLAN_IEEE_HEADER | VtxPacketHeader | Air2GroundPacketHeader | FramePayload 35 | A jpeg frame could be split to several air2ground packets. 36 | */ 37 | 38 | /* 39 | Do perf analyze: 40 | 1. install cargo-flamegraph 41 | 42 | cargo install flamegraph 43 | 44 | 2. release build and run: 45 | 46 | caro build --relase 47 | then execute it by sudo 48 | 49 | 3. generate flamegraph: 50 | 51 | sudo sysctl -w kernel.perf_event_paranoid=-1 52 | sudo sysctl -p 53 | sudo flamegraph [-o my_flamegraph.svg] --pid XXX 54 | 55 | 4. measure latency of gstreamer: 56 | 57 | env GST_DEBUG="GST_TRACER:7" GST_TRACERS="latency(flags=element+pipeline)" GST_DEBUG_FILE=./latency.log \ 58 | gst-launch-1.0 udpsrc port=12345 ! image/jpeg,width=200,height=200,framerate=30/1 ! rtpjpegpay mtu=1500 ! udpsink sync=false host=127.0.0.1 port=5600 59 | 60 | 61 | */ 62 | fn main() { 63 | let args = Cli::parse(); 64 | 65 | if let Some(dev) = args.dev { 66 | let wlan_dev = Arc::new(RwLock::new(Device::new(dev))); 67 | let mut cap_hander = CapHandler::new(2, 3); 68 | let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); 69 | 70 | let target_ip = Ipv4Addr::from_str(&args.target_ip.as_str()).unwrap(); 71 | let target = SocketAddr::new(target_ip.into(), args.port as u16); 72 | 73 | let count: Arc> = Arc::new(RwLock::new(0)); 74 | let count2 = count.clone(); 75 | 76 | let send_frames :Arc>> = Arc::new(Mutex::new(VecDeque::new())); 77 | let send_frames_push = send_frames.clone(); 78 | let cond= Arc::new(Condvar::new()); 79 | let cond_push = cond.clone(); 80 | 81 | cap_hander.do_when_recv_new_frame(move |frame| { 82 | let mut vec = send_frames_push.lock().unwrap(); 83 | vec.push_back(frame); 84 | cond_push.notify_all(); 85 | (*count2.write().unwrap()) += 1; 86 | }); 87 | 88 | std::thread::spawn(move ||{ 89 | loop{ 90 | let mut vec = send_frames.lock().unwrap(); 91 | if let Some(frame) = vec.pop_front(){ 92 | socket.send_to(&frame.get_jpegdata(),target).unwrap(); 93 | } 94 | drop(cond.wait(vec)); 95 | } 96 | }); 97 | 98 | 99 | if args.control_port.is_some(){ 100 | let wlan_dev_tx = wlan_dev.clone(); 101 | std::thread::spawn(move ||{ 102 | let config = Ground2Air_Config_Packet::default(); 103 | let mut inject_handler = InjectHandler::new(2,6); 104 | loop{ 105 | let mut wlan_dev = wlan_dev_tx.write().unwrap(); 106 | let push_ret = inject_handler.push_ground2air_config_packet(&config); 107 | for i in push_ret{ 108 | wlan_dev.cap.sendpacket(i).unwrap(); 109 | } 110 | drop(wlan_dev); 111 | std::thread::sleep(std::time::Duration::from_millis(500)); 112 | } 113 | }); 114 | } 115 | 116 | 117 | let mut last_time = std::time::SystemTime::now(); 118 | loop { 119 | let mut wlan_dev_unwrap = wlan_dev.write().unwrap(); 120 | let packet = wlan_dev_unwrap.cap.next_packet().unwrap(); // TODO: change this block action to epoll 121 | 122 | cap_hander.process_cap_packets(packet); 123 | drop(wlan_dev_unwrap); 124 | let block_indexs: Vec = cap_hander.blocks.keys().cloned().collect(); 125 | for block_idx in block_indexs { 126 | if let Some(complete_block) = cap_hander.process_block(block_idx) { 127 | cap_hander.process_air2ground_packets(complete_block); 128 | } 129 | } 130 | 131 | if last_time.elapsed().unwrap().as_secs() >= 1 { 132 | println!("fps:{}", count.read().unwrap()); 133 | *(count.write().unwrap()) = 0; 134 | last_time = SystemTime::now(); 135 | } 136 | 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/packet.rs: -------------------------------------------------------------------------------- 1 | use std::{mem::MaybeUninit, slice}; 2 | 3 | use crc::{Crc, CRC_8_SMBUS}; 4 | 5 | use crate::packet_h_bind::*; 6 | 7 | 8 | pub struct Air2GroundFramePacket { 9 | pub header: Air2Ground_Video_Packet, 10 | pub data: Vec, 11 | } 12 | 13 | static SMBUS_CRC:Crc = Crc::::new(&CRC_8_SMBUS); 14 | 15 | impl Air2Ground_Video_Packet{ 16 | 17 | pub fn crc_check(&mut self) -> bool{ 18 | let origin_crc = self._base.crc; 19 | self.crc_cal() == origin_crc 20 | } 21 | 22 | #[inline(always)] 23 | pub fn crc_cal(&mut self) -> u8{ 24 | self._base.crc = 0; 25 | unsafe{ 26 | let data = slice::from_raw_parts(self as *const Self as *const u8, std::mem::size_of::()); 27 | self._base.crc = SMBUS_CRC.checksum(data); 28 | self._base.crc 29 | } 30 | } 31 | } 32 | 33 | impl Air2GroundFramePacket { 34 | pub fn from_bytes(mut origin_data: Vec) -> Self { 35 | let payload = origin_data.split_off(std::mem::size_of::()); 36 | let mut header = MaybeUninit::::zeroed(); 37 | let mut header_inited; 38 | unsafe { 39 | std::ptr::copy_nonoverlapping( 40 | origin_data.as_ptr() as *const Air2Ground_Video_Packet, 41 | header.as_mut_ptr(), 42 | 1, 43 | ); 44 | header_inited = header.assume_init(); 45 | } 46 | 47 | if !header_inited.crc_check(){ 48 | //panic!(" crc failed!"); 49 | println!("[warning]crc check failed."); // just add a warning, as a crc failed frame is not a big issue on ground station. 50 | } 51 | 52 | Air2GroundFramePacket { 53 | header: header_inited, 54 | data: payload, 55 | } 56 | } 57 | } 58 | 59 | impl Default for Ground2Air_Config_Packet_Camera { 60 | fn default() -> Self { 61 | Self { 62 | resolution: Resolution_QVGA, 63 | fps_limit: 0, 64 | quality: 8, 65 | brightness: 0, 66 | contrast: 0, 67 | saturation: 0, 68 | sharpness: -1, 69 | denoise: 0, 70 | special_effect: 0, 71 | awb: true, 72 | awb_gain: true, 73 | wb_mode: 0, 74 | aec: true, 75 | aec2: true, 76 | ae_level: 0, 77 | aec_value: 0, 78 | agc: true, 79 | agc_gain: 0, 80 | gainceiling: 0, 81 | bpc: true, 82 | wpc: true, 83 | raw_gma: false, 84 | lenc: true, 85 | hmirror: false, 86 | vflip: false, 87 | dcw: true, 88 | } 89 | } 90 | } 91 | 92 | impl Default for Ground2Air_Header { 93 | fn default() -> Self { 94 | Self { 95 | type_: Ground2Air_Header_Type_Config, 96 | size: Default::default(), 97 | crc: Default::default(), 98 | } 99 | } 100 | } 101 | 102 | impl Ground2Air_Config_Packet{ 103 | fn update_crc(&mut self){ 104 | self._base.crc = 0; 105 | unsafe{ 106 | let data = slice::from_raw_parts(self as *const Self as *const u8, std::mem::size_of::()); 107 | self._base.crc = SMBUS_CRC.checksum(data); 108 | } 109 | } 110 | } 111 | 112 | impl Default for Ground2Air_Config_Packet { 113 | fn default() -> Self { 114 | let mut ret = Self { 115 | _base: Default::default(), 116 | ping: Default::default(), 117 | wifi_power: 20, 118 | wifi_rate: WIFI_Rate_RATE_G_48M_ODFM, 119 | fec_codec_k: 2, 120 | fec_codec_n: 3, 121 | fec_codec_mtu: 1470, 122 | dvr_record: false, 123 | camera: Default::default(), 124 | }; 125 | ret._base.size = std::mem::size_of::() as u32; 126 | ret.update_crc(); 127 | ret 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/packet_h_bind.rs: -------------------------------------------------------------------------------- 1 | #![allow(warnings)] 2 | /* automatically generated by rust-bindgen 0.69.4 */ 3 | 4 | #[repr(C)] 5 | #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] 6 | pub struct __BindgenBitfieldUnit { 7 | storage: Storage, 8 | } 9 | impl __BindgenBitfieldUnit { 10 | #[inline] 11 | pub const fn new(storage: Storage) -> Self { 12 | Self { storage } 13 | } 14 | } 15 | impl __BindgenBitfieldUnit 16 | where 17 | Storage: AsRef<[u8]> + AsMut<[u8]>, 18 | { 19 | #[inline] 20 | pub fn get_bit(&self, index: usize) -> bool { 21 | debug_assert!(index / 8 < self.storage.as_ref().len()); 22 | let byte_index = index / 8; 23 | let byte = self.storage.as_ref()[byte_index]; 24 | let bit_index = if cfg!(target_endian = "big") { 25 | 7 - (index % 8) 26 | } else { 27 | index % 8 28 | }; 29 | let mask = 1 << bit_index; 30 | byte & mask == mask 31 | } 32 | #[inline] 33 | pub fn set_bit(&mut self, index: usize, val: bool) { 34 | debug_assert!(index / 8 < self.storage.as_ref().len()); 35 | let byte_index = index / 8; 36 | let byte = &mut self.storage.as_mut()[byte_index]; 37 | let bit_index = if cfg!(target_endian = "big") { 38 | 7 - (index % 8) 39 | } else { 40 | index % 8 41 | }; 42 | let mask = 1 << bit_index; 43 | if val { 44 | *byte |= mask; 45 | } else { 46 | *byte &= !mask; 47 | } 48 | } 49 | #[inline] 50 | pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { 51 | debug_assert!(bit_width <= 64); 52 | debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); 53 | debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); 54 | let mut val = 0; 55 | for i in 0..(bit_width as usize) { 56 | if self.get_bit(i + bit_offset) { 57 | let index = if cfg!(target_endian = "big") { 58 | bit_width as usize - 1 - i 59 | } else { 60 | i 61 | }; 62 | val |= 1 << index; 63 | } 64 | } 65 | val 66 | } 67 | #[inline] 68 | pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { 69 | debug_assert!(bit_width <= 64); 70 | debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); 71 | debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); 72 | for i in 0..(bit_width as usize) { 73 | let mask = 1 << i; 74 | let val_bit_is_set = val & mask == mask; 75 | let index = if cfg!(target_endian = "big") { 76 | bit_width as usize - 1 - i 77 | } else { 78 | i 79 | }; 80 | self.set_bit(index + bit_offset, val_bit_is_set); 81 | } 82 | } 83 | } 84 | pub const _GLIBCXX_CXX_CONFIG_H: u32 = 1; 85 | pub const _GLIBCXX_RELEASE: u32 = 11; 86 | pub const __GLIBCXX__: u32 = 20230528; 87 | pub const _GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY: u32 = 1; 88 | pub const _GLIBCXX_USE_DEPRECATED: u32 = 1; 89 | pub const _GLIBCXX_EXTERN_TEMPLATE: u32 = 1; 90 | pub const _GLIBCXX_USE_DUAL_ABI: u32 = 1; 91 | pub const _GLIBCXX_USE_CXX11_ABI: u32 = 1; 92 | pub const _GLIBCXX_INLINE_VERSION: u32 = 0; 93 | pub const _GLIBCXX_USE_ALLOCATOR_NEW: u32 = 1; 94 | pub const _GLIBCXX_OS_DEFINES: u32 = 1; 95 | pub const __NO_CTYPE: u32 = 1; 96 | pub const _FEATURES_H: u32 = 1; 97 | pub const _ISOC95_SOURCE: u32 = 1; 98 | pub const _ISOC99_SOURCE: u32 = 1; 99 | pub const _ISOC11_SOURCE: u32 = 1; 100 | pub const _ISOC2X_SOURCE: u32 = 1; 101 | pub const _POSIX_SOURCE: u32 = 1; 102 | pub const _POSIX_C_SOURCE: u32 = 200809; 103 | pub const _XOPEN_SOURCE: u32 = 700; 104 | pub const _XOPEN_SOURCE_EXTENDED: u32 = 1; 105 | pub const _LARGEFILE64_SOURCE: u32 = 1; 106 | pub const _DEFAULT_SOURCE: u32 = 1; 107 | pub const _ATFILE_SOURCE: u32 = 1; 108 | pub const _DYNAMIC_STACK_SIZE_SOURCE: u32 = 1; 109 | pub const __GLIBC_USE_ISOC2X: u32 = 1; 110 | pub const __USE_ISOC11: u32 = 1; 111 | pub const __USE_ISOC99: u32 = 1; 112 | pub const __USE_ISOC95: u32 = 1; 113 | pub const __USE_ISOCXX11: u32 = 1; 114 | pub const __USE_POSIX: u32 = 1; 115 | pub const __USE_POSIX2: u32 = 1; 116 | pub const __USE_POSIX199309: u32 = 1; 117 | pub const __USE_POSIX199506: u32 = 1; 118 | pub const __USE_XOPEN2K: u32 = 1; 119 | pub const __USE_XOPEN2K8: u32 = 1; 120 | pub const __USE_XOPEN: u32 = 1; 121 | pub const __USE_XOPEN_EXTENDED: u32 = 1; 122 | pub const __USE_UNIX98: u32 = 1; 123 | pub const _LARGEFILE_SOURCE: u32 = 1; 124 | pub const __USE_XOPEN2K8XSI: u32 = 1; 125 | pub const __USE_XOPEN2KXSI: u32 = 1; 126 | pub const __USE_LARGEFILE: u32 = 1; 127 | pub const __USE_LARGEFILE64: u32 = 1; 128 | pub const __WORDSIZE: u32 = 64; 129 | pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1; 130 | pub const __SYSCALL_WORDSIZE: u32 = 64; 131 | pub const __TIMESIZE: u32 = 64; 132 | pub const __USE_MISC: u32 = 1; 133 | pub const __USE_ATFILE: u32 = 1; 134 | pub const __USE_DYNAMIC_STACK_SIZE: u32 = 1; 135 | pub const __USE_GNU: u32 = 1; 136 | pub const __USE_FORTIFY_LEVEL: u32 = 0; 137 | pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0; 138 | pub const __GLIBC_USE_DEPRECATED_SCANF: u32 = 0; 139 | pub const _STDC_PREDEF_H: u32 = 1; 140 | pub const __STDC_IEC_559__: u32 = 1; 141 | pub const __STDC_IEC_60559_BFP__: u32 = 201404; 142 | pub const __STDC_IEC_559_COMPLEX__: u32 = 1; 143 | pub const __STDC_IEC_60559_COMPLEX__: u32 = 201404; 144 | pub const __STDC_ISO_10646__: u32 = 201706; 145 | pub const __GNU_LIBRARY__: u32 = 6; 146 | pub const __GLIBC__: u32 = 2; 147 | pub const __GLIBC_MINOR__: u32 = 35; 148 | pub const _SYS_CDEFS_H: u32 = 1; 149 | pub const __glibc_c99_flexarr_available: u32 = 1; 150 | pub const __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI: u32 = 0; 151 | pub const __HAVE_GENERIC_SELECTION: u32 = 0; 152 | pub const _GLIBCXX_GTHREAD_USE_WEAK: u32 = 0; 153 | pub const _GLIBCXX_CPU_DEFINES: u32 = 1; 154 | pub const _GLIBCXX_FAST_MATH: u32 = 0; 155 | pub const _GLIBCXX_USE_FLOAT128: u32 = 1; 156 | pub const _GLIBCXX_FLOAT_IS_IEEE_BINARY32: u32 = 1; 157 | pub const _GLIBCXX_DOUBLE_IS_IEEE_BINARY64: u32 = 1; 158 | pub const _GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP: u32 = 1; 159 | pub const _GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE: u32 = 1; 160 | pub const _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED: u32 = 1; 161 | pub const _GLIBCXX_HAVE_BUILTIN_IS_SAME: u32 = 1; 162 | pub const _GLIBCXX_HAVE_BUILTIN_LAUNDER: u32 = 1; 163 | pub const _GLIBCXX_HAVE_ACOSF: u32 = 1; 164 | pub const _GLIBCXX_HAVE_ACOSL: u32 = 1; 165 | pub const _GLIBCXX_HAVE_ALIGNED_ALLOC: u32 = 1; 166 | pub const _GLIBCXX_HAVE_ARPA_INET_H: u32 = 1; 167 | pub const _GLIBCXX_HAVE_ASINF: u32 = 1; 168 | pub const _GLIBCXX_HAVE_ASINL: u32 = 1; 169 | pub const _GLIBCXX_HAVE_AS_SYMVER_DIRECTIVE: u32 = 1; 170 | pub const _GLIBCXX_HAVE_ATAN2F: u32 = 1; 171 | pub const _GLIBCXX_HAVE_ATAN2L: u32 = 1; 172 | pub const _GLIBCXX_HAVE_ATANF: u32 = 1; 173 | pub const _GLIBCXX_HAVE_ATANL: u32 = 1; 174 | pub const _GLIBCXX_HAVE_ATOMIC_LOCK_POLICY: u32 = 1; 175 | pub const _GLIBCXX_HAVE_AT_QUICK_EXIT: u32 = 1; 176 | pub const _GLIBCXX_HAVE_CEILF: u32 = 1; 177 | pub const _GLIBCXX_HAVE_CEILL: u32 = 1; 178 | pub const _GLIBCXX_HAVE_COMPLEX_H: u32 = 1; 179 | pub const _GLIBCXX_HAVE_COSF: u32 = 1; 180 | pub const _GLIBCXX_HAVE_COSHF: u32 = 1; 181 | pub const _GLIBCXX_HAVE_COSHL: u32 = 1; 182 | pub const _GLIBCXX_HAVE_COSL: u32 = 1; 183 | pub const _GLIBCXX_HAVE_DIRENT_H: u32 = 1; 184 | pub const _GLIBCXX_HAVE_DLFCN_H: u32 = 1; 185 | pub const _GLIBCXX_HAVE_ENDIAN_H: u32 = 1; 186 | pub const _GLIBCXX_HAVE_EXCEPTION_PTR_SINCE_GCC46: u32 = 1; 187 | pub const _GLIBCXX_HAVE_EXECINFO_H: u32 = 1; 188 | pub const _GLIBCXX_HAVE_EXPF: u32 = 1; 189 | pub const _GLIBCXX_HAVE_EXPL: u32 = 1; 190 | pub const _GLIBCXX_HAVE_FABSF: u32 = 1; 191 | pub const _GLIBCXX_HAVE_FABSL: u32 = 1; 192 | pub const _GLIBCXX_HAVE_FCNTL_H: u32 = 1; 193 | pub const _GLIBCXX_HAVE_FENV_H: u32 = 1; 194 | pub const _GLIBCXX_HAVE_FINITE: u32 = 1; 195 | pub const _GLIBCXX_HAVE_FINITEF: u32 = 1; 196 | pub const _GLIBCXX_HAVE_FINITEL: u32 = 1; 197 | pub const _GLIBCXX_HAVE_FLOAT_H: u32 = 1; 198 | pub const _GLIBCXX_HAVE_FLOORF: u32 = 1; 199 | pub const _GLIBCXX_HAVE_FLOORL: u32 = 1; 200 | pub const _GLIBCXX_HAVE_FMODF: u32 = 1; 201 | pub const _GLIBCXX_HAVE_FMODL: u32 = 1; 202 | pub const _GLIBCXX_HAVE_FREXPF: u32 = 1; 203 | pub const _GLIBCXX_HAVE_FREXPL: u32 = 1; 204 | pub const _GLIBCXX_HAVE_GETIPINFO: u32 = 1; 205 | pub const _GLIBCXX_HAVE_GETS: u32 = 1; 206 | pub const _GLIBCXX_HAVE_HYPOT: u32 = 1; 207 | pub const _GLIBCXX_HAVE_HYPOTF: u32 = 1; 208 | pub const _GLIBCXX_HAVE_HYPOTL: u32 = 1; 209 | pub const _GLIBCXX_HAVE_ICONV: u32 = 1; 210 | pub const _GLIBCXX_HAVE_INT64_T: u32 = 1; 211 | pub const _GLIBCXX_HAVE_INT64_T_LONG: u32 = 1; 212 | pub const _GLIBCXX_HAVE_INTTYPES_H: u32 = 1; 213 | pub const _GLIBCXX_HAVE_ISINFF: u32 = 1; 214 | pub const _GLIBCXX_HAVE_ISINFL: u32 = 1; 215 | pub const _GLIBCXX_HAVE_ISNANF: u32 = 1; 216 | pub const _GLIBCXX_HAVE_ISNANL: u32 = 1; 217 | pub const _GLIBCXX_HAVE_ISWBLANK: u32 = 1; 218 | pub const _GLIBCXX_HAVE_LC_MESSAGES: u32 = 1; 219 | pub const _GLIBCXX_HAVE_LDEXPF: u32 = 1; 220 | pub const _GLIBCXX_HAVE_LDEXPL: u32 = 1; 221 | pub const _GLIBCXX_HAVE_LIBINTL_H: u32 = 1; 222 | pub const _GLIBCXX_HAVE_LIMIT_AS: u32 = 1; 223 | pub const _GLIBCXX_HAVE_LIMIT_DATA: u32 = 1; 224 | pub const _GLIBCXX_HAVE_LIMIT_FSIZE: u32 = 1; 225 | pub const _GLIBCXX_HAVE_LIMIT_RSS: u32 = 1; 226 | pub const _GLIBCXX_HAVE_LIMIT_VMEM: u32 = 0; 227 | pub const _GLIBCXX_HAVE_LINK: u32 = 1; 228 | pub const _GLIBCXX_HAVE_LINUX_FUTEX: u32 = 1; 229 | pub const _GLIBCXX_HAVE_LINUX_RANDOM_H: u32 = 1; 230 | pub const _GLIBCXX_HAVE_LINUX_TYPES_H: u32 = 1; 231 | pub const _GLIBCXX_HAVE_LOCALE_H: u32 = 1; 232 | pub const _GLIBCXX_HAVE_LOG10F: u32 = 1; 233 | pub const _GLIBCXX_HAVE_LOG10L: u32 = 1; 234 | pub const _GLIBCXX_HAVE_LOGF: u32 = 1; 235 | pub const _GLIBCXX_HAVE_LOGL: u32 = 1; 236 | pub const _GLIBCXX_HAVE_MBSTATE_T: u32 = 1; 237 | pub const _GLIBCXX_HAVE_MEMALIGN: u32 = 1; 238 | pub const _GLIBCXX_HAVE_MEMORY_H: u32 = 1; 239 | pub const _GLIBCXX_HAVE_MODF: u32 = 1; 240 | pub const _GLIBCXX_HAVE_MODFF: u32 = 1; 241 | pub const _GLIBCXX_HAVE_MODFL: u32 = 1; 242 | pub const _GLIBCXX_HAVE_NETDB_H: u32 = 1; 243 | pub const _GLIBCXX_HAVE_NETINET_IN_H: u32 = 1; 244 | pub const _GLIBCXX_HAVE_NETINET_TCP_H: u32 = 1; 245 | pub const _GLIBCXX_HAVE_POLL: u32 = 1; 246 | pub const _GLIBCXX_HAVE_POLL_H: u32 = 1; 247 | pub const _GLIBCXX_HAVE_POSIX_MEMALIGN: u32 = 1; 248 | pub const _GLIBCXX_HAVE_POSIX_SEMAPHORE: u32 = 1; 249 | pub const _GLIBCXX_HAVE_POWF: u32 = 1; 250 | pub const _GLIBCXX_HAVE_POWL: u32 = 1; 251 | pub const _GLIBCXX_HAVE_QUICK_EXIT: u32 = 1; 252 | pub const _GLIBCXX_HAVE_READLINK: u32 = 1; 253 | pub const _GLIBCXX_HAVE_SECURE_GETENV: u32 = 1; 254 | pub const _GLIBCXX_HAVE_SETENV: u32 = 1; 255 | pub const _GLIBCXX_HAVE_SINCOS: u32 = 1; 256 | pub const _GLIBCXX_HAVE_SINCOSF: u32 = 1; 257 | pub const _GLIBCXX_HAVE_SINCOSL: u32 = 1; 258 | pub const _GLIBCXX_HAVE_SINF: u32 = 1; 259 | pub const _GLIBCXX_HAVE_SINHF: u32 = 1; 260 | pub const _GLIBCXX_HAVE_SINHL: u32 = 1; 261 | pub const _GLIBCXX_HAVE_SINL: u32 = 1; 262 | pub const _GLIBCXX_HAVE_SOCKATMARK: u32 = 1; 263 | pub const _GLIBCXX_HAVE_SQRTF: u32 = 1; 264 | pub const _GLIBCXX_HAVE_SQRTL: u32 = 1; 265 | pub const _GLIBCXX_HAVE_STDALIGN_H: u32 = 1; 266 | pub const _GLIBCXX_HAVE_STDBOOL_H: u32 = 1; 267 | pub const _GLIBCXX_HAVE_STDINT_H: u32 = 1; 268 | pub const _GLIBCXX_HAVE_STDLIB_H: u32 = 1; 269 | pub const _GLIBCXX_HAVE_STRERROR_L: u32 = 1; 270 | pub const _GLIBCXX_HAVE_STRERROR_R: u32 = 1; 271 | pub const _GLIBCXX_HAVE_STRINGS_H: u32 = 1; 272 | pub const _GLIBCXX_HAVE_STRING_H: u32 = 1; 273 | pub const _GLIBCXX_HAVE_STRTOF: u32 = 1; 274 | pub const _GLIBCXX_HAVE_STRTOLD: u32 = 1; 275 | pub const _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE: u32 = 1; 276 | pub const _GLIBCXX_HAVE_STRXFRM_L: u32 = 1; 277 | pub const _GLIBCXX_HAVE_SYMLINK: u32 = 1; 278 | pub const _GLIBCXX_HAVE_SYMVER_SYMBOL_RENAMING_RUNTIME_SUPPORT: u32 = 1; 279 | pub const _GLIBCXX_HAVE_SYS_IOCTL_H: u32 = 1; 280 | pub const _GLIBCXX_HAVE_SYS_IPC_H: u32 = 1; 281 | pub const _GLIBCXX_HAVE_SYS_PARAM_H: u32 = 1; 282 | pub const _GLIBCXX_HAVE_SYS_RESOURCE_H: u32 = 1; 283 | pub const _GLIBCXX_HAVE_SYS_SDT_H: u32 = 1; 284 | pub const _GLIBCXX_HAVE_SYS_SEM_H: u32 = 1; 285 | pub const _GLIBCXX_HAVE_SYS_SOCKET_H: u32 = 1; 286 | pub const _GLIBCXX_HAVE_SYS_STATVFS_H: u32 = 1; 287 | pub const _GLIBCXX_HAVE_SYS_STAT_H: u32 = 1; 288 | pub const _GLIBCXX_HAVE_SYS_SYSINFO_H: u32 = 1; 289 | pub const _GLIBCXX_HAVE_SYS_TIME_H: u32 = 1; 290 | pub const _GLIBCXX_HAVE_SYS_TYPES_H: u32 = 1; 291 | pub const _GLIBCXX_HAVE_SYS_UIO_H: u32 = 1; 292 | pub const _GLIBCXX_HAVE_S_ISREG: u32 = 1; 293 | pub const _GLIBCXX_HAVE_TANF: u32 = 1; 294 | pub const _GLIBCXX_HAVE_TANHF: u32 = 1; 295 | pub const _GLIBCXX_HAVE_TANHL: u32 = 1; 296 | pub const _GLIBCXX_HAVE_TANL: u32 = 1; 297 | pub const _GLIBCXX_HAVE_TGMATH_H: u32 = 1; 298 | pub const _GLIBCXX_HAVE_TIMESPEC_GET: u32 = 1; 299 | pub const _GLIBCXX_HAVE_TLS: u32 = 1; 300 | pub const _GLIBCXX_HAVE_TRUNCATE: u32 = 1; 301 | pub const _GLIBCXX_HAVE_UCHAR_H: u32 = 1; 302 | pub const _GLIBCXX_HAVE_UNISTD_H: u32 = 1; 303 | pub const _GLIBCXX_HAVE_USELOCALE: u32 = 1; 304 | pub const _GLIBCXX_HAVE_UTIME_H: u32 = 1; 305 | pub const _GLIBCXX_HAVE_VFWSCANF: u32 = 1; 306 | pub const _GLIBCXX_HAVE_VSWSCANF: u32 = 1; 307 | pub const _GLIBCXX_HAVE_VWSCANF: u32 = 1; 308 | pub const _GLIBCXX_HAVE_WCHAR_H: u32 = 1; 309 | pub const _GLIBCXX_HAVE_WCSTOF: u32 = 1; 310 | pub const _GLIBCXX_HAVE_WCTYPE_H: u32 = 1; 311 | pub const _GLIBCXX_HAVE_WRITEV: u32 = 1; 312 | pub const _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL: u32 = 1; 313 | pub const _GLIBCXX_LT_OBJDIR: &[u8; 7] = b".libs/\0"; 314 | pub const _GLIBCXX_PACKAGE_BUGREPORT: &[u8; 1] = b"\0"; 315 | pub const _GLIBCXX_PACKAGE_NAME: &[u8; 15] = b"package-unused\0"; 316 | pub const _GLIBCXX_PACKAGE_STRING: &[u8; 30] = b"package-unused version-unused\0"; 317 | pub const _GLIBCXX_PACKAGE_TARNAME: &[u8; 10] = b"libstdc++\0"; 318 | pub const _GLIBCXX_PACKAGE_URL: &[u8; 1] = b"\0"; 319 | pub const _GLIBCXX_PACKAGE__GLIBCXX_VERSION: &[u8; 15] = b"version-unused\0"; 320 | pub const _GLIBCXX_STDC_HEADERS: u32 = 1; 321 | pub const _GLIBCXX_DARWIN_USE_64_BIT_INODE: u32 = 1; 322 | pub const _GLIBCXX11_USE_C99_COMPLEX: u32 = 1; 323 | pub const _GLIBCXX11_USE_C99_MATH: u32 = 1; 324 | pub const _GLIBCXX11_USE_C99_STDIO: u32 = 1; 325 | pub const _GLIBCXX11_USE_C99_STDLIB: u32 = 1; 326 | pub const _GLIBCXX11_USE_C99_WCHAR: u32 = 1; 327 | pub const _GLIBCXX98_USE_C99_COMPLEX: u32 = 1; 328 | pub const _GLIBCXX98_USE_C99_MATH: u32 = 1; 329 | pub const _GLIBCXX98_USE_C99_STDIO: u32 = 1; 330 | pub const _GLIBCXX98_USE_C99_STDLIB: u32 = 1; 331 | pub const _GLIBCXX98_USE_C99_WCHAR: u32 = 1; 332 | pub const _GLIBCXX_ATOMIC_BUILTINS: u32 = 1; 333 | pub const _GLIBCXX_FULLY_DYNAMIC_STRING: u32 = 0; 334 | pub const _GLIBCXX_HAS_GTHREADS: u32 = 1; 335 | pub const _GLIBCXX_HOSTED: u32 = 1; 336 | pub const _GLIBCXX_RES_LIMITS: u32 = 1; 337 | pub const _GLIBCXX_STDIO_EOF: i32 = -1; 338 | pub const _GLIBCXX_STDIO_SEEK_CUR: u32 = 1; 339 | pub const _GLIBCXX_STDIO_SEEK_END: u32 = 2; 340 | pub const _GLIBCXX_SYMVER: u32 = 1; 341 | pub const _GLIBCXX_SYMVER_GNU: u32 = 1; 342 | pub const _GLIBCXX_USE_C11_UCHAR_CXX11: u32 = 1; 343 | pub const _GLIBCXX_USE_C99: u32 = 1; 344 | pub const _GLIBCXX_USE_C99_COMPLEX_TR1: u32 = 1; 345 | pub const _GLIBCXX_USE_C99_CTYPE_TR1: u32 = 1; 346 | pub const _GLIBCXX_USE_C99_FENV_TR1: u32 = 1; 347 | pub const _GLIBCXX_USE_C99_INTTYPES_TR1: u32 = 1; 348 | pub const _GLIBCXX_USE_C99_INTTYPES_WCHAR_T_TR1: u32 = 1; 349 | pub const _GLIBCXX_USE_C99_MATH_TR1: u32 = 1; 350 | pub const _GLIBCXX_USE_C99_STDINT_TR1: u32 = 1; 351 | pub const _GLIBCXX_USE_CLOCK_MONOTONIC: u32 = 1; 352 | pub const _GLIBCXX_USE_CLOCK_REALTIME: u32 = 1; 353 | pub const _GLIBCXX_USE_DECIMAL_FLOAT: u32 = 1; 354 | pub const _GLIBCXX_USE_DEV_RANDOM: u32 = 1; 355 | pub const _GLIBCXX_USE_FCHMOD: u32 = 1; 356 | pub const _GLIBCXX_USE_FCHMODAT: u32 = 1; 357 | pub const _GLIBCXX_USE_GETTIMEOFDAY: u32 = 1; 358 | pub const _GLIBCXX_USE_GET_NPROCS: u32 = 1; 359 | pub const _GLIBCXX_USE_INT128: u32 = 1; 360 | pub const _GLIBCXX_USE_LFS: u32 = 1; 361 | pub const _GLIBCXX_USE_LONG_LONG: u32 = 1; 362 | pub const _GLIBCXX_USE_LSTAT: u32 = 1; 363 | pub const _GLIBCXX_USE_NANOSLEEP: u32 = 1; 364 | pub const _GLIBCXX_USE_NLS: u32 = 1; 365 | pub const _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT: u32 = 1; 366 | pub const _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK: u32 = 1; 367 | pub const _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK: u32 = 1; 368 | pub const _GLIBCXX_USE_PTHREAD_RWLOCK_T: u32 = 1; 369 | pub const _GLIBCXX_USE_RANDOM_TR1: u32 = 1; 370 | pub const _GLIBCXX_USE_REALPATH: u32 = 1; 371 | pub const _GLIBCXX_USE_SCHED_YIELD: u32 = 1; 372 | pub const _GLIBCXX_USE_SC_NPROCESSORS_ONLN: u32 = 1; 373 | pub const _GLIBCXX_USE_SENDFILE: u32 = 1; 374 | pub const _GLIBCXX_USE_ST_MTIM: u32 = 1; 375 | pub const _GLIBCXX_USE_TMPNAM: u32 = 1; 376 | pub const _GLIBCXX_USE_UTIME: u32 = 1; 377 | pub const _GLIBCXX_USE_UTIMENSAT: u32 = 1; 378 | pub const _GLIBCXX_USE_WCHAR_T: u32 = 1; 379 | pub const _GLIBCXX_VERBOSE: u32 = 1; 380 | pub const _GLIBCXX_X86_RDRAND: u32 = 1; 381 | pub const _GLIBCXX_X86_RDSEED: u32 = 1; 382 | pub const _GTHREAD_USE_MUTEX_TIMEDLOCK: u32 = 1; 383 | pub const _ASSERT_H: u32 = 1; 384 | pub const _STRING_H: u32 = 1; 385 | pub const __GLIBC_USE_LIB_EXT2: u32 = 1; 386 | pub const __GLIBC_USE_IEC_60559_BFP_EXT: u32 = 1; 387 | pub const __GLIBC_USE_IEC_60559_BFP_EXT_C2X: u32 = 1; 388 | pub const __GLIBC_USE_IEC_60559_EXT: u32 = 1; 389 | pub const __GLIBC_USE_IEC_60559_FUNCS_EXT: u32 = 1; 390 | pub const __GLIBC_USE_IEC_60559_FUNCS_EXT_C2X: u32 = 1; 391 | pub const __GLIBC_USE_IEC_60559_TYPES_EXT: u32 = 1; 392 | pub const _BITS_TYPES_LOCALE_T_H: u32 = 1; 393 | pub const _BITS_TYPES___LOCALE_T_H: u32 = 1; 394 | pub const _STRINGS_H: u32 = 1; 395 | pub const _GLIBCXX_CSTRING: u32 = 1; 396 | pub const _GLIBCXX_CSTDINT: u32 = 1; 397 | pub const _STDINT_H: u32 = 1; 398 | pub const _BITS_TYPES_H: u32 = 1; 399 | pub const _BITS_TYPESIZES_H: u32 = 1; 400 | pub const __OFF_T_MATCHES_OFF64_T: u32 = 1; 401 | pub const __INO_T_MATCHES_INO64_T: u32 = 1; 402 | pub const __RLIM_T_MATCHES_RLIM64_T: u32 = 1; 403 | pub const __STATFS_MATCHES_STATFS64: u32 = 1; 404 | pub const __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64: u32 = 1; 405 | pub const __FD_SETSIZE: u32 = 1024; 406 | pub const _BITS_TIME64_H: u32 = 1; 407 | pub const _BITS_WCHAR_H: u32 = 1; 408 | pub const _BITS_STDINT_INTN_H: u32 = 1; 409 | pub const _BITS_STDINT_UINTN_H: u32 = 1; 410 | pub const INT8_MIN: i32 = -128; 411 | pub const INT16_MIN: i32 = -32768; 412 | pub const INT32_MIN: i32 = -2147483648; 413 | pub const INT8_MAX: u32 = 127; 414 | pub const INT16_MAX: u32 = 32767; 415 | pub const INT32_MAX: u32 = 2147483647; 416 | pub const UINT8_MAX: u32 = 255; 417 | pub const UINT16_MAX: u32 = 65535; 418 | pub const UINT32_MAX: u32 = 4294967295; 419 | pub const INT_LEAST8_MIN: i32 = -128; 420 | pub const INT_LEAST16_MIN: i32 = -32768; 421 | pub const INT_LEAST32_MIN: i32 = -2147483648; 422 | pub const INT_LEAST8_MAX: u32 = 127; 423 | pub const INT_LEAST16_MAX: u32 = 32767; 424 | pub const INT_LEAST32_MAX: u32 = 2147483647; 425 | pub const UINT_LEAST8_MAX: u32 = 255; 426 | pub const UINT_LEAST16_MAX: u32 = 65535; 427 | pub const UINT_LEAST32_MAX: u32 = 4294967295; 428 | pub const INT_FAST8_MIN: i32 = -128; 429 | pub const INT_FAST16_MIN: i64 = -9223372036854775808; 430 | pub const INT_FAST32_MIN: i64 = -9223372036854775808; 431 | pub const INT_FAST8_MAX: u32 = 127; 432 | pub const INT_FAST16_MAX: u64 = 9223372036854775807; 433 | pub const INT_FAST32_MAX: u64 = 9223372036854775807; 434 | pub const UINT_FAST8_MAX: u32 = 255; 435 | pub const UINT_FAST16_MAX: i32 = -1; 436 | pub const UINT_FAST32_MAX: i32 = -1; 437 | pub const INTPTR_MIN: i64 = -9223372036854775808; 438 | pub const INTPTR_MAX: u64 = 9223372036854775807; 439 | pub const UINTPTR_MAX: i32 = -1; 440 | pub const PTRDIFF_MIN: i64 = -9223372036854775808; 441 | pub const PTRDIFF_MAX: u64 = 9223372036854775807; 442 | pub const SIG_ATOMIC_MIN: i32 = -2147483648; 443 | pub const SIG_ATOMIC_MAX: u32 = 2147483647; 444 | pub const SIZE_MAX: i32 = -1; 445 | pub const WINT_MIN: u32 = 0; 446 | pub const WINT_MAX: u32 = 4294967295; 447 | pub const INT8_WIDTH: u32 = 8; 448 | pub const UINT8_WIDTH: u32 = 8; 449 | pub const INT16_WIDTH: u32 = 16; 450 | pub const UINT16_WIDTH: u32 = 16; 451 | pub const INT32_WIDTH: u32 = 32; 452 | pub const UINT32_WIDTH: u32 = 32; 453 | pub const INT64_WIDTH: u32 = 64; 454 | pub const UINT64_WIDTH: u32 = 64; 455 | pub const INT_LEAST8_WIDTH: u32 = 8; 456 | pub const UINT_LEAST8_WIDTH: u32 = 8; 457 | pub const INT_LEAST16_WIDTH: u32 = 16; 458 | pub const UINT_LEAST16_WIDTH: u32 = 16; 459 | pub const INT_LEAST32_WIDTH: u32 = 32; 460 | pub const UINT_LEAST32_WIDTH: u32 = 32; 461 | pub const INT_LEAST64_WIDTH: u32 = 64; 462 | pub const UINT_LEAST64_WIDTH: u32 = 64; 463 | pub const INT_FAST8_WIDTH: u32 = 8; 464 | pub const UINT_FAST8_WIDTH: u32 = 8; 465 | pub const INT_FAST16_WIDTH: u32 = 64; 466 | pub const UINT_FAST16_WIDTH: u32 = 64; 467 | pub const INT_FAST32_WIDTH: u32 = 64; 468 | pub const UINT_FAST32_WIDTH: u32 = 64; 469 | pub const INT_FAST64_WIDTH: u32 = 64; 470 | pub const UINT_FAST64_WIDTH: u32 = 64; 471 | pub const INTPTR_WIDTH: u32 = 64; 472 | pub const UINTPTR_WIDTH: u32 = 64; 473 | pub const INTMAX_WIDTH: u32 = 64; 474 | pub const UINTMAX_WIDTH: u32 = 64; 475 | pub const PTRDIFF_WIDTH: u32 = 64; 476 | pub const SIG_ATOMIC_WIDTH: u32 = 32; 477 | pub const SIZE_WIDTH: u32 = 64; 478 | pub const WCHAR_WIDTH: u32 = 32; 479 | pub const WINT_WIDTH: u32 = 32; 480 | pub type std_nullptr_t = *const ::std::os::raw::c_void; 481 | extern "C" { 482 | pub fn __assert_fail( 483 | __assertion: *const ::std::os::raw::c_char, 484 | __file: *const ::std::os::raw::c_char, 485 | __line: ::std::os::raw::c_uint, 486 | __function: *const ::std::os::raw::c_char, 487 | ) -> !; 488 | } 489 | extern "C" { 490 | pub fn __assert_perror_fail( 491 | __errnum: ::std::os::raw::c_int, 492 | __file: *const ::std::os::raw::c_char, 493 | __line: ::std::os::raw::c_uint, 494 | __function: *const ::std::os::raw::c_char, 495 | ) -> !; 496 | } 497 | extern "C" { 498 | pub fn __assert( 499 | __assertion: *const ::std::os::raw::c_char, 500 | __file: *const ::std::os::raw::c_char, 501 | __line: ::std::os::raw::c_int, 502 | ) -> !; 503 | } 504 | extern "C" { 505 | pub fn memcpy( 506 | __dest: *mut ::std::os::raw::c_void, 507 | __src: *const ::std::os::raw::c_void, 508 | __n: usize, 509 | ) -> *mut ::std::os::raw::c_void; 510 | } 511 | extern "C" { 512 | pub fn memmove( 513 | __dest: *mut ::std::os::raw::c_void, 514 | __src: *const ::std::os::raw::c_void, 515 | __n: usize, 516 | ) -> *mut ::std::os::raw::c_void; 517 | } 518 | extern "C" { 519 | pub fn memccpy( 520 | __dest: *mut ::std::os::raw::c_void, 521 | __src: *const ::std::os::raw::c_void, 522 | __c: ::std::os::raw::c_int, 523 | __n: usize, 524 | ) -> *mut ::std::os::raw::c_void; 525 | } 526 | extern "C" { 527 | pub fn memset( 528 | __s: *mut ::std::os::raw::c_void, 529 | __c: ::std::os::raw::c_int, 530 | __n: usize, 531 | ) -> *mut ::std::os::raw::c_void; 532 | } 533 | extern "C" { 534 | pub fn memcmp( 535 | __s1: *const ::std::os::raw::c_void, 536 | __s2: *const ::std::os::raw::c_void, 537 | __n: usize, 538 | ) -> ::std::os::raw::c_int; 539 | } 540 | extern "C" { 541 | pub fn __memcmpeq( 542 | __s1: *const ::std::os::raw::c_void, 543 | __s2: *const ::std::os::raw::c_void, 544 | __n: usize, 545 | ) -> ::std::os::raw::c_int; 546 | } 547 | extern "C" { 548 | pub fn memchr( 549 | __s: *mut ::std::os::raw::c_void, 550 | __c: ::std::os::raw::c_int, 551 | __n: usize, 552 | ) -> *mut ::std::os::raw::c_void; 553 | } 554 | extern "C" { 555 | pub fn rawmemchr( 556 | __s: *mut ::std::os::raw::c_void, 557 | __c: ::std::os::raw::c_int, 558 | ) -> *mut ::std::os::raw::c_void; 559 | } 560 | extern "C" { 561 | pub fn memrchr( 562 | __s: *mut ::std::os::raw::c_void, 563 | __c: ::std::os::raw::c_int, 564 | __n: usize, 565 | ) -> *mut ::std::os::raw::c_void; 566 | } 567 | extern "C" { 568 | pub fn strcpy( 569 | __dest: *mut ::std::os::raw::c_char, 570 | __src: *const ::std::os::raw::c_char, 571 | ) -> *mut ::std::os::raw::c_char; 572 | } 573 | extern "C" { 574 | pub fn strncpy( 575 | __dest: *mut ::std::os::raw::c_char, 576 | __src: *const ::std::os::raw::c_char, 577 | __n: usize, 578 | ) -> *mut ::std::os::raw::c_char; 579 | } 580 | extern "C" { 581 | pub fn strcat( 582 | __dest: *mut ::std::os::raw::c_char, 583 | __src: *const ::std::os::raw::c_char, 584 | ) -> *mut ::std::os::raw::c_char; 585 | } 586 | extern "C" { 587 | pub fn strncat( 588 | __dest: *mut ::std::os::raw::c_char, 589 | __src: *const ::std::os::raw::c_char, 590 | __n: usize, 591 | ) -> *mut ::std::os::raw::c_char; 592 | } 593 | extern "C" { 594 | pub fn strcmp( 595 | __s1: *const ::std::os::raw::c_char, 596 | __s2: *const ::std::os::raw::c_char, 597 | ) -> ::std::os::raw::c_int; 598 | } 599 | extern "C" { 600 | pub fn strncmp( 601 | __s1: *const ::std::os::raw::c_char, 602 | __s2: *const ::std::os::raw::c_char, 603 | __n: usize, 604 | ) -> ::std::os::raw::c_int; 605 | } 606 | extern "C" { 607 | pub fn strcoll( 608 | __s1: *const ::std::os::raw::c_char, 609 | __s2: *const ::std::os::raw::c_char, 610 | ) -> ::std::os::raw::c_int; 611 | } 612 | extern "C" { 613 | pub fn strxfrm( 614 | __dest: *mut ::std::os::raw::c_char, 615 | __src: *const ::std::os::raw::c_char, 616 | __n: usize, 617 | ) -> usize; 618 | } 619 | #[repr(C)] 620 | #[derive(Debug, Copy, Clone)] 621 | pub struct __locale_struct { 622 | pub __locales: [*mut __locale_data; 13usize], 623 | pub __ctype_b: *const ::std::os::raw::c_ushort, 624 | pub __ctype_tolower: *const ::std::os::raw::c_int, 625 | pub __ctype_toupper: *const ::std::os::raw::c_int, 626 | pub __names: [*const ::std::os::raw::c_char; 13usize], 627 | } 628 | #[test] 629 | fn bindgen_test_layout___locale_struct() { 630 | const UNINIT: ::std::mem::MaybeUninit<__locale_struct> = ::std::mem::MaybeUninit::uninit(); 631 | let ptr = UNINIT.as_ptr(); 632 | assert_eq!( 633 | ::std::mem::size_of::<__locale_struct>(), 634 | 232usize, 635 | concat!("Size of: ", stringify!(__locale_struct)) 636 | ); 637 | assert_eq!( 638 | ::std::mem::align_of::<__locale_struct>(), 639 | 8usize, 640 | concat!("Alignment of ", stringify!(__locale_struct)) 641 | ); 642 | assert_eq!( 643 | unsafe { ::std::ptr::addr_of!((*ptr).__locales) as usize - ptr as usize }, 644 | 0usize, 645 | concat!( 646 | "Offset of field: ", 647 | stringify!(__locale_struct), 648 | "::", 649 | stringify!(__locales) 650 | ) 651 | ); 652 | assert_eq!( 653 | unsafe { ::std::ptr::addr_of!((*ptr).__ctype_b) as usize - ptr as usize }, 654 | 104usize, 655 | concat!( 656 | "Offset of field: ", 657 | stringify!(__locale_struct), 658 | "::", 659 | stringify!(__ctype_b) 660 | ) 661 | ); 662 | assert_eq!( 663 | unsafe { ::std::ptr::addr_of!((*ptr).__ctype_tolower) as usize - ptr as usize }, 664 | 112usize, 665 | concat!( 666 | "Offset of field: ", 667 | stringify!(__locale_struct), 668 | "::", 669 | stringify!(__ctype_tolower) 670 | ) 671 | ); 672 | assert_eq!( 673 | unsafe { ::std::ptr::addr_of!((*ptr).__ctype_toupper) as usize - ptr as usize }, 674 | 120usize, 675 | concat!( 676 | "Offset of field: ", 677 | stringify!(__locale_struct), 678 | "::", 679 | stringify!(__ctype_toupper) 680 | ) 681 | ); 682 | assert_eq!( 683 | unsafe { ::std::ptr::addr_of!((*ptr).__names) as usize - ptr as usize }, 684 | 128usize, 685 | concat!( 686 | "Offset of field: ", 687 | stringify!(__locale_struct), 688 | "::", 689 | stringify!(__names) 690 | ) 691 | ); 692 | } 693 | pub type __locale_t = *mut __locale_struct; 694 | pub type locale_t = __locale_t; 695 | extern "C" { 696 | pub fn strcoll_l( 697 | __s1: *const ::std::os::raw::c_char, 698 | __s2: *const ::std::os::raw::c_char, 699 | __l: locale_t, 700 | ) -> ::std::os::raw::c_int; 701 | } 702 | extern "C" { 703 | pub fn strxfrm_l( 704 | __dest: *mut ::std::os::raw::c_char, 705 | __src: *const ::std::os::raw::c_char, 706 | __n: usize, 707 | __l: locale_t, 708 | ) -> usize; 709 | } 710 | extern "C" { 711 | pub fn strdup(__s: *const ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; 712 | } 713 | extern "C" { 714 | pub fn strndup( 715 | __string: *const ::std::os::raw::c_char, 716 | __n: usize, 717 | ) -> *mut ::std::os::raw::c_char; 718 | } 719 | extern "C" { 720 | pub fn strchr( 721 | __s: *mut ::std::os::raw::c_char, 722 | __c: ::std::os::raw::c_int, 723 | ) -> *mut ::std::os::raw::c_char; 724 | } 725 | extern "C" { 726 | pub fn strrchr( 727 | __s: *mut ::std::os::raw::c_char, 728 | __c: ::std::os::raw::c_int, 729 | ) -> *mut ::std::os::raw::c_char; 730 | } 731 | extern "C" { 732 | pub fn strchrnul( 733 | __s: *mut ::std::os::raw::c_char, 734 | __c: ::std::os::raw::c_int, 735 | ) -> *mut ::std::os::raw::c_char; 736 | } 737 | extern "C" { 738 | pub fn strcspn( 739 | __s: *const ::std::os::raw::c_char, 740 | __reject: *const ::std::os::raw::c_char, 741 | ) -> usize; 742 | } 743 | extern "C" { 744 | pub fn strspn( 745 | __s: *const ::std::os::raw::c_char, 746 | __accept: *const ::std::os::raw::c_char, 747 | ) -> usize; 748 | } 749 | extern "C" { 750 | pub fn strpbrk( 751 | __s: *mut ::std::os::raw::c_char, 752 | __accept: *const ::std::os::raw::c_char, 753 | ) -> *mut ::std::os::raw::c_char; 754 | } 755 | extern "C" { 756 | pub fn strstr( 757 | __haystack: *mut ::std::os::raw::c_char, 758 | __needle: *const ::std::os::raw::c_char, 759 | ) -> *mut ::std::os::raw::c_char; 760 | } 761 | extern "C" { 762 | pub fn strtok( 763 | __s: *mut ::std::os::raw::c_char, 764 | __delim: *const ::std::os::raw::c_char, 765 | ) -> *mut ::std::os::raw::c_char; 766 | } 767 | extern "C" { 768 | pub fn __strtok_r( 769 | __s: *mut ::std::os::raw::c_char, 770 | __delim: *const ::std::os::raw::c_char, 771 | __save_ptr: *mut *mut ::std::os::raw::c_char, 772 | ) -> *mut ::std::os::raw::c_char; 773 | } 774 | extern "C" { 775 | pub fn strtok_r( 776 | __s: *mut ::std::os::raw::c_char, 777 | __delim: *const ::std::os::raw::c_char, 778 | __save_ptr: *mut *mut ::std::os::raw::c_char, 779 | ) -> *mut ::std::os::raw::c_char; 780 | } 781 | extern "C" { 782 | pub fn strcasestr( 783 | __haystack: *mut ::std::os::raw::c_char, 784 | __needle: *const ::std::os::raw::c_char, 785 | ) -> *mut ::std::os::raw::c_char; 786 | } 787 | extern "C" { 788 | pub fn memmem( 789 | __haystack: *const ::std::os::raw::c_void, 790 | __haystacklen: usize, 791 | __needle: *const ::std::os::raw::c_void, 792 | __needlelen: usize, 793 | ) -> *mut ::std::os::raw::c_void; 794 | } 795 | extern "C" { 796 | pub fn __mempcpy( 797 | __dest: *mut ::std::os::raw::c_void, 798 | __src: *const ::std::os::raw::c_void, 799 | __n: usize, 800 | ) -> *mut ::std::os::raw::c_void; 801 | } 802 | extern "C" { 803 | pub fn mempcpy( 804 | __dest: *mut ::std::os::raw::c_void, 805 | __src: *const ::std::os::raw::c_void, 806 | __n: usize, 807 | ) -> *mut ::std::os::raw::c_void; 808 | } 809 | extern "C" { 810 | pub fn strlen(__s: *const ::std::os::raw::c_char) -> usize; 811 | } 812 | extern "C" { 813 | pub fn strnlen(__string: *const ::std::os::raw::c_char, __maxlen: usize) -> usize; 814 | } 815 | extern "C" { 816 | pub fn strerror(__errnum: ::std::os::raw::c_int) -> *mut ::std::os::raw::c_char; 817 | } 818 | extern "C" { 819 | pub fn strerror_r( 820 | __errnum: ::std::os::raw::c_int, 821 | __buf: *mut ::std::os::raw::c_char, 822 | __buflen: usize, 823 | ) -> *mut ::std::os::raw::c_char; 824 | } 825 | extern "C" { 826 | pub fn strerrordesc_np(__err: ::std::os::raw::c_int) -> *const ::std::os::raw::c_char; 827 | } 828 | extern "C" { 829 | pub fn strerrorname_np(__err: ::std::os::raw::c_int) -> *const ::std::os::raw::c_char; 830 | } 831 | extern "C" { 832 | pub fn strerror_l( 833 | __errnum: ::std::os::raw::c_int, 834 | __l: locale_t, 835 | ) -> *mut ::std::os::raw::c_char; 836 | } 837 | extern "C" { 838 | pub fn bcmp( 839 | __s1: *const ::std::os::raw::c_void, 840 | __s2: *const ::std::os::raw::c_void, 841 | __n: usize, 842 | ) -> ::std::os::raw::c_int; 843 | } 844 | extern "C" { 845 | pub fn bcopy( 846 | __src: *const ::std::os::raw::c_void, 847 | __dest: *mut ::std::os::raw::c_void, 848 | __n: usize, 849 | ); 850 | } 851 | extern "C" { 852 | pub fn bzero(__s: *mut ::std::os::raw::c_void, __n: usize); 853 | } 854 | extern "C" { 855 | pub fn index( 856 | __s: *const ::std::os::raw::c_char, 857 | __c: ::std::os::raw::c_int, 858 | ) -> *mut ::std::os::raw::c_char; 859 | } 860 | extern "C" { 861 | pub fn rindex( 862 | __s: *const ::std::os::raw::c_char, 863 | __c: ::std::os::raw::c_int, 864 | ) -> *mut ::std::os::raw::c_char; 865 | } 866 | extern "C" { 867 | pub fn ffs(__i: ::std::os::raw::c_int) -> ::std::os::raw::c_int; 868 | } 869 | extern "C" { 870 | pub fn ffsl(__l: ::std::os::raw::c_long) -> ::std::os::raw::c_int; 871 | } 872 | extern "C" { 873 | pub fn ffsll(__ll: ::std::os::raw::c_longlong) -> ::std::os::raw::c_int; 874 | } 875 | extern "C" { 876 | pub fn strcasecmp( 877 | __s1: *const ::std::os::raw::c_char, 878 | __s2: *const ::std::os::raw::c_char, 879 | ) -> ::std::os::raw::c_int; 880 | } 881 | extern "C" { 882 | pub fn strncasecmp( 883 | __s1: *const ::std::os::raw::c_char, 884 | __s2: *const ::std::os::raw::c_char, 885 | __n: usize, 886 | ) -> ::std::os::raw::c_int; 887 | } 888 | extern "C" { 889 | pub fn strcasecmp_l( 890 | __s1: *const ::std::os::raw::c_char, 891 | __s2: *const ::std::os::raw::c_char, 892 | __loc: locale_t, 893 | ) -> ::std::os::raw::c_int; 894 | } 895 | extern "C" { 896 | pub fn strncasecmp_l( 897 | __s1: *const ::std::os::raw::c_char, 898 | __s2: *const ::std::os::raw::c_char, 899 | __n: usize, 900 | __loc: locale_t, 901 | ) -> ::std::os::raw::c_int; 902 | } 903 | extern "C" { 904 | pub fn explicit_bzero(__s: *mut ::std::os::raw::c_void, __n: usize); 905 | } 906 | extern "C" { 907 | pub fn strsep( 908 | __stringp: *mut *mut ::std::os::raw::c_char, 909 | __delim: *const ::std::os::raw::c_char, 910 | ) -> *mut ::std::os::raw::c_char; 911 | } 912 | extern "C" { 913 | pub fn strsignal(__sig: ::std::os::raw::c_int) -> *mut ::std::os::raw::c_char; 914 | } 915 | extern "C" { 916 | pub fn sigabbrev_np(__sig: ::std::os::raw::c_int) -> *const ::std::os::raw::c_char; 917 | } 918 | extern "C" { 919 | pub fn sigdescr_np(__sig: ::std::os::raw::c_int) -> *const ::std::os::raw::c_char; 920 | } 921 | extern "C" { 922 | pub fn __stpcpy( 923 | __dest: *mut ::std::os::raw::c_char, 924 | __src: *const ::std::os::raw::c_char, 925 | ) -> *mut ::std::os::raw::c_char; 926 | } 927 | extern "C" { 928 | pub fn stpcpy( 929 | __dest: *mut ::std::os::raw::c_char, 930 | __src: *const ::std::os::raw::c_char, 931 | ) -> *mut ::std::os::raw::c_char; 932 | } 933 | extern "C" { 934 | pub fn __stpncpy( 935 | __dest: *mut ::std::os::raw::c_char, 936 | __src: *const ::std::os::raw::c_char, 937 | __n: usize, 938 | ) -> *mut ::std::os::raw::c_char; 939 | } 940 | extern "C" { 941 | pub fn stpncpy( 942 | __dest: *mut ::std::os::raw::c_char, 943 | __src: *const ::std::os::raw::c_char, 944 | __n: usize, 945 | ) -> *mut ::std::os::raw::c_char; 946 | } 947 | extern "C" { 948 | pub fn strverscmp( 949 | __s1: *const ::std::os::raw::c_char, 950 | __s2: *const ::std::os::raw::c_char, 951 | ) -> ::std::os::raw::c_int; 952 | } 953 | extern "C" { 954 | pub fn strfry(__string: *mut ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; 955 | } 956 | extern "C" { 957 | pub fn memfrob(__s: *mut ::std::os::raw::c_void, __n: usize) -> *mut ::std::os::raw::c_void; 958 | } 959 | extern "C" { 960 | pub fn basename(__filename: *mut ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; 961 | } 962 | pub type __u_char = ::std::os::raw::c_uchar; 963 | pub type __u_short = ::std::os::raw::c_ushort; 964 | pub type __u_int = ::std::os::raw::c_uint; 965 | pub type __u_long = ::std::os::raw::c_ulong; 966 | pub type __int8_t = ::std::os::raw::c_schar; 967 | pub type __uint8_t = ::std::os::raw::c_uchar; 968 | pub type __int16_t = ::std::os::raw::c_short; 969 | pub type __uint16_t = ::std::os::raw::c_ushort; 970 | pub type __int32_t = ::std::os::raw::c_int; 971 | pub type __uint32_t = ::std::os::raw::c_uint; 972 | pub type __int64_t = ::std::os::raw::c_long; 973 | pub type __uint64_t = ::std::os::raw::c_ulong; 974 | pub type __int_least8_t = __int8_t; 975 | pub type __uint_least8_t = __uint8_t; 976 | pub type __int_least16_t = __int16_t; 977 | pub type __uint_least16_t = __uint16_t; 978 | pub type __int_least32_t = __int32_t; 979 | pub type __uint_least32_t = __uint32_t; 980 | pub type __int_least64_t = __int64_t; 981 | pub type __uint_least64_t = __uint64_t; 982 | pub type __quad_t = ::std::os::raw::c_long; 983 | pub type __u_quad_t = ::std::os::raw::c_ulong; 984 | pub type __intmax_t = ::std::os::raw::c_long; 985 | pub type __uintmax_t = ::std::os::raw::c_ulong; 986 | pub type __dev_t = ::std::os::raw::c_ulong; 987 | pub type __uid_t = ::std::os::raw::c_uint; 988 | pub type __gid_t = ::std::os::raw::c_uint; 989 | pub type __ino_t = ::std::os::raw::c_ulong; 990 | pub type __ino64_t = ::std::os::raw::c_ulong; 991 | pub type __mode_t = ::std::os::raw::c_uint; 992 | pub type __nlink_t = ::std::os::raw::c_ulong; 993 | pub type __off_t = ::std::os::raw::c_long; 994 | pub type __off64_t = ::std::os::raw::c_long; 995 | pub type __pid_t = ::std::os::raw::c_int; 996 | #[repr(C)] 997 | #[derive(Debug, Copy, Clone)] 998 | pub struct __fsid_t { 999 | pub __val: [::std::os::raw::c_int; 2usize], 1000 | } 1001 | #[test] 1002 | fn bindgen_test_layout___fsid_t() { 1003 | const UNINIT: ::std::mem::MaybeUninit<__fsid_t> = ::std::mem::MaybeUninit::uninit(); 1004 | let ptr = UNINIT.as_ptr(); 1005 | assert_eq!( 1006 | ::std::mem::size_of::<__fsid_t>(), 1007 | 8usize, 1008 | concat!("Size of: ", stringify!(__fsid_t)) 1009 | ); 1010 | assert_eq!( 1011 | ::std::mem::align_of::<__fsid_t>(), 1012 | 4usize, 1013 | concat!("Alignment of ", stringify!(__fsid_t)) 1014 | ); 1015 | assert_eq!( 1016 | unsafe { ::std::ptr::addr_of!((*ptr).__val) as usize - ptr as usize }, 1017 | 0usize, 1018 | concat!( 1019 | "Offset of field: ", 1020 | stringify!(__fsid_t), 1021 | "::", 1022 | stringify!(__val) 1023 | ) 1024 | ); 1025 | } 1026 | pub type __clock_t = ::std::os::raw::c_long; 1027 | pub type __rlim_t = ::std::os::raw::c_ulong; 1028 | pub type __rlim64_t = ::std::os::raw::c_ulong; 1029 | pub type __id_t = ::std::os::raw::c_uint; 1030 | pub type __time_t = ::std::os::raw::c_long; 1031 | pub type __useconds_t = ::std::os::raw::c_uint; 1032 | pub type __suseconds_t = ::std::os::raw::c_long; 1033 | pub type __suseconds64_t = ::std::os::raw::c_long; 1034 | pub type __daddr_t = ::std::os::raw::c_int; 1035 | pub type __key_t = ::std::os::raw::c_int; 1036 | pub type __clockid_t = ::std::os::raw::c_int; 1037 | pub type __timer_t = *mut ::std::os::raw::c_void; 1038 | pub type __blksize_t = ::std::os::raw::c_long; 1039 | pub type __blkcnt_t = ::std::os::raw::c_long; 1040 | pub type __blkcnt64_t = ::std::os::raw::c_long; 1041 | pub type __fsblkcnt_t = ::std::os::raw::c_ulong; 1042 | pub type __fsblkcnt64_t = ::std::os::raw::c_ulong; 1043 | pub type __fsfilcnt_t = ::std::os::raw::c_ulong; 1044 | pub type __fsfilcnt64_t = ::std::os::raw::c_ulong; 1045 | pub type __fsword_t = ::std::os::raw::c_long; 1046 | pub type __ssize_t = ::std::os::raw::c_long; 1047 | pub type __syscall_slong_t = ::std::os::raw::c_long; 1048 | pub type __syscall_ulong_t = ::std::os::raw::c_ulong; 1049 | pub type __loff_t = __off64_t; 1050 | pub type __caddr_t = *mut ::std::os::raw::c_char; 1051 | pub type __intptr_t = ::std::os::raw::c_long; 1052 | pub type __socklen_t = ::std::os::raw::c_uint; 1053 | pub type __sig_atomic_t = ::std::os::raw::c_int; 1054 | pub type int_least8_t = __int_least8_t; 1055 | pub type int_least16_t = __int_least16_t; 1056 | pub type int_least32_t = __int_least32_t; 1057 | pub type int_least64_t = __int_least64_t; 1058 | pub type uint_least8_t = __uint_least8_t; 1059 | pub type uint_least16_t = __uint_least16_t; 1060 | pub type uint_least32_t = __uint_least32_t; 1061 | pub type uint_least64_t = __uint_least64_t; 1062 | pub type int_fast8_t = ::std::os::raw::c_schar; 1063 | pub type int_fast16_t = ::std::os::raw::c_long; 1064 | pub type int_fast32_t = ::std::os::raw::c_long; 1065 | pub type int_fast64_t = ::std::os::raw::c_long; 1066 | pub type uint_fast8_t = ::std::os::raw::c_uchar; 1067 | pub type uint_fast16_t = ::std::os::raw::c_ulong; 1068 | pub type uint_fast32_t = ::std::os::raw::c_ulong; 1069 | pub type uint_fast64_t = ::std::os::raw::c_ulong; 1070 | pub type intmax_t = __intmax_t; 1071 | pub type uintmax_t = __uintmax_t; 1072 | extern "C" { 1073 | #[link_name = "\u{1}_ZL27WLAN_IEEE_HEADER_AIR2GROUND"] 1074 | pub static WLAN_IEEE_HEADER_AIR2GROUND: [u8; 24usize]; 1075 | } 1076 | extern "C" { 1077 | #[link_name = "\u{1}_ZL27WLAN_IEEE_HEADER_GROUND2AIR"] 1078 | pub static WLAN_IEEE_HEADER_GROUND2AIR: [u8; 24usize]; 1079 | } 1080 | pub const WLAN_IEEE_HEADER_SIZE: usize = 24; 1081 | pub const WLAN_MAX_PACKET_SIZE: usize = 1500; 1082 | pub const WLAN_MAX_PAYLOAD_SIZE: usize = 1476; 1083 | #[repr(C)] 1084 | #[derive(Debug, Copy, Clone)] 1085 | pub struct Wlan_Outgoing_Packet { 1086 | pub ptr: *mut u8, 1087 | pub payload_ptr: *mut u8, 1088 | pub size: u16, 1089 | pub offset: u16, 1090 | } 1091 | #[test] 1092 | fn bindgen_test_layout_Wlan_Outgoing_Packet() { 1093 | const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); 1094 | let ptr = UNINIT.as_ptr(); 1095 | assert_eq!( 1096 | ::std::mem::size_of::(), 1097 | 24usize, 1098 | concat!("Size of: ", stringify!(Wlan_Outgoing_Packet)) 1099 | ); 1100 | assert_eq!( 1101 | ::std::mem::align_of::(), 1102 | 8usize, 1103 | concat!("Alignment of ", stringify!(Wlan_Outgoing_Packet)) 1104 | ); 1105 | assert_eq!( 1106 | unsafe { ::std::ptr::addr_of!((*ptr).ptr) as usize - ptr as usize }, 1107 | 0usize, 1108 | concat!( 1109 | "Offset of field: ", 1110 | stringify!(Wlan_Outgoing_Packet), 1111 | "::", 1112 | stringify!(ptr) 1113 | ) 1114 | ); 1115 | assert_eq!( 1116 | unsafe { ::std::ptr::addr_of!((*ptr).payload_ptr) as usize - ptr as usize }, 1117 | 8usize, 1118 | concat!( 1119 | "Offset of field: ", 1120 | stringify!(Wlan_Outgoing_Packet), 1121 | "::", 1122 | stringify!(payload_ptr) 1123 | ) 1124 | ); 1125 | assert_eq!( 1126 | unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, 1127 | 16usize, 1128 | concat!( 1129 | "Offset of field: ", 1130 | stringify!(Wlan_Outgoing_Packet), 1131 | "::", 1132 | stringify!(size) 1133 | ) 1134 | ); 1135 | assert_eq!( 1136 | unsafe { ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize }, 1137 | 18usize, 1138 | concat!( 1139 | "Offset of field: ", 1140 | stringify!(Wlan_Outgoing_Packet), 1141 | "::", 1142 | stringify!(offset) 1143 | ) 1144 | ); 1145 | } 1146 | #[repr(C)] 1147 | #[derive(Debug, Copy, Clone)] 1148 | pub struct Wlan_Incoming_Packet { 1149 | pub ptr: *mut u8, 1150 | pub size: u16, 1151 | pub offset: u16, 1152 | } 1153 | #[test] 1154 | fn bindgen_test_layout_Wlan_Incoming_Packet() { 1155 | const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); 1156 | let ptr = UNINIT.as_ptr(); 1157 | assert_eq!( 1158 | ::std::mem::size_of::(), 1159 | 16usize, 1160 | concat!("Size of: ", stringify!(Wlan_Incoming_Packet)) 1161 | ); 1162 | assert_eq!( 1163 | ::std::mem::align_of::(), 1164 | 8usize, 1165 | concat!("Alignment of ", stringify!(Wlan_Incoming_Packet)) 1166 | ); 1167 | assert_eq!( 1168 | unsafe { ::std::ptr::addr_of!((*ptr).ptr) as usize - ptr as usize }, 1169 | 0usize, 1170 | concat!( 1171 | "Offset of field: ", 1172 | stringify!(Wlan_Incoming_Packet), 1173 | "::", 1174 | stringify!(ptr) 1175 | ) 1176 | ); 1177 | assert_eq!( 1178 | unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, 1179 | 8usize, 1180 | concat!( 1181 | "Offset of field: ", 1182 | stringify!(Wlan_Incoming_Packet), 1183 | "::", 1184 | stringify!(size) 1185 | ) 1186 | ); 1187 | assert_eq!( 1188 | unsafe { ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize }, 1189 | 10usize, 1190 | concat!( 1191 | "Offset of field: ", 1192 | stringify!(Wlan_Incoming_Packet), 1193 | "::", 1194 | stringify!(offset) 1195 | ) 1196 | ); 1197 | } 1198 | pub const WIFI_Rate_RATE_B_2M_CCK: WIFI_Rate = 0; 1199 | pub const WIFI_Rate_RATE_B_2M_CCK_S: WIFI_Rate = 1; 1200 | pub const WIFI_Rate_RATE_B_5_5M_CCK: WIFI_Rate = 2; 1201 | pub const WIFI_Rate_RATE_B_5_5M_CCK_S: WIFI_Rate = 3; 1202 | pub const WIFI_Rate_RATE_B_11M_CCK: WIFI_Rate = 4; 1203 | pub const WIFI_Rate_RATE_B_11M_CCK_S: WIFI_Rate = 5; 1204 | pub const WIFI_Rate_RATE_G_6M_ODFM: WIFI_Rate = 6; 1205 | pub const WIFI_Rate_RATE_G_9M_ODFM: WIFI_Rate = 7; 1206 | pub const WIFI_Rate_RATE_G_12M_ODFM: WIFI_Rate = 8; 1207 | pub const WIFI_Rate_RATE_G_18M_ODFM: WIFI_Rate = 9; 1208 | pub const WIFI_Rate_RATE_G_24M_ODFM: WIFI_Rate = 10; 1209 | pub const WIFI_Rate_RATE_G_36M_ODFM: WIFI_Rate = 11; 1210 | pub const WIFI_Rate_RATE_G_48M_ODFM: WIFI_Rate = 12; 1211 | pub const WIFI_Rate_RATE_G_54M_ODFM: WIFI_Rate = 13; 1212 | pub const WIFI_Rate_RATE_N_6_5M_MCS0: WIFI_Rate = 14; 1213 | pub const WIFI_Rate_RATE_N_7_2M_MCS0_S: WIFI_Rate = 15; 1214 | pub const WIFI_Rate_RATE_N_13M_MCS1: WIFI_Rate = 16; 1215 | pub const WIFI_Rate_RATE_N_14_4M_MCS1_S: WIFI_Rate = 17; 1216 | pub const WIFI_Rate_RATE_N_19_5M_MCS2: WIFI_Rate = 18; 1217 | pub const WIFI_Rate_RATE_N_21_7M_MCS2_S: WIFI_Rate = 19; 1218 | pub const WIFI_Rate_RATE_N_26M_MCS3: WIFI_Rate = 20; 1219 | pub const WIFI_Rate_RATE_N_28_9M_MCS3_S: WIFI_Rate = 21; 1220 | pub const WIFI_Rate_RATE_N_39M_MCS4: WIFI_Rate = 22; 1221 | pub const WIFI_Rate_RATE_N_43_3M_MCS4_S: WIFI_Rate = 23; 1222 | pub const WIFI_Rate_RATE_N_52M_MCS5: WIFI_Rate = 24; 1223 | pub const WIFI_Rate_RATE_N_57_8M_MCS5_S: WIFI_Rate = 25; 1224 | pub const WIFI_Rate_RATE_N_58M_MCS6: WIFI_Rate = 26; 1225 | pub const WIFI_Rate_RATE_N_65M_MCS6_S: WIFI_Rate = 27; 1226 | pub const WIFI_Rate_RATE_N_65M_MCS7: WIFI_Rate = 28; 1227 | pub const WIFI_Rate_RATE_N_72M_MCS7_S: WIFI_Rate = 29; 1228 | pub type WIFI_Rate = u8; 1229 | pub const AIR2GROUND_MTU: usize = 1470; 1230 | pub const GROUND2AIR_DATA_MAX_SIZE: usize = 64; 1231 | #[repr(C, packed)] 1232 | #[derive(Debug, Copy, Clone)] 1233 | pub struct Ground2Air_Header { 1234 | pub type_: Ground2Air_Header_Type, 1235 | pub size: u32, 1236 | pub crc: u8, 1237 | } 1238 | pub const Ground2Air_Header_Type_Data: Ground2Air_Header_Type = 0; 1239 | pub const Ground2Air_Header_Type_Config: Ground2Air_Header_Type = 1; 1240 | pub type Ground2Air_Header_Type = u8; 1241 | #[test] 1242 | fn bindgen_test_layout_Ground2Air_Header() { 1243 | const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); 1244 | let ptr = UNINIT.as_ptr(); 1245 | assert_eq!( 1246 | ::std::mem::size_of::(), 1247 | 6usize, 1248 | concat!("Size of: ", stringify!(Ground2Air_Header)) 1249 | ); 1250 | assert_eq!( 1251 | ::std::mem::align_of::(), 1252 | 1usize, 1253 | concat!("Alignment of ", stringify!(Ground2Air_Header)) 1254 | ); 1255 | assert_eq!( 1256 | unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, 1257 | 0usize, 1258 | concat!( 1259 | "Offset of field: ", 1260 | stringify!(Ground2Air_Header), 1261 | "::", 1262 | stringify!(type_) 1263 | ) 1264 | ); 1265 | assert_eq!( 1266 | unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, 1267 | 1usize, 1268 | concat!( 1269 | "Offset of field: ", 1270 | stringify!(Ground2Air_Header), 1271 | "::", 1272 | stringify!(size) 1273 | ) 1274 | ); 1275 | assert_eq!( 1276 | unsafe { ::std::ptr::addr_of!((*ptr).crc) as usize - ptr as usize }, 1277 | 5usize, 1278 | concat!( 1279 | "Offset of field: ", 1280 | stringify!(Ground2Air_Header), 1281 | "::", 1282 | stringify!(crc) 1283 | ) 1284 | ); 1285 | } 1286 | #[repr(C)] 1287 | #[derive(Debug, Copy, Clone)] 1288 | pub struct Ground2Air_Data_Packet { 1289 | pub _base: Ground2Air_Header, 1290 | } 1291 | #[test] 1292 | fn bindgen_test_layout_Ground2Air_Data_Packet() { 1293 | assert_eq!( 1294 | ::std::mem::size_of::(), 1295 | 6usize, 1296 | concat!("Size of: ", stringify!(Ground2Air_Data_Packet)) 1297 | ); 1298 | assert_eq!( 1299 | ::std::mem::align_of::(), 1300 | 1usize, 1301 | concat!("Alignment of ", stringify!(Ground2Air_Data_Packet)) 1302 | ); 1303 | } 1304 | pub const Resolution_QVGA: Resolution = 0; 1305 | pub const Resolution_CIF: Resolution = 1; 1306 | pub const Resolution_HVGA: Resolution = 2; 1307 | pub const Resolution_VGA: Resolution = 3; 1308 | pub const Resolution_SVGA: Resolution = 4; 1309 | pub const Resolution_XGA: Resolution = 5; 1310 | pub const Resolution_SXGA: Resolution = 6; 1311 | pub const Resolution_UXGA: Resolution = 7; 1312 | pub type Resolution = u8; 1313 | #[repr(C, packed)] 1314 | #[derive(Debug, Copy, Clone)] 1315 | pub struct Ground2Air_Config_Packet { 1316 | pub _base: Ground2Air_Header, 1317 | pub ping: u8, 1318 | pub wifi_power: i8, 1319 | pub wifi_rate: WIFI_Rate, 1320 | pub fec_codec_k: u8, 1321 | pub fec_codec_n: u8, 1322 | pub fec_codec_mtu: u16, 1323 | pub dvr_record: bool, 1324 | pub camera: Ground2Air_Config_Packet_Camera, 1325 | } 1326 | #[repr(C, packed)] 1327 | #[derive(Debug, Copy, Clone)] 1328 | pub struct Ground2Air_Config_Packet_Camera { 1329 | pub resolution: Resolution, 1330 | pub fps_limit: u8, 1331 | pub quality: u8, 1332 | pub brightness: i8, 1333 | pub contrast: i8, 1334 | pub saturation: i8, 1335 | pub sharpness: i8, 1336 | pub denoise: u8, 1337 | pub special_effect: u8, 1338 | pub awb: bool, 1339 | pub awb_gain: bool, 1340 | pub wb_mode: u8, 1341 | pub aec: bool, 1342 | pub aec2: bool, 1343 | pub ae_level: i8, 1344 | pub aec_value: u16, 1345 | pub agc: bool, 1346 | pub agc_gain: u8, 1347 | pub gainceiling: u8, 1348 | pub bpc: bool, 1349 | pub wpc: bool, 1350 | pub raw_gma: bool, 1351 | pub lenc: bool, 1352 | pub hmirror: bool, 1353 | pub vflip: bool, 1354 | pub dcw: bool, 1355 | } 1356 | #[test] 1357 | fn bindgen_test_layout_Ground2Air_Config_Packet_Camera() { 1358 | const UNINIT: ::std::mem::MaybeUninit = 1359 | ::std::mem::MaybeUninit::uninit(); 1360 | let ptr = UNINIT.as_ptr(); 1361 | assert_eq!( 1362 | ::std::mem::size_of::(), 1363 | 27usize, 1364 | concat!("Size of: ", stringify!(Ground2Air_Config_Packet_Camera)) 1365 | ); 1366 | assert_eq!( 1367 | ::std::mem::align_of::(), 1368 | 1usize, 1369 | concat!("Alignment of ", stringify!(Ground2Air_Config_Packet_Camera)) 1370 | ); 1371 | assert_eq!( 1372 | unsafe { ::std::ptr::addr_of!((*ptr).resolution) as usize - ptr as usize }, 1373 | 0usize, 1374 | concat!( 1375 | "Offset of field: ", 1376 | stringify!(Ground2Air_Config_Packet_Camera), 1377 | "::", 1378 | stringify!(resolution) 1379 | ) 1380 | ); 1381 | assert_eq!( 1382 | unsafe { ::std::ptr::addr_of!((*ptr).fps_limit) as usize - ptr as usize }, 1383 | 1usize, 1384 | concat!( 1385 | "Offset of field: ", 1386 | stringify!(Ground2Air_Config_Packet_Camera), 1387 | "::", 1388 | stringify!(fps_limit) 1389 | ) 1390 | ); 1391 | assert_eq!( 1392 | unsafe { ::std::ptr::addr_of!((*ptr).quality) as usize - ptr as usize }, 1393 | 2usize, 1394 | concat!( 1395 | "Offset of field: ", 1396 | stringify!(Ground2Air_Config_Packet_Camera), 1397 | "::", 1398 | stringify!(quality) 1399 | ) 1400 | ); 1401 | assert_eq!( 1402 | unsafe { ::std::ptr::addr_of!((*ptr).brightness) as usize - ptr as usize }, 1403 | 3usize, 1404 | concat!( 1405 | "Offset of field: ", 1406 | stringify!(Ground2Air_Config_Packet_Camera), 1407 | "::", 1408 | stringify!(brightness) 1409 | ) 1410 | ); 1411 | assert_eq!( 1412 | unsafe { ::std::ptr::addr_of!((*ptr).contrast) as usize - ptr as usize }, 1413 | 4usize, 1414 | concat!( 1415 | "Offset of field: ", 1416 | stringify!(Ground2Air_Config_Packet_Camera), 1417 | "::", 1418 | stringify!(contrast) 1419 | ) 1420 | ); 1421 | assert_eq!( 1422 | unsafe { ::std::ptr::addr_of!((*ptr).saturation) as usize - ptr as usize }, 1423 | 5usize, 1424 | concat!( 1425 | "Offset of field: ", 1426 | stringify!(Ground2Air_Config_Packet_Camera), 1427 | "::", 1428 | stringify!(saturation) 1429 | ) 1430 | ); 1431 | assert_eq!( 1432 | unsafe { ::std::ptr::addr_of!((*ptr).sharpness) as usize - ptr as usize }, 1433 | 6usize, 1434 | concat!( 1435 | "Offset of field: ", 1436 | stringify!(Ground2Air_Config_Packet_Camera), 1437 | "::", 1438 | stringify!(sharpness) 1439 | ) 1440 | ); 1441 | assert_eq!( 1442 | unsafe { ::std::ptr::addr_of!((*ptr).denoise) as usize - ptr as usize }, 1443 | 7usize, 1444 | concat!( 1445 | "Offset of field: ", 1446 | stringify!(Ground2Air_Config_Packet_Camera), 1447 | "::", 1448 | stringify!(denoise) 1449 | ) 1450 | ); 1451 | assert_eq!( 1452 | unsafe { ::std::ptr::addr_of!((*ptr).special_effect) as usize - ptr as usize }, 1453 | 8usize, 1454 | concat!( 1455 | "Offset of field: ", 1456 | stringify!(Ground2Air_Config_Packet_Camera), 1457 | "::", 1458 | stringify!(special_effect) 1459 | ) 1460 | ); 1461 | assert_eq!( 1462 | unsafe { ::std::ptr::addr_of!((*ptr).awb) as usize - ptr as usize }, 1463 | 9usize, 1464 | concat!( 1465 | "Offset of field: ", 1466 | stringify!(Ground2Air_Config_Packet_Camera), 1467 | "::", 1468 | stringify!(awb) 1469 | ) 1470 | ); 1471 | assert_eq!( 1472 | unsafe { ::std::ptr::addr_of!((*ptr).awb_gain) as usize - ptr as usize }, 1473 | 10usize, 1474 | concat!( 1475 | "Offset of field: ", 1476 | stringify!(Ground2Air_Config_Packet_Camera), 1477 | "::", 1478 | stringify!(awb_gain) 1479 | ) 1480 | ); 1481 | assert_eq!( 1482 | unsafe { ::std::ptr::addr_of!((*ptr).wb_mode) as usize - ptr as usize }, 1483 | 11usize, 1484 | concat!( 1485 | "Offset of field: ", 1486 | stringify!(Ground2Air_Config_Packet_Camera), 1487 | "::", 1488 | stringify!(wb_mode) 1489 | ) 1490 | ); 1491 | assert_eq!( 1492 | unsafe { ::std::ptr::addr_of!((*ptr).aec) as usize - ptr as usize }, 1493 | 12usize, 1494 | concat!( 1495 | "Offset of field: ", 1496 | stringify!(Ground2Air_Config_Packet_Camera), 1497 | "::", 1498 | stringify!(aec) 1499 | ) 1500 | ); 1501 | assert_eq!( 1502 | unsafe { ::std::ptr::addr_of!((*ptr).aec2) as usize - ptr as usize }, 1503 | 13usize, 1504 | concat!( 1505 | "Offset of field: ", 1506 | stringify!(Ground2Air_Config_Packet_Camera), 1507 | "::", 1508 | stringify!(aec2) 1509 | ) 1510 | ); 1511 | assert_eq!( 1512 | unsafe { ::std::ptr::addr_of!((*ptr).ae_level) as usize - ptr as usize }, 1513 | 14usize, 1514 | concat!( 1515 | "Offset of field: ", 1516 | stringify!(Ground2Air_Config_Packet_Camera), 1517 | "::", 1518 | stringify!(ae_level) 1519 | ) 1520 | ); 1521 | assert_eq!( 1522 | unsafe { ::std::ptr::addr_of!((*ptr).aec_value) as usize - ptr as usize }, 1523 | 15usize, 1524 | concat!( 1525 | "Offset of field: ", 1526 | stringify!(Ground2Air_Config_Packet_Camera), 1527 | "::", 1528 | stringify!(aec_value) 1529 | ) 1530 | ); 1531 | assert_eq!( 1532 | unsafe { ::std::ptr::addr_of!((*ptr).agc) as usize - ptr as usize }, 1533 | 17usize, 1534 | concat!( 1535 | "Offset of field: ", 1536 | stringify!(Ground2Air_Config_Packet_Camera), 1537 | "::", 1538 | stringify!(agc) 1539 | ) 1540 | ); 1541 | assert_eq!( 1542 | unsafe { ::std::ptr::addr_of!((*ptr).agc_gain) as usize - ptr as usize }, 1543 | 18usize, 1544 | concat!( 1545 | "Offset of field: ", 1546 | stringify!(Ground2Air_Config_Packet_Camera), 1547 | "::", 1548 | stringify!(agc_gain) 1549 | ) 1550 | ); 1551 | assert_eq!( 1552 | unsafe { ::std::ptr::addr_of!((*ptr).gainceiling) as usize - ptr as usize }, 1553 | 19usize, 1554 | concat!( 1555 | "Offset of field: ", 1556 | stringify!(Ground2Air_Config_Packet_Camera), 1557 | "::", 1558 | stringify!(gainceiling) 1559 | ) 1560 | ); 1561 | assert_eq!( 1562 | unsafe { ::std::ptr::addr_of!((*ptr).bpc) as usize - ptr as usize }, 1563 | 20usize, 1564 | concat!( 1565 | "Offset of field: ", 1566 | stringify!(Ground2Air_Config_Packet_Camera), 1567 | "::", 1568 | stringify!(bpc) 1569 | ) 1570 | ); 1571 | assert_eq!( 1572 | unsafe { ::std::ptr::addr_of!((*ptr).wpc) as usize - ptr as usize }, 1573 | 21usize, 1574 | concat!( 1575 | "Offset of field: ", 1576 | stringify!(Ground2Air_Config_Packet_Camera), 1577 | "::", 1578 | stringify!(wpc) 1579 | ) 1580 | ); 1581 | assert_eq!( 1582 | unsafe { ::std::ptr::addr_of!((*ptr).raw_gma) as usize - ptr as usize }, 1583 | 22usize, 1584 | concat!( 1585 | "Offset of field: ", 1586 | stringify!(Ground2Air_Config_Packet_Camera), 1587 | "::", 1588 | stringify!(raw_gma) 1589 | ) 1590 | ); 1591 | assert_eq!( 1592 | unsafe { ::std::ptr::addr_of!((*ptr).lenc) as usize - ptr as usize }, 1593 | 23usize, 1594 | concat!( 1595 | "Offset of field: ", 1596 | stringify!(Ground2Air_Config_Packet_Camera), 1597 | "::", 1598 | stringify!(lenc) 1599 | ) 1600 | ); 1601 | assert_eq!( 1602 | unsafe { ::std::ptr::addr_of!((*ptr).hmirror) as usize - ptr as usize }, 1603 | 24usize, 1604 | concat!( 1605 | "Offset of field: ", 1606 | stringify!(Ground2Air_Config_Packet_Camera), 1607 | "::", 1608 | stringify!(hmirror) 1609 | ) 1610 | ); 1611 | assert_eq!( 1612 | unsafe { ::std::ptr::addr_of!((*ptr).vflip) as usize - ptr as usize }, 1613 | 25usize, 1614 | concat!( 1615 | "Offset of field: ", 1616 | stringify!(Ground2Air_Config_Packet_Camera), 1617 | "::", 1618 | stringify!(vflip) 1619 | ) 1620 | ); 1621 | assert_eq!( 1622 | unsafe { ::std::ptr::addr_of!((*ptr).dcw) as usize - ptr as usize }, 1623 | 26usize, 1624 | concat!( 1625 | "Offset of field: ", 1626 | stringify!(Ground2Air_Config_Packet_Camera), 1627 | "::", 1628 | stringify!(dcw) 1629 | ) 1630 | ); 1631 | } 1632 | #[test] 1633 | fn bindgen_test_layout_Ground2Air_Config_Packet() { 1634 | const UNINIT: ::std::mem::MaybeUninit = 1635 | ::std::mem::MaybeUninit::uninit(); 1636 | let ptr = UNINIT.as_ptr(); 1637 | assert_eq!( 1638 | ::std::mem::size_of::(), 1639 | 41usize, 1640 | concat!("Size of: ", stringify!(Ground2Air_Config_Packet)) 1641 | ); 1642 | assert_eq!( 1643 | ::std::mem::align_of::(), 1644 | 1usize, 1645 | concat!("Alignment of ", stringify!(Ground2Air_Config_Packet)) 1646 | ); 1647 | assert_eq!( 1648 | unsafe { ::std::ptr::addr_of!((*ptr).ping) as usize - ptr as usize }, 1649 | 6usize, 1650 | concat!( 1651 | "Offset of field: ", 1652 | stringify!(Ground2Air_Config_Packet), 1653 | "::", 1654 | stringify!(ping) 1655 | ) 1656 | ); 1657 | assert_eq!( 1658 | unsafe { ::std::ptr::addr_of!((*ptr).wifi_power) as usize - ptr as usize }, 1659 | 7usize, 1660 | concat!( 1661 | "Offset of field: ", 1662 | stringify!(Ground2Air_Config_Packet), 1663 | "::", 1664 | stringify!(wifi_power) 1665 | ) 1666 | ); 1667 | assert_eq!( 1668 | unsafe { ::std::ptr::addr_of!((*ptr).wifi_rate) as usize - ptr as usize }, 1669 | 8usize, 1670 | concat!( 1671 | "Offset of field: ", 1672 | stringify!(Ground2Air_Config_Packet), 1673 | "::", 1674 | stringify!(wifi_rate) 1675 | ) 1676 | ); 1677 | assert_eq!( 1678 | unsafe { ::std::ptr::addr_of!((*ptr).fec_codec_k) as usize - ptr as usize }, 1679 | 9usize, 1680 | concat!( 1681 | "Offset of field: ", 1682 | stringify!(Ground2Air_Config_Packet), 1683 | "::", 1684 | stringify!(fec_codec_k) 1685 | ) 1686 | ); 1687 | assert_eq!( 1688 | unsafe { ::std::ptr::addr_of!((*ptr).fec_codec_n) as usize - ptr as usize }, 1689 | 10usize, 1690 | concat!( 1691 | "Offset of field: ", 1692 | stringify!(Ground2Air_Config_Packet), 1693 | "::", 1694 | stringify!(fec_codec_n) 1695 | ) 1696 | ); 1697 | assert_eq!( 1698 | unsafe { ::std::ptr::addr_of!((*ptr).fec_codec_mtu) as usize - ptr as usize }, 1699 | 11usize, 1700 | concat!( 1701 | "Offset of field: ", 1702 | stringify!(Ground2Air_Config_Packet), 1703 | "::", 1704 | stringify!(fec_codec_mtu) 1705 | ) 1706 | ); 1707 | assert_eq!( 1708 | unsafe { ::std::ptr::addr_of!((*ptr).dvr_record) as usize - ptr as usize }, 1709 | 13usize, 1710 | concat!( 1711 | "Offset of field: ", 1712 | stringify!(Ground2Air_Config_Packet), 1713 | "::", 1714 | stringify!(dvr_record) 1715 | ) 1716 | ); 1717 | assert_eq!( 1718 | unsafe { ::std::ptr::addr_of!((*ptr).camera) as usize - ptr as usize }, 1719 | 14usize, 1720 | concat!( 1721 | "Offset of field: ", 1722 | stringify!(Ground2Air_Config_Packet), 1723 | "::", 1724 | stringify!(camera) 1725 | ) 1726 | ); 1727 | } 1728 | #[repr(C, packed)] 1729 | #[derive(Debug, Copy, Clone)] 1730 | pub struct Air2Ground_Header { 1731 | pub type_: Air2Ground_Header_Type, 1732 | pub size: u32, 1733 | pub pong: u8, 1734 | pub crc: u8, 1735 | } 1736 | pub const Air2Ground_Header_Type_Video: Air2Ground_Header_Type = 0; 1737 | pub const Air2Ground_Header_Type_Telemetry: Air2Ground_Header_Type = 1; 1738 | pub type Air2Ground_Header_Type = u8; 1739 | #[test] 1740 | fn bindgen_test_layout_Air2Ground_Header() { 1741 | const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); 1742 | let ptr = UNINIT.as_ptr(); 1743 | assert_eq!( 1744 | ::std::mem::size_of::(), 1745 | 7usize, 1746 | concat!("Size of: ", stringify!(Air2Ground_Header)) 1747 | ); 1748 | assert_eq!( 1749 | ::std::mem::align_of::(), 1750 | 1usize, 1751 | concat!("Alignment of ", stringify!(Air2Ground_Header)) 1752 | ); 1753 | assert_eq!( 1754 | unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, 1755 | 0usize, 1756 | concat!( 1757 | "Offset of field: ", 1758 | stringify!(Air2Ground_Header), 1759 | "::", 1760 | stringify!(type_) 1761 | ) 1762 | ); 1763 | assert_eq!( 1764 | unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, 1765 | 1usize, 1766 | concat!( 1767 | "Offset of field: ", 1768 | stringify!(Air2Ground_Header), 1769 | "::", 1770 | stringify!(size) 1771 | ) 1772 | ); 1773 | assert_eq!( 1774 | unsafe { ::std::ptr::addr_of!((*ptr).pong) as usize - ptr as usize }, 1775 | 5usize, 1776 | concat!( 1777 | "Offset of field: ", 1778 | stringify!(Air2Ground_Header), 1779 | "::", 1780 | stringify!(pong) 1781 | ) 1782 | ); 1783 | assert_eq!( 1784 | unsafe { ::std::ptr::addr_of!((*ptr).crc) as usize - ptr as usize }, 1785 | 6usize, 1786 | concat!( 1787 | "Offset of field: ", 1788 | stringify!(Air2Ground_Header), 1789 | "::", 1790 | stringify!(crc) 1791 | ) 1792 | ); 1793 | } 1794 | #[repr(C, packed)] 1795 | #[derive(Debug, Copy, Clone)] 1796 | pub struct Air2Ground_Video_Packet { 1797 | pub _base: Air2Ground_Header, 1798 | pub resolution: Resolution, 1799 | pub _bitfield_align_1: [u8; 0], 1800 | pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, 1801 | pub frame_index: u32, 1802 | } 1803 | #[test] 1804 | fn bindgen_test_layout_Air2Ground_Video_Packet() { 1805 | const UNINIT: ::std::mem::MaybeUninit = 1806 | ::std::mem::MaybeUninit::uninit(); 1807 | let ptr = UNINIT.as_ptr(); 1808 | assert_eq!( 1809 | ::std::mem::size_of::(), 1810 | 13usize, 1811 | concat!("Size of: ", stringify!(Air2Ground_Video_Packet)) 1812 | ); 1813 | assert_eq!( 1814 | ::std::mem::align_of::(), 1815 | 1usize, 1816 | concat!("Alignment of ", stringify!(Air2Ground_Video_Packet)) 1817 | ); 1818 | assert_eq!( 1819 | unsafe { ::std::ptr::addr_of!((*ptr).resolution) as usize - ptr as usize }, 1820 | 7usize, 1821 | concat!( 1822 | "Offset of field: ", 1823 | stringify!(Air2Ground_Video_Packet), 1824 | "::", 1825 | stringify!(resolution) 1826 | ) 1827 | ); 1828 | assert_eq!( 1829 | unsafe { ::std::ptr::addr_of!((*ptr).frame_index) as usize - ptr as usize }, 1830 | 9usize, 1831 | concat!( 1832 | "Offset of field: ", 1833 | stringify!(Air2Ground_Video_Packet), 1834 | "::", 1835 | stringify!(frame_index) 1836 | ) 1837 | ); 1838 | } 1839 | impl Air2Ground_Video_Packet { 1840 | #[inline] 1841 | pub fn part_index(&self) -> u8 { 1842 | unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 7u8) as u8) } 1843 | } 1844 | #[inline] 1845 | pub fn set_part_index(&mut self, val: u8) { 1846 | unsafe { 1847 | let val: u8 = ::std::mem::transmute(val); 1848 | self._bitfield_1.set(0usize, 7u8, val as u64) 1849 | } 1850 | } 1851 | #[inline] 1852 | pub fn last_part(&self) -> u8 { 1853 | unsafe { ::std::mem::transmute(self._bitfield_1.get(7usize, 1u8) as u8) } 1854 | } 1855 | #[inline] 1856 | pub fn set_last_part(&mut self, val: u8) { 1857 | unsafe { 1858 | let val: u8 = ::std::mem::transmute(val); 1859 | self._bitfield_1.set(7usize, 1u8, val as u64) 1860 | } 1861 | } 1862 | #[inline] 1863 | pub fn new_bitfield_1(part_index: u8, last_part: u8) -> __BindgenBitfieldUnit<[u8; 1usize]> { 1864 | let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = Default::default(); 1865 | __bindgen_bitfield_unit.set(0usize, 7u8, { 1866 | let part_index: u8 = unsafe { ::std::mem::transmute(part_index) }; 1867 | part_index as u64 1868 | }); 1869 | __bindgen_bitfield_unit.set(7usize, 1u8, { 1870 | let last_part: u8 = unsafe { ::std::mem::transmute(last_part) }; 1871 | last_part as u64 1872 | }); 1873 | __bindgen_bitfield_unit 1874 | } 1875 | } 1876 | #[repr(C)] 1877 | #[derive(Debug, Copy, Clone)] 1878 | pub struct __locale_data { 1879 | pub _address: u8, 1880 | } 1881 | -------------------------------------------------------------------------------- /tests/send_a_frame.rs: -------------------------------------------------------------------------------- 1 | 2 | use esp_vtx_gs_rs::tests::{self, init_cap_and_recv_packets}; 3 | use std::{net::{UdpSocket, SocketAddr, Ipv4Addr}, fs::OpenOptions, io::Write}; 4 | fn main(){ 5 | let mut cap_handler = init_cap_and_recv_packets(40); 6 | let mut keys:Vec = cap_handler.blocks.keys().cloned().collect(); 7 | keys.sort(); 8 | for block_index in keys{ 9 | if let Some(out) = cap_handler.process_block(block_index){ 10 | cap_handler.process_air2ground_packets(out); 11 | } 12 | } 13 | assert_ne!(cap_handler.finish_frame_index , 0); 14 | 15 | let frame = cap_handler.frames.get(&cap_handler.finish_frame_index).unwrap(); 16 | let data = frame.get_jpegdata(); 17 | let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); 18 | 19 | let mut file = OpenOptions::new().read(true).write(true).create(true).open("test.jpeg").unwrap(); 20 | file.write(&data).unwrap(); 21 | 22 | let target =SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(),12345); 23 | loop { 24 | socket.send_to(&data,target).unwrap(); 25 | } 26 | /* 27 | directly test the jpeg out: 28 | gst-launch-1.0 udpsrc port=12345 ! image/jpeg,width=200,height=200,framerate=30/1 ! jpegdec ! videoconvert ! autovideosink 29 | 30 | test adding rtp header to jpeg: 31 | server: 32 | gst-launch-1.0 udpsrc port=12345 ! image/jpeg,width=200,height=200,framerate=30/1 ! rtpjpegpay ! udpsink sync=false host=127.0.0.1 port=5600 33 | 34 | client(play): 35 | gst-launch-1.0 udpsrc port=5600 ! application/x-rtp, payload=26 ! rtpjpegdepay ! jpegdec ! videoconvert ! autovideosink 36 | or 37 | ffplay rtp://127.0.0.1:5600 -fflags nobuffer -flags low_delay -framedrop 38 | 39 | */ 40 | } 41 | -------------------------------------------------------------------------------- /tests/test.sdp: -------------------------------------------------------------------------------- 1 | m=video 5600 RTP/AVP 26 2 | c=IN IP4 127.0.0.1 3 | a=rtpmap:26 JPEG/90000 4 | --------------------------------------------------------------------------------