kopia lustrzana https://github.com/AlexandreRouma/SDRPlusPlus
Porównaj commity
812 Commity
Autor | SHA1 | Data |
---|---|---|
AlexandreRouma | e99e84e809 | |
AlexandreRouma | 7a4281dd76 | |
AlexandreRouma | c89763a989 | |
AlexandreRouma | 27edc260c9 | |
AlexandreRouma | 2ea7ac496f | |
AlexandreRouma | 314d78d9d2 | |
AlexandreRouma | 4e455e6661 | |
Rafael Beraldo | 58b86fcee5 | |
AlexandreRouma | 27072e9fe7 | |
AlexandreRouma | da1417b5ab | |
AlexandreRouma | e60eca5d6d | |
AlexandreRouma | ccb10bfb9a | |
AlexandreRouma | 2813aa7c93 | |
AlexandreRouma | c61fc400a6 | |
AlexandreRouma | 779ef7ecf1 | |
AlexandreRouma | 6fdab5e0c2 | |
AlexandreRouma | ea08fac32e | |
AlexandreRouma | 632a4eebab | |
AlexandreRouma | e118598f57 | |
AlexandreRouma | a2d49b2f87 | |
AlexandreRouma | 38abfc715e | |
AlexandreRouma | 07eebd7018 | |
AlexandreRouma | d12021fc2f | |
AlexandreRouma | db1682a2ac | |
AlexandreRouma | fdfb1dbf5e | |
AlexandreRouma | 17f698577f | |
AlexandreRouma | 8eaa987d90 | |
AlexandreRouma | 12f7efed32 | |
AlexandreRouma | 065a5b4c40 | |
AlexandreRouma | 70f90fd570 | |
AlexandreRouma | a2054ad780 | |
AlexandreRouma | e1c48e9a1f | |
AlexandreRouma | 867a8680e1 | |
AlexandreRouma | bf831e3a50 | |
AlexandreRouma | eb8b852ea6 | |
AlexandreRouma | 67520ea45e | |
AlexandreRouma | a3f0ad238a | |
AlexandreRouma | feb9789896 | |
AlexandreRouma | 3a5096092d | |
LEDFlighter | 9dc0196a16 | |
LEDFlighter | b1603f0e72 | |
LEDFlighter | 09467439e3 | |
AlexandreRouma | 021928bbda | |
AlexandreRouma | 7c933d5103 | |
AlexandreRouma | a987c112a3 | |
AlexandreRouma | f1339f08cf | |
AlexandreRouma | 650a61930c | |
AlexandreRouma | 61ffb3e6bf | |
AlexandreRouma | 9ab3c97c44 | |
AlexandreRouma | edc08ddc08 | |
AlexandreRouma | 95052c34ff | |
AlexandreRouma | 34171d4edc | |
AlexandreRouma | 726e1069bf | |
AlexandreRouma | 61c14bab48 | |
AlexandreRouma | 01ab1831e8 | |
AlexandreRouma | 2b752bb267 | |
AlexandreRouma | 5204cfec56 | |
AlexandreRouma | c616892eda | |
AlexandreRouma | 5f23c1f312 | |
AlexandreRouma | 5e0c4449f8 | |
AlexandreRouma | cd3e2b6c05 | |
AlexandreRouma | ba5380f9bb | |
AlexandreRouma | daf0f8c159 | |
AlexandreRouma | 63aa45de9e | |
AlexandreRouma | c0a84f8703 | |
AlexandreRouma | f66f2c25e1 | |
AlexandreRouma | bddfe5396f | |
AlexandreRouma | d5fa76df06 | |
AlexandreRouma | 8029cef4da | |
AlexandreRouma | d84bb9bdec | |
AlexandreRouma | a0ff745b63 | |
AlexandreRouma | a08d2a0f85 | |
AlexandreRouma | 7ab743d05b | |
AlexandreRouma | 122e67ef65 | |
AlexandreRouma | fbeb2195da | |
AlexandreRouma | 1f2b50c9bb | |
AlexandreRouma | f486c657c1 | |
AlexandreRouma | f1f04d59fe | |
AlexandreRouma | ef42ea01d8 | |
AlexandreRouma | 3fc893568a | |
AlexandreRouma | 4b6835141e | |
AlexandreRouma | a9e59bdf3c | |
AlexandreRouma | f0bd17f9f4 | |
AlexandreRouma | a8ed213ed3 | |
AlexandreRouma | f8183739f7 | |
AlexandreRouma | 120745de19 | |
AlexandreRouma | 05ab17add3 | |
AlexandreRouma | 2ef8ee3629 | |
AlexandreRouma | 14cb839863 | |
AlexandreRouma | 9501371c6c | |
AlexandreRouma | ff23d7e43f | |
AlexandreRouma | f541328e5c | |
AlexandreRouma | be8edbfa9e | |
AlexandreRouma | 11a7c382e8 | |
AlexandreRouma | 54276177ae | |
AlexandreRouma | bc77bab45f | |
AlexandreRouma | 97d0a07ec7 | |
AlexandreRouma | 6b5de78e80 | |
AlexandreRouma | 1cd8c2510a | |
AlexandreRouma | 32cbd726fd | |
AlexandreRouma | 175992b081 | |
AlexandreRouma | 31c9e5767e | |
AlexandreRouma | e6a02a3944 | |
AlexandreRouma | 00e6832055 | |
AlexandreRouma | bc8baca190 | |
AlexandreRouma | 08e75b6d14 | |
AlexandreRouma | e9ec79f6ef | |
AlexandreRouma | cd996292bc | |
AlexandreRouma | 06b7ad5c98 | |
AlexandreRouma | 38a95b4011 | |
AlexandreRouma | f6052d913a | |
AlexandreRouma | 2b00370cf3 | |
AlexandreRouma | 09f4071803 | |
AlexandreRouma | e61ef29e0f | |
AlexandreRouma | eb36f86d41 | |
AlexandreRouma | 29889a289f | |
AlexandreRouma | 859af77bd3 | |
Davide Rovelli | 0a3d1de02f | |
AlexandreRouma | db3fbd2975 | |
AlexandreRouma | f5adc7c587 | |
AlexandreRouma | 255988ee46 | |
AlexandreRouma | 68bf2fc16f | |
AlexandreRouma | 3aa167701e | |
AlexandreRouma | 97c1a132a5 | |
AlexandreRouma | 118e56897c | |
AlexandreRouma | af8c085d43 | |
Davide Rovelli | 708f74e179 | |
AlexandreRouma | eab4264604 | |
AlexandreRouma | 4b77d8c395 | |
AlexandreRouma | 854ed89b82 | |
AlexandreRouma | 27ab5bf3c1 | |
AlexandreRouma | 159f59b858 | |
AlexandreRouma | 93cafe7109 | |
AlexandreRouma | 74ae8a45d9 | |
AlexandreRouma | 691216a298 | |
AlexandreRouma | 3e58d4ba31 | |
AlexandreRouma | 86dcec7495 | |
Henner Zeller | 5a003e99d2 | |
AlexandreRouma | f197cf6bd9 | |
AlexandreRouma | 8cefeadbd4 | |
Henner Zeller | 23ae66151b | |
AlexandreRouma | fa76b4e865 | |
AlexandreRouma | 5e195a0d43 | |
AlexandreRouma | 5e299d9d23 | |
AlexandreRouma | fd5813df6d | |
AlexandreRouma | eabb842b6b | |
AlexandreRouma | 5a1945f779 | |
AlexandreRouma | 052167962d | |
AlexandreRouma | 6fc41a81a7 | |
AlexandreRouma | e710b6c6dc | |
AlexandreRouma | a91434c5fe | |
AlexandreRouma | 193580caf3 | |
AlexandreRouma | ead2ac6128 | |
Wil Clouser | 505cbb0ba2 | |
AlexandreRouma | b1030cbdfb | |
AlexandreRouma | f3c5b2c31f | |
AlexandreRouma | 2432390600 | |
AlexandreRouma | 794d6ff5ac | |
AlexandreRouma | 4803271115 | |
AlexandreRouma | 78daed7879 | |
AlexandreRouma | 5f297b1a69 | |
AlexandreRouma | 7c5d4226eb | |
AlexandreRouma | ec086ebbdf | |
AlexandreRouma | d10d420467 | |
AlexandreRouma | 5bf989f49d | |
AlexandreRouma | 4b3b6976d6 | |
AlexandreRouma | 55ddd383d2 | |
AlexandreRouma | a043ab2dd3 | |
Davide Rovelli | d270e1c5e8 | |
Davide Rovelli | e41f24a95e | |
Davide Rovelli | 766b3db363 | |
AlexandreRouma | 0632342bb7 | |
AlexandreRouma | 27b07ed0e8 | |
AlexandreRouma | a824c83848 | |
AlexandreRouma | 0e50ee0e67 | |
AlexandreRouma | a55d1d9c06 | |
Ivan | 97187b790f | |
AlexandreRouma | 9c1361a8a9 | |
AlexandreRouma | 4d0d14856b | |
AlexandreRouma | 365ab2325e | |
AlexandreRouma | 4da7e686f3 | |
AlexandreRouma | c1d9ab64f8 | |
AlexandreRouma | ea33135bf1 | |
Bastien Cabay | 2081384905 | |
theverygaming | 6b31134af2 | |
AlexandreRouma | 99d2786c25 | |
nmaster2042 | 320f4459ed | |
AlexandreRouma | de5816f79f | |
theverygaming | 7b9c01ec73 | |
AlexandreRouma | f06eccd97c | |
Manawyrm | 88baa8a48e | |
Matt Mead | b436fd0745 | |
AlexandreRouma | 6fa4299136 | |
AlexandreRouma | 220dcbcc76 | |
AlexandreRouma | 15ad065feb | |
Vladimir | dddf84510e | |
AlexandreRouma | acd9ad9781 | |
AlexandreRouma | 168e28cc44 | |
AlexandreRouma | 3b9867c1d7 | |
AlexandreRouma | ff7ef78b8f | |
AlexandreRouma | 87add9ad83 | |
Benjamin Vernoux | 6cd09f9b60 | |
AlexandreRouma | 8d05c1e181 | |
AlexandreRouma | 1c081cad78 | |
Kenji Rikitake | aa929a1e79 | |
AlexandreRouma | 5acdab0d22 | |
AlexandreRouma | 3e3846daa1 | |
AlexandreRouma | 47617e1acd | |
AlexandreRouma | 1df51020aa | |
AlexandreRouma | aa1fd9e573 | |
AlexandreRouma | 21816fb438 | |
AlexandreRouma | 3a06612ff5 | |
AlexandreRouma | a53bf05ed3 | |
AlexandreRouma | 78c57db116 | |
AlexandreRouma | c16281f68a | |
AlexandreRouma | 32c580ba57 | |
AlexandreRouma | 664b5d85e2 | |
AlexandreRouma | 6bcb62bfb2 | |
AlexandreRouma | 0e7c754b8b | |
AlexandreRouma | 71327cd695 | |
AlexandreRouma | f296730302 | |
AlexandreRouma | b89fdba433 | |
AlexandreRouma | 2c3b522787 | |
AlexandreRouma | 528763d10e | |
AlexandreRouma | 582aeed640 | |
AlexandreRouma | 9c0b57a036 | |
AlexandreRouma | 604f95fd96 | |
AlexandreRouma | c892e51000 | |
AlexandreRouma | 3336ae4aa5 | |
AlexandreRouma | 190cea8e4e | |
AlexandreRouma | 13a268a3e1 | |
AlexandreRouma | 800a8b22c7 | |
AlexandreRouma | 2eb030dd83 | |
AlexandreRouma | 365fe1930c | |
AlexandreRouma | 342a677c3f | |
AlexandreRouma | b5c41bcb3a | |
AlexandreRouma | f578adceef | |
AlexandreRouma | a9f882e5b1 | |
AlexandreRouma | 3420808f3a | |
AlexandreRouma | d3d245992d | |
AlexandreRouma | 9a3414b847 | |
Sergey Sharybin | 90c26f8c1b | |
AlexandreRouma | ec4dc6cc9e | |
AlexandreRouma | 93b28d1495 | |
AlexandreRouma | 84291deaf6 | |
AlexandreRouma | 21e0696917 | |
AlexandreRouma | 19247ef4f2 | |
AlexandreRouma | 1e5601e773 | |
Sergey Sharybin | ae1fd87f02 | |
AlexandreRouma | ab2aee316c | |
Bastien Cabay | 109374277e | |
AlexandreRouma | 692436f6e4 | |
Frank Werner-Krippendorf | eccb715d0c | |
AlexandreRouma | f6f074e0c7 | |
AlexandreRouma | 50a77a7e60 | |
AlexandreRouma | a4f3c92a03 | |
AlexandreRouma | 37920b6476 | |
AlexandreRouma | 314b8bf72d | |
AlexandreRouma | 5f0858bab2 | |
AlexandreRouma | 007761a027 | |
AlexandreRouma | 801f1be6b2 | |
AlexandreRouma | 9cc793e328 | |
konung-yaropolk | 1e01313612 | |
AlexandreRouma | 4283cacae6 | |
AlexandreRouma | 6f9dacdd53 | |
konung-yaropolk | e64c343645 | |
kek | b9effce7d6 | |
kek | 45a13227de | |
AlexandreRouma | 5b47f900a6 | |
AlexandreRouma | 82fd3732a9 | |
AlexandreRouma | 8d6ed17e01 | |
AlexandreRouma | aa2071e2df | |
AlexandreRouma | b32618708f | |
AlexandreRouma | ac875aee3b | |
AlexandreRouma | df83d65271 | |
AlexandreRouma | 7723d15e8f | |
AlexandreRouma | a8cbc37e0d | |
AlexandreRouma | 0d149f997f | |
AlexandreRouma | 7e80bbd02c | |
AlexandreRouma | edb4ac45b2 | |
AlexandreRouma | 63416fe93a | |
AlexandreRouma | 0fedcf8745 | |
AlexandreRouma | fe821fb830 | |
AlexandreRouma | ea882cb285 | |
AlexandreRouma | 13e81c9f6b | |
AlexandreRouma | 290c989451 | |
AlexandreRouma | b7ca19583a | |
AlexandreRouma | 1f97e9e10b | |
AlexandreRouma | 93e985ab54 | |
AlexandreRouma | 8f972ee0b2 | |
AlexandreRouma | 570b8dbd7c | |
AlexandreRouma | c0c5b1186c | |
AlexandreRouma | d5a9538d0c | |
AlexandreRouma | 7cfc30ee6e | |
AlexandreRouma | a1b6cbb38a | |
AlexandreRouma | a3b13e572b | |
AlexandreRouma | 16eaa0cf59 | |
AlexandreRouma | fd65984762 | |
AlexandreRouma | 7094368113 | |
AlexandreRouma | 208851ebc5 | |
AlexandreRouma | 0a6fbdb393 | |
AlexandreRouma | 3451edb131 | |
AlexandreRouma | bbf0c17cb8 | |
AlexandreRouma | 7758c40bd7 | |
AlexandreRouma | 8a2d0fe56b | |
AlexandreRouma | 31ff7f3224 | |
AlexandreRouma | e59d804b31 | |
AlexandreRouma | 66bbc93535 | |
AlexandreRouma | ab5d7a73c1 | |
AlexandreRouma | 7a1a37fbf6 | |
AlexandreRouma | a58683f748 | |
AlexandreRouma | d020dcc4a3 | |
AlexandreRouma | 691ab585e2 | |
AlexandreRouma | bad8ecba49 | |
KentuckyFriedData | d21a6af5a9 | |
AlexandreRouma | a53dc1a6ae | |
AlexandreRouma | b3222003b1 | |
AlexandreRouma | e3914ebdc6 | |
AlexandreRouma | 1ae1cc0e77 | |
AlexandreRouma | 55db98d1df | |
AlexandreRouma | 90ce82190b | |
AlexandreRouma | a1cbc69a65 | |
AlexandreRouma | ffefd9cce8 | |
AlexandreRouma | 4d890e78ed | |
AlexandreRouma | 4eabc829fa | |
AlexandreRouma | ee79bf9f81 | |
AlexandreRouma | 447d0e969e | |
AlexandreRouma | 637d683c0a | |
AlexandreRouma | 5773419257 | |
AlexandreRouma | 385b34a0a1 | |
AlexandreRouma | 8771e4bf09 | |
Circuit Chaos | 0ba0a3ab97 | |
AlexandreRouma | 9b33d8d63b | |
AlexandreRouma | bd99210fd3 | |
AlexandreRouma | a426f7b3ab | |
Jacopo Cassinis | 3d4c7550be | |
Jacopo Cassinis | d14fc3805c | |
AlexandreRouma | ea23c44266 | |
AlexandreRouma | fa2e13f3ea | |
AlexandreRouma | 643d47fe47 | |
AlexandreRouma | 5eba556605 | |
AlexandreRouma | 5c690c9753 | |
Frank Werner-Krippendorf | 643cad3581 | |
AlexandreRouma | bd854b590e | |
AlexandreRouma | f163e926c7 | |
AlexandreRouma | d069fb3af8 | |
AlexandreRouma | f97ca9ac05 | |
AlexandreRouma | b104e82874 | |
AlexandreRouma | 3520424208 | |
AlexandreRouma | 9ae6a74408 | |
AlexandreRouma | 5eb42b61e9 | |
AlexandreRouma | a1259d7d32 | |
AlexandreRouma | 31ac8f7b70 | |
AlexandreRouma | 9f472330f8 | |
AlexandreRouma | df91f56283 | |
AlexandreRouma | f022c21f11 | |
AlexandreRouma | 5aac9d66e0 | |
AlexandreRouma | a9a0798d7d | |
AlexandreRouma | bd947c2669 | |
AlexandreRouma | 6adf0baaa7 | |
AlexandreRouma | fb10d0f917 | |
Jeff Rizzo | 61f19f44a2 | |
AlexandreRouma | 638306e2da | |
AlexandreRouma | 2ac1a38ea4 | |
AlexandreRouma | 1c373e9cdb | |
AlexandreRouma | c4bac3b298 | |
AlexandreRouma | 0a4c191054 | |
AlexandreRouma | c72c8d056d | |
AlexandreRouma | d74ea13878 | |
AlexandreRouma | d16c08c8b2 | |
AlexandreRouma | ebc9911f18 | |
AlexandreRouma | aa06db4d7a | |
AlexandreRouma | 9ccc14848b | |
AlexandreRouma | 09d814e845 | |
AlexandreRouma | d4a6ada56e | |
AlexandreRouma | c4fd285f7b | |
AlexandreRouma | cc6b239d22 | |
AlexandreRouma | a9e8db2a24 | |
AlexandreRouma | 8eed0fcc9c | |
AlexandreRouma | 68ba6d7d19 | |
AlexandreRouma | a85bae9527 | |
AlexandreRouma | 34b0577f3b | |
AlexandreRouma | 52a4143cf5 | |
AlexandreRouma | b65da2fd49 | |
AlexandreRouma | c95c7b18af | |
AlexandreRouma | f4bd483410 | |
AlexandreRouma | 869b3e0abd | |
AlexandreRouma | 3421aae9a2 | |
AlexandreRouma | f49fbd2a73 | |
AlexandreRouma | 5b8b344142 | |
AlexandreRouma | 0c8f6ab836 | |
AlexandreRouma | 4047d3bcc2 | |
AlexandreRouma | dcb6321531 | |
AlexandreRouma | bd9df6ecf9 | |
AlexandreRouma | 81ac817639 | |
AlexandreRouma | fccd08a6e0 | |
AlexandreRouma | e97dcecc6e | |
AlexandreRouma | 54db4b41a4 | |
AlexandreRouma | 70ff76e553 | |
AlexandreRouma | 0f7c17f007 | |
AlexandreRouma | 6cf474144b | |
AlexandreRouma | 7ae59681d5 | |
AlexandreRouma | c7a1bda364 | |
AlexandreRouma | 1c02f4edca | |
AlexandreRouma | 4479170cc2 | |
AlexandreRouma | cd71becd8a | |
AlexandreRouma | 72b895fc67 | |
Zilog80 | 6c93d9b2fa | |
AlexandreRouma | ce3fea3747 | |
AlexandreRouma | 9f0daf7d45 | |
AlexandreRouma | 6d784dfe27 | |
AlexandreRouma | efcf26f0ac | |
AlexandreRouma | 14e37b41d4 | |
AlexandreRouma | ad36ede26b | |
EmstallZ | 18a924d3a9 | |
AlexandreRouma | fb85177987 | |
AlexandreRouma | 90a8f617e9 | |
AlexandreRouma | 575a941e24 | |
AlexandreRouma | 8efd5cd01a | |
AlexandreRouma | 50d7e5f86d | |
AlexandreRouma | dcda49aea8 | |
AlexandreRouma | 3262f54100 | |
AlexandreRouma | 63bb9ad9af | |
AlexandreRouma | 277d399e48 | |
AlexandreRouma | 25f09a355e | |
AlexandreRouma | 5bf5a10a12 | |
AlexandreRouma | 8b7afd88f9 | |
AlexandreRouma | c57482771b | |
AlexandreRouma | e03e95cc54 | |
AlexandreRouma | 76b41cb9ab | |
Daniele Forsi | 55b468a02e | |
AlexandreRouma | 039ef5eae3 | |
AlexandreRouma | d3e9ebef72 | |
AlexandreRouma | dbedc0d352 | |
AlexandreRouma | d422230ae9 | |
AlexandreRouma | db5914a4d1 | |
AlexandreRouma | 164970abf3 | |
AlexandreRouma | 76c744a1bb | |
AlexandreRouma | e5f73e36d9 | |
AlexandreRouma | 381c9d0e4b | |
AlexandreRouma | 30b6c2b1da | |
AlexandreRouma | 3ab8badb6a | |
AlexandreRouma | 96f5b37f76 | |
AlexandreRouma | bdd4998b1b | |
AlexandreRouma | ae149b256b | |
AlexandreRouma | 06210ae825 | |
AlexandreRouma | b5857e2078 | |
AlexandreRouma | edf22ccfe8 | |
Jacopo Cassinis | 1af234e379 | |
AlexandreRouma | 46f17019a7 | |
AlexandreRouma | 74fd30f08c | |
AlexandreRouma | ff6754099f | |
AlexandreRouma | 3f6687659e | |
AlexandreRouma | c3ddffb3a9 | |
AlexandreRouma | 7d64d78d67 | |
AlexandreRouma | fb0e0d732b | |
AlexandreRouma | db034527e9 | |
AlexandreRouma | 97643edf2f | |
AlexandreRouma | 01e1430847 | |
AlexandreRouma | 218fd6ccf4 | |
AlexandreRouma | f2b8418a25 | |
AlexandreRouma | b943e6e869 | |
AlexandreRouma | f7c566f652 | |
AlexandreRouma | 834890b69a | |
AlexandreRouma | 53afaeda9e | |
AlexandreRouma | ce1b0d0170 | |
AlexandreRouma | 927bbab330 | |
AlexandreRouma | fd5970b35a | |
AlexandreRouma | 1dddbadd04 | |
AlexandreRouma | ccc57cddc7 | |
AlexandreRouma | 9b1ec79d61 | |
AlexandreRouma | e06646367b | |
AlexandreRouma | b9e269f9dc | |
AlexandreRouma | ed3f87da29 | |
AlexandreRouma | 4f601405a1 | |
AlexandreRouma | cb59b04b17 | |
AlexandreRouma | c5f30f6d6a | |
AlexandreRouma | 36adc102ee | |
AlexandreRouma | d1318d3a0f | |
AlexandreRouma | 343ec6ca1c | |
cropinghigh | e4926c236f | |
Tomas Pytel | 61614da910 | |
Tomas Pytel | 5712db9bf8 | |
AlexandreRouma | 79a15ed186 | |
Cam K | 527d40c95e | |
AlexandreRouma | 6f747dad0d | |
AlexandreRouma | 663dd8d887 | |
AlexandreRouma | 2836292d58 | |
Ozies | 09c8346d4b | |
AlexandreRouma | 8dbae4e307 | |
Frank Werner-Krippendorf | 4c004d16a2 | |
AlexandreRouma | 747b6bfbc6 | |
AlexandreRouma | 83da29e80b | |
Ozies | 28dccee34b | |
AlexandreRouma | 54dd3a77db | |
AlexandreRouma | 8d78eb301c | |
AlexandreRouma | 03f173a3ac | |
AlexandreRouma | b8bc942b84 | |
AlexandreRouma | 80d244003a | |
AlexandreRouma | 50416b3319 | |
AlexandreRouma | ea59bc5cc0 | |
AlexandreRouma | 47b54743bd | |
AlexandreRouma | 58fcbbc5d2 | |
AlexandreRouma | 842b23b2f4 | |
AlexandreRouma | f58c7dd62f | |
Cam K | 6958e46875 | |
AlexandreRouma | e82e89a87c | |
AlexandreRouma | 763807565c | |
AlexandreRouma | 8a603c5420 | |
AlexandreRouma | 9999693c0d | |
AlexandreRouma | 81692fa910 | |
AlexandreRouma | 9bbc50ff3c | |
AlexandreRouma | 2779516378 | |
AlexandreRouma | 5c138aa4a5 | |
AlexandreRouma | 7de9f3f497 | |
Daniele Forsi | 98f4f560ad | |
AlexandreRouma | a87aedabb8 | |
AlexandreRouma | f46fa2157b | |
AlexandreRouma | b5cbafb01d | |
AlexandreRouma | 51c940acd4 | |
AlexandreRouma | 04e54a2d57 | |
AlexandreRouma | 6eb8bfc29a | |
AlexandreRouma | 96da404149 | |
AlexandreRouma | e9cb7fda42 | |
AlexandreRouma | e5f3d1672c | |
AlexandreRouma | 71c95af711 | |
Orry Verducci | 94cf720cfd | |
AlexandreRouma | 9969ce018b | |
AlexandreRouma | 3c19081561 | |
AlexandreRouma | 3ab669ecda | |
AlexandreRouma | 860121dad2 | |
AlexandreRouma | 5e5c575e93 | |
AlexandreRouma | 8dcf17bef7 | |
AlexandreRouma | 4fcd06eff6 | |
AlexandreRouma | dcc0fef235 | |
AlexandreRouma | 260651fb5c | |
AlexandreRouma | 97346e6621 | |
AlexandreRouma | 80dcf2d968 | |
AlexandreRouma | 963c5c6581 | |
AlexandreRouma | a7b0b52da9 | |
AlexandreRouma | 03f0704dff | |
AlexandreRouma | e158eabbf4 | |
AlexandreRouma | 4c0220a228 | |
Christopher Hewitt | aa265ea312 | |
Christopher Hewitt | 2c3b603b88 | |
AlexandreRouma | 75da59833a | |
AlexandreRouma | fa0967313f | |
AlexandreRouma | 6fba9d7904 | |
AlexandreRouma | c1685a441c | |
AlexandreRouma | 9d7c1369ca | |
AlexandreRouma | 6dc97de57b | |
AlexandreRouma | 0dc2f5f7c9 | |
AlexandreRouma | 983c4c0f87 | |
AlexandreRouma | 0ac85e0daf | |
AlexandreRouma | da06fc39db | |
AlexandreRouma | 4c1b50a3ac | |
AlexandreRouma | 34fc32dcf7 | |
AlexandreRouma | 070e27505b | |
AlexandreRouma | 74b9d13360 | |
kistlin | 81d23967b6 | |
kistlin | 174158233b | |
AlexandreRouma | 1185e4e114 | |
AlexandreRouma | 290bf5e32a | |
AlexandreRouma | 4db485e209 | |
AlexandreRouma | a58ae2bd98 | |
AlexandreRouma | aab9d9e6ad | |
AlexandreRouma | 7cc06b7a7b | |
AlexandreRouma | efecd14281 | |
AlexandreRouma | 33914a7316 | |
AlexandreRouma | 608979a0b7 | |
Michael Mangeng | 3a815d94b9 | |
Michael Mangeng | 7b77bb3d45 | |
AlexandreRouma | 201a612c19 | |
AlexandreRouma | 5a0c1ab5d0 | |
AlexandreRouma | 470e748e4a | |
AlexandreRouma | 66269659c5 | |
AlexandreRouma | 6ded678048 | |
AlexandreRouma | f34614e169 | |
AlexandreRouma | 9d3f0f4f7e | |
AlexandreRouma | 25d585a35a | |
AlexandreRouma | 34bd09a92e | |
AlexandreRouma | e5bbd0fdb3 | |
AlexandreRouma | b141c4b2a5 | |
AlexandreRouma | 5a19829068 | |
AlexandreRouma | 51f84566c4 | |
AlexandreRouma | db8f736d58 | |
AlexandreRouma | 07294034f6 | |
AlexandreRouma | ad2ddc6ad3 | |
AlexandreRouma | b736f83993 | |
AlexandreRouma | d893eaae32 | |
AlexandreRouma | ea587db0cb | |
AlexandreRouma | 8644957881 | |
AlexandreRouma | cc2d73202e | |
AlexandreRouma | fe0b63a275 | |
AlexandreRouma | ef01205fb6 | |
AlexandreRouma | c1cb3d5a1c | |
AlexandreRouma | f1a231b791 | |
AlexandreRouma | 5483268f8f | |
AlexandreRouma | 6c7e952be3 | |
AlexandreRouma | 20b44403b2 | |
AlexandreRouma | 964fd467f8 | |
AlexandreRouma | b4924a8fae | |
AlexandreRouma | cee0f75870 | |
AlexandreRouma | 15010cff01 | |
AlexandreRouma | 241632288e | |
AlexandreRouma | f8ff67c5b0 | |
AlexandreRouma | c1942ac51d | |
AlexandreRouma | 91370993a2 | |
AlexandreRouma | 2a5671878f | |
AlexandreRouma | 1594051a5d | |
AlexandreRouma | 355a6352da | |
AlexandreRouma | 7208028c01 | |
AlexandreRouma | cdc060aa2a | |
AlexandreRouma | 31b2cdd284 | |
AlexandreRouma | 636bb214e8 | |
AlexandreRouma | 8accb531b0 | |
AlexandreRouma | fe285c71ff | |
AlexandreRouma | 62d2dfafd7 | |
AlexandreRouma | 2748c13142 | |
AlexandreRouma | 2daaf00cb3 | |
AlexandreRouma | b148fc8a28 | |
AlexandreRouma | 407efef935 | |
AlexandreRouma | 8c35639767 | |
AlexandreRouma | 5e89c52007 | |
AlexandreRouma | 2261b0fc2b | |
AlexandreRouma | e394b64ad3 | |
AlexandreRouma | fc7d902c1d | |
AlexandreRouma | 2f5a8c38a1 | |
AlexandreRouma | f3e987fb7e | |
Alejandro Sior | abd718b024 | |
AlexandreRouma | 28d056b776 | |
AlexandreRouma | 8c631f40c7 | |
AlexandreRouma | a84d525252 | |
AlexandreRouma | 4ee677154f | |
AlexandreRouma | 098b78dcd1 | |
AlexandreRouma | 46a9ecee72 | |
AlexandreRouma | c320a486b3 | |
AlexandreRouma | 21b405d2bb | |
AlexandreRouma | 9c2cb26376 | |
AlexandreRouma | 3ca7dc87e7 | |
AlexandreRouma | 916c95a75e | |
Alexandre | dde95019ea | |
Alexandre | 170a48f83f | |
Alexandre | a08f5c35af | |
Alexandre | 1fe799b445 | |
Alexandre | 7474241e01 | |
Alexandre | 7faaa21ac1 | |
Alexandre | a6e6c93a50 | |
Alexandre | 10733f7a5d | |
Alexandre | 7f6c555310 | |
Alexandre | c659c4b007 | |
Alexandre | 66dcb5eb79 | |
AlexandreRouma | 6f8fc86236 | |
Ryzerth | 1bbb1eea0e | |
Alexandre | b81d0c47cf | |
AlexandreRouma | 49cf6944f0 | |
AlexandreRouma | ca657c8ca8 | |
AlexandreRouma | 2620d688ec | |
AlexandreRouma | 799e8c7e02 | |
AlexandreRouma | f5b07f6a60 | |
AlexandreRouma | 599a53b49b | |
AlexandreRouma | 0e5384b8ad | |
AlexandreRouma | 715129566d | |
AlexandreRouma | 106e0ada80 | |
AlexandreRouma | 7ad616d62b | |
AlexandreRouma | 40e2564ef9 | |
AlexandreRouma | 0ab4d16f9d | |
AlexandreRouma | d20b41401f | |
AlexandreRouma | cca18f3a70 | |
AlexandreRouma | 07a4ff3e9f | |
AlexandreRouma | a414b75ef4 | |
AlexandreRouma | 12d16fe9ee | |
AlexandreRouma | 07419275ff | |
AlexandreRouma | 927115b50b | |
AlexandreRouma | a938324886 | |
AlexandreRouma | 894700cbab | |
AlexandreRouma | 6ea4f5fd68 | |
AlexandreRouma | ca185bb416 | |
AlexandreRouma | a3dc20b384 | |
cropinghigh | fd643c37f5 | |
AlexandreRouma | c784630345 | |
AlexandreRouma | e6377d4f3d | |
AlexandreRouma | d5becc5fc2 | |
Raov | 9d44f91f45 | |
AlexandreRouma | c7db2d2b6a | |
AlexandreRouma | c8bdd2e52b | |
Nikolay Korotkiy | 2c7c93b64c | |
AlexandreRouma | 312c80b355 | |
AlexandreRouma | a11b74a595 | |
AlexandreRouma | 0f5398b064 | |
AlexandreRouma | f539cfad32 | |
Ryzerth | ab1a482352 | |
AlexandreRouma | 35fc973a65 | |
AlexandreRouma | db8eb47422 | |
KentuckyFriedData | d4795cb369 | |
Ryzerth | 75249fe849 | |
AlexandreRouma | d1aab6f25d | |
AlexandreRouma | afe13969a7 | |
AlexandreRouma | 47e5c589bc | |
AlexandreRouma | 3795e7cf23 | |
AlexandreRouma | d18a019abf | |
Christian Haeusler | 4d7b46b1a8 | |
Christian Haeusler | cf3e024fb9 | |
Ryzerth | 8deb018684 | |
Ryzerth | 33b9b53328 | |
Ryzerth | 011e7ca409 | |
AlexandreRouma | a27a46350e | |
Thomas Gimpel | 3fd4294afa | |
Ryzerth | 4b2f3e4f60 | |
AlexandreRouma | 82cacf14bb | |
AlexandreRouma | 0fffa7d45a | |
AlexandreRouma | 9555dda8a4 | |
AlexandreRouma | 44ad0a1a7e | |
AlexandreRouma | c515ddb811 | |
AlexandreRouma | ea0d905177 | |
AlexandreRouma | 1be3092c7d | |
AlexandreRouma | f29f77bbdc | |
AlexandreRouma | 91d960da3c | |
AlexandreRouma | dd083b6634 | |
AlexandreRouma | b4e2875acd | |
AlexandreRouma | 4ea9b96397 | |
AlexandreRouma | 8c15e78315 | |
AlexandreRouma | 94b7676ca5 | |
AlexandreRouma | 83fc20cacc | |
AlexandreRouma | fcd759654c | |
AlexandreRouma | 73393e36c6 | |
AlexandreRouma | c36034dbb8 | |
AlexandreRouma | a9d92d3a8e | |
AlexandreRouma | 8666aa07e7 | |
AlexandreRouma | a37a2d3b36 | |
AlexandreRouma | dc31539f6e | |
AlexandreRouma | 4564475821 | |
AlexandreRouma | 163e35727c | |
AlexandreRouma | 40d21b3321 | |
AlexandreRouma | fb9bbcb158 | |
AlexandreRouma | c0801a8aed | |
Christian Haeusler | dc43e76405 | |
AlexandreRouma | 8b2f019ce4 | |
AlexandreRouma | 13bafa002a | |
AlexandreRouma | 90ebe373df | |
AlexandreRouma | 5b7fc417ff | |
AlexandreRouma | b4213ea049 | |
AlexandreRouma | 26fa23c8f5 | |
AlexandreRouma | c2da150d43 | |
AlexandreRouma | 48f6642c70 | |
AlexandreRouma | efd3c47a6c | |
AlexandreRouma | 187fc2cb9e | |
AlexandreRouma | c9a78d5dc6 | |
AlexandreRouma | b7c95de8cc | |
AlexandreRouma | bc0de50ba6 | |
AlexandreRouma | 049fc77ff6 | |
AlexandreRouma | 9ee0951874 | |
AlexandreRouma | 841c31daf4 | |
AlexandreRouma | d9b061ef89 | |
AlexandreRouma | ce48257706 | |
AlexandreRouma | fe09a30279 | |
arkhnchul | daa26e8e97 | |
AlexandreRouma | 318e57dc3d | |
AlexandreRouma | b74e2d37a5 | |
AlexandreRouma | 9d34c6a8c1 | |
AlexandreRouma | 2184e15e44 | |
AlexandreRouma | bd427d23b3 | |
AlexandreRouma | 5a2b0c9d79 | |
arkhnchul | a208d4078e | |
arkhnchul | f56113aae4 | |
arkhnchul | 11c6377c7f | |
Ryzerth | 22acf33c01 | |
Ryzerth | ec6a258958 | |
Ryzerth | 012903fbf4 | |
AlexandreRouma | e48b5c6035 | |
arkhnchul | 0a54b92c58 | |
AlexandreRouma | 7c1d1cad22 | |
AlexandreRouma | e101c1ebd7 | |
AlexandreRouma | 68b3eb9b21 | |
AlexandreRouma | c579aca1db | |
AlexandreRouma | c31e260425 | |
AlexandreRouma | fa75a3a176 | |
AlexandreRouma | af59144f5b | |
ericek111 | 04ce4c3583 | |
AlexandreRouma | ba6d9f7202 | |
ericek111 | 49fd49b4d6 | |
ericek111 | 99441ea2eb | |
arkhnchul | dbd734a0b5 | |
AlexandreRouma | f572d12936 | |
Ryzerth | 37bf9c46c5 | |
AlexandreRouma | aa9a2a8b46 | |
Dmitry Obedkov | 124f3368d4 | |
Ryzerth | 51d084c20e | |
Ryzerth | 101674379d | |
Ryzerth | 61bbb4a374 | |
AlexandreRouma | 2d8bbef12a | |
Cyril "Nick" Engmann | 4109ea73b3 | |
Cyril "Nick" Engmann | a7d8ec8a2d | |
Ryzerth | 6036300ecb | |
AlexandreRouma | 9cf3ba79f3 | |
Shuyuan Liu | dcda74c0cf | |
Shuyuan Liu | 4f16c6bf90 | |
Shuyuan Liu | 73daca9116 | |
Ryzerth | 2fd91459fd | |
Ryzerth | 8502bae236 | |
Ryzerth | f01cb4af9f | |
AlexandreRouma | 53cb328c2c | |
Victor Antonovich | 9a2794a0dd | |
AlexandreRouma | c84371ba52 | |
AlexandreRouma | dbf1fb790f | |
AlexandreRouma | 271d1f9240 | |
Ryzerth | b2ce47d975 | |
Victor Antonovich | 6ab59ad3c5 | |
Shuyuan Liu | 3516baa042 | |
AlexandreRouma | 1465fb784f | |
adam | 42918908a0 | |
Ryzerth | 9f0e050d1b |
|
@ -0,0 +1,131 @@
|
|||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveMacros: true
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 0
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '.'
|
||||
Priority: 2
|
||||
SortPriority: 2
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentCaseLabels: false
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: All
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
Standard: Latest
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
...
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Report crashes or unexpected behavior
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
# WARNING: Filling out the template below is NOT optional. Issues not filling out this template will be closed without review.
|
||||
|
||||
FIRST: Before reporting any bug, make sure that the bug you are reporting has not been reported before. Also, try to use the [nightly version](https://www.sdrpp.org/nightly) if possible in case I've already fixed the bug.
|
||||
|
||||
**Hardware**
|
||||
- CPU:
|
||||
- RAM:
|
||||
- GPU:
|
||||
- SDR: (Remote or local? If remote, what protocol?)
|
||||
|
||||
**Software**
|
||||
- Operating System: Name + Exact version (eg. Windows 10 x64, Ubuntu 22.04, MacOS 10.15)
|
||||
- SDR++: Version + Build date (available either in the window title or in the credits menu which you can access by clicking on the SDR++ icon in the top right corner of the software).
|
||||
|
||||
**Bug Description**
|
||||
A clear description of the bug.
|
||||
|
||||
**Steps To Reproduce**
|
||||
1. ...
|
||||
2. ...
|
||||
3. ...
|
||||
|
||||
**Only If SDR++ fails to lauch or the SDR fails to start:**
|
||||
Run SDR++ from a command line window with special parameters:
|
||||
* On Windows, open a terminal and `cd` to SDR++'s directory and run `.\sdrpp.exe -c` (if running SDR++ version 1.0.4 or older, use `-s` instead, though you should probably update SDR++ instead...)
|
||||
* On Linux: Open a terminal and run `sdrpp -c`
|
||||
* On MacOS: Open a terminal and run `/path/to/the/SDR++.app/Contents/MacOS/sdrpp -c`
|
||||
Then, post the **entire** logs from start to after the issue. **DOT NOT truncate to where you *think* the error is...**
|
||||
|
||||
**Screenshots**
|
||||
Add any screenshot that is relevant to the bug (GUI error messages, strange behavior, graphics glitch, etc...).
|
||||
|
||||
**Additional info**
|
||||
Add any other relevant information.
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Feature description**
|
|
@ -0,0 +1,4 @@
|
|||
# Important
|
||||
|
||||
Only bandplan, colormaps and themes are accepted. Code pull requests are **NOT welcome**.
|
||||
Open an issue requesting a feature or discussing a possible bugfix instead.
|
|
@ -1,17 +1,24 @@
|
|||
name: Build Binaries
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- nightly
|
||||
pull_request:
|
||||
branches-ignore:
|
||||
- nightly
|
||||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: Release
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
jobs:
|
||||
build_windows:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create Build Environment
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
|
@ -27,74 +34,164 @@ jobs:
|
|||
|
||||
- name: Patch Pothos with earlier libusb version
|
||||
working-directory: ${{runner.workspace}}
|
||||
run: 7z x libusb.7z -olibusb_old ; rm "C:/Program Files/PothosSDR/bin/libusb-1.0.dll" ; cp "libusb_old/MS64/dll/libusb-1.0.dll" "C:/Program Files/PothosSDR/bin/"
|
||||
run: 7z x libusb.7z -olibusb_old ; rm "C:/Program Files/PothosSDR/bin/libusb-1.0.dll" ; cp "libusb_old/MS64/dll/libusb-1.0.dll" "C:/Program Files/PothosSDR/bin/" ; rm "C:/Program Files/PothosSDR/lib/libusb-1.0.lib" ; cp "libusb_old/MS64/dll/libusb-1.0.lib" "C:/Program Files/PothosSDR/lib/"
|
||||
|
||||
- name: Download SDRPlay API
|
||||
run: Invoke-WebRequest -Uri "https://drive.google.com/uc?id=12UHPMwkfa67A11QZDmpCT4iwHnyJHWuu" -OutFile ${{runner.workspace}}/SDRPlay.zip
|
||||
run: Invoke-WebRequest -Uri "https://www.sdrpp.org/SDRplay.zip" -OutFile ${{runner.workspace}}/SDRplay.zip
|
||||
|
||||
- name: Install SDRPlay API
|
||||
run: 7z x ${{runner.workspace}}/SDRPlay.zip -o"C:/Program Files/"
|
||||
run: 7z x ${{runner.workspace}}/SDRplay.zip -o"C:/Program Files/"
|
||||
|
||||
- name: Download codec2
|
||||
run: git clone https://github.com/AlexandreRouma/codec2
|
||||
|
||||
- name: Prepare MinGW
|
||||
run: C:/msys64/msys2_shell.cmd -defterm -here -no-start -mingw64 -c "pacman --noconfirm -S --needed base-devel mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja"
|
||||
|
||||
- name: Prepare build for codec2
|
||||
run: cd codec2 ; mkdir build ; cd build ; C:/msys64/msys2_shell.cmd -defterm -here -no-start -mingw64 -c "cmake .. -DCMAKE_GNUtoMS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS=-static-libgcc"
|
||||
|
||||
- name: Build codec2
|
||||
run: cd codec2/build ; C:/msys64/msys2_shell.cmd -defterm -here -no-start -mingw64 -c "ninja"
|
||||
|
||||
- name: Install codec2
|
||||
run: mkdir "C:/Program Files/codec2" ; mkdir "C:/Program Files/codec2/include" ; mkdir "C:/Program Files/codec2/include/codec2" ; mkdir "C:/Program Files/codec2/lib" ; cd "codec2" ; xcopy "src" "C:/Program Files/codec2/include" ; cd "build" ; xcopy "src" "C:/Program Files/codec2/lib" ; xcopy "codec2" "C:/Program Files/codec2/include/codec2"
|
||||
|
||||
- name: Install vcpkg dependencies
|
||||
run: vcpkg install fftw3:x64-windows glew:x64-windows glfw3:x64-windows portaudio:x64-windows
|
||||
run: vcpkg install fftw3:x64-windows glfw3:x64-windows portaudio:x64-windows zstd:x64-windows libusb:x64-windows
|
||||
|
||||
- name: Install rtaudio
|
||||
run: git clone https://github.com/thestk/rtaudio ; cd rtaudio ; mkdir build ; cd build ; cmake .. ; cmake --build . --config Release ; cmake --install .
|
||||
run: git clone https://github.com/thestk/rtaudio ; cd rtaudio ; git checkout 2f2fca4502d506abc50f6d4473b2836d24cfb1e3 ; mkdir build ; cd build ; cmake .. ; cmake --build . --config Release ; cmake --install .
|
||||
|
||||
- name: Install libperseus-sdr
|
||||
run: git clone https://github.com/AlexandreRouma/libperseus-sdr ; cd libperseus-sdr ; mkdir build ; cd build ; cmake "-DLIBUSB_LIBRARIES=C:/Program Files/PothosSDR/lib/libusb-1.0.lib" "-DLIBUSB_INCLUDE_DIRS=C:/Program Files/PothosSDR/include/libusb-1.0" .. "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" ; cmake --build . --config Release ; mkdir "C:/Program Files/PothosSDR/include/perseus-sdr" ; cp Release/perseus-sdr.dll "C:/Program Files/PothosSDR/bin" ; cp Release/perseus-sdr.lib "C:/Program Files/PothosSDR/bin" ; cd .. ; xcopy "src" "C:/Program Files/PothosSDR/include/perseus-sdr"
|
||||
|
||||
- name: Prepare CMake
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake "$Env:GITHUB_WORKSPACE" "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON
|
||||
run: cmake "$Env:GITHUB_WORKSPACE" "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake --build . --config Release
|
||||
run: cmake --build . --config Release --verbose
|
||||
|
||||
- name: Create Archive
|
||||
working-directory: ${{runner.workspace}}
|
||||
run: '&($Env:GITHUB_WORKSPACE + "/make_windows_package.ps1") ./build ($Env:GITHUB_WORKSPACE + "/root")'
|
||||
|
||||
- name: Save Archive
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdrpp_windows_x64
|
||||
path: ${{runner.workspace}}/sdrpp_windows_x64.zip
|
||||
|
||||
build_macos:
|
||||
runs-on: macos-latest
|
||||
build_macos_intel:
|
||||
runs-on: macos-12
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create Build Environment
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
|
||||
- name: Install dependencies
|
||||
run: brew install fftw glew glfw volk airspy portaudio hackrf rtl-sdr libbladerf
|
||||
run: brew install pkg-config libusb fftw glfw airspy airspyhf portaudio hackrf libbladerf codec2 zstd autoconf automake libtool && pip3 install mako
|
||||
|
||||
- name: Install volk
|
||||
run: git clone --recursive https://github.com/gnuradio/volk && cd volk && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||
|
||||
- name: Install SDRplay API
|
||||
run: wget https://www.sdrplay.com/software/SDRplayAPI-macos-installer-universal-3.14.0.pkg && sudo installer -pkg SDRplayAPI-macos-installer-universal-3.14.0.pkg -target /
|
||||
|
||||
- name: Install libiio
|
||||
run: wget https://github.com/analogdevicesinc/libiio/archive/refs/tags/v0.25.zip && 7z x v0.25.zip && cd libiio-0.25 && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||
|
||||
- name: Install libad9361
|
||||
run: git clone https://github.com/analogdevicesinc/libad9361-iio && cd libad9361-iio && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||
|
||||
- name: Install LimeSuite
|
||||
run: git clone https://github.com/myriadrf/LimeSuite && cd LimeSuite && mkdir builddir && cd builddir && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||
|
||||
- name: Install libperseus
|
||||
run: git clone https://github.com/Microtelecom/libperseus-sdr && cd libperseus-sdr && autoreconf -i && ./configure --prefix=/usr/local && make && make install && cd ..
|
||||
|
||||
- name: Install more recent librtlsdr
|
||||
run: git clone https://github.com/osmocom/rtl-sdr && cd rtl-sdr && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 LIBRARY_PATH=$(pkg-config --libs-only-L libusb-1.0 | sed 's/\-L//') && sudo make install && cd ../../
|
||||
|
||||
- name: Prepare CMake
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_AIRSPYHF_SOURCE=OFF -DOPT_BUILD_PLUTOSDR_SOURCE=OFF -DOPT_BUILD_SOAPY_SOURCE=OFF -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_AUDIO_SINK=OFF -DOPT_BUILD_PORTAUDIO_SINK=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON
|
||||
run: cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 $GITHUB_WORKSPACE -DOPT_BUILD_PLUTOSDR_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_AUDIO_SINK=OFF -DOPT_BUILD_PORTAUDIO_SINK=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_AUDIO_SOURCE=OFF -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: make -j3
|
||||
run: make VERBOSE=1 -j3
|
||||
|
||||
- name: Create Archive
|
||||
working-directory: ${{runner.workspace}}
|
||||
run: sh $GITHUB_WORKSPACE/make_macos_package.sh ${{runner.workspace}}/build
|
||||
run: cd $GITHUB_WORKSPACE && sh make_macos_bundle.sh ${{runner.workspace}}/build ./SDR++.app && zip -r ${{runner.workspace}}/sdrpp_macos_intel.zip SDR++.app
|
||||
|
||||
- name: Save Archive
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdrpp_macos_amd64
|
||||
path: ${{runner.workspace}}/sdrpp_macos_amd64.pkg
|
||||
|
||||
name: sdrpp_macos_intel
|
||||
path: ${{runner.workspace}}/sdrpp_macos_intel.zip
|
||||
|
||||
build_macos_arm:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create Build Environment
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
|
||||
- name: Install dependencies
|
||||
run: brew install pkg-config libusb fftw glfw airspy airspyhf portaudio hackrf libbladerf codec2 zstd autoconf automake libtool && pip3 install mako --break-system-packages
|
||||
|
||||
- name: Install volk
|
||||
run: git clone --recursive https://github.com/gnuradio/volk && cd volk && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||
|
||||
- name: Install SDRplay API
|
||||
run: wget https://www.sdrplay.com/software/SDRplayAPI-macos-installer-universal-3.14.0.pkg && sudo installer -pkg SDRplayAPI-macos-installer-universal-3.14.0.pkg -target /
|
||||
|
||||
- name: Install libiio
|
||||
run: wget https://github.com/analogdevicesinc/libiio/archive/refs/tags/v0.25.zip && 7z x v0.25.zip && cd libiio-0.25 && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||
|
||||
- name: Install libad9361
|
||||
run: git clone https://github.com/analogdevicesinc/libad9361-iio && cd libad9361-iio && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||
|
||||
- name: Install LimeSuite
|
||||
run: git clone https://github.com/myriadrf/LimeSuite && cd LimeSuite && mkdir builddir && cd builddir && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||
|
||||
# - name: Install libperseus
|
||||
# run: git clone https://github.com/Microtelecom/libperseus-sdr && cd libperseus-sdr && autoreconf -i && ./configure --prefix=/usr/local && make && make install && cd ..
|
||||
|
||||
- name: Install more recent librtlsdr
|
||||
run: git clone https://github.com/osmocom/rtl-sdr && cd rtl-sdr && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 LIBRARY_PATH=$(pkg-config --libs-only-L libusb-1.0 | sed 's/\-L//') && sudo make install && cd ../../
|
||||
|
||||
- name: Prepare CMake
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 $GITHUB_WORKSPACE -DOPT_BUILD_PLUTOSDR_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_AUDIO_SINK=OFF -DOPT_BUILD_PORTAUDIO_SINK=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=OFF -DOPT_BUILD_PERSEUS_SOURCE=OFF -DOPT_BUILD_AUDIO_SOURCE=OFF -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: make VERBOSE=1 -j3
|
||||
|
||||
- name: Create Archive
|
||||
working-directory: ${{runner.workspace}}
|
||||
run: cd $GITHUB_WORKSPACE && sh make_macos_bundle.sh ${{runner.workspace}}/build ./SDR++.app && zip -r ${{runner.workspace}}/sdrpp_macos_arm.zip SDR++.app
|
||||
|
||||
- name: Save Archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdrpp_macos_arm
|
||||
path: ${{runner.workspace}}/sdrpp_macos_arm.zip
|
||||
|
||||
build_debian_buster:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create Docker Image
|
||||
run: cd $GITHUB_WORKSPACE/docker_builds/debian_buster && docker build . --tag sdrpp_build
|
||||
|
||||
|
@ -106,7 +203,7 @@ jobs:
|
|||
run: docker cp build:/root/SDRPlusPlus/sdrpp_debian_amd64.deb ./
|
||||
|
||||
- name: Save Deb Archive
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdrpp_debian_buster_amd64
|
||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||
|
@ -115,7 +212,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create Docker Image
|
||||
run: cd $GITHUB_WORKSPACE/docker_builds/debian_bullseye && docker build . --tag sdrpp_build
|
||||
|
@ -128,16 +225,38 @@ jobs:
|
|||
run: docker cp build:/root/SDRPlusPlus/sdrpp_debian_amd64.deb ./
|
||||
|
||||
- name: Save Deb Archive
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdrpp_debian_bullseye_amd64
|
||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||
|
||||
build_debian_bookworm:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create Docker Image
|
||||
run: cd $GITHUB_WORKSPACE/docker_builds/debian_bookworm && docker build . --tag sdrpp_build
|
||||
|
||||
- name: Run Container
|
||||
run: docker run --name build -v $GITHUB_WORKSPACE:/root/SDRPlusPlus --env BUILD_NO="-$GITHUB_RUN_NUMBER" sdrpp_build /root/do_build.sh
|
||||
|
||||
- name: Recover Deb Archive
|
||||
working-directory: ${{runner.workspace}}
|
||||
run: docker cp build:/root/SDRPlusPlus/sdrpp_debian_amd64.deb ./
|
||||
|
||||
- name: Save Deb Archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdrpp_debian_bookworm_amd64
|
||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||
|
||||
build_debian_sid:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create Docker Image
|
||||
run: cd $GITHUB_WORKSPACE/docker_builds/debian_sid && docker build . --tag sdrpp_build
|
||||
|
@ -150,7 +269,7 @@ jobs:
|
|||
run: docker cp build:/root/SDRPlusPlus/sdrpp_debian_amd64.deb ./
|
||||
|
||||
- name: Save Deb Archive
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdrpp_debian_sid_amd64
|
||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||
|
@ -159,7 +278,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create Docker Image
|
||||
run: cd $GITHUB_WORKSPACE/docker_builds/ubuntu_focal && docker build . --tag sdrpp_build
|
||||
|
@ -172,19 +291,19 @@ jobs:
|
|||
run: docker cp build:/root/SDRPlusPlus/sdrpp_debian_amd64.deb ./
|
||||
|
||||
- name: Save Deb Archive
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdrpp_ubuntu_focal_amd64
|
||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||
|
||||
build_ubuntu_groovy:
|
||||
build_ubuntu_jammy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create Docker Image
|
||||
run: cd $GITHUB_WORKSPACE/docker_builds/ubuntu_groovy && docker build . --tag sdrpp_build
|
||||
run: cd $GITHUB_WORKSPACE/docker_builds/ubuntu_jammy && docker build . --tag sdrpp_build
|
||||
|
||||
- name: Run Container
|
||||
run: docker run --name build -v $GITHUB_WORKSPACE:/root/SDRPlusPlus --env BUILD_NO="-$GITHUB_RUN_NUMBER" sdrpp_build /root/do_build.sh
|
||||
|
@ -194,54 +313,145 @@ jobs:
|
|||
run: docker cp build:/root/SDRPlusPlus/sdrpp_debian_amd64.deb ./
|
||||
|
||||
- name: Save Deb Archive
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdrpp_ubuntu_groovy_amd64
|
||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||
|
||||
build_ubuntu_hirsute:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Create Docker Image
|
||||
run: cd $GITHUB_WORKSPACE/docker_builds/ubuntu_hirsute && docker build . --tag sdrpp_build
|
||||
|
||||
- name: Run Container
|
||||
run: docker run --name build -v $GITHUB_WORKSPACE:/root/SDRPlusPlus --env BUILD_NO="-$GITHUB_RUN_NUMBER" sdrpp_build /root/do_build.sh
|
||||
|
||||
- name: Recover Deb Archive
|
||||
working-directory: ${{runner.workspace}}
|
||||
run: docker cp build:/root/SDRPlusPlus/sdrpp_debian_amd64.deb ./
|
||||
|
||||
- name: Save Deb Archive
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: sdrpp_ubuntu_hirsute_amd64
|
||||
name: sdrpp_ubuntu_jammy_amd64
|
||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||
|
||||
build_ubuntu_mantic:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create Docker Image
|
||||
run: cd $GITHUB_WORKSPACE/docker_builds/ubuntu_mantic && docker build . --tag sdrpp_build
|
||||
|
||||
- name: Run Container
|
||||
run: docker run --name build -v $GITHUB_WORKSPACE:/root/SDRPlusPlus --env BUILD_NO="-$GITHUB_RUN_NUMBER" sdrpp_build /root/do_build.sh
|
||||
|
||||
- name: Recover Deb Archive
|
||||
working-directory: ${{runner.workspace}}
|
||||
run: docker cp build:/root/SDRPlusPlus/sdrpp_debian_amd64.deb ./
|
||||
|
||||
- name: Save Deb Archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdrpp_ubuntu_mantic_amd64
|
||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||
|
||||
build_raspios_bullseye_armhf:
|
||||
runs-on: ARM
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create Build Environment
|
||||
run: rm -rf ${{runner.workspace}}/build && cmake -E make_directory ${{runner.workspace}}/build
|
||||
|
||||
- name: Prepare CMake
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_USRP_SOURCE=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: make VERBOSE=1 -j3
|
||||
|
||||
- name: Create Dev Archive
|
||||
working-directory: ${{runner.workspace}}
|
||||
run: sh $GITHUB_WORKSPACE/make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk2-dev, librtaudio-dev' && mv sdrpp_debian_amd64.deb sdrpp_debian_armhf.deb
|
||||
|
||||
- name: Save Deb Archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdrpp_raspios_bullseye_armhf
|
||||
path: ${{runner.workspace}}/sdrpp_debian_armhf.deb
|
||||
|
||||
build_android:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Fetch container
|
||||
working-directory: ${{runner.workspace}}
|
||||
run: git clone https://github.com/AlexandreRouma/android-sdr-kit
|
||||
|
||||
- name: Build container
|
||||
working-directory: ${{runner.workspace}}/android-sdr-kit
|
||||
run: docker build --progress=plain -t android-sdr-kit .
|
||||
|
||||
- name: Build
|
||||
run: docker run --name build -v $GITHUB_WORKSPACE:/root/SDRPlusPlus android-sdr-kit /bin/bash -l -c "cd /root/SDRPlusPlus/android && gradle --info assembleDebug"
|
||||
|
||||
- name: Recover APK
|
||||
working-directory: ${{runner.workspace}}
|
||||
run: docker cp build:/root/SDRPlusPlus/android/app/build/outputs/apk/debug/app-debug.apk ./ && mv app-debug.apk sdrpp.apk
|
||||
|
||||
- name: Save APK
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdrpp_android
|
||||
path: ${{runner.workspace}}/sdrpp.apk
|
||||
|
||||
create_full_archive:
|
||||
needs: ['build_windows', 'build_macos', 'build_debian_buster', 'build_debian_bullseye', 'build_debian_sid', 'build_ubuntu_focal', 'build_ubuntu_groovy', 'build_ubuntu_hirsute']
|
||||
needs: ['build_windows', 'build_macos_intel', 'build_macos_arm', 'build_debian_buster', 'build_debian_bullseye', 'build_debian_bookworm', 'build_debian_sid', 'build_ubuntu_focal', 'build_ubuntu_jammy', 'build_ubuntu_mantic', 'build_raspios_bullseye_armhf', 'build_android']
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Download All Builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Create Archive
|
||||
run: >
|
||||
mkdir sdrpp_all &&
|
||||
mv sdrpp_windows_x64/sdrpp_windows_x64.zip sdrpp_all/ &&
|
||||
mv sdrpp_macos_amd64/sdrpp_macos_amd64.pkg sdrpp_all/ &&
|
||||
mv sdrpp_macos_intel/sdrpp_macos_intel.zip sdrpp_all/ &&
|
||||
mv sdrpp_macos_arm/sdrpp_macos_arm.zip sdrpp_all/ &&
|
||||
mv sdrpp_debian_buster_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_buster_amd64.deb &&
|
||||
mv sdrpp_debian_bullseye_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_bullseye_amd64.deb &&
|
||||
mv sdrpp_debian_bookworm_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_bookworm_amd64.deb &&
|
||||
mv sdrpp_debian_sid_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_sid_amd64.deb &&
|
||||
mv sdrpp_ubuntu_focal_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_focal_amd64.deb &&
|
||||
mv sdrpp_ubuntu_groovy_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_groovy_amd64.deb &&
|
||||
mv sdrpp_ubuntu_hirsute_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_hirsute_amd64.deb
|
||||
mv sdrpp_ubuntu_focal_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_focal_amd64.deb &&
|
||||
mv sdrpp_ubuntu_jammy_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_jammy_amd64.deb &&
|
||||
mv sdrpp_ubuntu_mantic_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_mantic_amd64.deb &&
|
||||
mv sdrpp_raspios_bullseye_armhf/sdrpp_debian_armhf.deb sdrpp_all/sdrpp_raspios_bullseye_armhf.deb &&
|
||||
mv sdrpp_android/sdrpp.apk sdrpp_all/sdrpp.apk
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdrpp_all
|
||||
path: sdrpp_all/
|
||||
|
||||
update_nightly_release:
|
||||
needs: [create_full_archive]
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
|
||||
steps:
|
||||
- name: Download All Builds
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Update Nightly
|
||||
run: gh release upload nightly sdrpp_all/* -R ${{github.repository}} --clobber
|
||||
|
||||
check_spelling:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install codespell
|
||||
run: sudo apt update -y && sudo apt install -y codespell
|
||||
|
||||
- name: Running codespell
|
||||
run: cd $GITHUB_WORKSPACE && codespell -q 2 || true
|
||||
|
||||
check_formatting:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run check_clang_format
|
||||
run: cd $GITHUB_WORKSPACE && chmod +x ./check_clang_format.sh && ./check_clang_format.sh || true
|
||||
|
|
|
@ -9,6 +9,11 @@ build/
|
|||
*.wav
|
||||
.DS_Store
|
||||
root_dev/
|
||||
root_dev_srv/
|
||||
Folder.DotSettings.user
|
||||
CMakeSettings.json
|
||||
poggers_decoder
|
||||
poggers_decoder
|
||||
m17_decoder/libcorrect
|
||||
SDR++.app
|
||||
android/deps
|
||||
android/app/assets
|
264
CMakeLists.txt
264
CMakeLists.txt
|
@ -1,169 +1,308 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
project(sdrpp)
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(CMAKE_INSTALL_PREFIX "/usr/local")
|
||||
else()
|
||||
set(CMAKE_INSTALL_PREFIX "/usr")
|
||||
endif()
|
||||
# Backends
|
||||
option(OPT_BACKEND_GLFW "Use the GLFW backend" ON)
|
||||
option(OPT_BACKEND_ANDROID "Use the Android backend" OFF)
|
||||
|
||||
# Compatibility Options
|
||||
option(OPT_OVERRIDE_STD_FILESYSTEM "Use a local version of std::filesystem on systems that don't have it yet" OFF)
|
||||
|
||||
# Sources
|
||||
option(OPT_BUILD_AIRSPY_SOURCE "Build Airspy Source Module (Depedencies: libairspy)" ON)
|
||||
option(OPT_BUILD_AIRSPYHF_SOURCE "Build Airspy HF+ Source Module (Depedencies: libairspyhf)" ON)
|
||||
option(OPT_BUILD_BLADERF_SOURCE "Build BladeRF Source Module (Depedencies: libbladeRF)" OFF)
|
||||
option(OPT_BUILD_AIRSPY_SOURCE "Build Airspy Source Module (Dependencies: libairspy)" ON)
|
||||
option(OPT_BUILD_AIRSPYHF_SOURCE "Build Airspy HF+ Source Module (Dependencies: libairspyhf)" ON)
|
||||
option(OPT_BUILD_AUDIO_SOURCE "Build Audio Source Module (Dependencies: rtaudio)" ON)
|
||||
option(OPT_BUILD_BLADERF_SOURCE "Build BladeRF Source Module (Dependencies: libbladeRF)" OFF)
|
||||
option(OPT_BUILD_FILE_SOURCE "Wav file source" ON)
|
||||
option(OPT_BUILD_HACKRF_SOURCE "Build HackRF Source Module (Depedencies: libhackrf)" ON)
|
||||
option(OPT_BUILD_LIMESDR_SOURCE "Build LimeSDR Source Module (Depedencies: liblimesuite)" OFF)
|
||||
option(OPT_BUILD_SDDC_SOURCE "Build SDDC Source Module (Depedencies: libusb-1.0)" OFF)
|
||||
option(OPT_BUILD_RTL_SDR_SOURCE "Build RTL-SDR Source Module (Depedencies: librtlsdr)" ON)
|
||||
option(OPT_BUILD_HACKRF_SOURCE "Build HackRF Source Module (Dependencies: libhackrf)" ON)
|
||||
option(OPT_BUILD_HERMES_SOURCE "Build Hermes Source Module (no dependencies required)" ON)
|
||||
option(OPT_BUILD_LIMESDR_SOURCE "Build LimeSDR Source Module (Dependencies: liblimesuite)" OFF)
|
||||
option(OPT_BUILD_NETWORK_SOURCE "Build Network Source Module (no dependencies required)" ON)
|
||||
option(OPT_BUILD_PERSEUS_SOURCE "Build Perseus Source Module (Dependencies: libperseus-sdr)" OFF)
|
||||
option(OPT_BUILD_PLUTOSDR_SOURCE "Build PlutoSDR Source Module (Dependencies: libiio, libad9361)" ON)
|
||||
option(OPT_BUILD_RFNM_SOURCE "Build RFNM Source Module (Dependencies: librfnm)" OFF)
|
||||
option(OPT_BUILD_RFSPACE_SOURCE "Build RFspace Source Module (no dependencies required)" ON)
|
||||
option(OPT_BUILD_RTL_SDR_SOURCE "Build RTL-SDR Source Module (Dependencies: librtlsdr)" ON)
|
||||
option(OPT_BUILD_RTL_TCP_SOURCE "Build RTL-TCP Source Module (no dependencies required)" ON)
|
||||
option(OPT_BUILD_SDRPLAY_SOURCE "Build SDRplay Source Module (Depedencies: libsdrplay)" OFF)
|
||||
option(OPT_BUILD_SOAPY_SOURCE "Build SoapySDR Source Module (Depedencies: soapysdr)" ON)
|
||||
option(OPT_BUILD_SDRPP_SERVER_SOURCE "Build SDR++ Server Source Module (no dependencies required)" ON)
|
||||
option(OPT_BUILD_SDRPLAY_SOURCE "Build SDRplay Source Module (Dependencies: libsdrplay)" OFF)
|
||||
option(OPT_BUILD_SOAPY_SOURCE "Build SoapySDR Source Module (Dependencies: soapysdr)" OFF)
|
||||
option(OPT_BUILD_SPECTRAN_SOURCE "Build Spectran Source Module (Dependencies: Aaronia RTSA Suite)" OFF)
|
||||
option(OPT_BUILD_SPECTRAN_HTTP_SOURCE "Build Spectran HTTP Source Module (no dependencies required)" ON)
|
||||
option(OPT_BUILD_SPYSERVER_SOURCE "Build SpyServer Source Module (no dependencies required)" ON)
|
||||
option(OPT_BUILD_PLUTOSDR_SOURCE "Build PlutoSDR Source Module (Depedencies: libiio, libad9361)" ON)
|
||||
option(OPT_BUILD_USRP_SOURCE "Build USRP Source Module (libuhd)" OFF)
|
||||
|
||||
# Sinks
|
||||
option(OPT_BUILD_AUDIO_SINK "Build Audio Sink Module (Depedencies: rtaudio)" ON)
|
||||
option(OPT_BUILD_PORTAUDIO_SINK "Build PortAudio Sink Module (Depedencies: portaudio)" OFF)
|
||||
option(OPT_BUILD_ANDROID_AUDIO_SINK "Build Android Audio Sink Module (Dependencies: AAudio, only for android)" OFF)
|
||||
option(OPT_BUILD_AUDIO_SINK "Build Audio Sink Module (Dependencies: rtaudio)" ON)
|
||||
option(OPT_BUILD_NETWORK_SINK "Build Audio Sink Module (no dependencies required)" ON)
|
||||
option(OPT_BUILD_NEW_PORTAUDIO_SINK "Build the new PortAudio Sink Module (Depedencies: portaudio)" OFF)
|
||||
option(OPT_BUILD_NEW_PORTAUDIO_SINK "Build the new PortAudio Sink Module (Dependencies: portaudio)" OFF)
|
||||
option(OPT_BUILD_PORTAUDIO_SINK "Build PortAudio Sink Module (Dependencies: portaudio)" OFF)
|
||||
|
||||
# Decoders
|
||||
option(OPT_BUILD_ATV_DECODER "Build ATV decoder (no dependencies required)" OFF)
|
||||
option(OPT_BUILD_FALCON9_DECODER "Build the falcon9 live decoder (Dependencies: ffplay)" OFF)
|
||||
option(OPT_BUILD_KG_SSTV_DECODER "Build the KG SSTV (KG-STV) decoder module (no dependencies required)" OFF)
|
||||
option(OPT_BUILD_M17_DECODER "Build the M17 decoder module (Dependencies: codec2)" OFF)
|
||||
option(OPT_BUILD_METEOR_DEMODULATOR "Build the meteor demodulator module (no dependencies required)" ON)
|
||||
option(OPT_BUILD_PAGER_DECODER "Build the pager decoder module (no dependencies required)" ON)
|
||||
option(OPT_BUILD_RADIO "Main audio modulation decoder (AM, FM, SSB, etc...)" ON)
|
||||
option(OPT_BUILD_WEATHER_SAT_DECODER "Build the HRPT decoder module (no dependencies required)" ON)
|
||||
option(OPT_BUILD_WEATHER_SAT_DECODER "Build the HRPT decoder module (no dependencies required)" OFF)
|
||||
|
||||
# Misc
|
||||
option(OPT_BUILD_DISCORD_PRESENCE "Build the Discord Rich Presence module" ON)
|
||||
option(OPT_BUILD_FREQUENCY_MANAGER "Build the Frequency Manager module" ON)
|
||||
option(OPT_BUILD_IQ_EXPORTER "Build the IQ Exporter module" ON)
|
||||
option(OPT_BUILD_RECORDER "Audio and baseband recorder" ON)
|
||||
option(OPT_BUILD_RIGCTL_CLIENT "Rigctl client to make SDR++ act as a panadapter" ON)
|
||||
option(OPT_BUILD_RIGCTL_SERVER "Rigctl backend for controlling SDR++ with software like gpredict" ON)
|
||||
option(OPT_BUILD_SCANNER "Frequency scanner" ON)
|
||||
option(OPT_BUILD_SCHEDULER "Build the scheduler" OFF)
|
||||
|
||||
# Compiler arguments for each platform
|
||||
if (MSVC)
|
||||
set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup")
|
||||
else ()
|
||||
set(CMAKE_CXX_FLAGS "-O3 -std=c++17")
|
||||
endif ()
|
||||
# Other options
|
||||
option(USE_INTERNAL_LIBCORRECT "Use an internal version of libcorrect" ON)
|
||||
option(USE_BUNDLE_DEFAULTS "Set the default resource and module directories to the right ones for a MacOS .app" OFF)
|
||||
|
||||
# Module cmake path
|
||||
set(SDRPP_MODULE_CMAKE "${CMAKE_SOURCE_DIR}/sdrpp_module.cmake")
|
||||
|
||||
# Root source folder
|
||||
set(SDRPP_CORE_ROOT "${CMAKE_SOURCE_DIR}/core/src/")
|
||||
|
||||
# Compiler flags
|
||||
if (${CMAKE_BUILD_TYPE} MATCHES "Debug")
|
||||
# Debug Flags
|
||||
if (MSVC)
|
||||
set(SDRPP_COMPILER_FLAGS /std:c++17 /EHsc)
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(SDRPP_COMPILER_FLAGS -g -Og -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup)
|
||||
else ()
|
||||
set(SDRPP_COMPILER_FLAGS -g -Og -std=c++17)
|
||||
endif ()
|
||||
else()
|
||||
# Normal Flags
|
||||
if (MSVC)
|
||||
set(SDRPP_COMPILER_FLAGS /O2 /Ob2 /std:c++17 /EHsc)
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(SDRPP_COMPILER_FLAGS -O3 -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup)
|
||||
else ()
|
||||
set(SDRPP_COMPILER_FLAGS -O3 -std=c++17)
|
||||
endif ()
|
||||
endif()
|
||||
set(SDRPP_MODULE_COMPILER_FLAGS ${SDRPP_COMPILER_FLAGS})
|
||||
|
||||
# Set a default install prefix
|
||||
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "..." FORCE)
|
||||
else()
|
||||
set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "..." FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Configure toolchain for android
|
||||
if (ANDROID)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS
|
||||
"${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate"
|
||||
)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=c++17")
|
||||
endif (ANDROID)
|
||||
|
||||
# Core of SDR++
|
||||
add_subdirectory("core")
|
||||
|
||||
|
||||
# Source modules
|
||||
if (OPT_BUILD_AIRSPY_SOURCE)
|
||||
add_subdirectory("airspy_source")
|
||||
add_subdirectory("source_modules/airspy_source")
|
||||
endif (OPT_BUILD_AIRSPY_SOURCE)
|
||||
|
||||
if (OPT_BUILD_AIRSPYHF_SOURCE)
|
||||
add_subdirectory("airspyhf_source")
|
||||
add_subdirectory("source_modules/airspyhf_source")
|
||||
endif (OPT_BUILD_AIRSPYHF_SOURCE)
|
||||
|
||||
if (OPT_BUILD_AUDIO_SOURCE)
|
||||
add_subdirectory("source_modules/audio_source")
|
||||
endif (OPT_BUILD_AUDIO_SOURCE)
|
||||
|
||||
if (OPT_BUILD_BLADERF_SOURCE)
|
||||
add_subdirectory("bladerf_source")
|
||||
add_subdirectory("source_modules/bladerf_source")
|
||||
endif (OPT_BUILD_BLADERF_SOURCE)
|
||||
|
||||
if (OPT_BUILD_FILE_SOURCE)
|
||||
add_subdirectory("file_source")
|
||||
add_subdirectory("source_modules/file_source")
|
||||
endif (OPT_BUILD_FILE_SOURCE)
|
||||
|
||||
if (OPT_BUILD_HACKRF_SOURCE)
|
||||
add_subdirectory("hackrf_source")
|
||||
add_subdirectory("source_modules/hackrf_source")
|
||||
endif (OPT_BUILD_HACKRF_SOURCE)
|
||||
|
||||
if (OPT_BUILD_HERMES_SOURCE)
|
||||
add_subdirectory("source_modules/hermes_source")
|
||||
endif (OPT_BUILD_HERMES_SOURCE)
|
||||
|
||||
if (OPT_BUILD_LIMESDR_SOURCE)
|
||||
add_subdirectory("limesdr_source")
|
||||
add_subdirectory("source_modules/limesdr_source")
|
||||
endif (OPT_BUILD_LIMESDR_SOURCE)
|
||||
|
||||
if (OPT_BUILD_SDDC_SOURCE)
|
||||
add_subdirectory("sddc_source")
|
||||
endif (OPT_BUILD_SDDC_SOURCE)
|
||||
if (OPT_BUILD_NETWORK_SOURCE)
|
||||
add_subdirectory("source_modules/network_source")
|
||||
endif (OPT_BUILD_NETWORK_SOURCE)
|
||||
|
||||
if (OPT_BUILD_PERSEUS_SOURCE)
|
||||
add_subdirectory("source_modules/perseus_source")
|
||||
endif (OPT_BUILD_PERSEUS_SOURCE)
|
||||
|
||||
if (OPT_BUILD_PLUTOSDR_SOURCE)
|
||||
add_subdirectory("source_modules/plutosdr_source")
|
||||
endif (OPT_BUILD_PLUTOSDR_SOURCE)
|
||||
|
||||
if (OPT_BUILD_RFNM_SOURCE)
|
||||
add_subdirectory("source_modules/rfnm_source")
|
||||
endif (OPT_BUILD_RFNM_SOURCE)
|
||||
|
||||
if (OPT_BUILD_RFSPACE_SOURCE)
|
||||
add_subdirectory("source_modules/rfspace_source")
|
||||
endif (OPT_BUILD_RFSPACE_SOURCE)
|
||||
|
||||
if (OPT_BUILD_RTL_SDR_SOURCE)
|
||||
add_subdirectory("rtl_sdr_source")
|
||||
add_subdirectory("source_modules/rtl_sdr_source")
|
||||
endif (OPT_BUILD_RTL_SDR_SOURCE)
|
||||
|
||||
if (OPT_BUILD_RTL_TCP_SOURCE)
|
||||
add_subdirectory("rtl_tcp_source")
|
||||
add_subdirectory("source_modules/rtl_tcp_source")
|
||||
endif (OPT_BUILD_RTL_TCP_SOURCE)
|
||||
|
||||
if (OPT_BUILD_SDRPP_SERVER_SOURCE)
|
||||
add_subdirectory("source_modules/sdrpp_server_source")
|
||||
endif (OPT_BUILD_SDRPP_SERVER_SOURCE)
|
||||
|
||||
if (OPT_BUILD_SDRPLAY_SOURCE)
|
||||
add_subdirectory("sdrplay_source")
|
||||
add_subdirectory("source_modules/sdrplay_source")
|
||||
endif (OPT_BUILD_SDRPLAY_SOURCE)
|
||||
|
||||
if (OPT_BUILD_SOAPY_SOURCE)
|
||||
add_subdirectory("soapy_source")
|
||||
add_subdirectory("source_modules/soapy_source")
|
||||
endif (OPT_BUILD_SOAPY_SOURCE)
|
||||
|
||||
if (OPT_BUILD_SPECTRAN_SOURCE)
|
||||
add_subdirectory("source_modules/spectran_source")
|
||||
endif (OPT_BUILD_SPECTRAN_SOURCE)
|
||||
|
||||
if (OPT_BUILD_SPECTRAN_HTTP_SOURCE)
|
||||
add_subdirectory("source_modules/spectran_http_source")
|
||||
endif (OPT_BUILD_SPECTRAN_HTTP_SOURCE)
|
||||
|
||||
if (OPT_BUILD_SPYSERVER_SOURCE)
|
||||
add_subdirectory("spyserver_source")
|
||||
add_subdirectory("source_modules/spyserver_source")
|
||||
endif (OPT_BUILD_SPYSERVER_SOURCE)
|
||||
|
||||
if (OPT_BUILD_PLUTOSDR_SOURCE)
|
||||
add_subdirectory("plutosdr_source")
|
||||
endif (OPT_BUILD_PLUTOSDR_SOURCE)
|
||||
if (OPT_BUILD_USRP_SOURCE)
|
||||
add_subdirectory("source_modules/usrp_source")
|
||||
endif (OPT_BUILD_USRP_SOURCE)
|
||||
|
||||
|
||||
# Sink modules
|
||||
if (OPT_BUILD_ANDROID_AUDIO_SINK)
|
||||
add_subdirectory("sink_modules/android_audio_sink")
|
||||
endif (OPT_BUILD_ANDROID_AUDIO_SINK)
|
||||
|
||||
if (OPT_BUILD_AUDIO_SINK)
|
||||
add_subdirectory("audio_sink")
|
||||
add_subdirectory("sink_modules/audio_sink")
|
||||
endif (OPT_BUILD_AUDIO_SINK)
|
||||
|
||||
if (OPT_BUILD_PORTAUDIO_SINK)
|
||||
add_subdirectory("portaudio_sink")
|
||||
add_subdirectory("sink_modules/portaudio_sink")
|
||||
endif (OPT_BUILD_PORTAUDIO_SINK)
|
||||
|
||||
if (OPT_BUILD_NETWORK_SINK)
|
||||
add_subdirectory("network_sink")
|
||||
add_subdirectory("sink_modules/network_sink")
|
||||
endif (OPT_BUILD_NETWORK_SINK)
|
||||
|
||||
if (OPT_BUILD_NEW_PORTAUDIO_SINK)
|
||||
add_subdirectory("new_portaudio_sink")
|
||||
add_subdirectory("sink_modules/new_portaudio_sink")
|
||||
endif (OPT_BUILD_NEW_PORTAUDIO_SINK)
|
||||
|
||||
|
||||
# Decoders
|
||||
if (OPT_BUILD_ATV_DECODER)
|
||||
add_subdirectory("decoder_modules/atv_decoder")
|
||||
endif (OPT_BUILD_ATV_DECODER)
|
||||
|
||||
if (OPT_BUILD_FALCON9_DECODER)
|
||||
add_subdirectory("falcon9_decoder")
|
||||
add_subdirectory("decoder_modules/falcon9_decoder")
|
||||
endif (OPT_BUILD_FALCON9_DECODER)
|
||||
|
||||
if (OPT_BUILD_KG_SSTV_DECODER)
|
||||
add_subdirectory("decoder_modules/kg_sstv_decoder")
|
||||
endif (OPT_BUILD_KG_SSTV_DECODER)
|
||||
|
||||
if (OPT_BUILD_M17_DECODER)
|
||||
add_subdirectory("decoder_modules/m17_decoder")
|
||||
endif (OPT_BUILD_M17_DECODER)
|
||||
|
||||
if (OPT_BUILD_METEOR_DEMODULATOR)
|
||||
add_subdirectory("meteor_demodulator")
|
||||
add_subdirectory("decoder_modules/meteor_demodulator")
|
||||
endif (OPT_BUILD_METEOR_DEMODULATOR)
|
||||
|
||||
if (OPT_BUILD_PAGER_DECODER)
|
||||
add_subdirectory("decoder_modules/pager_decoder")
|
||||
endif (OPT_BUILD_PAGER_DECODER)
|
||||
|
||||
if (OPT_BUILD_RADIO)
|
||||
add_subdirectory("radio")
|
||||
add_subdirectory("decoder_modules/radio")
|
||||
endif (OPT_BUILD_RADIO)
|
||||
|
||||
if (OPT_BUILD_WEATHER_SAT_DECODER)
|
||||
add_subdirectory("weather_sat_decoder")
|
||||
add_subdirectory("decoder_modules/weather_sat_decoder")
|
||||
endif (OPT_BUILD_WEATHER_SAT_DECODER)
|
||||
|
||||
|
||||
# Misc
|
||||
if (OPT_BUILD_DISCORD_PRESENCE)
|
||||
add_subdirectory("discord_integration")
|
||||
add_subdirectory("misc_modules/discord_integration")
|
||||
endif (OPT_BUILD_DISCORD_PRESENCE)
|
||||
|
||||
if (OPT_BUILD_FREQUENCY_MANAGER)
|
||||
add_subdirectory("frequency_manager")
|
||||
add_subdirectory("misc_modules/frequency_manager")
|
||||
endif (OPT_BUILD_FREQUENCY_MANAGER)
|
||||
|
||||
if (OPT_BUILD_IQ_EXPORTER)
|
||||
add_subdirectory("misc_modules/iq_exporter")
|
||||
endif (OPT_BUILD_IQ_EXPORTER)
|
||||
|
||||
if (OPT_BUILD_RECORDER)
|
||||
add_subdirectory("recorder")
|
||||
add_subdirectory("misc_modules/recorder")
|
||||
endif (OPT_BUILD_RECORDER)
|
||||
|
||||
if (OPT_BUILD_RIGCTL_CLIENT)
|
||||
add_subdirectory("misc_modules/rigctl_client")
|
||||
endif (OPT_BUILD_RIGCTL_CLIENT)
|
||||
|
||||
if (OPT_BUILD_RIGCTL_SERVER)
|
||||
add_subdirectory("rigctl_server")
|
||||
add_subdirectory("misc_modules/rigctl_server")
|
||||
endif (OPT_BUILD_RIGCTL_SERVER)
|
||||
|
||||
if (OPT_BUILD_SCANNER)
|
||||
add_subdirectory("misc_modules/scanner")
|
||||
endif (OPT_BUILD_SCANNER)
|
||||
|
||||
if (OPT_BUILD_SCHEDULER)
|
||||
add_subdirectory("misc_modules/scheduler")
|
||||
endif (OPT_BUILD_SCHEDULER)
|
||||
|
||||
if (MSVC)
|
||||
add_executable(sdrpp "src/main.cpp" "win32/resources.rc")
|
||||
else ()
|
||||
add_executable(sdrpp "src/main.cpp")
|
||||
endif ()
|
||||
|
||||
add_executable(sdrpp "src/main.cpp" "win32/resources.rc")
|
||||
target_link_libraries(sdrpp PRIVATE sdrpp_core)
|
||||
|
||||
# Compiler arguments
|
||||
target_compile_options(sdrpp PRIVATE ${SDRPP_COMPILER_FLAGS})
|
||||
|
||||
# Copy dynamic libs over
|
||||
if (MSVC)
|
||||
add_custom_target(do_always ALL xcopy /s \"$<TARGET_FILE_DIR:sdrpp_core>\\*.dll\" \"$<TARGET_FILE_DIR:sdrpp>\" /Y)
|
||||
|
@ -188,7 +327,10 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
|||
add_custom_target(do_always ALL cp \"$<TARGET_FILE_DIR:sdrpp_core>/libsdrpp_core.dylib\" \"$<TARGET_FILE_DIR:sdrpp>\")
|
||||
endif ()
|
||||
|
||||
# cmake .. "-DCMAKE_TOOLCHAIN_FILE=C:/Users/Alex/vcpkg/scripts/buildsystems/vcpkg.cmake" -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON
|
||||
# cmake .. "-DCMAKE_TOOLCHAIN_FILE=C:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake" -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_SCANNER=ON -DOPT_BUILD_SCHEDULER=ON -DOPT_BUILD_USRP_SOURCE=ON -DOPT_BUILD_PAGER_DECODER=ON
|
||||
|
||||
# Create module cmake file
|
||||
configure_file(${CMAKE_SOURCE_DIR}/sdrpp_module.cmake ${CMAKE_CURRENT_BINARY_DIR}/sdrpp_module.cmake @ONLY)
|
||||
|
||||
# Install directives
|
||||
install(TARGETS sdrpp DESTINATION bin)
|
||||
|
@ -200,9 +342,9 @@ install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/themes DESTINATION share/sdrpp)
|
|||
configure_file(${CMAKE_SOURCE_DIR}/sdrpp.desktop ${CMAKE_CURRENT_BINARY_DIR}/sdrpp.desktop @ONLY)
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sdrpp.desktop DESTINATION /usr/share/applications)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sdrpp.desktop DESTINATION share/applications)
|
||||
endif ()
|
||||
|
||||
# Create uninstall target
|
||||
configure_file(${CMAKE_SOURCE_DIR}/cmake_uninstall.cmake ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake @ONLY)
|
||||
add_custom_target(uninstall ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
add_custom_target(uninstall ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
|
@ -1,42 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
project(airspy_source)
|
||||
|
||||
if (MSVC)
|
||||
set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup")
|
||||
else ()
|
||||
set(CMAKE_CXX_FLAGS "-O3 -std=c++17")
|
||||
endif ()
|
||||
|
||||
include_directories("src/")
|
||||
|
||||
file(GLOB SRC "src/*.cpp")
|
||||
|
||||
add_library(airspy_source SHARED ${SRC})
|
||||
target_link_libraries(airspy_source PRIVATE sdrpp_core)
|
||||
set_target_properties(airspy_source PROPERTIES PREFIX "")
|
||||
|
||||
if (MSVC)
|
||||
# Lib path
|
||||
target_link_directories(airspy_source PUBLIC "C:/Program Files/PothosSDR/bin/")
|
||||
|
||||
target_link_libraries(airspy_source PUBLIC airspy)
|
||||
else (MSVC)
|
||||
find_package(PkgConfig)
|
||||
|
||||
pkg_check_modules(LIBAIRSPY REQUIRED libairspy)
|
||||
|
||||
target_include_directories(airspy_source PUBLIC ${LIBAIRSPY_INCLUDE_DIRS})
|
||||
target_link_directories(airspy_source PUBLIC ${LIBAIRSPY_LIBRARY_DIRS})
|
||||
target_link_libraries(airspy_source PUBLIC ${LIBAIRSPY_LIBRARIES})
|
||||
|
||||
# Include it because for some reason pkgconfig doesn't look here?
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
target_include_directories(airspy_source PUBLIC "/usr/local/include")
|
||||
endif()
|
||||
|
||||
endif ()
|
||||
|
||||
# Install directives
|
||||
install(TARGETS airspy_source DESTINATION lib/sdrpp/plugins)
|
|
@ -1,42 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
project(airspyhf_source)
|
||||
|
||||
if (MSVC)
|
||||
set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup")
|
||||
else ()
|
||||
set(CMAKE_CXX_FLAGS "-O3 -std=c++17")
|
||||
endif ()
|
||||
|
||||
include_directories("src/")
|
||||
|
||||
file(GLOB SRC "src/*.cpp")
|
||||
|
||||
add_library(airspyhf_source SHARED ${SRC})
|
||||
target_link_libraries(airspyhf_source PRIVATE sdrpp_core)
|
||||
set_target_properties(airspyhf_source PROPERTIES PREFIX "")
|
||||
|
||||
if (MSVC)
|
||||
# Lib path
|
||||
target_link_directories(airspyhf_source PUBLIC "C:/Program Files/PothosSDR/bin/")
|
||||
|
||||
target_link_libraries(airspyhf_source PUBLIC airspyhf)
|
||||
else (MSVC)
|
||||
find_package(PkgConfig)
|
||||
|
||||
pkg_check_modules(LIBAIRSPYHF REQUIRED libairspyhf)
|
||||
|
||||
target_include_directories(airspyhf_source PUBLIC ${LIBAIRSPYHF_INCLUDE_DIRS})
|
||||
target_link_directories(airspyhf_source PUBLIC ${LIBAIRSPYHF_LIBRARY_DIRS})
|
||||
target_link_libraries(airspyhf_source PUBLIC ${LIBAIRSPYHF_LIBRARIES})
|
||||
|
||||
# Include it because for some reason pkgconfig doesn't look here?
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
target_include_directories(airspyhf_source PUBLIC "/usr/local/include")
|
||||
endif()
|
||||
|
||||
endif ()
|
||||
|
||||
# Install directives
|
||||
install(TARGETS airspyhf_source DESTINATION lib/sdrpp/plugins)
|
|
@ -0,0 +1,12 @@
|
|||
.cxx
|
||||
.externalNativeBuild
|
||||
build/
|
||||
*.iml
|
||||
|
||||
.idea
|
||||
.gradle
|
||||
local.properties
|
||||
|
||||
# Android Studio puts a Gradle wrapper here, that we don't want:
|
||||
gradle/
|
||||
gradlew*
|
|
@ -0,0 +1,76 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "30.0.3"
|
||||
ndkVersion "25.1.8937393"
|
||||
defaultConfig {
|
||||
applicationId "org.sdrpp.sdrpp"
|
||||
minSdkVersion 28
|
||||
targetSdkVersion 28
|
||||
versionCode 1
|
||||
versionName "1.1.0"
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments "-DOPT_BACKEND_GLFW=OFF", "-DOPT_BACKEND_ANDROID=ON", "-DOPT_BUILD_SOAPY_SOURCE=OFF", "-DOPT_BUILD_ANDROID_AUDIO_SINK=ON", "-DOPT_BUILD_AUDIO_SINK=OFF", "-DOPT_BUILD_DISCORD_PRESENCE=OFF", "-DOPT_BUILD_M17_DECODER=ON", "-DOPT_BUILD_PLUTOSDR_SOURCE=ON", "-DOPT_BUILD_AUDIO_SOURCE=OFF"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
debug {
|
||||
storeFile file("debug.keystore")
|
||||
storePassword "android"
|
||||
keyAlias "androiddebugkey"
|
||||
keyPassword "android"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
|
||||
}
|
||||
debug {
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
version "3.18.1"
|
||||
path "../../CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
assets.srcDirs += ['assets']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task deleteTempAssets (type: Delete) {
|
||||
delete 'assets'
|
||||
}
|
||||
|
||||
task copyResources(type: Copy) {
|
||||
description = 'Copy resources...'
|
||||
from '../../root/'
|
||||
into 'assets/'
|
||||
include('**/*')
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.0.2'
|
||||
}
|
||||
|
||||
copyResources.dependsOn deleteTempAssets
|
||||
preBuild.dependsOn copyResources
|
Plik binarny nie jest wyświetlany.
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.sdrpp.sdrpp">
|
||||
|
||||
<application
|
||||
android:label="SDR++"
|
||||
android:allowBackup="false"
|
||||
android:fullBackupContent="false"
|
||||
android:hasCode="true">
|
||||
|
||||
<activity
|
||||
android:name="org.sdrpp.sdrpp.MainActivity"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize">
|
||||
<meta-data android:name="android.app.lib_name" android:value="sdrpp_core" />
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
|
@ -0,0 +1,32 @@
|
|||
package org.sdrpp.sdrpp;
|
||||
|
||||
import android.app.NativeActivity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.usb.*;
|
||||
import android.Manifest;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.util.Log;
|
||||
import android.content.res.AssetManager;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
||||
import androidx.core.content.PermissionChecker;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.io.*;
|
||||
|
||||
class DeviceManager {
|
||||
public fun init() {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
package org.sdrpp.sdrpp;
|
||||
|
||||
import android.app.NativeActivity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.usb.*;
|
||||
import android.Manifest;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.util.Log;
|
||||
import android.content.res.AssetManager;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
||||
import androidx.core.content.PermissionChecker;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.io.*;
|
||||
|
||||
private const val ACTION_USB_PERMISSION = "org.sdrpp.sdrpp.USB_PERMISSION";
|
||||
|
||||
private val usbReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (ACTION_USB_PERMISSION == intent.action) {
|
||||
synchronized(this) {
|
||||
var _this = context as MainActivity;
|
||||
_this.SDR_device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
|
||||
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
|
||||
_this.SDR_conn = _this.usbManager!!.openDevice(_this.SDR_device);
|
||||
|
||||
// Save SDR info
|
||||
_this.SDR_VID = _this.SDR_device!!.getVendorId();
|
||||
_this.SDR_PID = _this.SDR_device!!.getProductId()
|
||||
_this.SDR_FD = _this.SDR_conn!!.getFileDescriptor();
|
||||
}
|
||||
|
||||
// Whatever the hell this does
|
||||
context.unregisterReceiver(this);
|
||||
|
||||
// Hide again the system bars
|
||||
_this.hideSystemBars();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MainActivity : NativeActivity() {
|
||||
private val TAG : String = "SDR++";
|
||||
public var usbManager : UsbManager? = null;
|
||||
public var SDR_device : UsbDevice? = null;
|
||||
public var SDR_conn : UsbDeviceConnection? = null;
|
||||
public var SDR_VID : Int = -1;
|
||||
public var SDR_PID : Int = -1;
|
||||
public var SDR_FD : Int = -1;
|
||||
|
||||
fun checkAndAsk(permission: String) {
|
||||
if (PermissionChecker.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(this, arrayOf(permission), 1);
|
||||
}
|
||||
}
|
||||
|
||||
public fun hideSystemBars() {
|
||||
val decorView = getWindow().getDecorView();
|
||||
val uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
||||
decorView.setSystemUiVisibility(uiOptions);
|
||||
}
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// Hide bars
|
||||
hideSystemBars();
|
||||
|
||||
// Ask for required permissions, without these the app cannot run.
|
||||
checkAndAsk(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
checkAndAsk(Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
|
||||
// TODO: Have the main code wait until these two permissions are available
|
||||
|
||||
// Register events
|
||||
usbManager = getSystemService(Context.USB_SERVICE) as UsbManager;
|
||||
val permissionIntent = PendingIntent.getBroadcast(this, 0, Intent(ACTION_USB_PERMISSION), 0)
|
||||
val filter = IntentFilter(ACTION_USB_PERMISSION)
|
||||
registerReceiver(usbReceiver, filter)
|
||||
|
||||
// Get permission for all USB devices
|
||||
val devList = usbManager!!.getDeviceList();
|
||||
for ((name, dev) in devList) {
|
||||
usbManager!!.requestPermission(dev, permissionIntent);
|
||||
}
|
||||
|
||||
// Ask for internet permission
|
||||
checkAndAsk(Manifest.permission.INTERNET);
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
public override fun onResume() {
|
||||
// Hide bars again
|
||||
hideSystemBars();
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
fun showSoftInput() {
|
||||
val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager;
|
||||
inputMethodManager.showSoftInput(window.decorView, 0);
|
||||
}
|
||||
|
||||
fun hideSoftInput() {
|
||||
val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager;
|
||||
inputMethodManager.hideSoftInputFromWindow(window.decorView.windowToken, 0);
|
||||
hideSystemBars();
|
||||
}
|
||||
|
||||
// Queue for the Unicode characters to be polled from native code (via pollUnicodeChar())
|
||||
private var unicodeCharacterQueue: LinkedBlockingQueue<Int> = LinkedBlockingQueue()
|
||||
|
||||
// We assume dispatchKeyEvent() of the NativeActivity is actually called for every
|
||||
// KeyEvent and not consumed by any View before it reaches here
|
||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
if (event.action == KeyEvent.ACTION_DOWN) {
|
||||
unicodeCharacterQueue.offer(event.getUnicodeChar(event.metaState))
|
||||
}
|
||||
return super.dispatchKeyEvent(event)
|
||||
}
|
||||
|
||||
fun pollUnicodeChar(): Int {
|
||||
return unicodeCharacterQueue.poll() ?: 0
|
||||
}
|
||||
|
||||
public fun createIfDoesntExist(path: String) {
|
||||
// This is a directory, create it in the filesystem
|
||||
var folder = File(path);
|
||||
var success = true;
|
||||
if (!folder.exists()) {
|
||||
success = folder.mkdirs();
|
||||
}
|
||||
if (!success) {
|
||||
Log.e(TAG, "Could not create folder with path " + path);
|
||||
}
|
||||
}
|
||||
|
||||
public fun extractDir(aman: AssetManager, local: String, rsrc: String): Int {
|
||||
val flist = aman.list(rsrc);
|
||||
var ecount = 0;
|
||||
for (fp in flist) {
|
||||
val lpath = local + "/" + fp;
|
||||
val rpath = rsrc + "/" + fp;
|
||||
|
||||
Log.w(TAG, "Extracting '" + rpath + "' to '" + lpath + "'");
|
||||
|
||||
// Create local path if non-existent
|
||||
createIfDoesntExist(local);
|
||||
|
||||
// Create if directory
|
||||
val ext = extractDir(aman, lpath, rpath);
|
||||
|
||||
// Extract if file
|
||||
if (ext == 0) {
|
||||
// This is a file, extract it
|
||||
val _os = FileOutputStream(lpath);
|
||||
val _is = aman.open(rpath);
|
||||
val ilen = _is.available();
|
||||
var fbuf = ByteArray(ilen);
|
||||
_is.read(fbuf, 0, ilen);
|
||||
_os.write(fbuf);
|
||||
_os.close();
|
||||
_is.close();
|
||||
}
|
||||
|
||||
ecount++;
|
||||
}
|
||||
return ecount;
|
||||
}
|
||||
|
||||
public fun getAppDir(): String {
|
||||
val fdir = getFilesDir().getAbsolutePath();
|
||||
|
||||
// Extract all resources to the app directory
|
||||
val aman = getAssets();
|
||||
extractDir(aman, fdir + "/res", "res");
|
||||
createIfDoesntExist(fdir + "/modules");
|
||||
|
||||
return fdir;
|
||||
}
|
||||
}
|
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 21 KiB |
|
@ -0,0 +1,22 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.4.31'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
android.useAndroidX=true
|
|
@ -0,0 +1 @@
|
|||
include ':app'
|
|
@ -1,40 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
project(audio_sink)
|
||||
|
||||
if (MSVC)
|
||||
set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup")
|
||||
else ()
|
||||
set(CMAKE_CXX_FLAGS "-O3 -std=c++17")
|
||||
endif ()
|
||||
|
||||
file(GLOB SRC "src/*.cpp")
|
||||
|
||||
include_directories("src/")
|
||||
|
||||
add_library(audio_sink SHARED ${SRC})
|
||||
target_link_libraries(audio_sink PRIVATE sdrpp_core)
|
||||
set_target_properties(audio_sink PROPERTIES PREFIX "")
|
||||
|
||||
if (MSVC)
|
||||
# Lib path
|
||||
target_link_directories(audio_sink PUBLIC "C:/Program Files (x86)/RtAudio/lib")
|
||||
|
||||
# Misc headers
|
||||
target_include_directories(audio_sink PUBLIC "C:/Program Files (x86)/RtAudio/include/rtaudio")
|
||||
|
||||
target_link_libraries(audio_sink PUBLIC rtaudio)
|
||||
else (MSVC)
|
||||
find_package(PkgConfig)
|
||||
|
||||
pkg_check_modules(RTAUDIO REQUIRED rtaudio)
|
||||
|
||||
target_include_directories(audio_sink PUBLIC ${RTAUDIO_INCLUDE_DIRS})
|
||||
target_link_directories(audio_sink PUBLIC ${RTAUDIO_LIBRARY_DIRS})
|
||||
target_link_libraries(audio_sink PUBLIC ${RTAUDIO_LIBRARIES})
|
||||
|
||||
endif ()
|
||||
|
||||
# Install directives
|
||||
install(TARGETS audio_sink DESTINATION lib/sdrpp/plugins)
|
|
@ -1,36 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
project(bladerf_source)
|
||||
|
||||
if (MSVC)
|
||||
set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup")
|
||||
else ()
|
||||
set(CMAKE_CXX_FLAGS "-O3 -std=c++17")
|
||||
endif ()
|
||||
|
||||
include_directories("src/")
|
||||
|
||||
file(GLOB SRC "src/*.cpp")
|
||||
|
||||
add_library(bladerf_source SHARED ${SRC})
|
||||
target_link_libraries(bladerf_source PRIVATE sdrpp_core)
|
||||
set_target_properties(bladerf_source PROPERTIES PREFIX "")
|
||||
|
||||
if (MSVC)
|
||||
# Lib path
|
||||
target_link_directories(bladerf_source PUBLIC "C:/Program Files/PothosSDR/bin/")
|
||||
|
||||
target_link_libraries(bladerf_source PUBLIC bladeRF)
|
||||
else (MSVC)
|
||||
# Not in pkg-config
|
||||
target_link_libraries(bladerf_source PUBLIC bladeRF)
|
||||
|
||||
# Include it because for some reason pkgconfig doesn't look here?
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
target_include_directories(airspyhf_source PUBLIC "/usr/local/include")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
# Install directives
|
||||
install(TARGETS bladerf_source DESTINATION lib/sdrpp/plugins)
|
|
@ -0,0 +1,20 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo Searching directories...
|
||||
CODE_FILES=$(find . -iregex '.*\.\(h\|hpp\|c\|cpp\)$')
|
||||
while read -r CPP_FILE_PATH; do
|
||||
# Skip unwanted files
|
||||
if [[ "$CPP_FILE_PATH" == "./.old"* ]]; then continue; fi
|
||||
if [[ "$CPP_FILE_PATH" == "./build"* ]]; then continue; fi
|
||||
if [[ "$CPP_FILE_PATH" == "./core/libcorrect"* ]]; then continue; fi
|
||||
if [[ "$CPP_FILE_PATH" == "./core/std_replacement"* ]]; then continue; fi
|
||||
if [[ "$CPP_FILE_PATH" == "./core/src/imgui"* ]]; then continue; fi
|
||||
if [[ "$CPP_FILE_PATH" == "./misc_modules/discord_integration/discord-rpc"* ]]; then continue; fi
|
||||
if [[ "$CPP_FILE_PATH" == "./source_modules/sddc_source/src/libsddc"* ]]; then continue; fi
|
||||
|
||||
if [ "$CPP_FILE_PATH" = ./core/src/json.hpp ]; then continue; fi
|
||||
if [ "$CPP_FILE_PATH" = ./core/src/gui/file_dialogs.h ]; then continue; fi
|
||||
|
||||
echo Checking $CPP_FILE_PATH
|
||||
clang-format --style=file -i -n -Werror $CPP_FILE_PATH
|
||||
done <<< "$CODE_FILES"
|
|
@ -1,64 +1,6 @@
|
|||
# Pull Requests
|
||||
|
||||
TODO
|
||||
|
||||
# Code Style
|
||||
|
||||
## Naming Convention
|
||||
|
||||
- Files: `snake_case.h` `snake_case.cpp`
|
||||
- Namespaces: `CamelCase`
|
||||
- Classes: `CamelCase`
|
||||
- Structs: `CamelCase_t`
|
||||
- Members: `camelCase`
|
||||
- Enum: `SNAKE_CASE`
|
||||
- Macros: `SNAKE_CASE`
|
||||
|
||||
## Brace Style
|
||||
|
||||
```c++
|
||||
int myFunction() {
|
||||
if (shortIf) { shortFunctionName(); }
|
||||
|
||||
if (longIf) {
|
||||
longFunction();
|
||||
otherStuff();
|
||||
myLongFunction();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note: If it makes the code cleaner, remember to use the `?` keyword instead of a `if else` statement.
|
||||
|
||||
## Pointers
|
||||
|
||||
Please use `type* name` for pointers.
|
||||
|
||||
## Structure
|
||||
|
||||
Headers and their associated C++ files shall be in the same directory. All headers must use `#pragma once` instead of other include guards. Only include files in a header that are being used in that header. Include the rest in the associated C++ file.
|
||||
|
||||
# Modules
|
||||
|
||||
## Module Naming Convention
|
||||
|
||||
All modules names must be `snake_case`. If the module is a source, it must end with `_source`. If it is a sink, it must end with `_sink`.
|
||||
|
||||
For example, lets take the module named `cool_source`:
|
||||
|
||||
- Directory: `cool_source`
|
||||
- Class: `CoolSourceModule`
|
||||
- Binary: `cool_source.<os dynlib extension>`
|
||||
|
||||
## Integration into main repository
|
||||
|
||||
If the module meets the code quality requirements, it may be added to the official repository. A module that doesn't require any external dependencies that the core doesn't already use may be enabled for build by default. Otherwise, they must be disabled for build by default with a `OPT_BUILD_MODULE_NAME` variable set to `OFF`.
|
||||
|
||||
# JSON Formatting
|
||||
|
||||
The ability to add new radio band allocation identifiers and color maps relies on JSON files. Proper formatting of these JSOn files is important for reference and readability. The folowing guides will show you how to properly format the JSON files for their respective uses.
|
||||
|
||||
**IMPORTANT: JSON File cannot contain comments, there are only in this example for clarity**
|
||||
Code pull requests are **NOT welcome**. Please open an issue discussing potential bugfixes or feature requests instead.
|
||||
|
||||
## Band Frequency Allocation
|
||||
|
||||
|
@ -75,13 +17,13 @@ Please follow this guide to properly format the JSON files for custom radio band
|
|||
// Bands in this array must be sorted by their starting frequency
|
||||
{
|
||||
"name": "Name of the band",
|
||||
"type": "Type name ('amateur', 'broadcast', 'marine', 'military', or any type decalre in config.json)",
|
||||
"type": "Type name ('amateur', 'broadcast', 'marine', 'military', or any type declared in config.json)",
|
||||
"start": 148500, //In Hz, must be an integer
|
||||
"end": 283500 //In Hz, must be an integer
|
||||
},
|
||||
{
|
||||
"name": "Name of the band",
|
||||
"type": "Type name ('amateur', 'broadcast', 'marine', 'military', or any type decalre in config.json)",
|
||||
"type": "Type name ('amateur', 'broadcast', 'marine', 'military', or any type declared in config.json)",
|
||||
"start": 526500, //In Hz, must be an integer
|
||||
"end": 1606500 //In Hz, must be an integer
|
||||
}
|
||||
|
@ -98,7 +40,7 @@ Please follow this guide to properly format the JSON files for custom color maps
|
|||
"name": "Short name (has to fit in the menu)",
|
||||
"author": "Name of the original/main creator of the color map",
|
||||
"map": [
|
||||
// These are the color codes, in hexidecimal (#RRGGBB) format, for the custom color scales for the waterfall. They must be entered as strings, not integers, with the hastag/pound-symbol proceeding the 6 digit number.
|
||||
// These are the color codes, in hexadecimal (#RRGGBB) format, for the custom color scales for the waterfall. They must be entered as strings, not integers, with the hashtag/pound-symbol proceeding the 6 digit number.
|
||||
"#000020",
|
||||
"#000030",
|
||||
"#000050",
|
||||
|
@ -118,8 +60,8 @@ Please follow this guide to properly format the JSON files for custom color maps
|
|||
}
|
||||
```
|
||||
|
||||
# Best Practices
|
||||
# JSON Formatting
|
||||
|
||||
* All additions and/or bug fixes to the core must not add additional dependencies.
|
||||
* Use VSCode for development, VS seems to cause issues.
|
||||
* DO NOT use libboost for any code meant for this repository
|
||||
The ability to add new radio band allocation identifiers and color maps relies on JSON files. Proper formatting of these JSON files is important for reference and readability. The following guides will show you how to properly format the JSON files for their respective uses.
|
||||
|
||||
**IMPORTANT: JSON File cannot contain comments, there are only in this example for clarity**
|
|
@ -1,22 +1,37 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
project(sdrpp_core)
|
||||
|
||||
# Set compiler options
|
||||
if (MSVC)
|
||||
set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup")
|
||||
else ()
|
||||
set(CMAKE_CXX_FLAGS "-O3 -std=c++17")
|
||||
endif ()
|
||||
add_definitions(-DSDRPP_IS_CORE)
|
||||
if (USE_INTERNAL_LIBCORRECT)
|
||||
add_subdirectory("libcorrect/")
|
||||
endif (USE_INTERNAL_LIBCORRECT)
|
||||
|
||||
if (USE_BUNDLE_DEFAULTS)
|
||||
add_definitions(-DIS_MACOS_BUNDLE)
|
||||
endif (USE_BUNDLE_DEFAULTS)
|
||||
|
||||
# Main code
|
||||
file(GLOB_RECURSE SRC "src/*.cpp" "src/*.c")
|
||||
|
||||
add_definitions(-DSDRPP_IS_CORE)
|
||||
add_definitions(-DFLOG_ANDROID_TAG="SDR++")
|
||||
if (MSVC)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
endif ()
|
||||
|
||||
# Configure backend sources
|
||||
if (OPT_BACKEND_GLFW)
|
||||
file(GLOB_RECURSE BACKEND_SRC "backends/glfw/*.cpp" "backends/glfw/*.c")
|
||||
endif (OPT_BACKEND_GLFW)
|
||||
if (OPT_BACKEND_ANDROID)
|
||||
file(GLOB_RECURSE BACKEND_SRC "backends/android/*.cpp" "backends/android/*.c")
|
||||
set(BACKEND_SRC ${BACKEND_SRC} ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
|
||||
endif (OPT_BACKEND_ANDROID)
|
||||
|
||||
# Add code to dyn lib
|
||||
add_library(sdrpp_core SHARED ${SRC})
|
||||
add_library(sdrpp_core SHARED ${SRC} ${BACKEND_SRC})
|
||||
|
||||
# Set compiler options
|
||||
target_compile_options(sdrpp_core PRIVATE ${SDRPP_COMPILER_FLAGS})
|
||||
|
||||
# Set the install prefix
|
||||
target_compile_definitions(sdrpp_core PUBLIC INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}")
|
||||
|
@ -25,6 +40,38 @@ target_compile_definitions(sdrpp_core PUBLIC INSTALL_PREFIX="${CMAKE_INSTALL_PRE
|
|||
target_include_directories(sdrpp_core PUBLIC "src/")
|
||||
target_include_directories(sdrpp_core PUBLIC "src/imgui")
|
||||
|
||||
# Configure backend includes and libraries
|
||||
if (OPT_BACKEND_GLFW)
|
||||
target_include_directories(sdrpp_core PUBLIC "backends/glfw")
|
||||
target_include_directories(sdrpp_core PUBLIC "backends/glfw/imgui")
|
||||
|
||||
if (MSVC)
|
||||
# GLFW3
|
||||
find_package(glfw3 CONFIG REQUIRED)
|
||||
target_link_libraries(sdrpp_core PUBLIC glfw)
|
||||
else()
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(GLFW3 REQUIRED glfw3)
|
||||
|
||||
target_include_directories(sdrpp_core PUBLIC ${GLFW3_INCLUDE_DIRS})
|
||||
target_link_directories(sdrpp_core PUBLIC ${GLFW3_LIBRARY_DIRS})
|
||||
target_link_libraries(sdrpp_core PUBLIC ${GLFW3_LIBRARIES})
|
||||
endif()
|
||||
endif (OPT_BACKEND_GLFW)
|
||||
if (OPT_BACKEND_ANDROID)
|
||||
target_include_directories(sdrpp_core PUBLIC "backends/android")
|
||||
target_include_directories(sdrpp_core PUBLIC "backends/android/imgui")
|
||||
endif (OPT_BACKEND_ANDROID)
|
||||
|
||||
# Link to libcorrect
|
||||
if (USE_INTERNAL_LIBCORRECT)
|
||||
target_include_directories(sdrpp_core PUBLIC "libcorrect/include")
|
||||
target_link_libraries(sdrpp_core PUBLIC correct_static)
|
||||
endif (USE_INTERNAL_LIBCORRECT)
|
||||
|
||||
if (OPT_OVERRIDE_STD_FILESYSTEM)
|
||||
target_include_directories(sdrpp_core PUBLIC "std_replacement")
|
||||
endif (OPT_OVERRIDE_STD_FILESYSTEM)
|
||||
|
||||
if (MSVC)
|
||||
# Lib path
|
||||
|
@ -36,9 +83,9 @@ if (MSVC)
|
|||
# Volk
|
||||
target_link_libraries(sdrpp_core PUBLIC volk)
|
||||
|
||||
# Glew
|
||||
find_package(GLEW REQUIRED)
|
||||
target_link_libraries(sdrpp_core PUBLIC GLEW::GLEW)
|
||||
# OpenGL
|
||||
find_package(OpenGL REQUIRED)
|
||||
target_link_libraries(sdrpp_core PUBLIC OpenGL::GL)
|
||||
|
||||
# GLFW3
|
||||
find_package(glfw3 CONFIG REQUIRED)
|
||||
|
@ -49,53 +96,75 @@ if (MSVC)
|
|||
target_link_libraries(sdrpp_core PUBLIC FFTW3::fftw3f)
|
||||
|
||||
# WinSock2
|
||||
target_link_libraries(sdrpp_core PUBLIC wsock32 ws2_32)
|
||||
target_link_libraries(sdrpp_core PUBLIC wsock32 ws2_32 iphlpapi)
|
||||
|
||||
# ZSTD
|
||||
find_package(zstd CONFIG REQUIRED)
|
||||
target_link_libraries(sdrpp_core PUBLIC zstd::libzstd_shared)
|
||||
elseif (ANDROID)
|
||||
target_include_directories(sdrpp_core PUBLIC
|
||||
/sdr-kit/${ANDROID_ABI}/include
|
||||
${ANDROID_NDK}/sources/android/native_app_glue
|
||||
)
|
||||
|
||||
target_link_libraries(sdrpp_core PUBLIC
|
||||
/sdr-kit/${ANDROID_ABI}/lib/libvolk.so
|
||||
/sdr-kit/${ANDROID_ABI}/lib/libfftw3f.so
|
||||
/sdr-kit/${ANDROID_ABI}/lib/libzstd.so
|
||||
android
|
||||
EGL
|
||||
GLESv3
|
||||
log
|
||||
)
|
||||
else()
|
||||
find_package(PkgConfig)
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
pkg_check_modules(GLEW REQUIRED glew)
|
||||
pkg_check_modules(FFTW3 REQUIRED fftw3f)
|
||||
pkg_check_modules(VOLK REQUIRED volk)
|
||||
pkg_check_modules(GLFW3 REQUIRED glfw3)
|
||||
pkg_check_modules(LIBZSTD REQUIRED libzstd)
|
||||
|
||||
target_include_directories(sdrpp_core PUBLIC
|
||||
${GLEW_INCLUDE_DIRS}
|
||||
${OPENGL_INCLUDE_DIRS}
|
||||
${FFTW3_INCLUDE_DIRS}
|
||||
${GLFW3_INCLUDE_DIRS}
|
||||
${VOLK_INCLUDE_DIRS}
|
||||
${LIBZSTD_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
|
||||
target_link_directories(sdrpp_core PUBLIC
|
||||
${GLEW_LIBRARY_DIRS}
|
||||
${OPENGL_LIBRARY_DIRS}
|
||||
${FFTW3_LIBRARY_DIRS}
|
||||
${GLFW3_LIBRARY_DIRS}
|
||||
${VOLK_LIBRARY_DIRS}
|
||||
${LIBZSTD_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(sdrpp_core PUBLIC
|
||||
${OPENGL_LIBRARIES}
|
||||
${GLEW_LIBRARIES}
|
||||
${FFTW3_LIBRARIES}
|
||||
${GLFW3_LIBRARIES}
|
||||
${VOLK_LIBRARIES}
|
||||
${LIBZSTD_LIBRARIES}
|
||||
)
|
||||
|
||||
if (NOT USE_INTERNAL_LIBCORRECT)
|
||||
pkg_check_modules(CORRECT REQUIRED libcorrect)
|
||||
target_include_directories(sdrpp_core PUBLIC ${CORRECT_INCLUDE_DIRS})
|
||||
target_link_directories(sdrpp_core PUBLIC ${CORRECT_LIBRARY_DIRS})
|
||||
target_link_libraries(sdrpp_core PUBLIC ${CORRECT_LIBRARIES})
|
||||
endif (NOT USE_INTERNAL_LIBCORRECT)
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
target_link_libraries(sdrpp_core PUBLIC stdc++fs)
|
||||
endif ()
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
|
||||
endif ()
|
||||
|
||||
endif ()
|
||||
|
||||
set(CORE_FILES ${RUNTIME_OUTPUT_DIRECTORY} PARENT_SCOPE)
|
||||
|
||||
# cmake .. "-DCMAKE_TOOLCHAIN_FILE=C:/Users/Alex/vcpkg/scripts/buildsystems/vcpkg.cmake" -G "Visual Studio 15 2017 Win64"
|
||||
# cmake .. "-DCMAKE_TOOLCHAIN_FILE=C:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake"
|
||||
|
||||
# Install directives
|
||||
install(TARGETS sdrpp_core DESTINATION lib)
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace backend {
|
||||
struct DevVIDPID {
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
};
|
||||
|
||||
extern const std::vector<DevVIDPID> AIRSPY_VIDPIDS;
|
||||
extern const std::vector<DevVIDPID> AIRSPYHF_VIDPIDS;
|
||||
extern const std::vector<DevVIDPID> HACKRF_VIDPIDS;
|
||||
extern const std::vector<DevVIDPID> RTL_SDR_VIDPIDS;
|
||||
|
||||
int getDeviceFD(int& vid, int& pid, const std::vector<DevVIDPID>& allowedVidPids);
|
||||
}
|
|
@ -0,0 +1,483 @@
|
|||
#include <backend.h>log
|
||||
#include "android_backend.h"
|
||||
#include <core.h>
|
||||
#include <gui/gui.h>
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_android.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include <android/log.h>
|
||||
#include <android_native_app_glue.h>
|
||||
#include <android/asset_manager.h>
|
||||
#include <EGL/egl.h>
|
||||
#include <GLES3/gl3.h>
|
||||
#include <stdint.h>
|
||||
#include <gui/icons.h>
|
||||
#include <gui/style.h>
|
||||
#include <gui/menus/theme.h>
|
||||
#include <filesystem>
|
||||
|
||||
// Credit to the ImGui android OpenGL3 example for a lot of this code!
|
||||
|
||||
namespace backend {
|
||||
struct android_app* app = NULL;
|
||||
EGLDisplay _EglDisplay = EGL_NO_DISPLAY;
|
||||
EGLSurface _EglSurface = EGL_NO_SURFACE;
|
||||
EGLContext _EglContext = EGL_NO_CONTEXT;
|
||||
bool _Initialized = false;
|
||||
char _LogTag[] = "SDR++";
|
||||
bool initialized = false;
|
||||
bool pauseRendering = false;
|
||||
bool exited = false;
|
||||
|
||||
// Forward declaration
|
||||
int ShowSoftKeyboardInput();
|
||||
int PollUnicodeChars();
|
||||
|
||||
void doPartialInit() {
|
||||
std::string root = (std::string)core::args["root"];
|
||||
backend::init();
|
||||
style::loadFonts(root + "/res"); // TODO: Don't hardcode, use config
|
||||
icons::load(root + "/res");
|
||||
thememenu::applyTheme();
|
||||
ImGui::GetStyle().ScaleAllSizes(style::uiScale);
|
||||
gui::mainWindow.setFirstMenuRender();
|
||||
}
|
||||
|
||||
void handleAppCmd(struct android_app* app, int32_t appCmd) {
|
||||
switch (appCmd) {
|
||||
case APP_CMD_SAVE_STATE:
|
||||
flog::warn("APP_CMD_SAVE_STATE");
|
||||
break;
|
||||
case APP_CMD_INIT_WINDOW:
|
||||
flog::warn("APP_CMD_INIT_WINDOW");
|
||||
if (pauseRendering && !exited) {
|
||||
doPartialInit();
|
||||
pauseRendering = false;
|
||||
}
|
||||
exited = false;
|
||||
break;
|
||||
case APP_CMD_TERM_WINDOW:
|
||||
flog::warn("APP_CMD_TERM_WINDOW");
|
||||
pauseRendering = true;
|
||||
backend::end();
|
||||
break;
|
||||
case APP_CMD_GAINED_FOCUS:
|
||||
flog::warn("APP_CMD_GAINED_FOCUS");
|
||||
break;
|
||||
case APP_CMD_LOST_FOCUS:
|
||||
flog::warn("APP_CMD_LOST_FOCUS");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t handleInputEvent(struct android_app* app, AInputEvent* inputEvent) {
|
||||
return ImGui_ImplAndroid_HandleInputEvent(inputEvent);
|
||||
}
|
||||
|
||||
int aquireWindow() {
|
||||
while (!app->window) {
|
||||
flog::warn("Waiting on the shitty window thing"); std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
||||
int out_events;
|
||||
struct android_poll_source* out_data;
|
||||
|
||||
while (ALooper_pollAll(0, NULL, &out_events, (void**)&out_data) >= 0) {
|
||||
// Process one event
|
||||
if (out_data != NULL) { out_data->process(app, out_data); }
|
||||
|
||||
// Exit the app by returning from within the infinite loop
|
||||
if (app->destroyRequested != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
ANativeWindow_acquire(app->window);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int init(std::string resDir) {
|
||||
flog::warn("Backend init");
|
||||
|
||||
// Get window
|
||||
aquireWindow();
|
||||
|
||||
// EGL Init
|
||||
{
|
||||
_EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
if (_EglDisplay == EGL_NO_DISPLAY)
|
||||
__android_log_print(ANDROID_LOG_ERROR, _LogTag, "%s", "eglGetDisplay(EGL_DEFAULT_DISPLAY) returned EGL_NO_DISPLAY");
|
||||
|
||||
if (eglInitialize(_EglDisplay, 0, 0) != EGL_TRUE)
|
||||
__android_log_print(ANDROID_LOG_ERROR, _LogTag, "%s", "eglInitialize() returned with an error");
|
||||
|
||||
const EGLint egl_attributes[] = { EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_DEPTH_SIZE, 24, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE };
|
||||
EGLint num_configs = 0;
|
||||
if (eglChooseConfig(_EglDisplay, egl_attributes, nullptr, 0, &num_configs) != EGL_TRUE)
|
||||
__android_log_print(ANDROID_LOG_ERROR, _LogTag, "%s", "eglChooseConfig() returned with an error");
|
||||
if (num_configs == 0)
|
||||
__android_log_print(ANDROID_LOG_ERROR, _LogTag, "%s", "eglChooseConfig() returned 0 matching config");
|
||||
|
||||
// Get the first matching config
|
||||
EGLConfig egl_config;
|
||||
eglChooseConfig(_EglDisplay, egl_attributes, &egl_config, 1, &num_configs);
|
||||
EGLint egl_format;
|
||||
eglGetConfigAttrib(_EglDisplay, egl_config, EGL_NATIVE_VISUAL_ID, &egl_format);
|
||||
ANativeWindow_setBuffersGeometry(app->window, 0, 0, egl_format);
|
||||
|
||||
const EGLint egl_context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE };
|
||||
_EglContext = eglCreateContext(_EglDisplay, egl_config, EGL_NO_CONTEXT, egl_context_attributes);
|
||||
|
||||
if (_EglContext == EGL_NO_CONTEXT)
|
||||
__android_log_print(ANDROID_LOG_ERROR, _LogTag, "%s", "eglCreateContext() returned EGL_NO_CONTEXT");
|
||||
|
||||
_EglSurface = eglCreateWindowSurface(_EglDisplay, egl_config, app->window, NULL);
|
||||
eglMakeCurrent(_EglDisplay, _EglSurface, _EglSurface, _EglContext);
|
||||
}
|
||||
|
||||
// Setup Dear ImGui context
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
(void)io;
|
||||
|
||||
// Disable loading/saving of .ini file from disk.
|
||||
// FIXME: Consider using LoadIniSettingsFromMemory() / SaveIniSettingsToMemory() to save in appropriate location for Android.
|
||||
io.IniFilename = NULL;
|
||||
|
||||
// Setup Platform/Renderer backends
|
||||
ImGui_ImplAndroid_Init(app->window);
|
||||
ImGui_ImplOpenGL3_Init("#version 300 es");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void beginFrame() {
|
||||
// Start the Dear ImGui frame
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplAndroid_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
void render(bool vsync) {
|
||||
// Rendering
|
||||
ImGui::Render();
|
||||
auto dSize = ImGui::GetIO().DisplaySize;
|
||||
glViewport(0, 0, dSize.x, dSize.y);
|
||||
glClearColor(gui::themeManager.clearColor.x, gui::themeManager.clearColor.y, gui::themeManager.clearColor.z, gui::themeManager.clearColor.w);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
eglSwapBuffers(_EglDisplay, _EglSurface);
|
||||
}
|
||||
|
||||
// No screen pos to detect
|
||||
void getMouseScreenPos(double& x, double& y) { x = 0; y = 0; }
|
||||
void setMouseScreenPos(double x, double y) {}
|
||||
|
||||
int renderLoop() {
|
||||
while (true) {
|
||||
int out_events;
|
||||
struct android_poll_source* out_data;
|
||||
|
||||
while (ALooper_pollAll(0, NULL, &out_events, (void**)&out_data) >= 0) {
|
||||
// Process one event
|
||||
if (out_data != NULL) { out_data->process(app, out_data); }
|
||||
|
||||
// Exit the app by returning from within the infinite loop
|
||||
if (app->destroyRequested != 0) {
|
||||
flog::warn("ASKED TO EXIT");
|
||||
exited = true;
|
||||
|
||||
// Stop SDR
|
||||
gui::mainWindow.setPlayState(false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (_EglDisplay == EGL_NO_DISPLAY) { continue; }
|
||||
|
||||
if (!pauseRendering) {
|
||||
// Initiate a new frame
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
auto dsize = io.DisplaySize;
|
||||
|
||||
// Poll Unicode characters via JNI
|
||||
// FIXME: do not call this every frame because of JNI overhead
|
||||
PollUnicodeChars();
|
||||
|
||||
// Open on-screen (soft) input if requested by Dear ImGui
|
||||
static bool WantTextInputLast = false;
|
||||
if (io.WantTextInput && !WantTextInputLast)
|
||||
ShowSoftKeyboardInput();
|
||||
WantTextInputLast = io.WantTextInput;
|
||||
|
||||
// Render
|
||||
beginFrame();
|
||||
|
||||
if (dsize.x > 0 && dsize.y > 0) {
|
||||
ImGui::SetNextWindowPos(ImVec2(0, 0));
|
||||
ImGui::SetNextWindowSize(ImVec2(dsize.x, dsize.y));
|
||||
gui::mainWindow.draw();
|
||||
}
|
||||
render();
|
||||
}
|
||||
else {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int end() {
|
||||
// Cleanup
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplAndroid_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
|
||||
// Destroy all
|
||||
if (_EglDisplay != EGL_NO_DISPLAY) {
|
||||
eglMakeCurrent(_EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
if (_EglContext != EGL_NO_CONTEXT) { eglDestroyContext(_EglDisplay, _EglContext); }
|
||||
if (_EglSurface != EGL_NO_SURFACE) { eglDestroySurface(_EglDisplay, _EglSurface); }
|
||||
eglTerminate(_EglDisplay);
|
||||
}
|
||||
|
||||
_EglDisplay = EGL_NO_DISPLAY;
|
||||
_EglContext = EGL_NO_CONTEXT;
|
||||
_EglSurface = EGL_NO_SURFACE;
|
||||
|
||||
if (app->window) { ANativeWindow_release(app->window); }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ShowSoftKeyboardInput() {
|
||||
JavaVM* java_vm = app->activity->vm;
|
||||
JNIEnv* java_env = NULL;
|
||||
|
||||
jint jni_return = java_vm->GetEnv((void**)&java_env, JNI_VERSION_1_6);
|
||||
if (jni_return == JNI_ERR)
|
||||
return -1;
|
||||
|
||||
jni_return = java_vm->AttachCurrentThread(&java_env, NULL);
|
||||
if (jni_return != JNI_OK)
|
||||
return -2;
|
||||
|
||||
jclass native_activity_clazz = java_env->GetObjectClass(app->activity->clazz);
|
||||
if (native_activity_clazz == NULL)
|
||||
return -3;
|
||||
|
||||
jmethodID method_id = java_env->GetMethodID(native_activity_clazz, "showSoftInput", "()V");
|
||||
if (method_id == NULL)
|
||||
return -4;
|
||||
|
||||
java_env->CallVoidMethod(app->activity->clazz, method_id);
|
||||
|
||||
jni_return = java_vm->DetachCurrentThread();
|
||||
if (jni_return != JNI_OK)
|
||||
return -5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getDeviceFD(int& vid, int& pid, const std::vector<DevVIDPID>& allowedVidPids) {
|
||||
JavaVM* java_vm = app->activity->vm;
|
||||
JNIEnv* java_env = NULL;
|
||||
|
||||
jint jni_return = java_vm->GetEnv((void**)&java_env, JNI_VERSION_1_6);
|
||||
if (jni_return == JNI_ERR)
|
||||
return -1;
|
||||
|
||||
jni_return = java_vm->AttachCurrentThread(&java_env, NULL);
|
||||
if (jni_return != JNI_OK)
|
||||
return -1;
|
||||
|
||||
jclass native_activity_clazz = java_env->GetObjectClass(app->activity->clazz);
|
||||
if (native_activity_clazz == NULL)
|
||||
return -1;
|
||||
|
||||
jfieldID fd_field_id = java_env->GetFieldID(native_activity_clazz, "SDR_FD", "I");
|
||||
jfieldID vid_field_id = java_env->GetFieldID(native_activity_clazz, "SDR_VID", "I");
|
||||
jfieldID pid_field_id = java_env->GetFieldID(native_activity_clazz, "SDR_PID", "I");
|
||||
|
||||
if (!vid_field_id || !vid_field_id || !pid_field_id)
|
||||
return -1;
|
||||
|
||||
int fd = java_env->GetIntField(app->activity->clazz, fd_field_id);
|
||||
vid = java_env->GetIntField(app->activity->clazz, vid_field_id);
|
||||
pid = java_env->GetIntField(app->activity->clazz, pid_field_id);
|
||||
|
||||
jni_return = java_vm->DetachCurrentThread();
|
||||
if (jni_return != JNI_OK)
|
||||
return -1;
|
||||
|
||||
// If no vid/pid was given, just return successfully
|
||||
if (allowedVidPids.empty()) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
// Otherwise, check that the vid/pid combo is allowed
|
||||
for (auto const& vp : allowedVidPids) {
|
||||
if (vp.vid != vid || vp.pid != pid) { continue; }
|
||||
return fd;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Unfortunately, the native KeyEvent implementation has no getUnicodeChar() function.
|
||||
// Therefore, we implement the processing of KeyEvents in MainActivity.kt and poll
|
||||
// the resulting Unicode characters here via JNI and send them to Dear ImGui.
|
||||
int PollUnicodeChars() {
|
||||
JavaVM* java_vm = app->activity->vm;
|
||||
JNIEnv* java_env = NULL;
|
||||
|
||||
jint jni_return = java_vm->GetEnv((void**)&java_env, JNI_VERSION_1_6);
|
||||
if (jni_return == JNI_ERR)
|
||||
return -1;
|
||||
|
||||
jni_return = java_vm->AttachCurrentThread(&java_env, NULL);
|
||||
if (jni_return != JNI_OK)
|
||||
return -2;
|
||||
|
||||
jclass native_activity_clazz = java_env->GetObjectClass(app->activity->clazz);
|
||||
if (native_activity_clazz == NULL)
|
||||
return -3;
|
||||
|
||||
jmethodID method_id = java_env->GetMethodID(native_activity_clazz, "pollUnicodeChar", "()I");
|
||||
if (method_id == NULL)
|
||||
return -4;
|
||||
|
||||
// Send the actual characters to Dear ImGui
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
jint unicode_character;
|
||||
while ((unicode_character = java_env->CallIntMethod(app->activity->clazz, method_id)) != 0)
|
||||
io.AddInputCharacter(unicode_character);
|
||||
|
||||
jni_return = java_vm->DetachCurrentThread();
|
||||
if (jni_return != JNI_OK)
|
||||
return -5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string getAppFilesDir() {
|
||||
JavaVM* java_vm = app->activity->vm;
|
||||
JNIEnv* java_env = NULL;
|
||||
|
||||
jint jni_return = java_vm->GetEnv((void**)&java_env, JNI_VERSION_1_6);
|
||||
if (jni_return == JNI_ERR)
|
||||
throw std::runtime_error("Could not get JNI environment");
|
||||
|
||||
jni_return = java_vm->AttachCurrentThread(&java_env, NULL);
|
||||
if (jni_return != JNI_OK)
|
||||
throw std::runtime_error("Could not attach to thread");
|
||||
|
||||
jclass native_activity_clazz = java_env->GetObjectClass(app->activity->clazz);
|
||||
if (native_activity_clazz == NULL)
|
||||
throw std::runtime_error("Could not get MainActivity class");
|
||||
|
||||
jmethodID method_id = java_env->GetMethodID(native_activity_clazz, "getAppDir", "()Ljava/lang/String;");
|
||||
if (method_id == NULL)
|
||||
throw std::runtime_error("Could not get method ID");
|
||||
|
||||
jstring jstr = (jstring)java_env->CallObjectMethod(app->activity->clazz, method_id);
|
||||
|
||||
const char* _str = java_env->GetStringUTFChars(jstr, NULL);
|
||||
std::string str(_str);
|
||||
java_env->ReleaseStringUTFChars(jstr, _str);
|
||||
|
||||
jni_return = java_vm->DetachCurrentThread();
|
||||
if (jni_return != JNI_OK)
|
||||
throw std::runtime_error("Could not detach from thread");
|
||||
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
const std::vector<DevVIDPID> AIRSPY_VIDPIDS = {
|
||||
{ 0x1d50, 0x60a1 }
|
||||
};
|
||||
|
||||
const std::vector<DevVIDPID> AIRSPYHF_VIDPIDS = {
|
||||
{ 0x03EB, 0x800C }
|
||||
};
|
||||
|
||||
const std::vector<DevVIDPID> HACKRF_VIDPIDS = {
|
||||
{ 0x1d50, 0x604b },
|
||||
{ 0x1d50, 0x6089 },
|
||||
{ 0x1d50, 0xcc15 }
|
||||
};
|
||||
|
||||
const std::vector<DevVIDPID> RTL_SDR_VIDPIDS = {
|
||||
{ 0x0bda, 0x2832 },
|
||||
{ 0x0bda, 0x2838 },
|
||||
{ 0x0413, 0x6680 },
|
||||
{ 0x0413, 0x6f0f },
|
||||
{ 0x0458, 0x707f },
|
||||
{ 0x0ccd, 0x00a9 },
|
||||
{ 0x0ccd, 0x00b3 },
|
||||
{ 0x0ccd, 0x00b4 },
|
||||
{ 0x0ccd, 0x00b5 },
|
||||
{ 0x0ccd, 0x00b7 },
|
||||
{ 0x0ccd, 0x00b8 },
|
||||
{ 0x0ccd, 0x00b9 },
|
||||
{ 0x0ccd, 0x00c0 },
|
||||
{ 0x0ccd, 0x00c6 },
|
||||
{ 0x0ccd, 0x00d3 },
|
||||
{ 0x0ccd, 0x00d7 },
|
||||
{ 0x0ccd, 0x00e0 },
|
||||
{ 0x1554, 0x5020 },
|
||||
{ 0x15f4, 0x0131 },
|
||||
{ 0x15f4, 0x0133 },
|
||||
{ 0x185b, 0x0620 },
|
||||
{ 0x185b, 0x0650 },
|
||||
{ 0x185b, 0x0680 },
|
||||
{ 0x1b80, 0xd393 },
|
||||
{ 0x1b80, 0xd394 },
|
||||
{ 0x1b80, 0xd395 },
|
||||
{ 0x1b80, 0xd397 },
|
||||
{ 0x1b80, 0xd398 },
|
||||
{ 0x1b80, 0xd39d },
|
||||
{ 0x1b80, 0xd3a4 },
|
||||
{ 0x1b80, 0xd3a8 },
|
||||
{ 0x1b80, 0xd3af },
|
||||
{ 0x1b80, 0xd3b0 },
|
||||
{ 0x1d19, 0x1101 },
|
||||
{ 0x1d19, 0x1102 },
|
||||
{ 0x1d19, 0x1103 },
|
||||
{ 0x1d19, 0x1104 },
|
||||
{ 0x1f4d, 0xa803 },
|
||||
{ 0x1f4d, 0xb803 },
|
||||
{ 0x1f4d, 0xc803 },
|
||||
{ 0x1f4d, 0xd286 },
|
||||
{ 0x1f4d, 0xd803 }
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void android_main(struct android_app* app) {
|
||||
// Save app instance
|
||||
app->onAppCmd = backend::handleAppCmd;
|
||||
app->onInputEvent = backend::handleInputEvent;
|
||||
backend::app = app;
|
||||
|
||||
// Check if this is the first time we run or not
|
||||
if (backend::initialized) {
|
||||
flog::warn("android_main called again");
|
||||
backend::doPartialInit();
|
||||
backend::pauseRendering = false;
|
||||
backend::renderLoop();
|
||||
return;
|
||||
}
|
||||
backend::initialized = true;
|
||||
|
||||
// Grab files dir
|
||||
std::string appdir = backend::getAppFilesDir();
|
||||
|
||||
// Call main
|
||||
char* rootpath = new char[appdir.size() + 1];
|
||||
strcpy(rootpath, appdir.c_str());
|
||||
char* dummy[] = { "", "-r", rootpath };
|
||||
sdrpp_main(3, dummy);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,278 @@
|
|||
// dear imgui: Platform Binding for Android native app
|
||||
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||
// Missing features:
|
||||
// [ ] Platform: Clipboard support.
|
||||
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
|
||||
// Important:
|
||||
// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
|
||||
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
|
||||
// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago)with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
|
||||
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
|
||||
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
|
||||
// 2021-03-04: Initial version.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_android.h"
|
||||
#include <time.h>
|
||||
#include <android/native_window.h>
|
||||
#include <android/input.h>
|
||||
#include <android/keycodes.h>
|
||||
#include <android/log.h>
|
||||
|
||||
// Android data
|
||||
static double g_Time = 0.0;
|
||||
static ANativeWindow* g_Window;
|
||||
static char g_LogTag[] = "ImGuiExample";
|
||||
|
||||
static ImGuiKey ImGui_ImplAndroid_KeyCodeToImGuiKey(int32_t key_code)
|
||||
{
|
||||
switch (key_code)
|
||||
{
|
||||
case AKEYCODE_TAB: return ImGuiKey_Tab;
|
||||
case AKEYCODE_DPAD_LEFT: return ImGuiKey_LeftArrow;
|
||||
case AKEYCODE_DPAD_RIGHT: return ImGuiKey_RightArrow;
|
||||
case AKEYCODE_DPAD_UP: return ImGuiKey_UpArrow;
|
||||
case AKEYCODE_DPAD_DOWN: return ImGuiKey_DownArrow;
|
||||
case AKEYCODE_PAGE_UP: return ImGuiKey_PageUp;
|
||||
case AKEYCODE_PAGE_DOWN: return ImGuiKey_PageDown;
|
||||
case AKEYCODE_MOVE_HOME: return ImGuiKey_Home;
|
||||
case AKEYCODE_MOVE_END: return ImGuiKey_End;
|
||||
case AKEYCODE_INSERT: return ImGuiKey_Insert;
|
||||
case AKEYCODE_FORWARD_DEL: return ImGuiKey_Delete;
|
||||
case AKEYCODE_DEL: return ImGuiKey_Backspace;
|
||||
case AKEYCODE_SPACE: return ImGuiKey_Space;
|
||||
case AKEYCODE_ENTER: return ImGuiKey_Enter;
|
||||
case AKEYCODE_ESCAPE: return ImGuiKey_Escape;
|
||||
case AKEYCODE_APOSTROPHE: return ImGuiKey_Apostrophe;
|
||||
case AKEYCODE_COMMA: return ImGuiKey_Comma;
|
||||
case AKEYCODE_MINUS: return ImGuiKey_Minus;
|
||||
case AKEYCODE_PERIOD: return ImGuiKey_Period;
|
||||
case AKEYCODE_SLASH: return ImGuiKey_Slash;
|
||||
case AKEYCODE_SEMICOLON: return ImGuiKey_Semicolon;
|
||||
case AKEYCODE_EQUALS: return ImGuiKey_Equal;
|
||||
case AKEYCODE_LEFT_BRACKET: return ImGuiKey_LeftBracket;
|
||||
case AKEYCODE_BACKSLASH: return ImGuiKey_Backslash;
|
||||
case AKEYCODE_RIGHT_BRACKET: return ImGuiKey_RightBracket;
|
||||
case AKEYCODE_GRAVE: return ImGuiKey_GraveAccent;
|
||||
case AKEYCODE_CAPS_LOCK: return ImGuiKey_CapsLock;
|
||||
case AKEYCODE_SCROLL_LOCK: return ImGuiKey_ScrollLock;
|
||||
case AKEYCODE_NUM_LOCK: return ImGuiKey_NumLock;
|
||||
case AKEYCODE_SYSRQ: return ImGuiKey_PrintScreen;
|
||||
case AKEYCODE_BREAK: return ImGuiKey_Pause;
|
||||
case AKEYCODE_NUMPAD_0: return ImGuiKey_Keypad0;
|
||||
case AKEYCODE_NUMPAD_1: return ImGuiKey_Keypad1;
|
||||
case AKEYCODE_NUMPAD_2: return ImGuiKey_Keypad2;
|
||||
case AKEYCODE_NUMPAD_3: return ImGuiKey_Keypad3;
|
||||
case AKEYCODE_NUMPAD_4: return ImGuiKey_Keypad4;
|
||||
case AKEYCODE_NUMPAD_5: return ImGuiKey_Keypad5;
|
||||
case AKEYCODE_NUMPAD_6: return ImGuiKey_Keypad6;
|
||||
case AKEYCODE_NUMPAD_7: return ImGuiKey_Keypad7;
|
||||
case AKEYCODE_NUMPAD_8: return ImGuiKey_Keypad8;
|
||||
case AKEYCODE_NUMPAD_9: return ImGuiKey_Keypad9;
|
||||
case AKEYCODE_NUMPAD_DOT: return ImGuiKey_KeypadDecimal;
|
||||
case AKEYCODE_NUMPAD_DIVIDE: return ImGuiKey_KeypadDivide;
|
||||
case AKEYCODE_NUMPAD_MULTIPLY: return ImGuiKey_KeypadMultiply;
|
||||
case AKEYCODE_NUMPAD_SUBTRACT: return ImGuiKey_KeypadSubtract;
|
||||
case AKEYCODE_NUMPAD_ADD: return ImGuiKey_KeypadAdd;
|
||||
case AKEYCODE_NUMPAD_ENTER: return ImGuiKey_KeypadEnter;
|
||||
case AKEYCODE_NUMPAD_EQUALS: return ImGuiKey_KeypadEqual;
|
||||
case AKEYCODE_CTRL_LEFT: return ImGuiKey_LeftCtrl;
|
||||
case AKEYCODE_SHIFT_LEFT: return ImGuiKey_LeftShift;
|
||||
case AKEYCODE_ALT_LEFT: return ImGuiKey_LeftAlt;
|
||||
case AKEYCODE_META_LEFT: return ImGuiKey_LeftSuper;
|
||||
case AKEYCODE_CTRL_RIGHT: return ImGuiKey_RightCtrl;
|
||||
case AKEYCODE_SHIFT_RIGHT: return ImGuiKey_RightShift;
|
||||
case AKEYCODE_ALT_RIGHT: return ImGuiKey_RightAlt;
|
||||
case AKEYCODE_META_RIGHT: return ImGuiKey_RightSuper;
|
||||
case AKEYCODE_MENU: return ImGuiKey_Menu;
|
||||
case AKEYCODE_0: return ImGuiKey_0;
|
||||
case AKEYCODE_1: return ImGuiKey_1;
|
||||
case AKEYCODE_2: return ImGuiKey_2;
|
||||
case AKEYCODE_3: return ImGuiKey_3;
|
||||
case AKEYCODE_4: return ImGuiKey_4;
|
||||
case AKEYCODE_5: return ImGuiKey_5;
|
||||
case AKEYCODE_6: return ImGuiKey_6;
|
||||
case AKEYCODE_7: return ImGuiKey_7;
|
||||
case AKEYCODE_8: return ImGuiKey_8;
|
||||
case AKEYCODE_9: return ImGuiKey_9;
|
||||
case AKEYCODE_A: return ImGuiKey_A;
|
||||
case AKEYCODE_B: return ImGuiKey_B;
|
||||
case AKEYCODE_C: return ImGuiKey_C;
|
||||
case AKEYCODE_D: return ImGuiKey_D;
|
||||
case AKEYCODE_E: return ImGuiKey_E;
|
||||
case AKEYCODE_F: return ImGuiKey_F;
|
||||
case AKEYCODE_G: return ImGuiKey_G;
|
||||
case AKEYCODE_H: return ImGuiKey_H;
|
||||
case AKEYCODE_I: return ImGuiKey_I;
|
||||
case AKEYCODE_J: return ImGuiKey_J;
|
||||
case AKEYCODE_K: return ImGuiKey_K;
|
||||
case AKEYCODE_L: return ImGuiKey_L;
|
||||
case AKEYCODE_M: return ImGuiKey_M;
|
||||
case AKEYCODE_N: return ImGuiKey_N;
|
||||
case AKEYCODE_O: return ImGuiKey_O;
|
||||
case AKEYCODE_P: return ImGuiKey_P;
|
||||
case AKEYCODE_Q: return ImGuiKey_Q;
|
||||
case AKEYCODE_R: return ImGuiKey_R;
|
||||
case AKEYCODE_S: return ImGuiKey_S;
|
||||
case AKEYCODE_T: return ImGuiKey_T;
|
||||
case AKEYCODE_U: return ImGuiKey_U;
|
||||
case AKEYCODE_V: return ImGuiKey_V;
|
||||
case AKEYCODE_W: return ImGuiKey_W;
|
||||
case AKEYCODE_X: return ImGuiKey_X;
|
||||
case AKEYCODE_Y: return ImGuiKey_Y;
|
||||
case AKEYCODE_Z: return ImGuiKey_Z;
|
||||
case AKEYCODE_F1: return ImGuiKey_F1;
|
||||
case AKEYCODE_F2: return ImGuiKey_F2;
|
||||
case AKEYCODE_F3: return ImGuiKey_F3;
|
||||
case AKEYCODE_F4: return ImGuiKey_F4;
|
||||
case AKEYCODE_F5: return ImGuiKey_F5;
|
||||
case AKEYCODE_F6: return ImGuiKey_F6;
|
||||
case AKEYCODE_F7: return ImGuiKey_F7;
|
||||
case AKEYCODE_F8: return ImGuiKey_F8;
|
||||
case AKEYCODE_F9: return ImGuiKey_F9;
|
||||
case AKEYCODE_F10: return ImGuiKey_F10;
|
||||
case AKEYCODE_F11: return ImGuiKey_F11;
|
||||
case AKEYCODE_F12: return ImGuiKey_F12;
|
||||
default: return ImGuiKey_None;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
int32_t event_type = AInputEvent_getType(input_event);
|
||||
switch (event_type)
|
||||
{
|
||||
case AINPUT_EVENT_TYPE_KEY:
|
||||
{
|
||||
int32_t event_key_code = AKeyEvent_getKeyCode(input_event);
|
||||
int32_t event_scan_code = AKeyEvent_getScanCode(input_event);
|
||||
int32_t event_action = AKeyEvent_getAction(input_event);
|
||||
int32_t event_meta_state = AKeyEvent_getMetaState(input_event);
|
||||
|
||||
io.AddKeyEvent(ImGuiKey_ModCtrl, (event_meta_state & AMETA_CTRL_ON) != 0);
|
||||
io.AddKeyEvent(ImGuiKey_ModShift, (event_meta_state & AMETA_SHIFT_ON) != 0);
|
||||
io.AddKeyEvent(ImGuiKey_ModAlt, (event_meta_state & AMETA_ALT_ON) != 0);
|
||||
io.AddKeyEvent(ImGuiKey_ModSuper, (event_meta_state & AMETA_META_ON) != 0);
|
||||
|
||||
switch (event_action)
|
||||
{
|
||||
// FIXME: AKEY_EVENT_ACTION_DOWN and AKEY_EVENT_ACTION_UP occur at once as soon as a touch pointer
|
||||
// goes up from a key. We use a simple key event queue/ and process one event per key per frame in
|
||||
// ImGui_ImplAndroid_NewFrame()...or consider using IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787
|
||||
case AKEY_EVENT_ACTION_DOWN:
|
||||
case AKEY_EVENT_ACTION_UP:
|
||||
{
|
||||
ImGuiKey key = ImGui_ImplAndroid_KeyCodeToImGuiKey(event_key_code);
|
||||
if (key != ImGuiKey_None && (event_action == AKEY_EVENT_ACTION_DOWN || event_action == AKEY_EVENT_ACTION_UP))
|
||||
{
|
||||
io.AddKeyEvent(key, event_action == AKEY_EVENT_ACTION_DOWN);
|
||||
io.SetKeyEventNativeData(key, event_key_code, event_scan_code);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AINPUT_EVENT_TYPE_MOTION:
|
||||
{
|
||||
int32_t event_action = AMotionEvent_getAction(input_event);
|
||||
int32_t event_pointer_index = (event_action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
||||
event_action &= AMOTION_EVENT_ACTION_MASK;
|
||||
switch (event_action)
|
||||
{
|
||||
case AMOTION_EVENT_ACTION_DOWN:
|
||||
case AMOTION_EVENT_ACTION_UP:
|
||||
// Physical mouse buttons (and probably other physical devices) also invoke the actions AMOTION_EVENT_ACTION_DOWN/_UP,
|
||||
// but we have to process them separately to identify the actual button pressed. This is done below via
|
||||
// AMOTION_EVENT_ACTION_BUTTON_PRESS/_RELEASE. Here, we only process "FINGER" input (and "UNKNOWN", as a fallback).
|
||||
if((AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER)
|
||||
|| (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_STYLUS)
|
||||
|| (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_MOUSE)
|
||||
|| (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN))
|
||||
{
|
||||
io.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
|
||||
io.AddMouseButtonEvent(0, event_action == AMOTION_EVENT_ACTION_DOWN);
|
||||
}
|
||||
break;
|
||||
case AMOTION_EVENT_ACTION_BUTTON_PRESS:
|
||||
case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
|
||||
{
|
||||
int32_t button_state = AMotionEvent_getButtonState(input_event);
|
||||
io.AddMouseButtonEvent(0, (button_state & AMOTION_EVENT_BUTTON_PRIMARY) != 0);
|
||||
io.AddMouseButtonEvent(1, (button_state & AMOTION_EVENT_BUTTON_SECONDARY) != 0);
|
||||
io.AddMouseButtonEvent(2, (button_state & AMOTION_EVENT_BUTTON_TERTIARY) != 0);
|
||||
}
|
||||
break;
|
||||
case AMOTION_EVENT_ACTION_HOVER_MOVE: // Hovering: Tool moves while NOT pressed (such as a physical mouse)
|
||||
case AMOTION_EVENT_ACTION_MOVE: // Touch pointer moves while DOWN
|
||||
io.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
|
||||
break;
|
||||
case AMOTION_EVENT_ACTION_SCROLL:
|
||||
io.AddMouseWheelEvent(AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index), AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ImGui_ImplAndroid_Init(ANativeWindow* window)
|
||||
{
|
||||
g_Window = window;
|
||||
g_Time = 0.0;
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendPlatformName = "imgui_impl_android";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplAndroid_Shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
void ImGui_ImplAndroid_NewFrame()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
int32_t window_width = ANativeWindow_getWidth(g_Window);
|
||||
int32_t window_height = ANativeWindow_getHeight(g_Window);
|
||||
int display_width = window_width;
|
||||
int display_height = window_height;
|
||||
|
||||
io.DisplaySize = ImVec2((float)window_width, (float)window_height);
|
||||
if (window_width > 0 && window_height > 0)
|
||||
io.DisplayFramebufferScale = ImVec2((float)display_width / window_width, (float)display_height / window_height);
|
||||
|
||||
// Setup time step
|
||||
struct timespec current_timespec;
|
||||
clock_gettime(CLOCK_MONOTONIC, ¤t_timespec);
|
||||
double current_time = (double)(current_timespec.tv_sec) + (current_timespec.tv_nsec / 1000000000.0);
|
||||
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
|
||||
g_Time = current_time;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// dear imgui: Platform Binding for Android native app
|
||||
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||
// Missing features:
|
||||
// [ ] Platform: Clipboard support.
|
||||
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
|
||||
// Important:
|
||||
// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
|
||||
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
|
||||
// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
|
||||
struct ANativeWindow;
|
||||
struct AInputEvent;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplAndroid_Init(ANativeWindow* window);
|
||||
IMGUI_IMPL_API int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event);
|
||||
IMGUI_IMPL_API void ImGui_ImplAndroid_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplAndroid_NewFrame();
|
|
@ -0,0 +1,305 @@
|
|||
#include <backend.h>
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_glfw.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <utils/flog.h>
|
||||
#include <utils/opengl_include_code.h>
|
||||
#include <version.h>
|
||||
#include <core.h>
|
||||
#include <filesystem>
|
||||
#include <stb_image.h>
|
||||
#include <stb_image_resize.h>
|
||||
#include <gui/gui.h>
|
||||
|
||||
namespace backend {
|
||||
const char* OPENGL_VERSIONS_GLSL[] = {
|
||||
"#version 120",
|
||||
"#version 300 es",
|
||||
"#version 120"
|
||||
};
|
||||
|
||||
const int OPENGL_VERSIONS_MAJOR[] = {
|
||||
3,
|
||||
3,
|
||||
2
|
||||
};
|
||||
|
||||
const int OPENGL_VERSIONS_MINOR[] = {
|
||||
0,
|
||||
1,
|
||||
1
|
||||
};
|
||||
|
||||
const bool OPENGL_VERSIONS_IS_ES[] = {
|
||||
false,
|
||||
true,
|
||||
false
|
||||
};
|
||||
|
||||
#define OPENGL_VERSION_COUNT (sizeof(OPENGL_VERSIONS_GLSL) / sizeof(char*))
|
||||
|
||||
bool maximized = false;
|
||||
bool fullScreen = false;
|
||||
int winHeight;
|
||||
int winWidth;
|
||||
bool _maximized = maximized;
|
||||
int fsWidth, fsHeight, fsPosX, fsPosY;
|
||||
int _winWidth, _winHeight;
|
||||
GLFWwindow* window;
|
||||
GLFWmonitor* monitor;
|
||||
|
||||
static void glfw_error_callback(int error, const char* description) {
|
||||
flog::error("Glfw Error {0}: {1}", error, description);
|
||||
}
|
||||
|
||||
static void maximized_callback(GLFWwindow* window, int n) {
|
||||
if (n == GLFW_TRUE) {
|
||||
maximized = true;
|
||||
}
|
||||
else {
|
||||
maximized = false;
|
||||
}
|
||||
}
|
||||
|
||||
int init(std::string resDir) {
|
||||
// Load config
|
||||
core::configManager.acquire();
|
||||
winWidth = core::configManager.conf["windowSize"]["w"];
|
||||
winHeight = core::configManager.conf["windowSize"]["h"];
|
||||
maximized = core::configManager.conf["maximized"];
|
||||
fullScreen = core::configManager.conf["fullscreen"];
|
||||
core::configManager.release();
|
||||
|
||||
// Setup window
|
||||
glfwSetErrorCallback(glfw_error_callback);
|
||||
if (!glfwInit()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
// GL 3.2 + GLSL 150
|
||||
const char* glsl_version = "#version 150";
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
|
||||
|
||||
// Create window with graphics context
|
||||
monitor = glfwGetPrimaryMonitor();
|
||||
window = glfwCreateWindow(winWidth, winHeight, "SDR++ v" VERSION_STR " (Built at " __TIME__ ", " __DATE__ ")", NULL, NULL);
|
||||
if (window == NULL)
|
||||
return 1;
|
||||
glfwMakeContextCurrent(window);
|
||||
#else
|
||||
const char* glsl_version = "#version 120";
|
||||
monitor = NULL;
|
||||
for (int i = 0; i < OPENGL_VERSION_COUNT; i++) {
|
||||
glsl_version = OPENGL_VERSIONS_GLSL[i];
|
||||
glfwWindowHint(GLFW_CLIENT_API, OPENGL_VERSIONS_IS_ES[i] ? GLFW_OPENGL_ES_API : GLFW_OPENGL_API);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, OPENGL_VERSIONS_MAJOR[i]);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, OPENGL_VERSIONS_MINOR[i]);
|
||||
|
||||
// Create window with graphics context
|
||||
monitor = glfwGetPrimaryMonitor();
|
||||
window = glfwCreateWindow(winWidth, winHeight, "SDR++ v" VERSION_STR " (Built at " __TIME__ ", " __DATE__ ")", NULL, NULL);
|
||||
if (window == NULL) {
|
||||
flog::info("OpenGL {0}.{1} {2}was not supported", OPENGL_VERSIONS_MAJOR[i], OPENGL_VERSIONS_MINOR[i], OPENGL_VERSIONS_IS_ES[i] ? "ES " : "");
|
||||
continue;
|
||||
}
|
||||
flog::info("Using OpenGL {0}.{1}{2}", OPENGL_VERSIONS_MAJOR[i], OPENGL_VERSIONS_MINOR[i], OPENGL_VERSIONS_IS_ES[i] ? " ES" : "");
|
||||
glfwMakeContextCurrent(window);
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Load app icon
|
||||
if (!std::filesystem::is_regular_file(resDir + "/icons/sdrpp.png")) {
|
||||
flog::error("Icon file '{0}' doesn't exist!", resDir + "/icons/sdrpp.png");
|
||||
return 1;
|
||||
}
|
||||
|
||||
GLFWimage icons[10];
|
||||
icons[0].pixels = stbi_load(((std::string)(resDir + "/icons/sdrpp.png")).c_str(), &icons[0].width, &icons[0].height, 0, 4);
|
||||
icons[1].pixels = (unsigned char*)malloc(16 * 16 * 4);
|
||||
icons[1].width = icons[1].height = 16;
|
||||
icons[2].pixels = (unsigned char*)malloc(24 * 24 * 4);
|
||||
icons[2].width = icons[2].height = 24;
|
||||
icons[3].pixels = (unsigned char*)malloc(32 * 32 * 4);
|
||||
icons[3].width = icons[3].height = 32;
|
||||
icons[4].pixels = (unsigned char*)malloc(48 * 48 * 4);
|
||||
icons[4].width = icons[4].height = 48;
|
||||
icons[5].pixels = (unsigned char*)malloc(64 * 64 * 4);
|
||||
icons[5].width = icons[5].height = 64;
|
||||
icons[6].pixels = (unsigned char*)malloc(96 * 96 * 4);
|
||||
icons[6].width = icons[6].height = 96;
|
||||
icons[7].pixels = (unsigned char*)malloc(128 * 128 * 4);
|
||||
icons[7].width = icons[7].height = 128;
|
||||
icons[8].pixels = (unsigned char*)malloc(196 * 196 * 4);
|
||||
icons[8].width = icons[8].height = 196;
|
||||
icons[9].pixels = (unsigned char*)malloc(256 * 256 * 4);
|
||||
icons[9].width = icons[9].height = 256;
|
||||
stbir_resize_uint8(icons[0].pixels, icons[0].width, icons[0].height, icons[0].width * 4, icons[1].pixels, 16, 16, 16 * 4, 4);
|
||||
stbir_resize_uint8(icons[0].pixels, icons[0].width, icons[0].height, icons[0].width * 4, icons[2].pixels, 24, 24, 24 * 4, 4);
|
||||
stbir_resize_uint8(icons[0].pixels, icons[0].width, icons[0].height, icons[0].width * 4, icons[3].pixels, 32, 32, 32 * 4, 4);
|
||||
stbir_resize_uint8(icons[0].pixels, icons[0].width, icons[0].height, icons[0].width * 4, icons[4].pixels, 48, 48, 48 * 4, 4);
|
||||
stbir_resize_uint8(icons[0].pixels, icons[0].width, icons[0].height, icons[0].width * 4, icons[5].pixels, 64, 64, 64 * 4, 4);
|
||||
stbir_resize_uint8(icons[0].pixels, icons[0].width, icons[0].height, icons[0].width * 4, icons[6].pixels, 96, 96, 96 * 4, 4);
|
||||
stbir_resize_uint8(icons[0].pixels, icons[0].width, icons[0].height, icons[0].width * 4, icons[7].pixels, 128, 128, 128 * 4, 4);
|
||||
stbir_resize_uint8(icons[0].pixels, icons[0].width, icons[0].height, icons[0].width * 4, icons[8].pixels, 196, 196, 196 * 4, 4);
|
||||
stbir_resize_uint8(icons[0].pixels, icons[0].width, icons[0].height, icons[0].width * 4, icons[9].pixels, 256, 256, 256 * 4, 4);
|
||||
glfwSetWindowIcon(window, 10, icons);
|
||||
stbi_image_free(icons[0].pixels);
|
||||
for (int i = 1; i < 10; i++) {
|
||||
free(icons[i].pixels);
|
||||
}
|
||||
|
||||
// Add callback for max/min if GLFW supports it
|
||||
#if (GLFW_VERSION_MAJOR == 3) && (GLFW_VERSION_MINOR >= 3)
|
||||
if (maximized) {
|
||||
glfwMaximizeWindow(window);
|
||||
}
|
||||
|
||||
glfwSetWindowMaximizeCallback(window, maximized_callback);
|
||||
#endif
|
||||
|
||||
// Setup Dear ImGui context
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
(void)io;
|
||||
io.IniFilename = NULL;
|
||||
|
||||
// Setup Platform/Renderer bindings
|
||||
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
||||
|
||||
if (!ImGui_ImplOpenGL3_Init(glsl_version)) {
|
||||
// If init fail, try to fall back on GLSL 1.2
|
||||
flog::warn("Could not init using OpenGL with normal GLSL version, falling back to GLSL 1.2");
|
||||
if (!ImGui_ImplOpenGL3_Init("#version 120")) {
|
||||
flog::error("Failed to initialize OpenGL with GLSL 1.2");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Set window size and fullscreen state
|
||||
glfwGetWindowSize(window, &_winWidth, &_winHeight);
|
||||
if (fullScreen) {
|
||||
flog::info("Fullscreen: ON");
|
||||
fsWidth = _winWidth;
|
||||
fsHeight = _winHeight;
|
||||
glfwGetWindowPos(window, &fsPosX, &fsPosY);
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, 0);
|
||||
}
|
||||
|
||||
// Everything went according to plan
|
||||
return 0;
|
||||
}
|
||||
|
||||
void beginFrame() {
|
||||
// Start the Dear ImGui frame
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
void render(bool vsync) {
|
||||
// Rendering
|
||||
ImGui::Render();
|
||||
int display_w, display_h;
|
||||
glfwGetFramebufferSize(window, &display_w, &display_h);
|
||||
glViewport(0, 0, display_w, display_h);
|
||||
glClearColor(gui::themeManager.clearColor.x, gui::themeManager.clearColor.y, gui::themeManager.clearColor.z, gui::themeManager.clearColor.w);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
glfwSwapInterval(vsync);
|
||||
glfwSwapBuffers(window);
|
||||
}
|
||||
|
||||
void getMouseScreenPos(double& x, double& y) {
|
||||
glfwGetCursorPos(window, &x, &y);
|
||||
}
|
||||
|
||||
void setMouseScreenPos(double x, double y) {
|
||||
// Tell GLFW to move the cursor and then manually fire the event
|
||||
glfwSetCursorPos(window, x, y);
|
||||
ImGui_ImplGlfw_CursorPosCallback(window, x, y);
|
||||
}
|
||||
|
||||
int renderLoop() {
|
||||
// Main loop
|
||||
while (!glfwWindowShouldClose(window)) {
|
||||
glfwPollEvents();
|
||||
|
||||
beginFrame();
|
||||
|
||||
if (_maximized != maximized) {
|
||||
_maximized = maximized;
|
||||
core::configManager.acquire();
|
||||
core::configManager.conf["maximized"] = _maximized;
|
||||
if (!maximized) {
|
||||
glfwSetWindowSize(window, core::configManager.conf["windowSize"]["w"], core::configManager.conf["windowSize"]["h"]);
|
||||
}
|
||||
core::configManager.release(true);
|
||||
}
|
||||
|
||||
glfwGetWindowSize(window, &_winWidth, &_winHeight);
|
||||
|
||||
if (ImGui::IsKeyPressed(GLFW_KEY_F11)) {
|
||||
fullScreen = !fullScreen;
|
||||
if (fullScreen) {
|
||||
flog::info("Fullscreen: ON");
|
||||
fsWidth = _winWidth;
|
||||
fsHeight = _winHeight;
|
||||
glfwGetWindowPos(window, &fsPosX, &fsPosY);
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, 0);
|
||||
core::configManager.acquire();
|
||||
core::configManager.conf["fullscreen"] = true;
|
||||
core::configManager.release();
|
||||
}
|
||||
else {
|
||||
flog::info("Fullscreen: OFF");
|
||||
glfwSetWindowMonitor(window, nullptr, fsPosX, fsPosY, fsWidth, fsHeight, 0);
|
||||
core::configManager.acquire();
|
||||
core::configManager.conf["fullscreen"] = false;
|
||||
core::configManager.release();
|
||||
}
|
||||
}
|
||||
|
||||
if ((_winWidth != winWidth || _winHeight != winHeight) && !maximized && _winWidth > 0 && _winHeight > 0) {
|
||||
winWidth = _winWidth;
|
||||
winHeight = _winHeight;
|
||||
core::configManager.acquire();
|
||||
core::configManager.conf["windowSize"]["w"] = winWidth;
|
||||
core::configManager.conf["windowSize"]["h"] = winHeight;
|
||||
core::configManager.release(true);
|
||||
}
|
||||
|
||||
if (winWidth > 0 && winHeight > 0) {
|
||||
ImGui::SetNextWindowPos(ImVec2(0, 0));
|
||||
ImGui::SetNextWindowSize(ImVec2(_winWidth, _winHeight));
|
||||
gui::mainWindow.draw();
|
||||
}
|
||||
|
||||
render();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int end() {
|
||||
// Cleanup
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
|
||||
return 0; // TODO: Int really needed?
|
||||
}
|
||||
}
|
|
@ -0,0 +1,643 @@
|
|||
// dear imgui: Platform Backend for GLFW
|
||||
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
|
||||
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||
// (Requires: GLFW 3.1+)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2022-02-07: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing callbacks after iniitializing backend.
|
||||
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago)with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
|
||||
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
|
||||
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
|
||||
// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates.
|
||||
// 2022-01-12: *BREAKING CHANGE*: Now using glfwSetCursorPosCallback(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetCursorPosCallback() and forward it to the backend via ImGui_ImplGlfw_CursorPosCallback().
|
||||
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
|
||||
// 2022-01-05: Inputs: Converting GLFW untranslated keycodes back to translated keycodes (in the ImGui_ImplGlfw_KeyCallback() function) in order to match the behavior of every other backend, and facilitate the use of GLFW with lettered-shortcuts API.
|
||||
// 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback().
|
||||
// 2021-07-29: *BREAKING CHANGE*: Now using glfwSetCursorEnterCallback(). MousePos is correctly reported when the host platform window is hovered but not focused. If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() callback and forward it to the backend via ImGui_ImplGlfw_CursorEnterCallback().
|
||||
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||
// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
|
||||
// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
|
||||
// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
|
||||
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||
// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
|
||||
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
|
||||
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||
// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
|
||||
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
|
||||
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
|
||||
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||
// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
|
||||
// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
|
||||
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
|
||||
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
|
||||
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_glfw.h"
|
||||
|
||||
// Clang warnings with -Weverything
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#if __has_warning("-Wzero-as-null-pointer-constant")
|
||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// GLFW
|
||||
#include <GLFW/glfw3.h>
|
||||
#ifdef _WIN32
|
||||
#undef APIENTRY
|
||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||
#include <GLFW/glfw3native.h> // for glfwGetWin32Window
|
||||
#endif
|
||||
#ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
|
||||
#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
|
||||
#else
|
||||
#define GLFW_HAS_NEW_CURSORS (0)
|
||||
#endif
|
||||
#define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetGamepadState() new api
|
||||
#define GLFW_HAS_GET_KEY_NAME (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwGetKeyName()
|
||||
|
||||
// GLFW data
|
||||
enum GlfwClientApi
|
||||
{
|
||||
GlfwClientApi_Unknown,
|
||||
GlfwClientApi_OpenGL,
|
||||
GlfwClientApi_Vulkan
|
||||
};
|
||||
|
||||
struct ImGui_ImplGlfw_Data
|
||||
{
|
||||
GLFWwindow* Window;
|
||||
GlfwClientApi ClientApi;
|
||||
double Time;
|
||||
GLFWwindow* MouseWindow;
|
||||
GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT];
|
||||
ImVec2 LastValidMousePos;
|
||||
bool InstalledCallbacks;
|
||||
|
||||
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||
GLFWwindowfocusfun PrevUserCallbackWindowFocus;
|
||||
GLFWcursorposfun PrevUserCallbackCursorPos;
|
||||
GLFWcursorenterfun PrevUserCallbackCursorEnter;
|
||||
GLFWmousebuttonfun PrevUserCallbackMousebutton;
|
||||
GLFWscrollfun PrevUserCallbackScroll;
|
||||
GLFWkeyfun PrevUserCallbackKey;
|
||||
GLFWcharfun PrevUserCallbackChar;
|
||||
GLFWmonitorfun PrevUserCallbackMonitor;
|
||||
|
||||
ImGui_ImplGlfw_Data() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
|
||||
// - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks
|
||||
// (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks.
|
||||
// - Otherwise we may need to store a GLFWWindow* -> ImGuiContext* map and handle this in the backend, adding a little bit of extra complexity to it.
|
||||
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
|
||||
static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
|
||||
}
|
||||
|
||||
// Functions
|
||||
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
|
||||
{
|
||||
return glfwGetClipboardString((GLFWwindow*)user_data);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||
{
|
||||
glfwSetClipboardString((GLFWwindow*)user_data, text);
|
||||
}
|
||||
|
||||
static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case GLFW_KEY_TAB: return ImGuiKey_Tab;
|
||||
case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow;
|
||||
case GLFW_KEY_RIGHT: return ImGuiKey_RightArrow;
|
||||
case GLFW_KEY_UP: return ImGuiKey_UpArrow;
|
||||
case GLFW_KEY_DOWN: return ImGuiKey_DownArrow;
|
||||
case GLFW_KEY_PAGE_UP: return ImGuiKey_PageUp;
|
||||
case GLFW_KEY_PAGE_DOWN: return ImGuiKey_PageDown;
|
||||
case GLFW_KEY_HOME: return ImGuiKey_Home;
|
||||
case GLFW_KEY_END: return ImGuiKey_End;
|
||||
case GLFW_KEY_INSERT: return ImGuiKey_Insert;
|
||||
case GLFW_KEY_DELETE: return ImGuiKey_Delete;
|
||||
case GLFW_KEY_BACKSPACE: return ImGuiKey_Backspace;
|
||||
case GLFW_KEY_SPACE: return ImGuiKey_Space;
|
||||
case GLFW_KEY_ENTER: return ImGuiKey_Enter;
|
||||
case GLFW_KEY_ESCAPE: return ImGuiKey_Escape;
|
||||
case GLFW_KEY_APOSTROPHE: return ImGuiKey_Apostrophe;
|
||||
case GLFW_KEY_COMMA: return ImGuiKey_Comma;
|
||||
case GLFW_KEY_MINUS: return ImGuiKey_Minus;
|
||||
case GLFW_KEY_PERIOD: return ImGuiKey_Period;
|
||||
case GLFW_KEY_SLASH: return ImGuiKey_Slash;
|
||||
case GLFW_KEY_SEMICOLON: return ImGuiKey_Semicolon;
|
||||
case GLFW_KEY_EQUAL: return ImGuiKey_Equal;
|
||||
case GLFW_KEY_LEFT_BRACKET: return ImGuiKey_LeftBracket;
|
||||
case GLFW_KEY_BACKSLASH: return ImGuiKey_Backslash;
|
||||
case GLFW_KEY_RIGHT_BRACKET: return ImGuiKey_RightBracket;
|
||||
case GLFW_KEY_GRAVE_ACCENT: return ImGuiKey_GraveAccent;
|
||||
case GLFW_KEY_CAPS_LOCK: return ImGuiKey_CapsLock;
|
||||
case GLFW_KEY_SCROLL_LOCK: return ImGuiKey_ScrollLock;
|
||||
case GLFW_KEY_NUM_LOCK: return ImGuiKey_NumLock;
|
||||
case GLFW_KEY_PRINT_SCREEN: return ImGuiKey_PrintScreen;
|
||||
case GLFW_KEY_PAUSE: return ImGuiKey_Pause;
|
||||
case GLFW_KEY_KP_0: return ImGuiKey_Keypad0;
|
||||
case GLFW_KEY_KP_1: return ImGuiKey_Keypad1;
|
||||
case GLFW_KEY_KP_2: return ImGuiKey_Keypad2;
|
||||
case GLFW_KEY_KP_3: return ImGuiKey_Keypad3;
|
||||
case GLFW_KEY_KP_4: return ImGuiKey_Keypad4;
|
||||
case GLFW_KEY_KP_5: return ImGuiKey_Keypad5;
|
||||
case GLFW_KEY_KP_6: return ImGuiKey_Keypad6;
|
||||
case GLFW_KEY_KP_7: return ImGuiKey_Keypad7;
|
||||
case GLFW_KEY_KP_8: return ImGuiKey_Keypad8;
|
||||
case GLFW_KEY_KP_9: return ImGuiKey_Keypad9;
|
||||
case GLFW_KEY_KP_DECIMAL: return ImGuiKey_KeypadDecimal;
|
||||
case GLFW_KEY_KP_DIVIDE: return ImGuiKey_KeypadDivide;
|
||||
case GLFW_KEY_KP_MULTIPLY: return ImGuiKey_KeypadMultiply;
|
||||
case GLFW_KEY_KP_SUBTRACT: return ImGuiKey_KeypadSubtract;
|
||||
case GLFW_KEY_KP_ADD: return ImGuiKey_KeypadAdd;
|
||||
case GLFW_KEY_KP_ENTER: return ImGuiKey_KeypadEnter;
|
||||
case GLFW_KEY_KP_EQUAL: return ImGuiKey_KeypadEqual;
|
||||
case GLFW_KEY_LEFT_SHIFT: return ImGuiKey_LeftShift;
|
||||
case GLFW_KEY_LEFT_CONTROL: return ImGuiKey_LeftCtrl;
|
||||
case GLFW_KEY_LEFT_ALT: return ImGuiKey_LeftAlt;
|
||||
case GLFW_KEY_LEFT_SUPER: return ImGuiKey_LeftSuper;
|
||||
case GLFW_KEY_RIGHT_SHIFT: return ImGuiKey_RightShift;
|
||||
case GLFW_KEY_RIGHT_CONTROL: return ImGuiKey_RightCtrl;
|
||||
case GLFW_KEY_RIGHT_ALT: return ImGuiKey_RightAlt;
|
||||
case GLFW_KEY_RIGHT_SUPER: return ImGuiKey_RightSuper;
|
||||
case GLFW_KEY_MENU: return ImGuiKey_Menu;
|
||||
case GLFW_KEY_0: return ImGuiKey_0;
|
||||
case GLFW_KEY_1: return ImGuiKey_1;
|
||||
case GLFW_KEY_2: return ImGuiKey_2;
|
||||
case GLFW_KEY_3: return ImGuiKey_3;
|
||||
case GLFW_KEY_4: return ImGuiKey_4;
|
||||
case GLFW_KEY_5: return ImGuiKey_5;
|
||||
case GLFW_KEY_6: return ImGuiKey_6;
|
||||
case GLFW_KEY_7: return ImGuiKey_7;
|
||||
case GLFW_KEY_8: return ImGuiKey_8;
|
||||
case GLFW_KEY_9: return ImGuiKey_9;
|
||||
case GLFW_KEY_A: return ImGuiKey_A;
|
||||
case GLFW_KEY_B: return ImGuiKey_B;
|
||||
case GLFW_KEY_C: return ImGuiKey_C;
|
||||
case GLFW_KEY_D: return ImGuiKey_D;
|
||||
case GLFW_KEY_E: return ImGuiKey_E;
|
||||
case GLFW_KEY_F: return ImGuiKey_F;
|
||||
case GLFW_KEY_G: return ImGuiKey_G;
|
||||
case GLFW_KEY_H: return ImGuiKey_H;
|
||||
case GLFW_KEY_I: return ImGuiKey_I;
|
||||
case GLFW_KEY_J: return ImGuiKey_J;
|
||||
case GLFW_KEY_K: return ImGuiKey_K;
|
||||
case GLFW_KEY_L: return ImGuiKey_L;
|
||||
case GLFW_KEY_M: return ImGuiKey_M;
|
||||
case GLFW_KEY_N: return ImGuiKey_N;
|
||||
case GLFW_KEY_O: return ImGuiKey_O;
|
||||
case GLFW_KEY_P: return ImGuiKey_P;
|
||||
case GLFW_KEY_Q: return ImGuiKey_Q;
|
||||
case GLFW_KEY_R: return ImGuiKey_R;
|
||||
case GLFW_KEY_S: return ImGuiKey_S;
|
||||
case GLFW_KEY_T: return ImGuiKey_T;
|
||||
case GLFW_KEY_U: return ImGuiKey_U;
|
||||
case GLFW_KEY_V: return ImGuiKey_V;
|
||||
case GLFW_KEY_W: return ImGuiKey_W;
|
||||
case GLFW_KEY_X: return ImGuiKey_X;
|
||||
case GLFW_KEY_Y: return ImGuiKey_Y;
|
||||
case GLFW_KEY_Z: return ImGuiKey_Z;
|
||||
case GLFW_KEY_F1: return ImGuiKey_F1;
|
||||
case GLFW_KEY_F2: return ImGuiKey_F2;
|
||||
case GLFW_KEY_F3: return ImGuiKey_F3;
|
||||
case GLFW_KEY_F4: return ImGuiKey_F4;
|
||||
case GLFW_KEY_F5: return ImGuiKey_F5;
|
||||
case GLFW_KEY_F6: return ImGuiKey_F6;
|
||||
case GLFW_KEY_F7: return ImGuiKey_F7;
|
||||
case GLFW_KEY_F8: return ImGuiKey_F8;
|
||||
case GLFW_KEY_F9: return ImGuiKey_F9;
|
||||
case GLFW_KEY_F10: return ImGuiKey_F10;
|
||||
case GLFW_KEY_F11: return ImGuiKey_F11;
|
||||
case GLFW_KEY_F12: return ImGuiKey_F12;
|
||||
default: return ImGuiKey_None;
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateKeyModifiers(int mods)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddKeyEvent(ImGuiKey_ModCtrl, (mods & GLFW_MOD_CONTROL) != 0);
|
||||
io.AddKeyEvent(ImGuiKey_ModShift, (mods & GLFW_MOD_SHIFT) != 0);
|
||||
io.AddKeyEvent(ImGuiKey_ModAlt, (mods & GLFW_MOD_ALT) != 0);
|
||||
io.AddKeyEvent(ImGuiKey_ModSuper, (mods & GLFW_MOD_SUPER) != 0);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackMousebutton != NULL && window == bd->Window)
|
||||
bd->PrevUserCallbackMousebutton(window, button, action, mods);
|
||||
|
||||
ImGui_ImplGlfw_UpdateKeyModifiers(mods);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (button >= 0 && button < ImGuiMouseButton_COUNT)
|
||||
io.AddMouseButtonEvent(button, action == GLFW_PRESS);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackScroll != NULL && window == bd->Window)
|
||||
bd->PrevUserCallbackScroll(window, xoffset, yoffset);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddMouseWheelEvent((float)xoffset, (float)yoffset);
|
||||
}
|
||||
|
||||
static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
|
||||
{
|
||||
#if GLFW_HAS_GET_KEY_NAME && !defined(__EMSCRIPTEN__)
|
||||
// GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult.
|
||||
// (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently)
|
||||
// See https://github.com/glfw/glfw/issues/1502 for details.
|
||||
// Adding a workaround to undo this (so our keys are translated->untranslated->translated, likely a lossy process).
|
||||
// This won't cover edge cases but this is at least going to cover common cases.
|
||||
if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_EQUAL)
|
||||
return key;
|
||||
const char* key_name = glfwGetKeyName(key, scancode);
|
||||
if (key_name && key_name[0] != 0 && key_name[1] == 0)
|
||||
{
|
||||
const char char_names[] = "`-=[]\\,;\'./";
|
||||
const int char_keys[] = { GLFW_KEY_GRAVE_ACCENT, GLFW_KEY_MINUS, GLFW_KEY_EQUAL, GLFW_KEY_LEFT_BRACKET, GLFW_KEY_RIGHT_BRACKET, GLFW_KEY_BACKSLASH, GLFW_KEY_COMMA, GLFW_KEY_SEMICOLON, GLFW_KEY_APOSTROPHE, GLFW_KEY_PERIOD, GLFW_KEY_SLASH, 0 };
|
||||
IM_ASSERT(IM_ARRAYSIZE(char_names) == IM_ARRAYSIZE(char_keys));
|
||||
if (key_name[0] >= '0' && key_name[0] <= '9') { key = GLFW_KEY_0 + (key_name[0] - '0'); }
|
||||
else if (key_name[0] >= 'A' && key_name[0] <= 'Z') { key = GLFW_KEY_A + (key_name[0] - 'A'); }
|
||||
else if (const char* p = strchr(char_names, key_name[0])) { key = char_keys[p - char_names]; }
|
||||
}
|
||||
// if (action == GLFW_PRESS) printf("key %d scancode %d name '%s'\n", key, scancode, key_name);
|
||||
#else
|
||||
IM_UNUSED(scancode);
|
||||
#endif
|
||||
return key;
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackKey != NULL && window == bd->Window)
|
||||
bd->PrevUserCallbackKey(window, keycode, scancode, action, mods);
|
||||
|
||||
if (action != GLFW_PRESS && action != GLFW_RELEASE)
|
||||
return;
|
||||
|
||||
ImGui_ImplGlfw_UpdateKeyModifiers(mods);
|
||||
|
||||
keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode);
|
||||
io.AddKeyEvent(imgui_key, (action == GLFW_PRESS));
|
||||
io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code)
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackWindowFocus != NULL && window == bd->Window)
|
||||
bd->PrevUserCallbackWindowFocus(window, focused);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddFocusEvent(focused != 0);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackCursorPos != NULL && window == bd->Window)
|
||||
bd->PrevUserCallbackCursorPos(window, x, y);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddMousePosEvent((float)x, (float)y);
|
||||
bd->LastValidMousePos = ImVec2((float)x, (float)y);
|
||||
}
|
||||
|
||||
// Workaround: X11 seems to send spurious Leave/Enter events which would make us lose our position,
|
||||
// so we back it up and restore on Leave/Enter (see https://github.com/ocornut/imgui/issues/4984)
|
||||
void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackCursorEnter != NULL && window == bd->Window)
|
||||
bd->PrevUserCallbackCursorEnter(window, entered);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (entered)
|
||||
{
|
||||
bd->MouseWindow = window;
|
||||
io.AddMousePosEvent(bd->LastValidMousePos.x, bd->LastValidMousePos.y);
|
||||
}
|
||||
else if (!entered && bd->MouseWindow == window)
|
||||
{
|
||||
bd->LastValidMousePos = io.MousePos;
|
||||
bd->MouseWindow = NULL;
|
||||
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackChar != NULL && window == bd->Window)
|
||||
bd->PrevUserCallbackChar(window, c);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddInputCharacter(c);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
|
||||
{
|
||||
// Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too.
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
IM_ASSERT(bd->InstalledCallbacks == false && "Callbacks already installed!");
|
||||
IM_ASSERT(bd->Window == window);
|
||||
|
||||
bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback);
|
||||
bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback);
|
||||
bd->PrevUserCallbackCursorPos = glfwSetCursorPosCallback(window, ImGui_ImplGlfw_CursorPosCallback);
|
||||
bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
|
||||
bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
|
||||
bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
|
||||
bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
|
||||
bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
|
||||
bd->InstalledCallbacks = true;
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
IM_ASSERT(bd->InstalledCallbacks == true && "Callbacks not installed!");
|
||||
IM_ASSERT(bd->Window == window);
|
||||
|
||||
glfwSetWindowFocusCallback(window, bd->PrevUserCallbackWindowFocus);
|
||||
glfwSetCursorEnterCallback(window, bd->PrevUserCallbackCursorEnter);
|
||||
glfwSetCursorPosCallback(window, bd->PrevUserCallbackCursorPos);
|
||||
glfwSetMouseButtonCallback(window, bd->PrevUserCallbackMousebutton);
|
||||
glfwSetScrollCallback(window, bd->PrevUserCallbackScroll);
|
||||
glfwSetKeyCallback(window, bd->PrevUserCallbackKey);
|
||||
glfwSetCharCallback(window, bd->PrevUserCallbackChar);
|
||||
glfwSetMonitorCallback(bd->PrevUserCallbackMonitor);
|
||||
bd->InstalledCallbacks = false;
|
||||
bd->PrevUserCallbackWindowFocus = NULL;
|
||||
bd->PrevUserCallbackCursorEnter = NULL;
|
||||
bd->PrevUserCallbackCursorPos = NULL;
|
||||
bd->PrevUserCallbackMousebutton = NULL;
|
||||
bd->PrevUserCallbackScroll = NULL;
|
||||
bd->PrevUserCallbackKey = NULL;
|
||||
bd->PrevUserCallbackChar = NULL;
|
||||
bd->PrevUserCallbackMonitor = NULL;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)();
|
||||
io.BackendPlatformUserData = (void*)bd;
|
||||
io.BackendPlatformName = "imgui_impl_glfw";
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
|
||||
bd->Window = window;
|
||||
bd->Time = 0.0;
|
||||
|
||||
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
|
||||
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
|
||||
io.ClipboardUserData = bd->Window;
|
||||
|
||||
// Set platform dependent data in viewport
|
||||
#if defined(_WIN32)
|
||||
ImGui::GetMainViewport()->PlatformHandleRaw = (void*)glfwGetWin32Window(bd->Window);
|
||||
#endif
|
||||
|
||||
// Create mouse cursors
|
||||
// (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
|
||||
// GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
|
||||
// Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
|
||||
GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
|
||||
bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
|
||||
#if GLFW_HAS_NEW_CURSORS
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
|
||||
#else
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
#endif
|
||||
glfwSetErrorCallback(prev_error_callback);
|
||||
|
||||
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||
if (install_callbacks)
|
||||
ImGui_ImplGlfw_InstallCallbacks(window);
|
||||
|
||||
bd->ClientApi = client_api;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
|
||||
{
|
||||
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
|
||||
}
|
||||
|
||||
bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
|
||||
{
|
||||
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
|
||||
}
|
||||
|
||||
bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
|
||||
{
|
||||
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_Shutdown()
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
if (bd->InstalledCallbacks)
|
||||
ImGui_ImplGlfw_RestoreCallbacks(bd->Window);
|
||||
|
||||
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||
glfwDestroyCursor(bd->MouseCursors[cursor_n]);
|
||||
|
||||
io.BackendPlatformName = NULL;
|
||||
io.BackendPlatformUserData = NULL;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateMouseData()
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
const bool is_app_focused = true;
|
||||
#else
|
||||
const bool is_app_focused = glfwGetWindowAttrib(bd->Window, GLFW_FOCUSED) != 0;
|
||||
#endif
|
||||
if (is_app_focused)
|
||||
{
|
||||
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
||||
if (io.WantSetMousePos)
|
||||
glfwSetCursorPos(bd->Window, (double)io.MousePos.x, (double)io.MousePos.y);
|
||||
|
||||
// (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured)
|
||||
if (is_app_focused && bd->MouseWindow == NULL)
|
||||
{
|
||||
double mouse_x, mouse_y;
|
||||
glfwGetCursorPos(bd->Window, &mouse_x, &mouse_y);
|
||||
io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
|
||||
bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateMouseCursor()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
|
||||
return;
|
||||
|
||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
|
||||
{
|
||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||
glfwSetInputMode(bd->Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show OS mouse cursor
|
||||
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
|
||||
glfwSetCursor(bd->Window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
|
||||
glfwSetInputMode(bd->Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
// Update gamepad inputs
|
||||
static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; }
|
||||
static void ImGui_ImplGlfw_UpdateGamepads()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
||||
return;
|
||||
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||
#if GLFW_HAS_GAMEPAD_API
|
||||
GLFWgamepadstate gamepad;
|
||||
if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &gamepad))
|
||||
return;
|
||||
#define MAP_BUTTON(KEY_NO, BUTTON_NO, _UNUSED) do { io.AddKeyEvent(KEY_NO, gamepad.buttons[BUTTON_NO] != 0); } while (0)
|
||||
#define MAP_ANALOG(KEY_NO, AXIS_NO, _UNUSED, V0, V1) do { float v = gamepad.axes[AXIS_NO]; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
|
||||
#else
|
||||
int axes_count = 0, buttons_count = 0;
|
||||
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
|
||||
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
|
||||
if (axes_count == 0 || buttons_count == 0)
|
||||
return;
|
||||
#define MAP_BUTTON(KEY_NO, _UNUSED, BUTTON_NO) do { io.AddKeyEvent(KEY_NO, (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS)); } while (0)
|
||||
#define MAP_ANALOG(KEY_NO, _UNUSED, AXIS_NO, V0, V1) do { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
|
||||
#endif
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||
MAP_BUTTON(ImGuiKey_GamepadStart, GLFW_GAMEPAD_BUTTON_START, 7);
|
||||
MAP_BUTTON(ImGuiKey_GamepadBack, GLFW_GAMEPAD_BUTTON_BACK, 6);
|
||||
MAP_BUTTON(ImGuiKey_GamepadFaceDown, GLFW_GAMEPAD_BUTTON_A, 0); // Xbox A, PS Cross
|
||||
MAP_BUTTON(ImGuiKey_GamepadFaceRight, GLFW_GAMEPAD_BUTTON_B, 1); // Xbox B, PS Circle
|
||||
MAP_BUTTON(ImGuiKey_GamepadFaceLeft, GLFW_GAMEPAD_BUTTON_X, 2); // Xbox X, PS Square
|
||||
MAP_BUTTON(ImGuiKey_GamepadFaceUp, GLFW_GAMEPAD_BUTTON_Y, 3); // Xbox Y, PS Triangle
|
||||
MAP_BUTTON(ImGuiKey_GamepadDpadLeft, GLFW_GAMEPAD_BUTTON_DPAD_LEFT, 13);
|
||||
MAP_BUTTON(ImGuiKey_GamepadDpadRight, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, 11);
|
||||
MAP_BUTTON(ImGuiKey_GamepadDpadUp, GLFW_GAMEPAD_BUTTON_DPAD_UP, 10);
|
||||
MAP_BUTTON(ImGuiKey_GamepadDpadDown, GLFW_GAMEPAD_BUTTON_DPAD_DOWN, 12);
|
||||
MAP_BUTTON(ImGuiKey_GamepadL1, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, 4);
|
||||
MAP_BUTTON(ImGuiKey_GamepadR1, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, 5);
|
||||
MAP_ANALOG(ImGuiKey_GamepadL2, GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, 4, -0.75f, +1.0f);
|
||||
MAP_ANALOG(ImGuiKey_GamepadR2, GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, 5, -0.75f, +1.0f);
|
||||
MAP_BUTTON(ImGuiKey_GamepadL3, GLFW_GAMEPAD_BUTTON_LEFT_THUMB, 8);
|
||||
MAP_BUTTON(ImGuiKey_GamepadR3, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, 9);
|
||||
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, GLFW_GAMEPAD_AXIS_LEFT_X, 0, -0.25f, -1.0f);
|
||||
MAP_ANALOG(ImGuiKey_GamepadLStickRight, GLFW_GAMEPAD_AXIS_LEFT_X, 0, +0.25f, +1.0f);
|
||||
MAP_ANALOG(ImGuiKey_GamepadLStickUp, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, -0.25f, -1.0f);
|
||||
MAP_ANALOG(ImGuiKey_GamepadLStickDown, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, +0.25f, +1.0f);
|
||||
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, -0.25f, -1.0f);
|
||||
MAP_ANALOG(ImGuiKey_GamepadRStickRight, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, +0.25f, +1.0f);
|
||||
MAP_ANALOG(ImGuiKey_GamepadRStickUp, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, -0.25f, -1.0f);
|
||||
MAP_ANALOG(ImGuiKey_GamepadRStickDown, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, +0.25f, +1.0f);
|
||||
#undef MAP_BUTTON
|
||||
#undef MAP_ANALOG
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_NewFrame()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplGlfw_InitForXXX()?");
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
int w, h;
|
||||
int display_w, display_h;
|
||||
glfwGetWindowSize(bd->Window, &w, &h);
|
||||
glfwGetFramebufferSize(bd->Window, &display_w, &display_h);
|
||||
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||
if (w > 0 && h > 0)
|
||||
io.DisplayFramebufferScale = ImVec2((float)display_w / (float)w, (float)display_h / (float)h);
|
||||
|
||||
// Setup time step
|
||||
double current_time = glfwGetTime();
|
||||
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
|
||||
bd->Time = current_time;
|
||||
|
||||
ImGui_ImplGlfw_UpdateMouseData();
|
||||
ImGui_ImplGlfw_UpdateMouseCursor();
|
||||
|
||||
// Update game controllers (if enabled and available)
|
||||
ImGui_ImplGlfw_UpdateGamepads();
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
|
@ -4,11 +4,12 @@
|
|||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
|
||||
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
|
@ -20,6 +21,7 @@
|
|||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct GLFWwindow;
|
||||
struct GLFWmonitor;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
|
||||
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
|
||||
|
@ -27,10 +29,18 @@ IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool ins
|
|||
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
|
||||
|
||||
// GLFW callbacks
|
||||
// - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any.
|
||||
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks.
|
||||
// GLFW callbacks (installer)
|
||||
// - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-call user's previously installed callbacks, if any.
|
||||
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call individual function yourself from your own GLFW callbacks.
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window);
|
||||
|
||||
// GLFW callbacks (individual callbacks to call if you didn't install callbacks)
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event);
|
|
@ -0,0 +1,47 @@
|
|||
@echo on
|
||||
|
||||
if NOT EXIST C:\projects\tools (
|
||||
mkdir C:\projects\tools
|
||||
)
|
||||
cd C:\projects\tools
|
||||
|
||||
::###########################################################################
|
||||
:: Setup Compiler
|
||||
::###########################################################################
|
||||
if NOT EXIST llvm-installer.exe (
|
||||
appveyor DownloadFile http://prereleases.llvm.org/win-snapshots/LLVM-5.0.0-r306282-win32.exe -FileName llvm-installer.exe
|
||||
)
|
||||
|
||||
START /WAIT llvm-installer.exe /S /D=C:\"projects\tools\LLVM-install"
|
||||
@set PATH="C:\projects\tools\LLVM-install\bin";%PATH%
|
||||
clang-cl -v
|
||||
|
||||
if DEFINED MINGW_PATH rename "C:\Program Files\Git\usr\bin\sh.exe" "sh-ignored.exe"
|
||||
if DEFINED MINGW_PATH @set "PATH=%PATH:C:\Program Files (x86)\Git\bin=%"
|
||||
if DEFINED MINGW_PATH @set "PATH=%PATH%;%MINGW_PATH%"
|
||||
if DEFINED MINGW_PATH g++ -v
|
||||
|
||||
::###########################################################################
|
||||
:: Install a recent CMake
|
||||
::###########################################################################
|
||||
if NOT EXIST cmake (
|
||||
appveyor DownloadFile https://cmake.org/files/v3.7/cmake-3.7.2-win64-x64.zip -FileName cmake.zip
|
||||
7z x cmake.zip -oC:\projects\tools > nul
|
||||
move C:\projects\tools\cmake-* C:\projects\tools\cmake
|
||||
rm cmake.zip
|
||||
)
|
||||
@set PATH=C:\projects\tools\cmake\bin;%PATH%
|
||||
cmake --version
|
||||
|
||||
::###########################################################################
|
||||
:: Install Ninja
|
||||
::###########################################################################
|
||||
if NOT EXIST ninja (
|
||||
appveyor DownloadFile https://github.com/ninja-build/ninja/releases/download/v1.6.0/ninja-win.zip -FileName ninja.zip
|
||||
7z x ninja.zip -oC:\projects\tools\ninja > nul
|
||||
rm ninja.zip
|
||||
)
|
||||
@set PATH=C:\projects\tools\ninja;%PATH%
|
||||
ninja --version
|
||||
|
||||
@echo off
|
|
@ -0,0 +1 @@
|
|||
build
|
|
@ -0,0 +1,12 @@
|
|||
language: c
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
dist: trusty
|
||||
- os: osx
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake ..
|
||||
- make shim
|
||||
- make check CTEST_OUTPUT_ON_FAILURE=TRUE
|
|
@ -0,0 +1,108 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
project(Correct C)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckCSourceCompiles)
|
||||
include(CMakePushCheckState)
|
||||
include(CheckCCompilerFlag)
|
||||
|
||||
if(MSVC)
|
||||
set(LIBM "")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
|
||||
else(MSVC)
|
||||
set(LIBM "m")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -std=c99 -Wall")
|
||||
check_c_compiler_flag(-Wpedantic COMPILER_SUPPORTS_WPEDANTIC)
|
||||
if(COMPILER_SUPPORTS_WPEDANTIC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wpedantic")
|
||||
endif()
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
# On android, keep optimisations and don't use asan
|
||||
if (ANDROID)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g3 -O3")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,")
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g3 -O0 -fsanitize=address")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-no_pie,")
|
||||
endif()
|
||||
else()
|
||||
if("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
|
||||
endif()
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Profiling")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -g3")
|
||||
endif()
|
||||
endif()
|
||||
endif(MSVC)
|
||||
|
||||
find_library(FEC fec)
|
||||
CHECK_LIBRARY_EXISTS(FEC dotprod "" HAVE_LIBFEC)
|
||||
|
||||
if(NOT CMAKE_CROSSCOMPILING)
|
||||
# Check if host machine can compile with SSE 4.1 intrinsic
|
||||
cmake_push_check_state(RESET)
|
||||
set(CMAKE_REQUIRED_DEFINITIONS -march=native)
|
||||
check_c_source_compiles("
|
||||
#include <x86intrin.h>
|
||||
int main() {
|
||||
__m128i a;
|
||||
__m128i b;
|
||||
__m128i c = _mm_min_epu16(a, b);
|
||||
return 0;
|
||||
}" HAVE_SSE)
|
||||
cmake_pop_check_state()
|
||||
endif()
|
||||
|
||||
if(HAVE_SSE)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4.1")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
|
||||
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
|
||||
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
|
||||
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||
add_subdirectory(src)
|
||||
|
||||
set(INSTALL_HEADERS "${PROJECT_BINARY_DIR}/include/correct.h")
|
||||
|
||||
add_custom_target(correct-h ALL COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/correct.h ${PROJECT_BINARY_DIR}/include/correct.h)
|
||||
|
||||
if(HAVE_SSE)
|
||||
set(correct_obj_files $<TARGET_OBJECTS:correct-reed-solomon> $<TARGET_OBJECTS:correct-convolutional> $<TARGET_OBJECTS:correct-convolutional-sse>)
|
||||
set(INSTALL_HEADERS ${INSTALL_HEADERS} ${PROJECT_BINARY_DIR}/include/correct-sse.h)
|
||||
add_custom_target(correct-sse-h ALL COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/correct-sse.h ${PROJECT_BINARY_DIR}/include/correct-sse.h)
|
||||
else()
|
||||
set(correct_obj_files $<TARGET_OBJECTS:correct-reed-solomon> $<TARGET_OBJECTS:correct-convolutional>)
|
||||
endif()
|
||||
add_library(correct SHARED ${correct_obj_files})
|
||||
add_library(correct_static STATIC ${correct_obj_files})
|
||||
set_target_properties(correct_static PROPERTIES OUTPUT_NAME "correct")
|
||||
if(HAVE_SSE)
|
||||
target_compile_definitions(correct PUBLIC HAVE_SSE=1)
|
||||
target_compile_definitions(correct_static PUBLIC HAVE_SSE=1)
|
||||
endif()
|
||||
|
||||
add_subdirectory(util)
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(tools)
|
||||
# add_subdirectory(benchmarks)
|
||||
|
||||
# install(TARGETS correct correct_static
|
||||
# DESTINATION lib)
|
||||
# install(FILES ${INSTALL_HEADERS} DESTINATION "${CMAKE_INSTALL_PREFIX}/include")
|
||||
|
||||
add_library(fec_shim_static EXCLUDE_FROM_ALL src/fec_shim.c ${correct_obj_files})
|
||||
set_target_properties(fec_shim_static PROPERTIES OUTPUT_NAME "fec")
|
||||
add_library(fec_shim_shared SHARED EXCLUDE_FROM_ALL src/fec_shim.c ${correct_obj_files})
|
||||
set_target_properties(fec_shim_shared PROPERTIES OUTPUT_NAME "fec")
|
||||
add_custom_target(fec-shim-h COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/fec_shim.h ${PROJECT_BINARY_DIR}/include/fec.h)
|
||||
add_custom_target(shim DEPENDS fec_shim_static fec_shim_shared fec-shim-h)
|
||||
|
||||
# install(TARGETS fec_shim_static fec_shim_shared
|
||||
# DESTINATION lib
|
||||
# OPTIONAL)
|
||||
# install(FILES ${PROJECT_BINARY_DIR}/include/fec.h DESTINATION "${CMAKE_INSTALL_PREFIX}/include" OPTIONAL)
|
|
@ -0,0 +1,12 @@
|
|||
Copyright (c) 2016, Brian Armstrong
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,38 @@
|
|||
[libcorrect](https://github.com/quiet/libcorrect)
|
||||
===========
|
||||
[![OSX/Linux Build Status](https://travis-ci.org/quiet/libcorrect.svg?branch=master)](https://travis-ci.org/quiet/libcorrect)
|
||||
[![Windows Build status](https://ci.appveyor.com/api/projects/status/i3e84jmj00fa5my8/branch/master?svg=true)](https://ci.appveyor.com/project/brian-armstrong/libcorrect/branch/master)
|
||||
|
||||
libcorrect is a library for Forward Error Correction. By using libcorrect, you can encode extra redundancy into a packet of data and then send it across a lossy channel. When the packet is received, it can be decoded to recover the original, pre-encoded data.
|
||||
|
||||
libcorrect accomplishes this task with two algorithms, [Convolutional codes](https://en.wikipedia.org/wiki/Convolutional_code) and [Reed-Solomon](https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction). Convolutional codes are robust to a constant background noise, while Reed-Solomon error correction is effective at dealing with noise that occurs in bursts. These algorithms have played an important role in [telecommunications](https://en.wikipedia.org/wiki/Error_detection_and_correction#Deep-space_telecommunications). libcorrect uses a [Viterbi algorithm](https://en.wikipedia.org/wiki/Viterbi_algorithm) decoder to decode convolutional codes.
|
||||
|
||||
libcorrect is a performant, BSD-licensed library. It is also the author's hope that this library's contents could help others learn how its algorithms work.
|
||||
|
||||
Design goals
|
||||
-----------
|
||||
|
||||
1. libcorrect should be a drop-in, BSD-licensed substitute for [libfec](http://www.ka9q.net/code/fec/), which offers similar functionality under the LGPL-license. Although libfec is a fantastic library, the state of LGPL-licensed libraries on mobile devices is somewhat uncertain. For this reason, libcorrect is a completely new approach under the BSD license which supports the same algorithms as libfec. Additionally, libcorrect can be built with a compatibility layer so that libcorrect can be linked in place of libfec.
|
||||
|
||||
Achieving this goal gives [libquiet](https://github.com/quiet/quiet) a fully BSD-/MIT-licensed set of dependencies, which gives libquiet more flexibility in mobile applications.
|
||||
|
||||
2. libcorrect should make it easier to investigate how forward error correction works. To accomplish this, libcorrect provides tools to test the fitness of convolutional codes and their polynomials. Additionally, libcorrect should be written in a way that leads to easy understanding of these powerful algorithms. This library's roadmap includes more documentation on how these algorithms work and how to increase their computational performance.
|
||||
|
||||
3. libcorrect should explore further into error correction. This goal would help libquiet operate in noisier situations. One approach might be to use parts of libcorrect's Viterbi Algorithm decoder to create a [Turbo code](https://en.wikipedia.org/wiki/Turbo_code) decoder, although this is just an idea and may turn out to be prohibitively difficult.
|
||||
|
||||
Build
|
||||
-----------
|
||||
libcorrect uses CMake, which allows for out-of-source builds. To get started, make sure that you have CMake installed, and then, from libcorrect's source directory, run `mkdir build && cd build && cmake .. && make && make install`. Additionally, if you would like the libfec compatibility layer, you can run `make shim && make install`, though do be cautioned that this can overwrite an existing installation of libfec.
|
||||
|
||||
If you are on a host which has `<x86intrin.h>` available, then libcorrect will automatically build its SSE version as well. The SSE headers are provided under `<correct-sse.h>`. For now, it is on the caller of this code to ensure that SSE is available and can be used. libcorrect requires SSE functions up to and including SSE4.
|
||||
|
||||
If you have any questions or problems with libcorrect, do not hesitate to open an issue.
|
||||
|
||||
-----------
|
||||
I'd like to thank Ryan Hitchman and Josh Gao for all of their help and rubber ducking.
|
||||
|
||||
A huge thank you goes to [Lucas Teske](https://github.com/racerxdl) for finding all the ways that libcorrect was broken on Windows and to [Denis Golovan](https://github.com/MageSlayer) for finding an error in the returned length of the convolutional code decoder.
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
version: '{build}'
|
||||
|
||||
build:
|
||||
verbosity: detailed
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
COMPILER: cl.exe
|
||||
MSVC_BAT: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
|
||||
MSVC_BAT_ARCH: x86
|
||||
GENERATOR: "Visual Studio 14 2015 Win64"
|
||||
APPVEYOR_SAVE_CACHE_ON_ERROR: true
|
||||
DLL_PATH: lib\Release\fec.dll
|
||||
|
||||
install:
|
||||
- call "%APPVEYOR_BUILD_FOLDER%\\.appveyor-install-tools.cmd"
|
||||
|
||||
before_build:
|
||||
- if DEFINED MSVC_BAT call "%MSVC_BAT%" %MSVC_BAT_ARCH%
|
||||
- cd %APPVEYOR_BUILD_FOLDER%
|
||||
|
||||
build_script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake -G "%GENERATOR%" -DCMAKE_C_COMPILER=%COMPILER% -DCMAKE_CXX_COMPILER=%COMPILER% -DCMAKE_BUILD_TYPE=Release ..
|
||||
- cmake --build . --config Release --target shim
|
||||
- cmake --build . --config Release --target test_runners
|
||||
- dumpbin /EXPORTS %DLL_PATH%
|
||||
|
||||
test_script:
|
||||
- cd tests
|
||||
- set CTEST_OUTPUT_ON_FAILURE=1
|
||||
- ctest -C Release
|
||||
|
||||
cache:
|
||||
- C:\projects\tools\ninja
|
||||
- C:\projects\tools\cmake
|
||||
- C:\projects\tools\llvm-installer.exe
|
|
@ -0,0 +1,2 @@
|
|||
add_subdirectory(convolutional)
|
||||
add_subdirectory(reed-solomon)
|
|
@ -45,7 +45,7 @@ uint8_t *history_buffer_get_slice(history_buffer *buf) { return buf->history[buf
|
|||
|
||||
shift_register_t history_buffer_search(history_buffer *buf, const distance_t *distances,
|
||||
unsigned int search_every) {
|
||||
shift_register_t bestpath;
|
||||
shift_register_t bestpath = 0;
|
||||
distance_t leasterror = USHRT_MAX;
|
||||
// search for a state with the least error
|
||||
for (shift_register_t state = 0; state < buf->num_states; state += search_every) {
|
|
@ -0,0 +1,54 @@
|
|||
include_directories("include")
|
||||
|
||||
|
||||
add_executable(convolutional_test_runner EXCLUDE_FROM_ALL convolutional.c $<TARGET_OBJECTS:error_sim>)
|
||||
target_link_libraries(convolutional_test_runner correct_static "${LIBM}")
|
||||
set_target_properties(convolutional_test_runner PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
add_test(NAME convolutional_test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests" COMMAND convolutional_test_runner)
|
||||
set(all_test_runners ${all_test_runners} convolutional_test_runner)
|
||||
|
||||
if(HAVE_SSE)
|
||||
add_executable(convolutional_sse_test_runner EXCLUDE_FROM_ALL convolutional-sse.c $<TARGET_OBJECTS:error_sim_sse>)
|
||||
target_link_libraries(convolutional_sse_test_runner correct_static "${LIBM}")
|
||||
set_target_properties(convolutional_sse_test_runner PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
add_test(NAME convolutional_sse_test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests" COMMAND convolutional_sse_test_runner)
|
||||
set(all_test_runners ${all_test_runners} convolutional_sse_test_runner)
|
||||
endif()
|
||||
|
||||
if(HAVE_LIBFEC)
|
||||
add_executable(convolutional_fec_test_runner EXCLUDE_FROM_ALL convolutional-fec.c $<TARGET_OBJECTS:error_sim_fec>)
|
||||
target_link_libraries(convolutional_fec_test_runner correct_static FEC "${LIBM}")
|
||||
set_target_properties(convolutional_fec_test_runner PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
add_test(NAME convolutional_fec_test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests" COMMAND convolutional_fec_test_runner)
|
||||
set(all_test_runners ${all_test_runners} convolutional_fec_test_runner)
|
||||
endif()
|
||||
|
||||
add_executable(convolutional_shim_test_runner EXCLUDE_FROM_ALL convolutional-shim.c $<TARGET_OBJECTS:error_sim_shim>)
|
||||
target_link_libraries(convolutional_shim_test_runner correct_static fec_shim_static "${LIBM}")
|
||||
set_target_properties(convolutional_shim_test_runner PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
add_test(NAME convolutional_shim_test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests" COMMAND convolutional_shim_test_runner)
|
||||
set(all_test_runners ${all_test_runners} convolutional_shim_test_runner)
|
||||
|
||||
add_executable(reed_solomon_test_runner EXCLUDE_FROM_ALL reed-solomon.c rs_tester.c)
|
||||
target_link_libraries(reed_solomon_test_runner correct_static "${LIBM}")
|
||||
set_target_properties(reed_solomon_test_runner PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
add_test(NAME reed_solomon_test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests" COMMAND reed_solomon_test_runner)
|
||||
set(all_test_runners ${all_test_runners} reed_solomon_test_runner)
|
||||
|
||||
if(HAVE_LIBFEC)
|
||||
add_executable(reed_solomon_interop_test_runner EXCLUDE_FROM_ALL reed-solomon-fec-interop.c rs_tester.c rs_tester_fec.c)
|
||||
target_link_libraries(reed_solomon_interop_test_runner correct_static FEC "${LIBM}")
|
||||
set_target_properties(reed_solomon_interop_test_runner PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
add_test(NAME reed_solomon_interop_test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests" COMMAND reed_solomon_interop_test_runner)
|
||||
set(all_test_runners ${all_test_runners} reed_solomon_interop_test_runner)
|
||||
endif()
|
||||
|
||||
add_executable(reed_solomon_shim_interop_test_runner EXCLUDE_FROM_ALL reed-solomon-shim-interop.c rs_tester.c rs_tester_fec_shim.c)
|
||||
target_link_libraries(reed_solomon_shim_interop_test_runner correct_static fec_shim_static "${LIBM}")
|
||||
set_target_properties(reed_solomon_shim_interop_test_runner PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
add_test(NAME reed_solomon_shim_interop_test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests" COMMAND reed_solomon_shim_interop_test_runner)
|
||||
set(all_test_runners ${all_test_runners} reed_solomon_shim_interop_test_runner)
|
||||
|
||||
add_custom_target(test_runners DEPENDS ${all_test_runners})
|
||||
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS test_runners)
|
||||
enable_testing()
|
|
@ -0,0 +1,123 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <fec.h>
|
||||
|
||||
#include "correct.h"
|
||||
#include "correct/util/error-sim-fec.h"
|
||||
|
||||
size_t max_block_len = 4096;
|
||||
|
||||
size_t test_conv(correct_convolutional *conv, void *fec,
|
||||
void (*decode)(void *, uint8_t *, size_t, uint8_t *),
|
||||
conv_testbench **testbench_ptr, size_t msg_len, double eb_n0,
|
||||
double bpsk_bit_energy, double bpsk_voltage) {
|
||||
uint8_t *msg = malloc(max_block_len);
|
||||
|
||||
size_t num_errors = 0;
|
||||
|
||||
while (msg_len) {
|
||||
size_t block_len = (max_block_len < msg_len) ? max_block_len : msg_len;
|
||||
msg_len -= block_len;
|
||||
|
||||
for (unsigned int j = 0; j < block_len; j++) {
|
||||
msg[j] = rand() % 256;
|
||||
}
|
||||
|
||||
*testbench_ptr =
|
||||
resize_conv_testbench(*testbench_ptr, conv_correct_enclen, conv, block_len);
|
||||
conv_testbench *testbench = *testbench_ptr;
|
||||
testbench->encoder = conv;
|
||||
testbench->encode = conv_correct_encode;
|
||||
testbench->decoder = fec;
|
||||
testbench->decode = decode;
|
||||
build_white_noise(testbench->noise, testbench->enclen, eb_n0, bpsk_bit_energy);
|
||||
num_errors += test_conv_noise(testbench, msg, block_len, bpsk_voltage);
|
||||
}
|
||||
free(msg);
|
||||
return num_errors;
|
||||
}
|
||||
|
||||
void assert_test_result(correct_convolutional *conv, void *fec,
|
||||
void (*decode)(void *, uint8_t *, size_t, uint8_t *),
|
||||
conv_testbench **testbench, size_t test_length, size_t rate, size_t order,
|
||||
double eb_n0, double error_rate) {
|
||||
double bpsk_voltage = 1.0 / sqrt(2.0);
|
||||
double bpsk_sym_energy = 2 * pow(bpsk_voltage, 2.0);
|
||||
double bpsk_bit_energy = bpsk_sym_energy * rate;
|
||||
|
||||
size_t error_count =
|
||||
test_conv(conv, fec, decode, testbench, test_length, eb_n0, bpsk_bit_energy, bpsk_voltage);
|
||||
double observed_error_rate = error_count / ((double)test_length * 8);
|
||||
if (observed_error_rate > error_rate) {
|
||||
printf(
|
||||
"test failed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu "
|
||||
"order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
exit(1);
|
||||
} else {
|
||||
printf(
|
||||
"test passed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu "
|
||||
"order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time(NULL));
|
||||
|
||||
conv_testbench *testbench = NULL;
|
||||
|
||||
correct_convolutional *conv;
|
||||
void *fec;
|
||||
uint16_t *poly;
|
||||
|
||||
poly = (uint16_t[]){V27POLYA, V27POLYB};
|
||||
conv = correct_convolutional_create(2, 7, poly);
|
||||
fec = create_viterbi27(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_fec27_decode, &testbench, 1000000, 2, 6, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_fec27_decode, &testbench, 1000000, 2, 6, 4.5, 8e-06);
|
||||
assert_test_result(conv, fec, conv_fec27_decode, &testbench, 1000000, 2, 6, 4.0, 5e-05);
|
||||
delete_viterbi27(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
poly = (uint16_t[]){V29POLYA, V29POLYB};
|
||||
conv = correct_convolutional_create(2, 9, poly);
|
||||
fec = create_viterbi29(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_fec29_decode, &testbench, 1000000, 2, 9, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_fec29_decode, &testbench, 1000000, 2, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, fec, conv_fec29_decode, &testbench, 1000000, 2, 9, 4.0, 8e-06);
|
||||
delete_viterbi29(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
poly = (uint16_t[]){V39POLYA, V39POLYB, V39POLYC};
|
||||
conv = correct_convolutional_create(3, 9, poly);
|
||||
fec = create_viterbi39(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_fec39_decode, &testbench, 1000000, 3, 9, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_fec39_decode, &testbench, 1000000, 3, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, fec, conv_fec39_decode, &testbench, 1000000, 3, 9, 4.0, 5e-06);
|
||||
delete_viterbi39(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
poly = (uint16_t[]){V615POLYA, V615POLYB, V615POLYC, V615POLYD, V615POLYE, V615POLYF};
|
||||
conv = correct_convolutional_create(6, 15, poly);
|
||||
fec = create_viterbi615(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_fec615_decode, &testbench, 100000, 6, 15, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_fec615_decode, &testbench, 100000, 6, 15, 3.0, 3e-06);
|
||||
assert_test_result(conv, fec, conv_fec615_decode, &testbench, 100000, 6, 15, 2.5, 1e-05);
|
||||
delete_viterbi615(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
free_scratch(testbench);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "correct.h"
|
||||
#include "fec_shim.h"
|
||||
#include "correct/util/error-sim-shim.h"
|
||||
|
||||
size_t max_block_len = 4096;
|
||||
|
||||
size_t test_conv(correct_convolutional *conv, void *fec,
|
||||
ssize_t (*decode)(void *, uint8_t *, size_t, uint8_t *),
|
||||
conv_testbench **testbench_ptr, size_t msg_len, double eb_n0,
|
||||
double bpsk_bit_energy, double bpsk_voltage) {
|
||||
uint8_t *msg = malloc(max_block_len);
|
||||
|
||||
size_t num_errors = 0;
|
||||
|
||||
while (msg_len) {
|
||||
size_t block_len = (max_block_len < msg_len) ? max_block_len : msg_len;
|
||||
msg_len -= block_len;
|
||||
|
||||
for (unsigned int j = 0; j < block_len; j++) {
|
||||
msg[j] = rand() % 256;
|
||||
}
|
||||
|
||||
*testbench_ptr =
|
||||
resize_conv_testbench(*testbench_ptr, conv_correct_enclen, conv, block_len);
|
||||
conv_testbench *testbench = *testbench_ptr;
|
||||
testbench->encoder = conv;
|
||||
testbench->encode = conv_correct_encode;
|
||||
testbench->decoder = fec;
|
||||
testbench->decode = decode;
|
||||
build_white_noise(testbench->noise, testbench->enclen, eb_n0, bpsk_bit_energy);
|
||||
num_errors += test_conv_noise(testbench, msg, block_len, bpsk_voltage);
|
||||
}
|
||||
free(msg);
|
||||
return num_errors;
|
||||
}
|
||||
|
||||
void assert_test_result(correct_convolutional *conv, void *fec,
|
||||
ssize_t (*decode)(void *, uint8_t *, size_t, uint8_t *),
|
||||
conv_testbench **testbench, size_t test_length, size_t rate, size_t order,
|
||||
double eb_n0, double error_rate) {
|
||||
double bpsk_voltage = 1.0 / sqrt(2.0);
|
||||
double bpsk_sym_energy = 2 * pow(bpsk_voltage, 2.0);
|
||||
double bpsk_bit_energy = bpsk_sym_energy * rate;
|
||||
|
||||
size_t error_count =
|
||||
test_conv(conv, fec, decode, testbench, test_length, eb_n0, bpsk_bit_energy, bpsk_voltage);
|
||||
double observed_error_rate = error_count / ((double)test_length * 8);
|
||||
if (observed_error_rate > error_rate) {
|
||||
printf(
|
||||
"test failed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu "
|
||||
"order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
exit(1);
|
||||
} else {
|
||||
printf(
|
||||
"test passed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu "
|
||||
"order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time(NULL));
|
||||
|
||||
conv_testbench *testbench = NULL;
|
||||
|
||||
correct_convolutional *conv;
|
||||
void *fec;
|
||||
uint16_t *poly;
|
||||
|
||||
poly = (uint16_t[]){V27POLYA, V27POLYB};
|
||||
conv = correct_convolutional_create(2, 7, poly);
|
||||
fec = create_viterbi27(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_shim27_decode, &testbench, 1000000, 2, 6, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_shim27_decode, &testbench, 1000000, 2, 6, 4.5, 8e-06);
|
||||
assert_test_result(conv, fec, conv_shim27_decode, &testbench, 1000000, 2, 6, 4.0, 5e-05);
|
||||
delete_viterbi27(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
poly = (uint16_t[]){V29POLYA, V29POLYB};
|
||||
conv = correct_convolutional_create(2, 9, poly);
|
||||
fec = create_viterbi29(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_shim29_decode, &testbench, 1000000, 2, 9, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_shim29_decode, &testbench, 1000000, 2, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, fec, conv_shim29_decode, &testbench, 1000000, 2, 9, 4.0, 8e-06);
|
||||
delete_viterbi29(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
poly = (uint16_t[]){V39POLYA, V39POLYB, V39POLYC};
|
||||
conv = correct_convolutional_create(3, 9, poly);
|
||||
fec = create_viterbi39(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_shim39_decode, &testbench, 1000000, 3, 9, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_shim39_decode, &testbench, 1000000, 3, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, fec, conv_shim39_decode, &testbench, 1000000, 3, 9, 4.0, 9e-06);
|
||||
delete_viterbi39(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
poly = (uint16_t[]){V615POLYA, V615POLYB, V615POLYC, V615POLYD, V615POLYE, V615POLYF};
|
||||
conv = correct_convolutional_create(6, 15, poly);
|
||||
fec = create_viterbi615(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_shim615_decode, &testbench, 100000, 6, 15, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_shim615_decode, &testbench, 100000, 6, 15, 3.0, 2e-05);
|
||||
assert_test_result(conv, fec, conv_shim615_decode, &testbench, 100000, 6, 15, 2.5, 4e-05);
|
||||
delete_viterbi615(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
free_scratch(testbench);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "correct/util/error-sim-sse.h"
|
||||
|
||||
size_t max_block_len = 4096;
|
||||
|
||||
size_t test_conv(correct_convolutional_sse *conv, conv_testbench **testbench_ptr,
|
||||
size_t msg_len, double eb_n0, double bpsk_bit_energy,
|
||||
double bpsk_voltage) {
|
||||
uint8_t *msg = malloc(max_block_len);
|
||||
|
||||
size_t num_errors = 0;
|
||||
|
||||
while (msg_len) {
|
||||
size_t block_len = (max_block_len < msg_len) ? max_block_len : msg_len;
|
||||
msg_len -= block_len;
|
||||
|
||||
for (unsigned int j = 0; j < block_len; j++) {
|
||||
msg[j] = rand() % 256;
|
||||
}
|
||||
|
||||
*testbench_ptr = resize_conv_testbench(*testbench_ptr, conv_correct_sse_enclen, conv, block_len);
|
||||
conv_testbench *testbench = *testbench_ptr;
|
||||
testbench->encoder = conv;
|
||||
testbench->encode = conv_correct_sse_encode;
|
||||
testbench->decoder = conv;
|
||||
testbench->decode = conv_correct_sse_decode;
|
||||
build_white_noise(testbench->noise, testbench->enclen, eb_n0, bpsk_bit_energy);
|
||||
num_errors += test_conv_noise(testbench, msg, block_len, bpsk_voltage);
|
||||
}
|
||||
free(msg);
|
||||
return num_errors;
|
||||
}
|
||||
|
||||
void assert_test_result(correct_convolutional_sse *conv, conv_testbench **testbench,
|
||||
size_t test_length, size_t rate, size_t order, double eb_n0, double error_rate) {
|
||||
double bpsk_voltage = 1.0/sqrt(2.0);
|
||||
double bpsk_sym_energy = 2*pow(bpsk_voltage, 2.0);
|
||||
double bpsk_bit_energy = bpsk_sym_energy * rate;
|
||||
|
||||
size_t error_count = test_conv(conv, testbench, test_length, eb_n0, bpsk_bit_energy, bpsk_voltage);
|
||||
double observed_error_rate = error_count/((double)test_length * 8);
|
||||
if (observed_error_rate > error_rate) {
|
||||
printf("test failed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
exit(1);
|
||||
} else {
|
||||
printf("test passed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time(NULL));
|
||||
|
||||
conv_testbench *testbench = NULL;
|
||||
|
||||
correct_convolutional_sse *conv;
|
||||
|
||||
// n.b. the error rates below are at 5.0dB/4.5dB for order 6 polys
|
||||
// and 4.5dB/4.0dB for order 7-9 polys. this can be easy to miss.
|
||||
|
||||
conv = correct_convolutional_sse_create(2, 6, correct_conv_r12_6_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 6, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 6, 5.0, 8e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 6, 4.5, 3e-05);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_sse_create(2, 7, correct_conv_r12_7_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 7, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 7, 4.5, 1e-05);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 7, 4.0, 5e-05);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_sse_create(2, 8, correct_conv_r12_8_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 8, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 8, 4.5, 5e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 8, 4.0, 3e-05);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_sse_create(2, 9, correct_conv_r12_9_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 9, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 9, 4.0, 8e-06);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_sse_create(3, 6, correct_conv_r13_6_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 6, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 6, 5.0, 5e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 6, 4.5, 2e-05);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_sse_create(3, 7, correct_conv_r13_7_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 7, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 7, 4.5, 5e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 7, 4.0, 3e-05);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_sse_create(3, 8, correct_conv_r13_8_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 8, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 8, 4.5, 4e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 8, 4.0, 1e-05);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_sse_create(3, 9, correct_conv_r13_9_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 9, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 9, 4.0, 5e-06);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
free_scratch(testbench);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "correct.h"
|
||||
#include "correct/util/error-sim.h"
|
||||
|
||||
size_t max_block_len = 4096;
|
||||
|
||||
size_t test_conv(correct_convolutional *conv, conv_testbench **testbench_ptr,
|
||||
size_t msg_len, double eb_n0, double bpsk_bit_energy,
|
||||
double bpsk_voltage) {
|
||||
uint8_t *msg = malloc(max_block_len);
|
||||
|
||||
size_t num_errors = 0;
|
||||
|
||||
while (msg_len) {
|
||||
size_t block_len = (max_block_len < msg_len) ? max_block_len : msg_len;
|
||||
msg_len -= block_len;
|
||||
|
||||
for (unsigned int j = 0; j < block_len; j++) {
|
||||
msg[j] = rand() % 256;
|
||||
}
|
||||
|
||||
*testbench_ptr = resize_conv_testbench(*testbench_ptr, conv_correct_enclen, conv, block_len);
|
||||
conv_testbench *testbench = *testbench_ptr;
|
||||
testbench->encoder = conv;
|
||||
testbench->encode = conv_correct_encode;
|
||||
testbench->decoder = conv;
|
||||
testbench->decode = conv_correct_decode;
|
||||
build_white_noise(testbench->noise, testbench->enclen, eb_n0, bpsk_bit_energy);
|
||||
num_errors += test_conv_noise(testbench, msg, block_len, bpsk_voltage);
|
||||
}
|
||||
free(msg);
|
||||
return num_errors;
|
||||
}
|
||||
|
||||
void assert_test_result(correct_convolutional *conv, conv_testbench **testbench,
|
||||
size_t test_length, size_t rate, size_t order, double eb_n0, double error_rate) {
|
||||
double bpsk_voltage = 1.0/sqrt(2.0);
|
||||
double bpsk_sym_energy = 2*pow(bpsk_voltage, 2.0);
|
||||
double bpsk_bit_energy = bpsk_sym_energy * rate;
|
||||
|
||||
size_t error_count = test_conv(conv, testbench, test_length, eb_n0, bpsk_bit_energy, bpsk_voltage);
|
||||
double observed_error_rate = error_count/((double)test_length * 8);
|
||||
if (observed_error_rate > error_rate) {
|
||||
printf("test failed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
exit(1);
|
||||
} else {
|
||||
printf("test passed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time(NULL));
|
||||
|
||||
conv_testbench *testbench = NULL;
|
||||
|
||||
correct_convolutional *conv;
|
||||
|
||||
// n.b. the error rates below are at 5.0dB/4.5dB for order 6 polys
|
||||
// and 4.5dB/4.0dB for order 7-9 polys. this can be easy to miss.
|
||||
|
||||
conv = correct_convolutional_create(2, 6, correct_conv_r12_6_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 6, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 6, 5.0, 5e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 6, 4.5, 3e-05);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_create(2, 7, correct_conv_r12_7_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 7, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 7, 4.5, 1e-05);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 7, 4.0, 5e-05);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_create(2, 8, correct_conv_r12_8_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 8, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 8, 4.5, 5e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 8, 4.0, 3e-05);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_create(2, 9, correct_conv_r12_9_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 9, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 9, 4.0, 1e-05);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_create(3, 6, correct_conv_r13_6_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 6, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 6, 5.0, 5e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 6, 4.5, 2e-05);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_create(3, 7, correct_conv_r13_7_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 7, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 7, 4.5, 5e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 7, 4.0, 3e-05);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_create(3, 8, correct_conv_r13_8_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 8, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 8, 4.5, 4e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 8, 4.0, 1e-05);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_create(3, 9, correct_conv_r13_9_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 9, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 9, 4.0, 5e-06);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
free_scratch(testbench);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "correct.h"
|
||||
|
||||
void rs_correct_encode(void *encoder, uint8_t *msg, size_t msg_length,
|
||||
uint8_t *msg_out);
|
||||
void rs_correct_decode(void *decoder, uint8_t *encoded, size_t encoded_length,
|
||||
uint8_t *erasure_locations, size_t erasure_length,
|
||||
uint8_t *msg, size_t pad_length, size_t num_roots);
|
||||
|
||||
typedef struct {
|
||||
size_t block_length;
|
||||
size_t message_length;
|
||||
size_t min_distance;
|
||||
unsigned char *msg;
|
||||
uint8_t *encoded;
|
||||
int *indices;
|
||||
uint8_t *corrupted_encoded;
|
||||
uint8_t *erasure_locations;
|
||||
unsigned char *recvmsg;
|
||||
} rs_testbench;
|
||||
|
||||
typedef struct {
|
||||
void (*encode)(void *, uint8_t *, size_t, uint8_t *);
|
||||
void *encoder;
|
||||
void (*decode)(void *, uint8_t *, size_t, uint8_t *, size_t, uint8_t *, size_t, size_t);
|
||||
void *decoder;
|
||||
} rs_test;
|
||||
|
||||
rs_testbench *rs_testbench_create(size_t block_length, size_t min_distance);
|
||||
void rs_testbench_destroy(rs_testbench *testbench);
|
||||
|
||||
typedef struct {
|
||||
bool output_matches;
|
||||
} rs_test_run;
|
||||
|
||||
rs_test_run test_rs_errors(rs_test *test, rs_testbench *testbench, size_t msg_length,
|
||||
size_t num_errors, size_t num_erasures);
|
|
@ -0,0 +1,10 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fec.h>
|
||||
void rs_fec_encode(void *encoder, uint8_t *msg, size_t msg_length,
|
||||
uint8_t *msg_out);
|
||||
void rs_fec_decode(void *decoder, uint8_t *encoded, size_t encoded_length,
|
||||
uint8_t *erasure_locations, size_t erasure_length,
|
||||
uint8_t *msg, size_t pad_length, size_t num_roots);
|
|
@ -0,0 +1,10 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fec_shim.h"
|
||||
void rs_fec_encode(void *encoder, uint8_t *msg, size_t msg_length,
|
||||
uint8_t *msg_out);
|
||||
void rs_fec_decode(void *decoder, uint8_t *encoded, size_t encoded_length,
|
||||
uint8_t *erasure_locations, size_t erasure_length,
|
||||
uint8_t *msg, size_t pad_length, size_t num_roots);
|
|
@ -0,0 +1,138 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "rs_tester.h"
|
||||
#include "rs_tester_fec.h"
|
||||
|
||||
void print_test_type(size_t block_length, size_t message_length,
|
||||
size_t num_errors, size_t num_erasures) {
|
||||
printf(
|
||||
"testing reed solomon block length=%zu, message length=%zu, "
|
||||
"errors=%zu, erasures=%zu...",
|
||||
block_length, message_length, num_errors, num_erasures);
|
||||
}
|
||||
|
||||
void fail_test() {
|
||||
printf("FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void pass_test() { printf("PASSED\n"); }
|
||||
|
||||
void run_tests(correct_reed_solomon *rs, void *fec_rs, rs_testbench *testbench,
|
||||
size_t block_length, size_t test_msg_length, size_t num_errors,
|
||||
size_t num_erasures, size_t num_iterations) {
|
||||
// run both ways, correct->fec and fec->correct
|
||||
rs_test test;
|
||||
test.encode = rs_correct_encode;
|
||||
test.encoder = rs;
|
||||
test.decode = rs_fec_decode;
|
||||
test.decoder = fec_rs;
|
||||
|
||||
print_test_type(block_length, test_msg_length, num_errors, num_erasures);
|
||||
for (size_t i = 0; i < num_iterations; i++) {
|
||||
rs_test_run run = test_rs_errors(&test, testbench, test_msg_length,
|
||||
num_errors, num_erasures);
|
||||
if (!run.output_matches) {
|
||||
fail_test();
|
||||
}
|
||||
}
|
||||
|
||||
test.encode = rs_fec_encode;
|
||||
test.encoder = fec_rs;
|
||||
test.decode = rs_correct_decode;
|
||||
test.decoder = rs;
|
||||
for (size_t i = 0; i < num_iterations; i++) {
|
||||
rs_test_run run = test_rs_errors(&test, testbench, test_msg_length,
|
||||
num_errors, num_erasures);
|
||||
if (!run.output_matches) {
|
||||
fail_test();
|
||||
}
|
||||
}
|
||||
pass_test();
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time(NULL));
|
||||
|
||||
size_t block_length = 255;
|
||||
size_t min_distance = 32;
|
||||
size_t message_length = block_length - min_distance;
|
||||
|
||||
size_t pad_length;
|
||||
void *fec_rs;
|
||||
|
||||
correct_reed_solomon *rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
rs_testbench *testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
pad_length = message_length / 2;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
pad_length = 0;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
min_distance = 16;
|
||||
message_length = block_length - min_distance;
|
||||
rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
pad_length = message_length / 2;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
pad_length = 0;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
printf("test passed\n");
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "rs_tester.h"
|
||||
#include "rs_tester_fec_shim.h"
|
||||
|
||||
void print_test_type(size_t block_length, size_t message_length,
|
||||
size_t num_errors, size_t num_erasures) {
|
||||
printf(
|
||||
"testing reed solomon block length=%zu, message length=%zu, "
|
||||
"errors=%zu, erasures=%zu...",
|
||||
block_length, message_length, num_errors, num_erasures);
|
||||
}
|
||||
|
||||
void fail_test() {
|
||||
printf("FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void pass_test() { printf("PASSED\n"); }
|
||||
|
||||
void run_tests(correct_reed_solomon *rs, void *fec_rs, rs_testbench *testbench,
|
||||
size_t block_length, size_t test_msg_length, size_t num_errors,
|
||||
size_t num_erasures, size_t num_iterations) {
|
||||
// run both ways, correct->fec and fec->correct
|
||||
rs_test test;
|
||||
test.encode = rs_correct_encode;
|
||||
test.encoder = rs;
|
||||
test.decode = rs_fec_decode;
|
||||
test.decoder = fec_rs;
|
||||
|
||||
print_test_type(block_length, test_msg_length, num_errors, num_erasures);
|
||||
for (size_t i = 0; i < num_iterations; i++) {
|
||||
rs_test_run run = test_rs_errors(&test, testbench, test_msg_length, num_errors,
|
||||
num_erasures);
|
||||
if (!run.output_matches) {
|
||||
fail_test();
|
||||
}
|
||||
}
|
||||
|
||||
test.encode = rs_fec_encode;
|
||||
test.encoder = fec_rs;
|
||||
test.decode = rs_correct_decode;
|
||||
test.decoder = rs;
|
||||
for (size_t i = 0; i < num_iterations; i++) {
|
||||
rs_test_run run = test_rs_errors(&test, testbench, test_msg_length, num_errors,
|
||||
num_erasures);
|
||||
if (!run.output_matches) {
|
||||
fail_test();
|
||||
}
|
||||
}
|
||||
pass_test();
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time(NULL));
|
||||
|
||||
size_t block_length = 255;
|
||||
size_t min_distance = 32;
|
||||
size_t message_length = block_length - min_distance;
|
||||
|
||||
size_t pad_length;
|
||||
void *fec_rs;
|
||||
|
||||
correct_reed_solomon *rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
rs_testbench *testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
pad_length = message_length / 2;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
pad_length = 0;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
min_distance = 16;
|
||||
message_length = block_length - min_distance;
|
||||
rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
pad_length = message_length / 2;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
pad_length = 0;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
printf("test passed\n");
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "rs_tester.h"
|
||||
|
||||
void print_test_type(size_t block_length, size_t message_length,
|
||||
size_t num_errors, size_t num_erasures) {
|
||||
printf(
|
||||
"testing reed solomon block length=%zu, message length=%zu, "
|
||||
"errors=%zu, erasures=%zu...",
|
||||
block_length, message_length, num_errors, num_erasures);
|
||||
}
|
||||
|
||||
void fail_test() {
|
||||
printf("FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void pass_test() { printf("PASSED\n"); }
|
||||
|
||||
void run_tests(correct_reed_solomon *rs, rs_testbench *testbench,
|
||||
size_t block_length, size_t test_msg_length, size_t num_errors,
|
||||
size_t num_erasures, size_t num_iterations) {
|
||||
rs_test test;
|
||||
test.encode = rs_correct_encode;
|
||||
test.decode = rs_correct_decode;
|
||||
test.encoder = rs;
|
||||
test.decoder = rs;
|
||||
print_test_type(block_length, test_msg_length, num_errors, num_erasures);
|
||||
for (size_t i = 0; i < num_iterations; i++) {
|
||||
rs_test_run run = test_rs_errors(&test, testbench, test_msg_length, num_errors,
|
||||
num_erasures);
|
||||
if (!run.output_matches) {
|
||||
fail_test();
|
||||
}
|
||||
}
|
||||
pass_test();
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time(NULL));
|
||||
|
||||
size_t block_length = 255;
|
||||
size_t min_distance = 32;
|
||||
size_t message_length = block_length - min_distance;
|
||||
|
||||
correct_reed_solomon *rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
rs_testbench *testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 2,
|
||||
0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 2, 0,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
min_distance = 16;
|
||||
message_length = block_length - min_distance;
|
||||
rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 2,
|
||||
0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 2, 0,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
min_distance = 8;
|
||||
message_length = block_length - min_distance;
|
||||
rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 2,
|
||||
0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 2, 0,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
min_distance = 4;
|
||||
message_length = block_length - min_distance;
|
||||
rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 2,
|
||||
0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 2, 0,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
printf("test passed\n");
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
#include "rs_tester.h"
|
||||
|
||||
void shuffle(int *a, size_t len) {
|
||||
for (size_t i = 0; i < len - 2; i++) {
|
||||
size_t j = rand() % (len - i) + i;
|
||||
int temp = a[i];
|
||||
a[i] = a[j];
|
||||
a[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
void rs_correct_encode(void *encoder, uint8_t *msg, size_t msg_length,
|
||||
uint8_t *msg_out) {
|
||||
correct_reed_solomon_encode((correct_reed_solomon *)encoder, msg,
|
||||
msg_length, msg_out);
|
||||
}
|
||||
|
||||
void rs_correct_decode(void *decoder, uint8_t *encoded, size_t encoded_length,
|
||||
uint8_t *erasure_locations, size_t erasure_length,
|
||||
uint8_t *msg, size_t pad_length, size_t num_roots) {
|
||||
correct_reed_solomon_decode_with_erasures(
|
||||
(correct_reed_solomon *)decoder, encoded, encoded_length,
|
||||
erasure_locations, erasure_length, msg);
|
||||
}
|
||||
|
||||
rs_testbench *rs_testbench_create(size_t block_length, size_t min_distance) {
|
||||
rs_testbench *testbench = calloc(1, sizeof(rs_testbench));
|
||||
|
||||
size_t message_length = block_length - min_distance;
|
||||
testbench->message_length = message_length;
|
||||
testbench->block_length = block_length;
|
||||
testbench->min_distance = min_distance;
|
||||
|
||||
testbench->msg = calloc(message_length, sizeof(unsigned char));
|
||||
testbench->encoded = malloc(block_length * sizeof(uint8_t));
|
||||
|
||||
testbench->indices = malloc(block_length * sizeof(int));
|
||||
|
||||
testbench->corrupted_encoded = malloc(block_length * sizeof(uint8_t));
|
||||
testbench->erasure_locations = malloc(min_distance * sizeof(uint8_t));
|
||||
testbench->recvmsg = malloc(sizeof(unsigned char) * message_length);
|
||||
|
||||
return testbench;
|
||||
}
|
||||
|
||||
void rs_testbench_destroy(rs_testbench *testbench) {
|
||||
free(testbench->msg);
|
||||
free(testbench->encoded);
|
||||
free(testbench->indices);
|
||||
free(testbench->corrupted_encoded);
|
||||
free(testbench->erasure_locations);
|
||||
free(testbench->recvmsg);
|
||||
free(testbench);
|
||||
}
|
||||
|
||||
rs_test_run test_rs_errors(rs_test *test, rs_testbench *testbench, size_t msg_length,
|
||||
size_t num_errors, size_t num_erasures) {
|
||||
rs_test_run run;
|
||||
run.output_matches = false;
|
||||
|
||||
if (msg_length > testbench->message_length) {
|
||||
return run;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < msg_length; i++) {
|
||||
testbench->msg[i] = rand() % 256;
|
||||
}
|
||||
|
||||
size_t block_length = msg_length + testbench->min_distance;
|
||||
size_t pad_length = testbench->message_length - msg_length;
|
||||
|
||||
test->encode(test->encoder, testbench->msg, msg_length, testbench->encoded);
|
||||
|
||||
memcpy(testbench->corrupted_encoded, testbench->encoded, block_length);
|
||||
|
||||
for (int i = 0; i < block_length; i++) {
|
||||
testbench->indices[i] = i;
|
||||
}
|
||||
|
||||
shuffle(testbench->indices, block_length);
|
||||
|
||||
for (unsigned int i = 0; i < num_erasures; i++) {
|
||||
int index = testbench->indices[i];
|
||||
uint8_t corruption_mask = (rand() % 255) + 1;
|
||||
testbench->corrupted_encoded[index] ^= corruption_mask;
|
||||
testbench->erasure_locations[i] = index;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < num_errors; i++) {
|
||||
int index = testbench->indices[i + num_erasures];
|
||||
uint8_t corruption_mask = (rand() % 255) + 1;
|
||||
testbench->corrupted_encoded[index] ^= corruption_mask;
|
||||
}
|
||||
|
||||
test->decode(test->decoder, testbench->corrupted_encoded, block_length,
|
||||
testbench->erasure_locations, num_erasures,
|
||||
testbench->recvmsg, pad_length, testbench->min_distance);
|
||||
|
||||
run.output_matches = (bool)(memcmp(testbench->msg, testbench->recvmsg, msg_length) == 0);
|
||||
|
||||
return run;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#include "rs_tester_fec.h"
|
||||
void rs_fec_encode(void *encoder, uint8_t *msg, size_t msg_length,
|
||||
uint8_t *msg_out) {
|
||||
// XXX make sure that pad length used to build encoder corresponds to this
|
||||
// msg_length
|
||||
memcpy(msg_out, msg, msg_length);
|
||||
encode_rs_char(encoder, msg_out, msg_out + msg_length);
|
||||
}
|
||||
|
||||
void rs_fec_decode(void *decoder, uint8_t *encoded, size_t encoded_length,
|
||||
uint8_t *erasure_locations, size_t erasure_length,
|
||||
uint8_t *msg, size_t pad_length, size_t num_roots) {
|
||||
// XXX make sure that pad length used to build decoder corresponds to this
|
||||
// encoded_length
|
||||
if (erasure_length) {
|
||||
static size_t locations_len = 0;
|
||||
static int *locations = NULL;
|
||||
if (locations_len < erasure_length) {
|
||||
locations = realloc(locations, erasure_length * sizeof(int));
|
||||
locations_len = erasure_length;
|
||||
}
|
||||
for (size_t i = 0; i < erasure_length; i++) {
|
||||
locations[i] = (unsigned int)(erasure_locations[i]) + pad_length;
|
||||
}
|
||||
decode_rs_char(decoder, encoded, locations, erasure_length);
|
||||
} else {
|
||||
decode_rs_char(decoder, encoded, NULL, 0);
|
||||
}
|
||||
memcpy(msg, encoded, encoded_length - num_roots);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#include "rs_tester_fec_shim.h"
|
||||
void rs_fec_encode(void *encoder, uint8_t *msg, size_t msg_length,
|
||||
uint8_t *msg_out) {
|
||||
// XXX make sure that pad length used to build encoder corresponds to this
|
||||
// msg_length
|
||||
memcpy(msg_out, msg, msg_length);
|
||||
encode_rs_char(encoder, msg_out, msg_out + msg_length);
|
||||
}
|
||||
|
||||
void rs_fec_decode(void *decoder, uint8_t *encoded, size_t encoded_length,
|
||||
uint8_t *erasure_locations, size_t erasure_length,
|
||||
uint8_t *msg, size_t pad_length, size_t num_roots) {
|
||||
// XXX make sure that pad length used to build decoder corresponds to this
|
||||
// encoded_length
|
||||
if (erasure_length) {
|
||||
int *locations = malloc(erasure_length * sizeof(int));
|
||||
for (size_t i = 0; i < erasure_length; i++) {
|
||||
locations[i] = (unsigned int)(erasure_locations[i]) + pad_length;
|
||||
}
|
||||
decode_rs_char(decoder, encoded, locations, erasure_length);
|
||||
free(locations);
|
||||
} else {
|
||||
decode_rs_char(decoder, encoded, NULL, 0);
|
||||
}
|
||||
memcpy(msg, encoded, encoded_length - num_roots);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
add_executable(rs_find_primitive_poly EXCLUDE_FROM_ALL find_rs_primitive_poly.c)
|
||||
target_link_libraries(rs_find_primitive_poly correct_static)
|
||||
set(all_tools ${all_tools} rs_find_primitive_poly)
|
||||
|
||||
if(HAVE_LIBFEC)
|
||||
add_executable(conv_find_libfec_poly EXCLUDE_FROM_ALL find_conv_libfec_poly.c)
|
||||
target_link_libraries(conv_find_libfec_poly correct_static fec)
|
||||
set(all_tools ${all_tools} conv_find_libfec_poly)
|
||||
endif()
|
||||
|
||||
if(HAVE_SSE)
|
||||
add_executable(conv_find_optim_poly EXCLUDE_FROM_ALL find_conv_optim_poly.c $<TARGET_OBJECTS:error_sim_sse>)
|
||||
target_link_libraries(conv_find_optim_poly correct_static)
|
||||
set(all_tools ${all_tools} conv_find_optim_poly)
|
||||
|
||||
add_executable(conv_find_optim_poly_annealing EXCLUDE_FROM_ALL find_conv_optim_poly_annealing.c $<TARGET_OBJECTS:error_sim_sse>)
|
||||
target_link_libraries(conv_find_optim_poly_annealing correct_static)
|
||||
set(all_tools ${all_tools} conv_find_optim_poly_annealing)
|
||||
else()
|
||||
add_executable(conv_find_optim_poly EXCLUDE_FROM_ALL find_conv_optim_poly.c $<TARGET_OBJECTS:error_sim>)
|
||||
target_link_libraries(conv_find_optim_poly correct_static)
|
||||
set(all_tools ${all_tools} conv_find_optim_poly)
|
||||
|
||||
add_executable(conv_find_optim_poly_annealing EXCLUDE_FROM_ALL find_conv_optim_poly_annealing.c $<TARGET_OBJECTS:error_sim>)
|
||||
target_link_libraries(conv_find_optim_poly_annealing correct_static)
|
||||
set(all_tools ${all_tools} conv_find_optim_poly_annealing)
|
||||
endif()
|
||||
|
||||
add_custom_target(tools DEPENDS ${all_tools})
|
|
@ -0,0 +1,279 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <correct.h>
|
||||
#include <fec.h>
|
||||
|
||||
// this program allows us to find all of the polynomials that come with libfec
|
||||
// this way, we can provide compatibility with libfec-encoded streams and vice versa
|
||||
// we can do this without directly copy-pasting from libfec's source, thanks
|
||||
// to this finder
|
||||
|
||||
typedef struct {
|
||||
void *vit;
|
||||
int update_len;
|
||||
int (*init)(void *, int);
|
||||
int (*update)(void *, unsigned char *, int);
|
||||
int (*chainback)(void *, unsigned char *, unsigned int, unsigned int);
|
||||
} libfec_decoder_t;
|
||||
|
||||
void byte2bit(uint8_t *bytes, uint8_t *bits, size_t n_bits) {
|
||||
unsigned char cmask = 0x80;
|
||||
for (size_t i = 0; i < n_bits; i++) {
|
||||
bits[i] = (bytes[i/8] & cmask) ? 255 : 0;
|
||||
cmask >>= 1;
|
||||
if (!cmask) {
|
||||
cmask = 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
correct_convolutional_polynomial_t *resize_poly_list(correct_convolutional_polynomial_t *polys, size_t cap) {
|
||||
polys = realloc(polys, cap * sizeof(correct_convolutional_polynomial_t));
|
||||
return polys;
|
||||
}
|
||||
|
||||
void find_poly_coeff(size_t rate, size_t order, uint8_t *msg, size_t msg_len, libfec_decoder_t libfec, correct_convolutional_polynomial_t **polys_dest, size_t *polys_len, size_t search_coeff) {
|
||||
// find a single coefficient of an unknown convolutional polynomial
|
||||
// we are given a payload to encode, and we'll test all possible coefficients
|
||||
// to see which ones yield correct decodings by libfec, which has some
|
||||
// unknown polynomial "baked in"
|
||||
|
||||
// temp poly (this will be the one we search with)
|
||||
correct_convolutional_polynomial_t *poly = malloc(rate * sizeof(correct_convolutional_polynomial_t));
|
||||
|
||||
// what's the largest coefficient value we'll test?
|
||||
correct_convolutional_polynomial_t maxcoeff = (1 << order) - 1;
|
||||
|
||||
// note that we start about half way in
|
||||
// this sum asks that we have the
|
||||
// a) highest order bit set
|
||||
// b) lowest order bit set
|
||||
// we're only interested in coefficient values for which this is
|
||||
// true because if it weren't, the coefficient would actually be
|
||||
// of a smaller order than its supposed given order
|
||||
correct_convolutional_polynomial_t startcoeff = (1 << (order - 1)) + 1;
|
||||
|
||||
// the values of this don't really matter except for the coeff we're searching for
|
||||
// but just to be safe, we set them all
|
||||
for (size_t i = 0; i < rate; i++) {
|
||||
poly[i] = startcoeff;
|
||||
}
|
||||
|
||||
// create a dummy encoder so that we can find how long the resulting encoded value is
|
||||
correct_convolutional *conv_dummy = correct_convolutional_create(rate, order, poly);
|
||||
size_t enclen_bits = correct_convolutional_encode_len(conv_dummy, msg_len);
|
||||
size_t enclen = (enclen_bits % 8) ? (enclen_bits / 8 + 1) : enclen_bits / 8;
|
||||
correct_convolutional_destroy(conv_dummy);
|
||||
|
||||
// compact encoded format (this comes from libcorrect)
|
||||
uint8_t *encoded = malloc(enclen * sizeof(uint8_t));
|
||||
// soft encoded format (this goes to libfec, one byte per bit)
|
||||
uint8_t *encoded_bits = malloc(enclen * 8 * sizeof(uint8_t));
|
||||
// resulting decoded message which we'll compare to our given payload
|
||||
uint8_t *msg_cmp = malloc(msg_len * sizeof(uint8_t));
|
||||
|
||||
// we keep a list of coefficients which yielded correct decodings
|
||||
// there could be 0, 1, or more than 1, and we'll return all of them
|
||||
// we'll dynamically resize this as we go
|
||||
size_t polys_cap = 1;
|
||||
*polys_len = 0;
|
||||
correct_convolutional_polynomial_t *polys = NULL;
|
||||
polys = resize_poly_list(polys, polys_cap);
|
||||
|
||||
// iteration constants -- we go by 2 because we want the lowest order bit to
|
||||
// stay set
|
||||
for (correct_convolutional_polynomial_t i = startcoeff; i <= maxcoeff; i += 2) {
|
||||
poly[search_coeff] = i;
|
||||
correct_convolutional *conv = correct_convolutional_create(rate, order, poly);
|
||||
|
||||
correct_convolutional_encode(conv, (uint8_t*)msg, msg_len, encoded);
|
||||
byte2bit(encoded, encoded_bits, enclen);
|
||||
|
||||
// now erase all the bits we're not searching for
|
||||
for (size_t i = 0; i < msg_len * 8; i++) {
|
||||
for (size_t j = 0; j < rate; j++) {
|
||||
if (j != search_coeff) {
|
||||
// 128 is a soft erasure
|
||||
encoded_bits[i * rate + j] = 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libfec.init(libfec.vit, 0);
|
||||
libfec.update(libfec.vit, encoded_bits, libfec.update_len);
|
||||
libfec.chainback(libfec.vit, msg_cmp, 8 * msg_len, 0);
|
||||
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
if (memcmp(msg_cmp, msg, msg_len) == 0) {
|
||||
// match found
|
||||
|
||||
// resize list to make room
|
||||
if (*polys_len == polys_cap) {
|
||||
polys = resize_poly_list(polys, polys_cap * 2);
|
||||
polys_cap *= 2;
|
||||
}
|
||||
polys[*polys_len] = i;
|
||||
*polys_len = *polys_len + 1;
|
||||
}
|
||||
}
|
||||
|
||||
polys = resize_poly_list(polys, *polys_len);
|
||||
*polys_dest = polys;
|
||||
free(poly);
|
||||
free(msg_cmp);
|
||||
free(encoded);
|
||||
free(encoded_bits);
|
||||
}
|
||||
|
||||
// we choose 2 bytes because we need a payload that's longer than
|
||||
// the shift register under test. since that includes an order 15
|
||||
// s.r., we need at least 15 bits.
|
||||
size_t msg_len = 2;
|
||||
|
||||
void find_poly(size_t rate, size_t order, libfec_decoder_t libfec, correct_convolutional_polynomial_t *poly) {
|
||||
// find the complete set of coefficients that are "baked in" to
|
||||
// one particular method of libfec
|
||||
// most of this method is described by find_poly_coeff
|
||||
|
||||
// for each coeff we want to find, we'll generate random 2-byte payloads and give
|
||||
// them to find_poly_coeff. If find_poly_coeff returns an empty list, we
|
||||
// try again. If it returns a nonempty list, then we find the intersection of
|
||||
// all the coefficient values find_poly_coeff has given us so far (we start
|
||||
// with the complete set). we are finished when only one coeff value remains
|
||||
|
||||
// we perform this process for each coeff e.g. 6 times for a rate 1/6 polynomial
|
||||
|
||||
uint8_t msg[msg_len];
|
||||
|
||||
// this is the list returned to us by find_poly_coeff
|
||||
correct_convolutional_polynomial_t *polys;
|
||||
// the list's length is written here
|
||||
size_t polys_len;
|
||||
|
||||
printf("rate 1/%zu order %zu poly:", rate, order);
|
||||
|
||||
for (size_t search_coeff = 0; search_coeff < rate; search_coeff++) {
|
||||
correct_convolutional_polynomial_t *fit = NULL;
|
||||
size_t fit_len = 0;
|
||||
size_t fit_cap = 0;
|
||||
bool done = false;
|
||||
|
||||
while (!done) {
|
||||
for (size_t i = 0; i < msg_len; i++) {
|
||||
msg[i] = rand() % 256;
|
||||
}
|
||||
find_poly_coeff(rate, order, msg, msg_len, libfec, &polys, &polys_len, search_coeff);
|
||||
|
||||
if (polys_len == 0) {
|
||||
// skip if none fit (this is a special case)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fit_len == 0) {
|
||||
// the very first intersection
|
||||
// we'll just copy the list handed to us
|
||||
fit_cap = polys_len;
|
||||
fit_len = polys_len;
|
||||
fit = resize_poly_list(fit, fit_cap);
|
||||
for (size_t i = 0; i < polys_len; i++) {
|
||||
fit[i] = polys[i];
|
||||
}
|
||||
} else {
|
||||
// find intersection
|
||||
ptrdiff_t polys_iter = 0;
|
||||
ptrdiff_t fit_iter = 0;
|
||||
ptrdiff_t new_fit_iter = 0;
|
||||
// the lists generated by find_poly_coeff are sorted
|
||||
// so we just retain the sorted property and walk both
|
||||
while (polys_iter < polys_len && fit_iter < fit_len) {
|
||||
if (polys[polys_iter] < fit[fit_iter]) {
|
||||
polys_iter++;
|
||||
} else if (polys[polys_iter] > fit[fit_iter]) {
|
||||
fit_iter++;
|
||||
} else {
|
||||
fit[new_fit_iter] = fit[fit_iter];
|
||||
polys_iter++;
|
||||
fit_iter++;
|
||||
new_fit_iter++;
|
||||
}
|
||||
}
|
||||
// if new_fit_iter is 0 here then we don't intersect at all
|
||||
// in this case we have to restart the search for this coeff
|
||||
if (new_fit_iter != 0) {
|
||||
fit_len = new_fit_iter;
|
||||
} else {
|
||||
free(fit);
|
||||
fit = NULL;
|
||||
fit_cap = 0;
|
||||
fit_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
free(polys);
|
||||
|
||||
if (fit_len == 1) {
|
||||
poly[search_coeff] = fit[0];
|
||||
if (order <= 9) {
|
||||
printf(" %04o", fit[0]);
|
||||
} else {
|
||||
printf(" %06o", fit[0]);
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
free(fit);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main() {
|
||||
libfec_decoder_t libfec;
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
correct_convolutional_polynomial_t poly[6];
|
||||
|
||||
libfec.vit = create_viterbi27(8 * msg_len);
|
||||
libfec.update_len = 8 * msg_len + 6;
|
||||
libfec.init = init_viterbi27;
|
||||
libfec.update = update_viterbi27_blk;
|
||||
libfec.chainback = chainback_viterbi27;
|
||||
find_poly(2, 7, libfec, poly);
|
||||
delete_viterbi27(libfec.vit);
|
||||
|
||||
libfec.vit = create_viterbi29(8 * msg_len);
|
||||
libfec.update_len = 8 * msg_len + 8;
|
||||
libfec.init = init_viterbi29;
|
||||
libfec.update = update_viterbi29_blk;
|
||||
libfec.chainback = chainback_viterbi29;
|
||||
find_poly(2, 9, libfec, poly);
|
||||
delete_viterbi29(libfec.vit);
|
||||
|
||||
libfec.vit = create_viterbi39(8 * msg_len);
|
||||
libfec.update_len = 8 * msg_len + 8;
|
||||
libfec.init = init_viterbi39;
|
||||
libfec.update = update_viterbi39_blk;
|
||||
libfec.chainback = chainback_viterbi39;
|
||||
find_poly(3, 9, libfec, poly);
|
||||
delete_viterbi39(libfec.vit);
|
||||
|
||||
libfec.vit = create_viterbi615(8 * msg_len);
|
||||
libfec.update_len = 8 * msg_len + 14;
|
||||
libfec.init = init_viterbi615;
|
||||
libfec.update = update_viterbi615_blk;
|
||||
libfec.chainback = chainback_viterbi615;
|
||||
find_poly(6, 15, libfec, poly);
|
||||
delete_viterbi615(libfec.vit);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,330 @@
|
|||
#include <stdbool.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#if HAVE_SSE
|
||||
#include "correct/util/error-sim-sse.h"
|
||||
typedef correct_convolutional_sse conv_t;
|
||||
static conv_t*(*conv_create)(size_t, size_t, const uint16_t *) = correct_convolutional_sse_create;
|
||||
static void(*conv_destroy)(conv_t *) = correct_convolutional_sse_destroy;
|
||||
static size_t(*conv_enclen)(void *, size_t) = conv_correct_sse_enclen;
|
||||
static void(*conv_encode)(void *, uint8_t *, size_t, uint8_t *) = conv_correct_sse_encode;
|
||||
static void(*conv_decode)(void *, uint8_t *, size_t, uint8_t *) = conv_correct_sse_decode;
|
||||
#else
|
||||
#include "correct/util/error-sim.h"
|
||||
typedef correct_convolutional conv_t;
|
||||
static conv_t*(*conv_create)(size_t, size_t, const uint16_t *) = correct_convolutional_create;
|
||||
static void(*conv_destroy)(conv_t *) = correct_convolutional_destroy;
|
||||
static size_t(*conv_enclen)(void *, size_t) = conv_correct_enclen;
|
||||
static void(*conv_encode)(void *, uint8_t *, size_t, uint8_t *) = conv_correct_encode;
|
||||
static void(*conv_decode)(void *, uint8_t *, size_t, uint8_t *) = conv_correct_decode;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
conv_t *conv;
|
||||
correct_convolutional_polynomial_t *poly;
|
||||
} conv_tester_t;
|
||||
|
||||
typedef struct {
|
||||
int *distances;
|
||||
float cost;
|
||||
correct_convolutional_polynomial_t *poly;
|
||||
} conv_result_t;
|
||||
|
||||
int compare_conv_results(const void *avoid, const void *bvoid) {
|
||||
const conv_result_t *a = (const conv_result_t *)avoid;
|
||||
const conv_result_t *b = (const conv_result_t *)bvoid;
|
||||
|
||||
if (a->cost > b->cost) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
size_t rate;
|
||||
size_t order;
|
||||
conv_result_t *items;
|
||||
size_t items_len;
|
||||
conv_testbench *scratch;
|
||||
uint8_t *msg;
|
||||
size_t msg_len;
|
||||
size_t test_offset;
|
||||
double bpsk_voltage;
|
||||
} exhaustive_thread_args;
|
||||
|
||||
void *search_exhaustive_thread(void *vargs) {
|
||||
exhaustive_thread_args *args = (exhaustive_thread_args *)vargs;
|
||||
conv_t *conv;
|
||||
for (size_t i = 0; i < args->items_len; i++) {
|
||||
conv = conv_create(args->rate, args->order, args->items[i].poly);
|
||||
args->scratch->encode = conv_encode;
|
||||
args->scratch->encoder = conv;
|
||||
args->scratch->decode = conv_decode;
|
||||
args->scratch->decoder = conv;
|
||||
args->items[i].distances[args->test_offset] += test_conv_noise(args->scratch, args->msg, args->msg_len, args->bpsk_voltage);
|
||||
conv_destroy(conv);
|
||||
}
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
void search_exhaustive(size_t rate, size_t order,
|
||||
size_t n_bytes, uint8_t *msg,
|
||||
conv_testbench **scratches, size_t num_scratches,
|
||||
float *weights,
|
||||
conv_result_t *items,
|
||||
size_t items_len, double bpsk_voltage) {
|
||||
|
||||
exhaustive_thread_args *args = malloc(num_scratches * sizeof(exhaustive_thread_args));
|
||||
pthread_t *threads = malloc(num_scratches * sizeof(pthread_t));
|
||||
|
||||
for (size_t i = 0; i < num_scratches; i++) {
|
||||
args[i].rate = rate;
|
||||
args[i].order = order;
|
||||
args[i].items = items;
|
||||
args[i].items_len = items_len;
|
||||
args[i].scratch = scratches[i];
|
||||
args[i].msg = msg;
|
||||
args[i].msg_len = n_bytes;
|
||||
args[i].test_offset = i;
|
||||
args[i].bpsk_voltage = bpsk_voltage;
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
pthread_create(&threads[i], &attr, search_exhaustive_thread, &args[i]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_scratches; i++) {
|
||||
pthread_join(threads[i], NULL);
|
||||
}
|
||||
|
||||
free(args);
|
||||
free(threads);
|
||||
|
||||
}
|
||||
|
||||
void search_exhaustive_init(conv_result_t *items, size_t items_len,
|
||||
size_t num_scratches) {
|
||||
for (size_t i = 0; i < items_len; i++) {
|
||||
for (size_t j = 0; j < num_scratches; j++) {
|
||||
items[i].distances[j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void search_exhaustive_fin(conv_result_t *items, size_t items_len,
|
||||
float *weights, size_t weights_len) {
|
||||
for (size_t i = 0; i < items_len; i++) {
|
||||
items[i].cost = 0;
|
||||
for (size_t j = 0; j < weights_len; j++) {
|
||||
items[i].cost += weights[j] * items[i].distances[j];
|
||||
}
|
||||
}
|
||||
|
||||
qsort(items, items_len, sizeof(conv_result_t), compare_conv_results);
|
||||
}
|
||||
|
||||
const size_t max_block_len = 16384;
|
||||
const size_t max_msg_len = 50000000;
|
||||
|
||||
void test(size_t rate, size_t order,
|
||||
conv_tester_t start, conv_testbench **scratches,
|
||||
size_t num_scratches, float *weights,
|
||||
size_t n_bytes, double *eb_n0,
|
||||
double bpsk_bit_energy, size_t n_iter,
|
||||
double bpsk_voltage) {
|
||||
|
||||
uint8_t *msg = malloc(max_block_len * sizeof(uint8_t));
|
||||
|
||||
correct_convolutional_polynomial_t maxcoeff = (1 << order) - 1;
|
||||
correct_convolutional_polynomial_t startcoeff = (1 << (order - 1)) + 1;
|
||||
size_t num_polys = (maxcoeff - startcoeff) / 2 + 1;
|
||||
size_t convs_len = 1;
|
||||
for (size_t i = 0; i < rate; i++) {
|
||||
convs_len *= num_polys;
|
||||
}
|
||||
|
||||
conv_result_t *exhaustive = malloc(convs_len * sizeof(conv_result_t));
|
||||
correct_convolutional_polynomial_t *iter_poly = malloc(rate * sizeof(correct_convolutional_polynomial_t));
|
||||
|
||||
for (size_t i = 0; i < rate; i++) {
|
||||
iter_poly[i] = startcoeff;
|
||||
}
|
||||
|
||||
// init exhaustive with all polys
|
||||
for (size_t i = 0; i < convs_len; i++) {
|
||||
exhaustive[i].poly = malloc(rate * sizeof(correct_convolutional_polynomial_t));
|
||||
exhaustive[i].distances = calloc(num_scratches, sizeof(int));
|
||||
exhaustive[i].cost = 0;
|
||||
memcpy(exhaustive[i].poly, iter_poly, rate * sizeof(correct_convolutional_polynomial_t));
|
||||
// this next loop adds 2 with "carry"
|
||||
for (size_t j = 0; j < rate; j++) {
|
||||
if (iter_poly[j] < maxcoeff) {
|
||||
iter_poly[j] += 2;
|
||||
// no more carries to propagate
|
||||
break;
|
||||
} else {
|
||||
iter_poly[j] = startcoeff;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(iter_poly);
|
||||
|
||||
while (convs_len > 20) {
|
||||
size_t bytes_remaining = n_bytes;
|
||||
|
||||
// call init(), which sets all the error metrics to 0 for our new run
|
||||
search_exhaustive_init(exhaustive, convs_len, num_scratches);
|
||||
|
||||
while (bytes_remaining) {
|
||||
// in order to keep memory usage constant, we separate the msg into
|
||||
// blocks and send each one through
|
||||
// each time we do this, we have to calculate a new noise for each
|
||||
// testbench
|
||||
|
||||
size_t block_len = (max_block_len < bytes_remaining) ? max_block_len : bytes_remaining;
|
||||
bytes_remaining -= block_len;
|
||||
|
||||
for (unsigned int j = 0; j < block_len; j++) {
|
||||
msg[j] = rand() % 256;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_scratches; i++) {
|
||||
scratches[i] = resize_conv_testbench(scratches[i], conv_enclen, start.conv, block_len);
|
||||
build_white_noise(scratches[i]->noise, scratches[i]->enclen, eb_n0[i], bpsk_bit_energy);
|
||||
}
|
||||
|
||||
search_exhaustive(rate, order,
|
||||
block_len, msg, scratches, num_scratches, weights,
|
||||
exhaustive, convs_len, bpsk_voltage);
|
||||
}
|
||||
|
||||
// call fin(), which calculates a cost metric for all of the distances
|
||||
// added by our msg block iterations and then sorts by this metric
|
||||
search_exhaustive_fin(exhaustive, convs_len, weights, num_scratches);
|
||||
|
||||
// decide parameters for next loop iter
|
||||
// if we've reduced to 20 or fewer items, we're going to just select
|
||||
// those and declare the test done
|
||||
size_t new_convs_len = (convs_len / 2) < 20 ? 20 : convs_len / 2;
|
||||
|
||||
// normally we'll double the message length each time we halve
|
||||
// the number of entries so that each iter takes roughly the
|
||||
// same time but has twice the resolution of the previous run.
|
||||
//
|
||||
// however, if we've reached max_msg_len, then we assume that
|
||||
// the error stats collected are likely converged to whatever
|
||||
// final value they'll take, and adding more length will not
|
||||
// help us get better metrics. if we're at that point, then
|
||||
// we just select the top 20 items and declare them winners
|
||||
if (n_bytes >= max_msg_len) {
|
||||
// converged case
|
||||
new_convs_len = 20;
|
||||
} else {
|
||||
// increase our error metric resolution next run
|
||||
n_bytes *= 2;
|
||||
n_bytes = (n_bytes < max_msg_len) ? n_bytes : max_msg_len;
|
||||
}
|
||||
for (size_t i = new_convs_len; i < convs_len; i++) {
|
||||
// these entries lost, free their memory here
|
||||
free(exhaustive[i].poly);
|
||||
free(exhaustive[i].distances);
|
||||
}
|
||||
convs_len = new_convs_len;
|
||||
printf("exhaustive run: %zu items remain\n", convs_len);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < convs_len; i++) {
|
||||
for (size_t j = 0; j < rate; j++) {
|
||||
printf(" %06o", exhaustive[i].poly[j]);
|
||||
}
|
||||
printf(":");
|
||||
for (size_t j = 0; j < num_scratches; j++) {
|
||||
printf(" %.2e@%.1fdB", exhaustive[i].distances[j]/((float)n_bytes * 8), eb_n0[j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < convs_len; i++) {
|
||||
free(exhaustive[i].poly);
|
||||
free(exhaustive[i].distances);
|
||||
}
|
||||
free(exhaustive);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
srand(time(NULL));
|
||||
|
||||
size_t rate, order, n_bytes, n_iter;
|
||||
|
||||
sscanf(argv[1], "%zu", &rate);
|
||||
sscanf(argv[2], "%zu", &order);
|
||||
sscanf(argv[3], "%zu", &n_bytes);
|
||||
sscanf(argv[4], "%zu", &n_iter);
|
||||
|
||||
double bpsk_voltage = 1.0/sqrt(2.0);
|
||||
double bpsk_sym_energy = 2*pow(bpsk_voltage, 2.0);
|
||||
double bpsk_bit_energy = bpsk_sym_energy/1.0;
|
||||
|
||||
bpsk_bit_energy = bpsk_sym_energy * rate; // rate bits transmitted for every input bit
|
||||
|
||||
correct_convolutional_polynomial_t maxcoeff = (1 << order) - 1;
|
||||
correct_convolutional_polynomial_t startcoeff = (1 << (order - 1)) + 1;
|
||||
|
||||
conv_tester_t start;
|
||||
|
||||
start.poly = malloc(rate * sizeof(correct_convolutional_polynomial_t));
|
||||
|
||||
for (size_t i = 0; i < rate; i++) {
|
||||
start.poly[i] = ((maxcoeff - startcoeff) / 2) + startcoeff + 1;
|
||||
}
|
||||
|
||||
start.conv = conv_create(rate, order, start.poly);
|
||||
|
||||
size_t num_scratches = 4;
|
||||
float *weights;
|
||||
conv_testbench **scratches = malloc(num_scratches * sizeof(conv_testbench *));
|
||||
double *eb_n0;
|
||||
|
||||
for (size_t i = 0; i < num_scratches; i++) {
|
||||
scratches[i] = resize_conv_testbench(NULL, conv_enclen, start.conv, max_block_len);
|
||||
}
|
||||
|
||||
switch (order) {
|
||||
case 6:
|
||||
eb_n0 = (double[]){6.0, 5.5, 5.0, 4.5};
|
||||
weights = (float[]){8000, 400, 20, 1};
|
||||
break;
|
||||
case 7:
|
||||
eb_n0 = (double[]){5.5, 5.0, 4.5, 4.0};
|
||||
weights = (float[]){8000, 400, 20, 1};
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
eb_n0 = (double[]){5.0, 4.5, 4.0, 3.5};
|
||||
weights = (float[]){8000, 400, 20, 1};
|
||||
break;
|
||||
default:
|
||||
eb_n0 = (double[]){4.5, 4.0, 3.5, 3.0};
|
||||
weights = (float[]){8000, 400, 20, 1};
|
||||
}
|
||||
|
||||
test(rate, order, start, scratches, num_scratches, weights, n_bytes, eb_n0, bpsk_bit_energy, n_iter, bpsk_voltage);
|
||||
|
||||
free(start.poly);
|
||||
conv_destroy(start.conv);
|
||||
for (size_t i = 0; i < num_scratches; i++) {
|
||||
free_scratch(scratches[i]);
|
||||
}
|
||||
free(scratches);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,350 @@
|
|||
#include <stdbool.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
#if HAVE_SSE
|
||||
#include "correct/util/error-sim-sse.h"
|
||||
typedef correct_convolutional_sse conv_t;
|
||||
static conv_t*(*conv_create)(size_t, size_t, const uint16_t *) = correct_convolutional_sse_create;
|
||||
static void(*conv_destroy)(conv_t *) = correct_convolutional_sse_destroy;
|
||||
static size_t(*conv_enclen)(void *, size_t) = conv_correct_sse_enclen;
|
||||
static void(*conv_encode)(void *, uint8_t *, size_t, uint8_t *) = conv_correct_sse_encode;
|
||||
static void(*conv_decode)(void *, uint8_t *, size_t, uint8_t *) = conv_correct_sse_decode;
|
||||
#else
|
||||
#include "correct/util/error-sim.h"
|
||||
typedef correct_convolutional conv_t;
|
||||
static conv_t*(*conv_create)(size_t, size_t, const uint16_t *) = correct_convolutional_create;
|
||||
static void(*conv_destroy)(conv_t *) = correct_convolutional_destroy;
|
||||
static size_t(*conv_enclen)(void *, size_t) = conv_correct_enclen;
|
||||
static void(*conv_encode)(void *, uint8_t *, size_t, uint8_t *) = conv_correct_encode;
|
||||
static void(*conv_decode)(void *, uint8_t *, size_t, uint8_t *) = conv_correct_decode;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
conv_t *conv;
|
||||
correct_convolutional_polynomial_t *poly;
|
||||
} conv_tester_t;
|
||||
|
||||
void shuffle(int *a, size_t len) {
|
||||
for (size_t i = 0; i < len - 2; i++) {
|
||||
size_t j = rand() % (len - i) + i;
|
||||
int temp = a[i];
|
||||
a[i] = a[j];
|
||||
a[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
int rand_geo(float p, int max) {
|
||||
int geo = 1;
|
||||
while (geo < max) {
|
||||
if (rand() / (float)RAND_MAX > p) {
|
||||
geo++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return geo;
|
||||
}
|
||||
|
||||
void next_neighbor(correct_convolutional_polynomial_t *start,
|
||||
correct_convolutional_polynomial_t *neighbor, size_t rate, size_t order) {
|
||||
int coeffs[rate * (order - 2)];
|
||||
for (int i = 0; i < rate * (order - 2); i++) {
|
||||
coeffs[i] = i;
|
||||
}
|
||||
shuffle(coeffs, rate * (order - 2));
|
||||
|
||||
memcpy(neighbor, start, rate * sizeof(correct_convolutional_polynomial_t));
|
||||
size_t nflips = rand_geo(0.4, rate * (order - 2));
|
||||
for (int i = 0; i < nflips; i++) {
|
||||
ptrdiff_t index = coeffs[i] / (order - 2);
|
||||
// decide which bit to flip
|
||||
// we avoid the edge bits to prevent creating a degenerate poly
|
||||
neighbor[index] ^= 1 << (coeffs[i] % (order - 2) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool accept(float cost_a, float cost_b, double temperature) {
|
||||
if (cost_b < cost_a) {
|
||||
return true;
|
||||
}
|
||||
|
||||
float p = (float)(rand()) / (float)(RAND_MAX);
|
||||
|
||||
return exp((cost_a - cost_b) / (cost_a * temperature)) > p;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
size_t rate;
|
||||
size_t order;
|
||||
correct_convolutional_polynomial_t *poly;
|
||||
unsigned int distance;
|
||||
conv_testbench *scratch;
|
||||
size_t msg_len;
|
||||
double eb_n0;
|
||||
double bpsk_voltage;
|
||||
double bpsk_bit_energy;
|
||||
} thread_args;
|
||||
|
||||
const size_t max_block_len = 16384;
|
||||
|
||||
void *find_cost_thread(void *vargs) {
|
||||
thread_args *args = (thread_args *)vargs;
|
||||
conv_t *conv;
|
||||
uint8_t *msg = malloc(max_block_len);
|
||||
|
||||
conv = conv_create(args->rate, args->order, args->poly);
|
||||
args->distance = 0;
|
||||
conv_testbench *scratch = args->scratch;
|
||||
|
||||
size_t bytes_remaining = args->msg_len;
|
||||
while (bytes_remaining) {
|
||||
// in order to keep memory usage constant, we separate the msg into
|
||||
// blocks and send each one through
|
||||
// each time we do this, we have to calculate a new noise for each
|
||||
// testbench
|
||||
size_t block_len = (max_block_len < bytes_remaining) ? max_block_len : bytes_remaining;
|
||||
bytes_remaining -= block_len;
|
||||
|
||||
for (unsigned int j = 0; j < block_len; j++) {
|
||||
msg[j] = rand() % 256;
|
||||
}
|
||||
|
||||
scratch = resize_conv_testbench(scratch, conv_enclen, conv, block_len);
|
||||
scratch->encode = conv_encode;
|
||||
scratch->encoder = conv;
|
||||
scratch->decode = conv_decode;
|
||||
scratch->decoder = conv;
|
||||
|
||||
build_white_noise(scratch->noise, scratch->enclen, args->eb_n0, args->bpsk_bit_energy);
|
||||
|
||||
args->distance += test_conv_noise(scratch, msg, block_len, args->bpsk_voltage);
|
||||
}
|
||||
conv_destroy(conv);
|
||||
free(msg);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
float find_cost(size_t rate, size_t order, correct_convolutional_polynomial_t *poly, size_t msg_len,
|
||||
conv_testbench **scratches, size_t num_scratches, float *weights, double *eb_n0,
|
||||
double bpsk_voltage, double bpsk_bit_energy) {
|
||||
thread_args *args = malloc(num_scratches * sizeof(thread_args));
|
||||
pthread_t *threads = malloc(num_scratches * sizeof(pthread_t));
|
||||
|
||||
for (size_t i = 0; i < num_scratches; i++) {
|
||||
args[i].rate = rate;
|
||||
args[i].order = order;
|
||||
args[i].poly = poly;
|
||||
args[i].scratch = scratches[i];
|
||||
args[i].msg_len = msg_len;
|
||||
args[i].eb_n0 = eb_n0[i];
|
||||
args[i].bpsk_voltage = bpsk_voltage;
|
||||
args[i].bpsk_bit_energy = bpsk_bit_energy;
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
pthread_create(&threads[i], &attr, find_cost_thread, &args[i]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_scratches; i++) {
|
||||
pthread_join(threads[i], NULL);
|
||||
}
|
||||
|
||||
float cost = 0;
|
||||
printf("poly:");
|
||||
for (size_t i = 0; i < rate; i++) {
|
||||
printf(" %06o", poly[i]);
|
||||
}
|
||||
printf(" error:");
|
||||
for (size_t i = 0; i < num_scratches; i++) {
|
||||
cost += weights[i] * args[i].distance;
|
||||
printf(" %.2e@%.1fdB", (args[i].distance / (float)(msg_len * 8)), eb_n0[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
free(args);
|
||||
free(threads);
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
static bool terminated = false;
|
||||
|
||||
void sig_handler(int sig) {
|
||||
if (sig == SIGINT || sig == SIGTERM || sig == SIGHUP) {
|
||||
if (!terminated) {
|
||||
terminated = true;
|
||||
printf("terminating after current poly\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void search_simulated_annealing(size_t rate, size_t order, size_t n_steps, conv_tester_t *start,
|
||||
size_t n_bytes, conv_testbench **scratches, size_t num_scratches,
|
||||
float *weights, double start_temperature, double cooling_factor,
|
||||
double *eb_n0, double bpsk_voltage, double bpsk_bit_energy) {
|
||||
// perform simulated annealing to find the optimal polynomial
|
||||
|
||||
float cost = find_cost(rate, order, start->poly, n_bytes, scratches, num_scratches, weights,
|
||||
eb_n0, bpsk_voltage, bpsk_bit_energy);
|
||||
|
||||
correct_convolutional_polynomial_t *neighbor_poly =
|
||||
malloc(rate * sizeof(correct_convolutional_polynomial_t));
|
||||
|
||||
correct_convolutional_polynomial_t *state =
|
||||
malloc(rate * sizeof(correct_convolutional_polynomial_t));
|
||||
correct_convolutional_polynomial_t *best =
|
||||
malloc(rate * sizeof(correct_convolutional_polynomial_t));
|
||||
|
||||
float best_cost = cost;
|
||||
|
||||
memcpy(state, start->poly, rate * sizeof(correct_convolutional_polynomial_t));
|
||||
memcpy(best, start->poly, rate * sizeof(correct_convolutional_polynomial_t));
|
||||
|
||||
double temperature = start_temperature;
|
||||
|
||||
for (size_t i = 0; i < n_steps; i++) {
|
||||
next_neighbor(state, neighbor_poly, rate, order);
|
||||
float neighbor_cost =
|
||||
find_cost(rate, order, neighbor_poly, n_bytes, scratches, num_scratches, weights, eb_n0,
|
||||
bpsk_voltage, bpsk_bit_energy);
|
||||
if (accept(cost, neighbor_cost, temperature)) {
|
||||
// we're moving to our neighbor's house
|
||||
memcpy(state, neighbor_poly, rate * sizeof(correct_convolutional_polynomial_t));
|
||||
cost = neighbor_cost;
|
||||
} else {
|
||||
// actually where we live now is nice
|
||||
}
|
||||
|
||||
if (cost < best_cost) {
|
||||
best_cost = cost;
|
||||
memcpy(best, state, rate * sizeof(correct_convolutional_polynomial_t));
|
||||
}
|
||||
|
||||
temperature *= cooling_factor;
|
||||
|
||||
if (terminated) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("last state:");
|
||||
for (size_t i = 0; i < rate; i++) {
|
||||
printf(" %06o", state[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("best state:");
|
||||
for (size_t i = 0; i < rate; i++) {
|
||||
printf(" %06o", best[i]);
|
||||
}
|
||||
|
||||
memcpy(start->poly, best, rate * sizeof(correct_convolutional_polynomial_t));
|
||||
|
||||
free(state);
|
||||
free(best);
|
||||
free(neighbor_poly);
|
||||
}
|
||||
|
||||
void test_sa(size_t rate, size_t order, conv_tester_t start, conv_testbench **scratches,
|
||||
size_t num_scratches, float *weights, size_t n_bytes, double *eb_n0,
|
||||
double bpsk_bit_energy, size_t n_iter, double bpsk_voltage) {
|
||||
for (size_t i = 0; i < n_iter; i++) {
|
||||
double temperature = (i == 0) ? 0.5 : 250;
|
||||
double cooling_factor = (i == 0) ? 0.985 : 0.95;
|
||||
size_t n_steps = (i == 0) ? 500 : 100;
|
||||
|
||||
search_simulated_annealing(rate, order, n_steps, &start, n_bytes, scratches, num_scratches,
|
||||
weights, temperature, cooling_factor, eb_n0, bpsk_voltage,
|
||||
bpsk_bit_energy);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
srand(time(NULL));
|
||||
|
||||
signal(SIGINT, sig_handler);
|
||||
signal(SIGTERM, sig_handler);
|
||||
signal(SIGHUP, sig_handler);
|
||||
|
||||
size_t rate, order, n_bytes, n_iter;
|
||||
|
||||
sscanf(argv[1], "%zu", &rate);
|
||||
sscanf(argv[2], "%zu", &order);
|
||||
sscanf(argv[3], "%zu", &n_bytes);
|
||||
sscanf(argv[4], "%zu", &n_iter);
|
||||
|
||||
double bpsk_voltage = 1.0 / sqrt(2.0);
|
||||
double bpsk_sym_energy = 2 * pow(bpsk_voltage, 2.0);
|
||||
double bpsk_bit_energy = bpsk_sym_energy / 1.0;
|
||||
|
||||
bpsk_bit_energy = bpsk_sym_energy * rate; // rate bits transmitted for every input bit
|
||||
|
||||
// correct_convolutional_polynomial_t maxcoeff = (1 << order) - 1;
|
||||
correct_convolutional_polynomial_t startcoeff = (1 << (order - 1)) + 1;
|
||||
|
||||
conv_tester_t start;
|
||||
|
||||
start.poly = malloc(rate * sizeof(correct_convolutional_polynomial_t));
|
||||
|
||||
for (size_t i = 0; i < rate; i++) {
|
||||
start.poly[i] = ((rand() % (1 << (order - 2))) << 1) + startcoeff;
|
||||
}
|
||||
|
||||
start.conv = conv_create(rate, order, start.poly);
|
||||
|
||||
size_t num_scratches = 4;
|
||||
float *weights;
|
||||
conv_testbench **scratches = malloc(num_scratches * sizeof(conv_testbench *));
|
||||
double *eb_n0;
|
||||
|
||||
for (size_t i = 0; i < num_scratches; i++) {
|
||||
scratches[i] = resize_conv_testbench(NULL, conv_enclen, start.conv, max_block_len);
|
||||
}
|
||||
|
||||
switch (order) {
|
||||
case 6:
|
||||
eb_n0 = (double[]){6.0, 5.5, 5.0, 4.5};
|
||||
weights = (float[]){8000, 400, 20, 1};
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
eb_n0 = (double[]){5.5, 5.0, 4.5, 4.0};
|
||||
weights = (float[]){8000, 400, 20, 1};
|
||||
break;
|
||||
case 9:
|
||||
case 10:
|
||||
eb_n0 = (double[]){5.0, 4.5, 4.0, 3.5};
|
||||
weights = (float[]){8000, 400, 20, 1};
|
||||
break;
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
eb_n0 = (double[]){4.5, 4.0, 3.5, 3.0};
|
||||
weights = (float[]){8000, 400, 20, 1};
|
||||
break;
|
||||
default:
|
||||
eb_n0 = (double[]){3.5, 3.0, 2.5, 2.0};
|
||||
weights = (float[]){8000, 400, 20, 1};
|
||||
}
|
||||
|
||||
test_sa(rate, order, start, scratches, num_scratches, weights, n_bytes, eb_n0, bpsk_bit_energy,
|
||||
n_iter, bpsk_voltage);
|
||||
|
||||
free(start.poly);
|
||||
conv_destroy(start.conv);
|
||||
for (size_t i = 0; i < num_scratches; i++) {
|
||||
free_scratch(scratches[i]);
|
||||
}
|
||||
free(scratches);
|
||||
|
||||
return 0;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Ładowanie…
Reference in New Issue