Compare commits
983 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| afb2d86560 | |||
| d1bed1f9dc | |||
| 0865041adb | |||
| 0dcba3c680 | |||
| 2e3025a07c | |||
| 20e1d81386 | |||
| e1b3711d88 | |||
| 7b38157c6e | |||
| 2528e51d29 | |||
| abdf507c2e | |||
| cb712ef60d | |||
| b3fd84e6c2 | |||
| 6e99ccb07d | |||
| 6ebd36b1aa | |||
| d95a22c873 | |||
| 7f10734457 | |||
| 89786a000c | |||
| cb9a8c12ed | |||
| 3c7931665b | |||
| 7a7e4a0e93 | |||
| 9689a35819 | |||
| 7942f48e75 | |||
| 3ad2328bac | |||
| 7d1f7f23df | |||
| a5a803a83f | |||
| 6422d4ed88 | |||
| f3fcd9ddef | |||
| b47101666a | |||
| 683aaa74cd | |||
| 85317d52a1 | |||
| 6b1aef2c7f | |||
| 5bda82614c | |||
| 6c3527a268 | |||
| 8d9b3c8cd8 | |||
| ab1443ce54 | |||
| a5cfc60e4a | |||
| 61577db82b | |||
| 09cfec8ed0 | |||
| a1d703a7dd | |||
| c3632b1a89 | |||
| 50072ad337 | |||
| ebffde6170 | |||
| b5d98a03fe | |||
| 3cff737064 | |||
| f53a9860c6 | |||
| e8e7a194ca | |||
| cebb6cf0b0 | |||
| 75c5588a76 | |||
| 96f7db2387 | |||
| 6df7d74e2b | |||
| 4cadada18a | |||
| 8df70aab80 | |||
| 2b74737351 | |||
| 47fad215d6 | |||
| 64464f186d | |||
| 0b01a6a664 | |||
| 2f1c75268f | |||
| b0158b3a1e | |||
| b619806d6d | |||
| f6b2f374c4 | |||
| 34c40569bd | |||
| 86178e5788 | |||
| 0eb9b1149d | |||
| b7be159a3b | |||
| 43c0820686 | |||
| a0bd47e39f | |||
| 63b0b477eb | |||
| 7571d806ad | |||
| 6e39214f3b | |||
| f4741c88c5 | |||
| 768f0e0520 | |||
| 71b1d21656 | |||
| 4fcb545ae6 | |||
| a26f484cb4 | |||
| 5b4a2f57b9 | |||
| b51b68de45 | |||
| 61c1455557 | |||
| f3c34ae5bc | |||
| 030c798d5c | |||
| dbaa273b6b | |||
| 16cf07b91f | |||
| 5b5751dea4 | |||
| 56522adddb | |||
| 25753334fc | |||
| 4369ed5e7a | |||
| 4e97a3f1ef | |||
| 8ffe4bbbc5 | |||
| 078a642e1f | |||
| dd1d07cf03 | |||
| 04c7e9c93e | |||
| a0bbadba06 | |||
| 124b2b16ec | |||
| 7b60100d18 | |||
| ea23f27f43 | |||
| 080521625e | |||
| 362a2b51ca | |||
| 06056db521 | |||
| 5d9fae0bc8 | |||
| 6227d8f19e | |||
| 182aea5ef6 | |||
| 04abf6780c | |||
| 78c750445f | |||
| 9e0ee49a73 | |||
| 470617b957 | |||
| 93db93ccee | |||
| a3d00a585d | |||
| b4d7d81bf5 | |||
| 293b497909 | |||
| 28945301c5 | |||
| 67ab6689b1 | |||
| 30086f9ce2 | |||
| 2df77e9b82 | |||
| 4475e7c074 | |||
| 9878630ad3 | |||
| 3a6e18e72c | |||
| 3292b80269 | |||
| be4ad6ef3d | |||
| d0c34e1ca5 | |||
| cda10cc2c4 | |||
| 34e8e95df4 | |||
| dce714556e | |||
| ffb4c5d2e0 | |||
| 863c4559dd | |||
| 47357e074a | |||
| 84be5a77d8 | |||
| df2fba6206 | |||
| 0340c23cb8 | |||
| 501b97098a | |||
| 72e0ce885f | |||
| aae495062c | |||
| 99c3fc1054 | |||
| b1c9fe13a8 | |||
| effd281be1 | |||
| 578b26d4d3 | |||
| ae0baa3d3c | |||
| f42d952020 | |||
| 5f0bcf0835 | |||
| 71e368d8f0 | |||
| b2aa871a0d | |||
| 0b27b371d7 | |||
| 144f71303d | |||
| f6259800d0 | |||
| 84c0382226 | |||
| 3a82c6dedb | |||
| b85d22ecb8 | |||
| a3071a966e | |||
| 2065aea794 | |||
| 73826cdbbf | |||
| 7c0680bc9a | |||
| 138a224675 | |||
| da3dc260bf | |||
| b28a906a42 | |||
| f4dd914139 | |||
| 37b465570b | |||
| 8f3d576ffa | |||
| dc55df76cf | |||
| 816b783225 | |||
| e4e8de72e4 | |||
| a09bfc136f | |||
| 8064fd1d43 | |||
| 9681b80ffc | |||
| c7077989a8 | |||
| 5f9c792cd3 | |||
| 2b83eaac4a | |||
| fe8674ef6b | |||
| 50414472b9 | |||
| df5b5aea39 | |||
| 9cf815ebd6 | |||
| be091818a6 | |||
| 2012225307 | |||
| dca30b1830 | |||
| dcf3101b17 | |||
| 2598946891 | |||
| 3a2e1e5ea2 | |||
| e95ac4639f | |||
| cd7bd6e99c | |||
| ec8f2dba30 | |||
| 6c1fa1953e | |||
| ac927e63f0 | |||
| e9311cde2d | |||
| 11b6a8eab9 | |||
| 1bd2178753 | |||
| 61b241c1b6 | |||
| b54c232e75 | |||
| 3274e5818c | |||
| c17d27fff5 | |||
| 7b400b7cb8 | |||
| e722f2accb | |||
| d59490c309 | |||
| b5b66f903f | |||
| d31275a873 | |||
| 7aa965eb9c | |||
| bd7795d5be | |||
| 6baabd445b | |||
| 033fd635c6 | |||
| c064fa3472 | |||
| fb614956bc | |||
| 71b53f3455 | |||
| cb393ca5e2 | |||
| 8ef5ceac41 | |||
| 5764e73a84 | |||
| 23a395c231 | |||
| b748811487 | |||
| 9642c2f6eb | |||
| 1d5e21e577 | |||
| b400a21c62 | |||
| 9dc49741e6 | |||
| bde2cb3630 | |||
| 6477fa6d8f | |||
| bd553dc9ed | |||
| 3c933fbb1c | |||
| 9ed18d443f | |||
| d4dcca8fcc | |||
| 0b78fb627e | |||
| 9ebd422aa2 | |||
| 8c21f88ac0 | |||
| dc06b9f6bc | |||
| e9072f6b76 | |||
| 74669077d4 | |||
| 895213c01e | |||
| 18fa309d92 | |||
| 82035de603 | |||
| 2bba3bfe71 | |||
| 0bbc64d382 | |||
| 194d226903 | |||
| 3583857225 | |||
| 2a3e8a69d8 | |||
| 09cc92fbea | |||
| 0b19e19ce7 | |||
| 16dea9fd3e | |||
| 7409b8621b | |||
| 0f5dad4dd5 | |||
| 3561c2541a | |||
| 9a5d12edab | |||
| 9e35258da1 | |||
| bdf6af5ae4 | |||
| 4057179aa5 | |||
| 9e39e461cc | |||
| 927ea7538f | |||
| ddfd11cdf3 | |||
| 555f68c2e7 | |||
| 09adccaa1a | |||
| bbc5d2d202 | |||
| 2e9e366dbb | |||
| 80e29f4c49 | |||
| c5ef8bbb23 | |||
| 16384b5d83 | |||
| 45d4007131 | |||
| 7b957f5cf3 | |||
| 21d8cf97ba | |||
| 6707ba4599 | |||
| bed30d333a | |||
| b0f26b4717 | |||
| 52f14b35d9 | |||
| cc077a9088 | |||
| d0192ab2be | |||
| c6bf211ee4 | |||
| 7aa17844d4 | |||
| 69b5a51646 | |||
| a2c98d2fbb | |||
| fa8097cbf2 | |||
| 7c97574595 | |||
| 32e22372f9 | |||
| 040ff45116 | |||
| 9c6f2d7fa1 | |||
| c27889358e | |||
| 7f96884927 | |||
| 8d7b42a966 | |||
| 0f1f091931 | |||
| a234f60ff5 | |||
| 98a6aaa2ba | |||
| 3d7d7e51fb | |||
| 45c303c81a | |||
| a8c4cfded2 | |||
| f62f367e0a | |||
| 084162b4f3 | |||
| eccb7f6424 | |||
| 7d49d0035b | |||
| 2b1909f441 | |||
| 7725731c54 | |||
| 479df8b469 | |||
| 79aa45a7fa | |||
| 6ee22ab229 | |||
| ebac6de662 | |||
| 2780a4b2fe | |||
| e7cf168eef | |||
| 8b2ac12d42 | |||
| f8dac21700 | |||
| 29a552f870 | |||
| 6f45c82c55 | |||
| 627c0282c9 | |||
| 5e7722b766 | |||
| 5780a8fd78 | |||
| 26692b457b | |||
| 2ff56febb8 | |||
| 0b3d9a7c16 | |||
| f813b9923d | |||
| d3e839c8d0 | |||
| a030f215dd | |||
| 6a15e5373f | |||
| 490243eb11 | |||
| 00e28d3c0e | |||
| cf6f0f6f0b | |||
| 75ed73412d | |||
| 677df3c18e | |||
| 25761039f6 | |||
| 23e2c50300 | |||
| 31f1c7761f | |||
| 415544d012 | |||
| fd7f839342 | |||
| d363f957f5 | |||
| 7f7a694799 | |||
| e67cb385be | |||
| f858fa2234 | |||
| 0d7a486630 | |||
| 350acc3cc3 | |||
| 3407f91aa0 | |||
| 1a96655173 | |||
| d35a8bdea3 | |||
| 419da20ca4 | |||
| cad0d48456 | |||
| fb4160e8e8 | |||
| e1d056486f | |||
| 32a7b50318 | |||
| c7896aeecf | |||
| 74b9446a30 | |||
| c3cb7b78fe | |||
| b50a152dd5 | |||
| edec4149cf | |||
| 2f4863241b | |||
| 03835558fc | |||
| 2ed1b6cf7c | |||
| 1d28f31916 | |||
| 19898e3e0a | |||
| 3ecf8448f0 | |||
| ac80681b77 | |||
| 45ebb29de4 | |||
| 874356694c | |||
| 609a2a7d02 | |||
| 8c336d52fa | |||
| ef94cf1dc1 | |||
| 861bb78be5 | |||
| 48070764e0 | |||
| c8676783d1 | |||
| 5233fc85b8 | |||
| 543021a300 | |||
| 9d93d88a66 | |||
| 2ddc047ac8 | |||
| da0fe00c10 | |||
| afb99946b2 | |||
| 4ab9730ed6 | |||
| 8a56cbd577 | |||
| d1ff86d336 | |||
| 73d9d0ec06 | |||
| 04c95d2fdb | |||
| 577eb6224f | |||
| 8dd10103d6 | |||
| 3dbcd436e8 | |||
| b393976879 | |||
| c19e363025 | |||
| 4525087ce9 | |||
| 15ed4f6d56 | |||
| 7064a9fbcc | |||
| 53df20c005 | |||
| bbfa94151f | |||
| fd4b309e0b | |||
| 2823fe9a12 | |||
| 67b145b22e | |||
| 62dcd6ac5e | |||
| 946f66b128 | |||
| f798bbfcc7 | |||
| 713402b572 | |||
| 415cda6fc9 | |||
| 1156aa24d0 | |||
| 3faa7e10d0 | |||
| b97696624f | |||
| ece41bdd75 | |||
| eddce1d770 | |||
| 4387fef301 | |||
| 39e761b76c | |||
| f330ea8a90 | |||
| 34f0ca5e8f | |||
| e954d87b53 | |||
| 1c7a2194e1 | |||
| af0b55f642 | |||
| bfcc0ffddf | |||
| b280886bca | |||
| 8d3ea37309 | |||
| 3ee37466fd | |||
| 26c4927993 | |||
| 1bd8558eeb | |||
| a93ab235be | |||
| 347a6251e3 | |||
| f8afc40198 | |||
| 681bc82185 | |||
| b4d992f490 | |||
| 13b156402f | |||
| fdcee1ca9f | |||
| 02655d055c | |||
| d8a06158b1 | |||
| 62608cdc7d | |||
| 1b00fd2a9d | |||
| 0ea4b9ed9b | |||
| e85ad43821 | |||
| 1257b50bf4 | |||
| aa9fa1dc84 | |||
| 6ed7c30952 | |||
| 31b9f805ea | |||
| 8da83db1e5 | |||
| 9b6ac82ad8 | |||
| 66cd99bf6b | |||
| a2006940db | |||
| 942ae1847d | |||
| 691d3e6e33 | |||
| 55789db088 | |||
| a006abb94b | |||
| a4e92e8821 | |||
| 7b61185287 | |||
| 210cee96d8 | |||
| 4ff75ae87f | |||
| f13bf76699 | |||
| ddb9fac4e1 | |||
| c259dbc6e0 | |||
| 34891142ac | |||
| cc92c8a229 | |||
| e97cdd00a8 | |||
| 95c035ed73 | |||
| 6113494d08 | |||
| e2f126dd27 | |||
| a476ee53aa | |||
| bf5e5874b4 | |||
| 51b3a0c68f | |||
| e65f72476a | |||
| 9df21ceb6e | |||
| d3d5e6f215 | |||
| a13d17e413 | |||
| baf44c321a | |||
| fbcdcabab5 | |||
| 73c1ed4023 | |||
| 2c47883cc2 | |||
| 8a51682190 | |||
| f1c6333d5f | |||
| 92de1313e7 | |||
| ce7cb7f7e9 | |||
| 4f741dfad2 | |||
| f226cde6fe | |||
| 7eb3eb9ec5 | |||
| ffa012eeb6 | |||
| 94f9eb7a35 | |||
| 6a520f18cf | |||
| de8f9ebac9 | |||
| b14f1f29a9 | |||
| 49aac252d7 | |||
| ed91931184 | |||
| ea76998beb | |||
| f3bfde242b | |||
| f60733b561 | |||
| d47c3cedb4 | |||
| ea7ade197e | |||
| bba0e5e00c | |||
| b1cd632bd4 | |||
| 61b82254d0 | |||
| 3c66454953 | |||
| 85ad25e0e8 | |||
| 131078e3a0 | |||
| a77f00d665 | |||
| eaae858a38 | |||
| cdfdcf6d13 | |||
| 298f41fc76 | |||
| cdab8a4d9e | |||
| d6d3bc0159 | |||
| 9ee8f3613f | |||
| 3b8dd447fa | |||
| b6a97318ec | |||
| 989abd017e | |||
| 71fd6dfa47 | |||
| 8d00e1dc8c | |||
| 34e1075582 | |||
| df5722717a | |||
| 71c5132c57 | |||
| b15ac0f2e1 | |||
| 2296cd5faf | |||
| b50826bc74 | |||
| 409036b6ed | |||
| 5ee3825a50 | |||
| c99dc375e8 | |||
| ca63b92e5b | |||
| 70aa7c6ad8 | |||
| 81c33b6432 | |||
| b76a0a8789 | |||
| ed255ce1c3 | |||
| 3b8d177861 | |||
| 00efc0d571 | |||
| 7bc59784b5 | |||
| 3556d7c0e8 | |||
| b5078c5326 | |||
| 89656d8195 | |||
| 69d3e9be0a | |||
| 94bd8a237d | |||
| e10cbed69f | |||
| 12d675a0a7 | |||
| d2697345e1 | |||
| a8707baf57 | |||
| 5eff34ce8a | |||
| 0bb96a7413 | |||
| db1d3fcb32 | |||
| 3f1d09bc68 | |||
| 39db1b6537 | |||
| c408c30bc1 | |||
| 1e6cfc373e | |||
| a611281a01 | |||
| 6110bbce98 | |||
| d507dbb5dd | |||
| f60d3b80be | |||
| e24a736fc9 | |||
| e916c6dc9a | |||
| 3540015132 | |||
| 4909d176ec | |||
| 2001c0d408 | |||
| 1383afb36f | |||
| 9904d6deb0 | |||
| e8d8fc1806 | |||
| 10e6745e21 | |||
| b2713df6bb | |||
| 23aaee9ecf | |||
| 1fec7a7c51 | |||
| 25c02b96f3 | |||
| 8e39de0368 | |||
| 7806382d8e | |||
| 96afa57d84 | |||
| caaba0ab3f | |||
| 5dd365238e | |||
| e6aea64689 | |||
| 86b48d8258 | |||
| 4880497db5 | |||
| d253c3163b | |||
| 961c1d60e0 | |||
| aa5d8c4ba7 | |||
| c80f0da4ac | |||
| 9c7cfe9252 | |||
| a5b44fa877 | |||
| fdedcf4de0 | |||
| 8530cce10a | |||
| c75d873b91 | |||
| cbf60380f2 | |||
| e76d1d0c3d | |||
| d831b0f55e | |||
| 4300e4b022 | |||
| ca3093e07e | |||
| 47cfd7da98 | |||
| 8e66b32c95 | |||
| 1dd3aadbd8 | |||
| ec49fb9e49 | |||
| 4313d23ba7 | |||
| 5a6f3f04e7 | |||
| aa1493cad0 | |||
| dd632969f3 | |||
| c032b30247 | |||
| ec0c82a4bf | |||
| b07547df75 | |||
| 617cc47231 | |||
| fd68286b2f | |||
| daedeed8d7 | |||
| 337e224ad3 | |||
| 8dda878c62 | |||
| eeaab1268e | |||
| 66ffa18dce | |||
| 5dd0ac75bc | |||
| a236b4c59b | |||
| ff82a575f6 | |||
| 86fb88cdee | |||
| 316a2508a5 | |||
| 63476c03f3 | |||
| 60c8b1b2be | |||
| 988c837011 | |||
| 2869d8574d | |||
| d233fa39bd | |||
| a26879dca8 | |||
| 429d55769c | |||
| 9cbd0b9813 | |||
| 71912cfdbd | |||
| 7db74cb017 | |||
| 2eec091ac0 | |||
| cb19949a82 | |||
| 54e0795e51 | |||
| 1492a346d3 | |||
| 968e7233e5 | |||
| 17b4aa2466 | |||
| 6be0c3f4c6 | |||
| c3b23fcc6e | |||
| af88b60c0e | |||
| 793e971460 | |||
| a9e88c272a | |||
| f76c23d7f7 | |||
| c8205c4cff | |||
| ab9b77fa90 | |||
| 80c2bc7242 | |||
| 4d126dd91a | |||
| 8a30c5d951 | |||
| 817994c47e | |||
| e3ea859592 | |||
| 23f53077cf | |||
| 091bf2fdf0 | |||
| 47dbd0dd3e | |||
| 67585a6fa7 | |||
| 0d9aca84a9 | |||
| a0c2f0bf19 | |||
| bd1c9274b3 | |||
| 812ba76e0d | |||
| 60cf6b8058 | |||
| ee4f8bda88 | |||
| f50f2aefc0 | |||
| 0e7e27edbf | |||
| a2d797310a | |||
| 1de4d86661 | |||
| cd7c075b3b | |||
| 6595bcfc3c | |||
| 60423b81ad | |||
| 6898efcc02 | |||
| 7aca3eb5b7 | |||
| 6f116510da | |||
| ad26e4acba | |||
| 169d03ea9c | |||
| 2de9c62083 | |||
| fd9ecc589e | |||
| d74c6acc0b | |||
| 9bdd0c682d | |||
| f135413b6d | |||
| cebe1d0cb7 | |||
| a3ee869ee9 | |||
| f510650a42 | |||
| add297920a | |||
| 8cc61e5a8a | |||
| d58c660822 | |||
| d460f005c6 | |||
| 13c5387dc9 | |||
| 45804b318a | |||
| 9ffcac744a | |||
| 365554980d | |||
| 702a8cb0c3 | |||
| 0a4ca595ed | |||
| 5302254462 | |||
| 41419b4cee | |||
| 8de53f18e6 | |||
| 777fc58578 | |||
| e2977540d9 | |||
| 0073889d93 | |||
| c11a88f108 | |||
| 14a96e17be | |||
| 2c5b54d7f3 | |||
| 3af2b090e5 | |||
| 9796654816 | |||
| a6afbebc94 | |||
| 487c0de90f | |||
| c19b1a65bf | |||
| cd8f006d31 | |||
| 40c5f0432c | |||
| 6c51026357 | |||
| 806715e166 | |||
| 0e1a6bd60b | |||
| 48f804210c | |||
| a87722b078 | |||
| e3f2664440 | |||
| ce77fbd2ff | |||
| 9612d6e347 | |||
| dd4cc710f2 | |||
| db9420e715 | |||
| f2c82a6262 | |||
| d23dd5b430 | |||
| 6d649279c8 | |||
| 2cd4e6acfa | |||
| b8e9d5542d | |||
| 487bf8bce7 | |||
| 535e41d43e | |||
| adbeb30c8b | |||
| fc9ca545ad | |||
| 3680b93d89 | |||
| dba05e9adf | |||
| ce344bc704 | |||
| 1df88dcb5f | |||
| 3665d2afb4 | |||
| ffb6b1a6fd | |||
| a1de19c105 | |||
| 31073fc0a9 | |||
| 5fefc69eb6 | |||
| f0bea027c1 | |||
| 7ce17c56a2 | |||
| e4fc76503c | |||
| d181050706 | |||
| a93692ee59 | |||
| 88c72e0cb9 | |||
| 7379f6064e | |||
| ea898e5122 | |||
| 842b04627a | |||
| a368d74619 | |||
| 899240d2ac | |||
| 526f460cd4 | |||
| 8e7e036591 | |||
| 993e543162 | |||
| 1b3897a425 | |||
| 2f91eba85d | |||
| 25049d041d | |||
| ae1aff6863 | |||
| 9227edac18 | |||
| f5d61306c9 | |||
| 396b5fb270 | |||
| d2c0b0e0f5 | |||
| 8366d6ec2a | |||
| 0eeb197c81 | |||
| 065c5916b7 | |||
| 0e93a43ab5 | |||
| fd3f2eb1e5 | |||
| 46881aff2e | |||
| db276cecbf | |||
| 0c7add8f8e | |||
| 6896381ab2 | |||
| 56d040ee06 | |||
| 462f6244aa | |||
| 54d430f3c5 | |||
| f2d444e2d5 | |||
| 23e2e3743c | |||
| 2d207b528a | |||
| 843f17e56f | |||
| 9915a1fd3a | |||
| 3334e06ec6 | |||
| 78e0a4ff1e | |||
| b5d6761fe4 | |||
| b29352b816 | |||
| a778116b9a | |||
| 1afaded712 | |||
| c7e63f52ce | |||
| 5696165d66 | |||
| 2ef3d72c72 | |||
| 33807621bc | |||
| cfc02f67eb | |||
| 6ec64b227c | |||
| 5ca7cbc91e | |||
| bb51e7c0f6 | |||
| 6ada5d46b0 | |||
| 69bf7b3cd3 | |||
| b386dd23fb | |||
| fd4e03c565 | |||
| 15c5898488 | |||
| a0c1beb61f | |||
| 7979401675 | |||
| 09e6fde327 | |||
| a2518c1156 | |||
| f70dba5e6e | |||
| 99604dccc9 | |||
| 37f96d452a | |||
| 584a4e082e | |||
| d59a853f0c | |||
| 2ad0db2d80 | |||
| 9a66d29b6b | |||
| 2cb53563f2 | |||
| 4f8f00c4e2 | |||
| 697403b841 | |||
| 43add842ae | |||
| b4b6e064f3 | |||
| 44bbcd9c06 | |||
| 1f8ebea10c | |||
| fb4bc0a528 | |||
| 01c37701d9 | |||
| 23c1d39bc4 | |||
| 5b15481138 | |||
| 8f8b809756 | |||
| a13f6f4dd9 | |||
| 29cbeb8782 | |||
| ea55b42bc8 | |||
| 746a2ae528 | |||
| 9c4a81a6ee | |||
| bae00c0e20 | |||
| 1835cb12be | |||
| 9e4a0680ab | |||
| 7b12c99a0b | |||
| 39c5d65f76 | |||
| 5f91426fec | |||
| 3049096b3e | |||
| 910fc28dce | |||
| 2a57b9317c | |||
| 64e79d6a78 | |||
| f79703e7fd | |||
| 73e72be323 | |||
| 16009cfde9 | |||
| 99369facbf | |||
| 85a2a575a3 | |||
| a07f37e99d | |||
| 3d0fd81cc4 | |||
| ec463819fe | |||
| fabee0e675 | |||
| 1b005c83eb | |||
| c7e882e97d | |||
| 0c09c07cd2 | |||
| b02344ffc5 | |||
| 329b753df5 | |||
| 6535ccbdd8 | |||
| 6a7ed83f6a | |||
| a1863b9fed | |||
| 5af04b84f0 | |||
| f11de747de | |||
| e51eae5203 | |||
| a3838e1023 | |||
| fb6790c4f5 | |||
| 93ca928e98 | |||
| 40cd40cebd | |||
| 59f680048b | |||
| 33998c2981 | |||
| 6e756c434a | |||
| b00c4e30d0 | |||
| 0025c01024 | |||
| 05c7fbeb0b | |||
| 84c4b3c1b8 | |||
| d76c693147 | |||
| b331363de1 | |||
| daad94eedb | |||
| 2b604a49ea | |||
| 2415418dca | |||
| 1ffc4b9f7f | |||
| dd5fb2cf88 | |||
| cdb2b2e1a7 | |||
| 14ea97337b | |||
| 533225f106 | |||
| 760b5ad276 | |||
| b5d689f39f | |||
| e5203b6e4a | |||
| a9d787b340 | |||
| 05144f39df | |||
| 6bd38ce13a | |||
| a9716a340d | |||
| 4a88660a3d | |||
| da5af2cac2 | |||
| f7756d7d4d | |||
| a7a6a3d124 | |||
| c905ed0338 | |||
| 455093ca23 | |||
| cbf596e410 | |||
| 78b3c5ec3f | |||
| 236b8991f6 | |||
| c8d9d18537 | |||
| 3d7cca91ff | |||
| 09a391dbf4 | |||
| 9e0d29db1a | |||
| fcf32c82ba | |||
| 3ea835117a | |||
| 90ebc1a8be | |||
| af7183151c | |||
| b8cb379234 | |||
| fdf4d4926f | |||
| 4cccff934f | |||
| 52e3a3fc15 | |||
| 4b7f822848 | |||
| a35ffe16cc | |||
| 3785e24077 | |||
| 82ba845fc7 | |||
| a113154708 | |||
| 11c2440dcd | |||
| 17f686f39c | |||
| f498b54648 | |||
| 06141feb8b | |||
| b74b005215 | |||
| 4c212ae507 | |||
| 1ebd2894c2 | |||
| d3951235bd | |||
| 073e1a8462 | |||
| 4cf257b997 | |||
| 51db756385 | |||
| fc4d70a5e9 | |||
| a73d8bc8f4 | |||
| dc0b5838b1 | |||
| afb0ca384a | |||
| 817f81ebb2 | |||
| 119b367205 | |||
| 975ecd0b9d | |||
| 13c0b4b5f6 | |||
| 25d1cf4455 | |||
| cd456a9a60 | |||
| cae1dd964d | |||
| 16a3bf10c8 | |||
| 5e0f93210d | |||
| 2396a2b2e5 | |||
| 4dfbb9e597 | |||
| 6af5f94f90 | |||
| 4925e756a6 | |||
| 95df593c2f | |||
| 8be6818a6d | |||
| fcc3cd369e | |||
| 87eec92c5d | |||
| d745e14cb5 | |||
| 3355d41642 | |||
| 0832a5c254 | |||
| c7df47703e | |||
| a1ee9f865f | |||
| 1033e9fe96 | |||
| 323b30a14b | |||
| 2a2c0420a7 | |||
| f78704af93 | |||
| 34e61c45c9 | |||
| a1951f9756 | |||
| c96dc403b9 | |||
| 48f05f97b7 | |||
| 3208946017 | |||
| 7052f9504a | |||
| 45d1755e19 | |||
| bf29ebc354 | |||
| e50fc2022f | |||
| a63e0eed4c | |||
| 1218c9fa7d | |||
| e50d10bfe6 | |||
| 18a9758511 | |||
| fcd8f05c3c | |||
| 56afc57b7b | |||
| b3a0befe33 | |||
| 669dfe73a4 | |||
| c4001c8507 | |||
| 269831e0c4 | |||
| b22fa48e90 | |||
| 397388d230 | |||
| f5de319f40 | |||
| 1c2fe7b9a6 | |||
| c545a2f0ed | |||
| 7f1dea6129 | |||
| 96d9ae4776 | |||
| 8ee9199abc | |||
| 3cba3a76a4 | |||
| 84d2a22b18 | |||
| 8f87a07f62 | |||
| fa9e829f5d | |||
| 920faa97d2 | |||
| f018425e12 | |||
| ad0f727880 | |||
| 9696284e1d | |||
| 10d733d312 | |||
| e9c2768cc0 | |||
| 4f7aba9c05 | |||
| 892cece2aa | |||
| 7cb3f43862 | |||
| 04ab98a634 | |||
| 18ff09d52f | |||
| a951292f27 | |||
| 7806c2096d | |||
| b7855cf14d | |||
| dfb4153049 | |||
| 14d5416616 | |||
| 63f6e0c43d | |||
| 8069426b5c | |||
| 59a835b1b3 | |||
| 727da06266 | |||
| 38762fb618 | |||
| aff40dac8d | |||
| e097d88ab2 | |||
| a16e64420e | |||
| 76ee7cdd7f | |||
| 0e0ae3c4d1 | |||
| 76ce186bd4 | |||
| b69f36afe4 | |||
| 716a91fc0c | |||
| 0d7832b208 | |||
| 908adb4d2b | |||
| 7697bcb087 | |||
| 975759284d | |||
| d13e770ac4 | |||
| 04547a9206 | |||
| 7dd32c8878 | |||
| d0ec3e0266 | |||
| 0dbad182e8 | |||
| e63a877ed6 | |||
| 4df64695c7 | |||
| 394bc1689f | |||
| 6839939140 | |||
| 00c7b23d15 | |||
| bc6bfccade | |||
| ed2becce88 | |||
| b39acdf18a | |||
| 149e039cd0 | |||
| f99fadaa20 | |||
| b5fd533362 | |||
| 8e88cfbf9a | |||
| 3969413779 | |||
| eedbf2fbb7 | |||
| fbb358bf71 | |||
| b3602cad87 | |||
| b9387ceeda | |||
| 3aa7452e48 |
@@ -0,0 +1,69 @@
|
||||
# Use the latest 2.1 version of CircleCI pipeline process engine.
|
||||
# See: https://circleci.com/docs/2.0/configuration-reference
|
||||
version: 2.1
|
||||
|
||||
# Define a job to be invoked later in a workflow.
|
||||
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
|
||||
jobs:
|
||||
build-elrsv2:
|
||||
machine: true
|
||||
steps:
|
||||
- checkout
|
||||
- run: docker run -it -e "BOARD_NAME=I6X" -e "CMAKE_FLAGS=PCB=I6X HELI=NO GVARS=NO LUA_COMPILER=NO MULTIMODULE=NO DEBUG=NO PCBI6_ELRSV2=YES" -v $PWD:/opentx vitass/opentx-fw-build
|
||||
- store_artifacts:
|
||||
path: opentx-i6x-2.3.0.bin
|
||||
destination: ./artifacts/opentx-i6x-elrsv2-<< pipeline.git.tag >>.bin
|
||||
build-gvars:
|
||||
machine: true
|
||||
steps:
|
||||
- checkout
|
||||
- run: docker run -it -e "BOARD_NAME=I6X" -e "CMAKE_FLAGS=PCB=I6X HELI=NO GVARS=YES LUA_COMPILER=NO MULTIMODULE=NO DEBUG=NO" -v $PWD:/opentx vitass/opentx-fw-build
|
||||
- store_artifacts:
|
||||
path: opentx-i6x-2.3.0.bin
|
||||
destination: ./artifacts/opentx-i6x-gvars-<< pipeline.git.tag >>.bin
|
||||
build-heli:
|
||||
machine: true
|
||||
steps:
|
||||
- checkout
|
||||
- run: docker run -it -e "BOARD_NAME=I6X" -e "CMAKE_FLAGS=PCB=I6X HELI=YES GVARS=YES LUA_COMPILER=NO MULTIMODULE=NO DEBUG=NO" -v $PWD:/opentx vitass/opentx-fw-build
|
||||
- store_artifacts:
|
||||
path: opentx-i6x-2.3.0.bin
|
||||
destination: ./artifacts/opentx-i6x-heli-<< pipeline.git.tag >>.bin
|
||||
publish-github-release:
|
||||
docker:
|
||||
- image: cibuilds/github:0.13
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ./artifacts
|
||||
- run:
|
||||
name: "Publish Release on GitHub"
|
||||
command: |
|
||||
ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete latest ./artifacts/
|
||||
# Invoke jobs via workflows
|
||||
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
|
||||
workflows:
|
||||
openi6x-workflow:
|
||||
jobs:
|
||||
- build-elrsv2
|
||||
# filters:
|
||||
# branches:
|
||||
# ignore: /.*/
|
||||
# tags:
|
||||
# only: /.*-release$/
|
||||
- build-gvars
|
||||
# filters:
|
||||
# branches:
|
||||
# ignore: /.*/
|
||||
# tags:
|
||||
# only: /.*-release$/
|
||||
- build-heli
|
||||
# filters:
|
||||
# branches:
|
||||
# ignore: /.*/
|
||||
# tags:
|
||||
# only: /.*-release$/
|
||||
- publish-github-release:
|
||||
requires:
|
||||
- build-elrsv2
|
||||
- build-gvars
|
||||
- build-heli
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help the OpenTX team to improve OpenTX
|
||||
|
||||
---
|
||||
*Before submitting, search the open issue if there is already a report of the bug*
|
||||
|
||||
Also often minor bugs are already fixed in nightly builds, often it is
|
||||
a good idea to test (in a controlled environment like a bench setup)
|
||||
with a nightly firmware to see if the bug still exists.
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**General information**
|
||||
- OpenTX version (e.g. 2.1.23 or N123)
|
||||
- Hardware (e.g. Frsky X9D+ or 9X Pro)
|
||||
- OpenTX Companion (e.g. 2.1.23 on Ubuntu 16.04)
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: Help
|
||||
about: Problems or question of using OpenTX
|
||||
|
||||
---
|
||||
|
||||
The issue tracker here is for devlopment of OpenTX. This is not a
|
||||
support site, only a bug tracking system. Please use support groups
|
||||
like [rcgroups](https://rcgroups.com/) or
|
||||
[openrcforum](https://www.openrcforums.com/forum/). See also our
|
||||
[manual](https://opentx.gitbooks.io/manual-for-opentx-2-2/).
|
||||
|
||||
For quick questions you can also join our general chat.
|
||||
|
||||
Issues that fall into the category of asking for help, will be
|
||||
generally closed as invalid without an answer.
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project to make OpenTX even better
|
||||
|
||||
---
|
||||
*Before suggesting a new feature here, please search the open issue if there is already a request for the feature*
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -2,7 +2,21 @@
|
||||
/.*project
|
||||
/.settings
|
||||
/.autotools
|
||||
/doc/
|
||||
/*.user
|
||||
/*.user.*
|
||||
build*/
|
||||
cmake-build-*/
|
||||
/debian/
|
||||
/CMakeFiles/*
|
||||
radio/src/CmakeFiles/*
|
||||
/.vscode/
|
||||
*.cmake
|
||||
*.make
|
||||
*.marks
|
||||
/nbproject/
|
||||
*.bin
|
||||
/radio/src/CMakeFiles/firmware.dir/link.txt
|
||||
.push.settings.jsonc
|
||||
build.sh
|
||||
firm.sh
|
||||
flash.sh
|
||||
|
||||
@@ -1,23 +1,16 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
language: python
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
|
||||
virtualenv:
|
||||
system_site_packages: true
|
||||
|
||||
python:
|
||||
- 3.4
|
||||
|
||||
env:
|
||||
global:
|
||||
- QT_BASE=53
|
||||
# - QT_BASE=53
|
||||
# - QT_BASE=54
|
||||
# - QT_BASE=55
|
||||
# - QT_BASE=56
|
||||
# - QT_BASE=57
|
||||
#- GCC_ARM=/opt/gcc-arm-none-eabi/bin
|
||||
- AVR_FLAVORS="AVR9X 9X GRUVIN9X MEGA2560"
|
||||
- QT_BASE=57
|
||||
# - GCC_ARM=/opt/gcc-arm-none-eabi/bin
|
||||
- PYTHONPATH=${PYTHONPATH}:/usr/lib/python3/dist-packages
|
||||
matrix:
|
||||
#
|
||||
@@ -26,15 +19,12 @@ env:
|
||||
#
|
||||
# - FLAVOR=ALL
|
||||
- FLAVOR=DEFAULT
|
||||
- FLAVOR=AVR9X
|
||||
# - FLAVOR=9X
|
||||
# - FLAVOR=GRUVIN9X
|
||||
# - FLAVOR=MEGA2560
|
||||
- FLAVOR=ARM9X
|
||||
# - FLAVOR=AR9X
|
||||
# - FLAVOR=SKY9X
|
||||
# - FLAVOR=9XRPRO
|
||||
- FLAVOR=X7
|
||||
- FLAVOR=XLITE
|
||||
- FLAVOR=X9
|
||||
# - FLAVOR=X9D
|
||||
# - FLAVOR=X9D+
|
||||
@@ -54,40 +44,17 @@ before_install:
|
||||
- if [ "$QT_BASE" = "56" ]; then sudo add-apt-repository ppa:beineri/opt-qt562-trusty -y; fi
|
||||
- if [ "$QT_BASE" = "57" ]; then sudo add-apt-repository ppa:beineri/opt-qt571-trusty -y; fi
|
||||
- sudo apt-get update -qq
|
||||
- pyenv uninstall -f 2.7.6 && pyenv install 3.5.4 && pyenv global 3.5.4
|
||||
- pip install pillow
|
||||
|
||||
install:
|
||||
- sudo apt-get --yes --force-yes install python3-pyqt5 curl libmpfr4 libmpc3 libfox-1.6-dev libgtest-dev
|
||||
- |
|
||||
if [[ " ${AVR_FLAVORS} " =~ " ${FLAVOR} " || ${FLAVOR} == "ALL" ]]; then
|
||||
wget --quiet https://launchpad.net/ubuntu/+source/gcc-avr/1:4.9.2+Atmel3.5.0-1/+build/8403710/+files/gcc-avr_4.9.2+Atmel3.5.0-1_amd64.deb
|
||||
wget --quiet https://launchpad.net/ubuntu/+source/avr-libc/1:1.8.0+Atmel3.5.0-1/+build/8435473/+files/avr-libc_1.8.0+Atmel3.5.0-1_all.deb
|
||||
wget --quiet https://launchpad.net/ubuntu/+source/binutils-avr/2.25+Atmel3.5.0-2/+build/8435474/+files/binutils-avr_2.25+Atmel3.5.0-2_amd64.deb
|
||||
sudo dpkg --install gcc-avr_4.9.2+Atmel3.5.0-1_amd64.deb avr-libc_1.8.0+Atmel3.5.0-1_all.deb binutils-avr_2.25+Atmel3.5.0-2_amd64.deb
|
||||
fi
|
||||
if [[ ! " ${AVR_FLAVORS} " =~ " ${FLAVOR} " || ${FLAVOR} == "ALL" ]]; then
|
||||
sudo apt-get --yes --force-yes install gcc-arm-none-eabi
|
||||
# Trying to build with gcc-arm 4.7 isn't working because it can't find the compiler, despite adding to PATH (in commit-tests.sh) by defining GCC_ARM above
|
||||
- sudo apt-get --yes --force-yes install curl libmpfr4 libmpc3 libfox-1.6-dev libgtest-dev
|
||||
- sudo apt-get --yes --force-yes install gcc-arm-none-eabi
|
||||
# Trying to build with gcc-arm 4.7 isn't working because it can't find the compiler, despite adding to PATH (in commit-tests.sh) by defining GCC_ARM above
|
||||
# - wget --quiet https://launchpad.net/gcc-arm-embedded/4.7/4.7-2013-q3-update/+download/gcc-arm-none-eabi-4_7-2013q3-20130916-linux.tar.bz2
|
||||
# - tar xjf gcc-arm-none-eabi-4_7-2013q3-20130916-linux.tar.bz2
|
||||
# - mv gcc-arm-none-eabi-4_7-2013q3 /opt/gcc-arm-none-eabi
|
||||
fi
|
||||
- sudo apt-get install --yes --force-yes -qq qt${QT_BASE}base qt${QT_BASE}multimedia qt${QT_BASE}svg qt${QT_BASE}tools; source /opt/qt${QT_BASE}/bin/qt${QT_BASE}-env.sh
|
||||
|
||||
addons:
|
||||
sonarcloud:
|
||||
organization: "opentx-github"
|
||||
token:
|
||||
secure: "BuQrGRijNpL2V/IQNcOxvjChj8PScfCdiv403EE73Nqb4+sB8YL92Fnzrnw9bC8wF7BVSDJVpYF0gbdaTzuCmaeZfM8NJK0TOJAbH6+B8bhIrU/V1SBuVjHQnndV/wysieruKnK/KxYJZqItgSlnPo+PmiFxtXJNlas0Kstb2O4="
|
||||
# github_token:
|
||||
# secure: "Qkmp4VrQJtKgZ/pz65SNnCDiF4slgFfQS/3whyLXLcDbFb1Hv1oj7Hqz9EVDUSO2eEhgQGaOKkRc0CfAAOBwW6OvhE0xh7P1CJEjzOp6+3gI/LyZUNsqa+awVRZTsfm1YZaOPaPWJ7cI0uz3/OoSUeIecs4PDWPrQMGRlsrq7Q8="
|
||||
branches:
|
||||
- "2.2"
|
||||
|
||||
script:
|
||||
- build-wrapper-linux-x86-64 --out-dir bw_output ./tools/commit-tests.sh
|
||||
- sonar-scanner
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- '$HOME/.sonar/cache'
|
||||
|
||||
- ./tools/commit-tests.sh
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
project(OpenTX)
|
||||
|
||||
set(VERSION_MAJOR "2")
|
||||
set(VERSION_MINOR "2")
|
||||
set(VERSION_REVISION "1")
|
||||
set(VERSION_MINOR "3")
|
||||
set(VERSION_REVISION "0")
|
||||
set(VERSION_SUFFIX $ENV{OPENTX_VERSION_SUFFIX})
|
||||
set(VERSION_FAMILY ${VERSION_MAJOR}.${VERSION_MINOR})
|
||||
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}${VERSION_SUFFIX})
|
||||
set(SDCARD_REVISION "0013")
|
||||
set(SDCARD_REVISION "0018")
|
||||
set(SDCARD_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}V${SDCARD_REVISION})
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
@@ -72,6 +72,13 @@ else()
|
||||
set(LUA NO)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # regular Clang or AppleClang
|
||||
set(CLANG TRUE)
|
||||
endif()
|
||||
|
||||
option(DISABLE_COMPANION "Disable building companion and simulators" OFF)
|
||||
|
||||
if(NOT DISABLE_COMPANION) # FIXME cosmetics/style
|
||||
find_package(Qt5Core)
|
||||
find_package(Qt5Widgets)
|
||||
find_package(Qt5Xml)
|
||||
@@ -111,6 +118,9 @@ if(Qt5Core_FOUND)
|
||||
list(APPEND APP_COMMON_DEFINES -DQXT_STATIC)
|
||||
list(APPEND APP_COMMON_DEFINES -DQT_USE_QSTRINGBUILDER) # more efficient QString construction using % operator
|
||||
|
||||
if(MSVC)
|
||||
list(APPEND APP_COMMON_DEFINES -D__STDC_LIMIT_MACROS)
|
||||
endif()
|
||||
if(APP_CUSTOM_DBG_HANDLER)
|
||||
# provide full qDebug log context to our custom handler. This may also affect libsimulator, which is why it is here
|
||||
list(APPEND APP_COMMON_DEFINES -DQT_MESSAGELOGCONTEXT)
|
||||
@@ -150,6 +160,7 @@ if(Qt5Core_FOUND OR FOX_FOUND)
|
||||
message(STATUS "SDL not found! Simulator audio, and joystick inputs, will not work.")
|
||||
endif()
|
||||
endif()
|
||||
endif(NOT DISABLE_COMPANION)
|
||||
|
||||
# Check for a file that is typically left from a OpenTX 2.1 build and abort if found
|
||||
if (EXISTS ${RADIO_SRC_DIRECTORY}/stamp.h OR EXISTS ${RADIO_SRC_DIRECTORY}/translations/en.h)
|
||||
@@ -180,6 +191,6 @@ endif()
|
||||
|
||||
add_subdirectory(${RADIO_SRC_DIRECTORY})
|
||||
|
||||
if(Qt5Core_FOUND)
|
||||
if(Qt5Core_FOUND AND NOT DISABLE_COMPANION)
|
||||
add_subdirectory(${COMPANION_SRC_DIRECTORY})
|
||||
endif()
|
||||
|
||||
@@ -26,20 +26,22 @@ Pat Mackenzie
|
||||
Michael Byrne
|
||||
|
||||
[Companies and projects who have donated to OpenTX]
|
||||
<a href="http://frsky-rc.com">FrSky (monthly)</a>
|
||||
<a href="http://alofthobbies.com">Aloft Hobbies</a>
|
||||
<a href="http://jonathan.it">Jonathan Modellismo</a>
|
||||
<a href="https://www.frsky-rc.com">FrSky (monthly)</a>
|
||||
<a href="https://alofthobbies.com">Aloft Hobbies</a>
|
||||
<a href="https://jonathan.it">Jonathan Modellismo</a>
|
||||
<a href="http://wstech.de">WsTech</a>
|
||||
<a href="http://aviomotive.com">Aviomotive</a>
|
||||
<a href="http://boltrc.com">BoltRC</a>
|
||||
<a href="http://aerialtechhobbies.com">Aerial Tech Hobbies</a>
|
||||
<a href="http://litepilots.com">LitePilots</a>
|
||||
<a href="http://openpilot.com">David Ankers (OpenPilot)</a>
|
||||
<a href="http://3drobotics.com">3D Robotics</a>
|
||||
<a href="http://rcstudio.cz">RC Studio (monthly)</a>
|
||||
<a href="https://3dr.com">3D Robotics</a>
|
||||
<a href="https://rcstudio.cz">RC Studio (monthly)</a>
|
||||
<a href="http://www.craftandtheoryllc.com">Craft & Theory (monthly)</a>
|
||||
<a href="http://alofthobbies.com/taranis-q-x7--opentx-user-manual.html">OpenTX Manuals by Lothar Thole</a>
|
||||
<a href="http://www.team-blacksheep.com">Team BlackSheep</a>
|
||||
<a href="https://alofthobbies.com/taranis-q-x7--opentx-user-manual.html">OpenTX Manuals by Lothar Thole</a>
|
||||
<a href="https://www.team-blacksheep.com">Team BlackSheep</a>
|
||||
<a href="https://www.3dxr.co.uk">Team BlackSheep</a>
|
||||
www.3dxr.co.uk
|
||||
|
||||
[People who have donated to OpenTX]
|
||||
Mario Sette
|
||||
@@ -1301,3 +1303,191 @@ Rachel Berkhahn
|
||||
Luca Massimiliano Comolli
|
||||
Mario Wesierski
|
||||
Evening Shade Pottery
|
||||
Jean Desmet
|
||||
Alexis Pons
|
||||
Roger Bergevin
|
||||
Eddie Ehlin
|
||||
Bernard Avisse
|
||||
Brent Warman
|
||||
Tim Johnson
|
||||
Reinhard Herden
|
||||
Mark Hanson
|
||||
Sander Helling
|
||||
Anthony Hrabusicky
|
||||
David Frazier
|
||||
Alexander Orlov
|
||||
Wes Warner
|
||||
Samuel Grob
|
||||
Wolfgang Kuhl
|
||||
Stuart Olson
|
||||
Michael Shellim
|
||||
Jay Watkins
|
||||
Juan Rodriguez
|
||||
John Bitzer
|
||||
Bryan Anderson
|
||||
Claudio Piccinini
|
||||
Patrick Breidenbach
|
||||
Harald Puff
|
||||
Mike Frizell
|
||||
James A Davey
|
||||
Ronald Fahlbusch
|
||||
Piet Teekens
|
||||
Jean Jacques Bultez
|
||||
Paul Dittman
|
||||
Philippe Faure
|
||||
Jean-Jacques Pointel
|
||||
Didier Christien
|
||||
Huguette Viale
|
||||
Marc Rivière
|
||||
Cyril Maquaire
|
||||
Nick Webb
|
||||
Kristjan Crnoja
|
||||
Gaines Smith
|
||||
Tomasz Łapucha
|
||||
Karl-Heinz Behn
|
||||
Geir Atle Storhaug
|
||||
Marco Lange
|
||||
2 Brains Design
|
||||
Philip Michels
|
||||
Peter Helbling
|
||||
Guy Lamaison
|
||||
Michael Oeschger
|
||||
Alistair Sutherland
|
||||
Chris Hawley
|
||||
Jeffrey Albers
|
||||
Thomas Hollatz
|
||||
Patrice Lafeuille
|
||||
Gary Jones
|
||||
Benoit Gruson
|
||||
Petr Kysela
|
||||
Sebastien Jehan
|
||||
Jean Mathieu
|
||||
Barry Andersen
|
||||
James Vincent
|
||||
Baker Hart
|
||||
Thomas Voth
|
||||
Michael Kiefer
|
||||
Ronald Dalton
|
||||
Thierry Laligand
|
||||
Joel Lefebvre
|
||||
Murray Rogers
|
||||
Renato Elias
|
||||
Richard Husta
|
||||
Ian Ferreira
|
||||
Zhang Tianyu
|
||||
Josef de Beer
|
||||
Ewald Moehring
|
||||
Kevin Karamitros
|
||||
Beat Zurflueh
|
||||
Frank Morris
|
||||
Edwin Butin Bik
|
||||
Geir Atle Storhaug
|
||||
Ted Hoenderdos
|
||||
Sebastian Stefanitsch
|
||||
Leif Pernstig
|
||||
Michael Garofalo
|
||||
Chris Sunman
|
||||
Adam Kalus
|
||||
Christoffer H Henni
|
||||
Michael Stauning
|
||||
Stuart Smith
|
||||
Giuseppe Esposito
|
||||
Stefano Boggia
|
||||
Manuel Peon
|
||||
Mark Bennett
|
||||
Nicholas Platts
|
||||
Carol B Meravi
|
||||
Norman Hunt
|
||||
Raymond Henderson
|
||||
Christopher Marshall
|
||||
Christopher Prinos
|
||||
AntiSocial Engineering
|
||||
Pierre Duvezin-Caubet
|
||||
Hermann Haberer
|
||||
Guy Poignonec
|
||||
Robin Lauff
|
||||
Renato Müller
|
||||
Hannes Mössler
|
||||
Cédric Lagoutte
|
||||
Alexander Mathis
|
||||
Barry Andersen
|
||||
Philippe Glur
|
||||
Felix Tang
|
||||
Heiko Polig
|
||||
Pierre Marty
|
||||
Dirk Weiler
|
||||
Eddie Ehlin
|
||||
John Clarke
|
||||
Laurent Thibaudet
|
||||
James A Davey
|
||||
Stuart Olson
|
||||
claudio Piccinini
|
||||
Kenneth Kriegel
|
||||
Evening Shade Pottery
|
||||
Raymond Henderson
|
||||
Clifton Hipsher
|
||||
François Carton
|
||||
Olivier Portron
|
||||
Didier Hochedez
|
||||
Julien Gérard
|
||||
Christian Syrbe
|
||||
Juan Luis Guerrero Portero
|
||||
Jonathan Badley
|
||||
Ms Place
|
||||
Heart of NM LLC
|
||||
Daniele Gnesutta
|
||||
Erik Peterson
|
||||
SkyRaccoon
|
||||
James Lummel
|
||||
Jürgen Husske
|
||||
Marko Domagoj Zic
|
||||
Fabrice Debonnet
|
||||
Ms Place
|
||||
Jörg Hammer
|
||||
Rapid Informatics LLC
|
||||
Renaud Perriguey
|
||||
Edmond Dufresne
|
||||
Jaroslav Gazik
|
||||
Philippe Desrichard
|
||||
Vincent Heron
|
||||
Marcel Schäfer
|
||||
Stefano Pascucci
|
||||
Frédéric Bourgois
|
||||
Stefan Hufnagl
|
||||
Jean Philippe Bonacci
|
||||
Jack Mitchell
|
||||
Santiago Iglesias Garcia
|
||||
Steve Kurywchak
|
||||
Tore Skjefstad
|
||||
Sergio Digiandco di Molino
|
||||
Xavier Delepine
|
||||
Miles Shearman
|
||||
Bernard Teyssier
|
||||
Entel Consulting BVBA
|
||||
Stuart Olson
|
||||
Maximilian Wechselberger
|
||||
Kenneth Crump
|
||||
Ken Elder
|
||||
Darko Perković
|
||||
Martin Krueger
|
||||
Jack Lopes
|
||||
Huguette Viale
|
||||
Didier Christien
|
||||
Pascal Roublot
|
||||
Arnaud Sourisse
|
||||
Aldo Midali
|
||||
Sidney Gates
|
||||
Serhiy Semenenko
|
||||
Miguel Esquer Ramiro
|
||||
Stefan Grunenberg
|
||||
Ferenc Kunkli
|
||||
Stefano Boggia
|
||||
Lee Bennett
|
||||
Morgantech
|
||||
Marek Přikryl
|
||||
Peter Scott
|
||||
Ernst Camenzind
|
||||
Steve Robbins
|
||||
Jean Noel Berlan
|
||||
Walter Szempruch
|
||||
Petr Kysela
|
||||
|
||||
@@ -1,16 +1,52 @@
|
||||
## OpenTX 2.2 Branch
|
||||
# FlySky i6x port of OpenTX
|
||||
|
||||
[](https://travis-ci.org/opentx/opentx)
|
||||
[](https://sonarcloud.io/dashboard?id=OpenTX:2.2)
|
||||
[](https://opentx.rocket.chat)
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DJ9MASSKVW8WN)
|
||||
This is a port of OpenTX for the venerable Flysky I6X RC radio transmitter. You can find the latest build and some instructions and videos contributed by fellow early adopters in the [RCGroups thread](https://www.rcgroups.com/forums/showthread.php?3916435-FlySky-I6X-port-of-OpenTX)
|
||||
|
||||
The ongoing development on 2.2.x is done in this branch.
|
||||
## Implemented features
|
||||
|
||||
Refer to the [OpenTX wiki](https://github.com/opentx/opentx/wiki) for information about setting up the tool chains for building OpenTX and OpenTX Companion as well as other development related issues.
|
||||
* AFHDS2A protocol
|
||||
* PPM out
|
||||
* CRSF working with ExpressLRS and Crossfire modules at rates from 115k to 3.75M bauds, CRSFshot enabled
|
||||
* Telemetry
|
||||
* Audio tones, alarms and vario custom implementation (Janek)
|
||||
* USB (To enable on standard cable: General Settings > USB Detect set to "Once") (Janek)
|
||||
* Joystick mode (Janek)
|
||||
* Mass Storage to backup/restore eeprom (Janek)
|
||||
* ExpressLRS V1.x configuration in model setup
|
||||
|
||||
## Users Telegram group
|
||||
|
||||
Useful links:
|
||||
* OpenTX Main Site http://www.open-tx.org/
|
||||
* OpenTx University http://open-txu.org/
|
||||
* OpenTX User Manual https://www.gitbook.com/book/opentx/opentx-taranis-manual/details
|
||||
* OpenTX Lua Reference Guide https://www.gitbook.com/book/opentx/opentx-lua-reference-guide/details
|
||||
https://t.me/otx_flysky_i6x
|
||||
|
||||
## Navigation:
|
||||
|
||||
| Key | Function |
|
||||
| --- | --- |
|
||||
| UP | Hold for stats |
|
||||
| DOWN | Hold for telemetry |
|
||||
| OK | Hold for Model menu |
|
||||
| CANCEL | EXIT. Hold for graceful shutdown (Needed to save timers) |
|
||||
| BIND | Go RIGHT. Go to next PAGE. Hold for general menu. |
|
||||
| RIGHT POT | Scroll right or left |
|
||||
|
||||
## ST-Link pinout
|
||||
|
||||

|
||||
|
||||
## Linux instructions
|
||||
### Compile
|
||||
`docker run --rm -it -e "BOARD_NAME=I6X" -e "CMAKE_FLAGS=PCB=I6X HELI=NO GVARS=NO LUA_COMPILER=NO MULTIMODULE=NO DEBUG=YES" -v $PWD:/opentx vitass/opentx-fw-build`
|
||||
|
||||
### Flash
|
||||
`sudo st-flash write <file_to_flash>.bin 0x08000000`
|
||||
|
||||
### Debug tty:
|
||||
`sudo cat /dev/ttyUSB0 115200`
|
||||
|
||||
## Contributors
|
||||
|
||||
* Janek (@ajjjjjjjj) ongoing collaboration.
|
||||
* All the RF code was taken from the great KotelloRC's erfly6: Er9X for i6 and i6x. You can find his project here: https://bitbucket.org/KotelloRC/erfly6/src/master/
|
||||
* ADC code taken from OpenGround: https://github.com/fishpepper/OpenGround
|
||||
* This work is based on Jakub's (qba667) work and is forked from his repo.
|
||||
* All the contributors of OpenTX.
|
||||
|
||||
@@ -14,10 +14,10 @@ macro(add_bitmaps_target targetname filter width format)
|
||||
add_custom_target(${targetname} DEPENDS ${bitmaps_files})
|
||||
endmacro(add_bitmaps_target)
|
||||
|
||||
macro(add_truetype_font_target radio name font size bold)
|
||||
macro(add_truetype_font_target radio name font size offset)
|
||||
set(target ${RADIO_SRC_DIRECTORY}/fonts/${radio}/font_${name})
|
||||
add_custom_target(ttf_${radio}_${name}
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${RADIO_DIRECTORY}/util/font2png.py ${font} ${size} ${bold} ${target}
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${RADIO_DIRECTORY}/util/font2png.py ${font} ${size} ${offset} ${target}
|
||||
WORKING_DIRECTORY ${RADIO_SRC_DIRECTORY}
|
||||
)
|
||||
set(ttf_${radio}_fonts_targets ${ttf_${radio}_fonts_targets} ttf_${radio}_${name})
|
||||
|
||||
@@ -49,8 +49,8 @@ macro(use_cxx11)
|
||||
endmacro(use_cxx11)
|
||||
|
||||
macro(PrintTargetReport targetName)
|
||||
if(CMAKE_CXX_COMPILER MATCHES "/cl\\.exe$")
|
||||
set(cpp_version ${MSVC_VERSION})
|
||||
if(CMAKE_CXX_COMPILER MATCHES "/(clang-)?cl\\.exe$")
|
||||
set(cpp_version ${CMAKE_CXX_COMPILER_VERSION})
|
||||
else()
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE cpp_version)
|
||||
endif()
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
<h2>Version 2.2.1 / 2017-12-17</h2>
|
||||
|
||||
Please see <a href=http://www.open-tx.org/2017/12/16/opentx-2.2.1>this page</a> for details.
|
||||
|
||||
<h2>Version 2.2.0 / 2017-05-30</h2>
|
||||
|
||||
Major release! Please see <a href=http://www.open-tx.org/2017/05/30/opentx-2.2.0>this page</a> for details.
|
||||
@@ -91,10 +95,10 @@ Notice: version 2.1.4 was skipped by the OpenTX team to avoid confusion with FrS
|
||||
<li>Fixed a problem with updates path on Windows (<a href=https://github.com/opentx/opentx/issues/2876>#2876</a>)</li>
|
||||
<li>Edge representation unified (changed from "no release" to "instant") (<a href=https://github.com/opentx/opentx/issues/2837>#2837</a>)</li>
|
||||
<li>Added channel names on failsafe sliders (<a href=https://github.com/opentx/opentx/issues/3021>#3021</a>)</li>
|
||||
<li>Corrected failsafe mapping when using Custom failsafe mode, D16 protocol and channel range different from from 1-8.
|
||||
<li>Corrected failsafe mapping when using Custom failsafe mode, D16 protocol and channel range different from from 1-8.
|
||||
Users with such setups are advised to re-check their failsafe settings (<a href=https://github.com/opentx/opentx/issues/2975>#2975</a>)</li>
|
||||
<li>Various texts and translations corrections</li>
|
||||
<li>Various small bug-fixes: <a href=https://github.com/opentx/opentx/issues/2994>#2994</a>,
|
||||
<li>Various small bug-fixes: <a href=https://github.com/opentx/opentx/issues/2994>#2994</a>,
|
||||
<a href=https://github.com/opentx/opentx/issues/3016>#3016</a>,
|
||||
<a href=https://github.com/opentx/opentx/issues/3012>#3012</a>
|
||||
</li>
|
||||
@@ -112,8 +116,8 @@ Notice: version 2.1.4 was skipped by the OpenTX team to avoid confusion with FrS
|
||||
|
||||
<ul>
|
||||
<li>Fixed: Lua model scripts outputs not working in a simulator (<a href=https://github.com/opentx/opentx/issues/2684>#2684</a>)</li>
|
||||
<li>Fixed a problem of Companion 2.1 trying to install into 2.0 path.
|
||||
The effect will only be visible for the users that did not install any of the previous 2.1.x versions.
|
||||
<li>Fixed a problem of Companion 2.1 trying to install into 2.0 path.
|
||||
The effect will only be visible for the users that did not install any of the previous 2.1.x versions.
|
||||
(<a href=https://github.com/opentx/opentx/issues/2645>#2645</a>)</li>
|
||||
<li>Added missing SDL libraries to MAC package (<a href=https://github.com/opentx/opentx/issues/2678>#2678</a>)</li>
|
||||
<li>Added used channels check/warning in Wizard (<a href=https://github.com/opentx/opentx/issues/2091>#2091</a>)</li>
|
||||
@@ -194,7 +198,7 @@ Notice: version 2.1.4 was skipped by the OpenTX team to avoid confusion with FrS
|
||||
<li>Added Battery meter range setting (<a href=https://github.com/opentx/opentx/issues/2195>#2195</a>)</li>
|
||||
<li>Improvements in Print and Compare dialogs (<a href=https://github.com/opentx/opentx/issues/2219>#2219</a>)</li>
|
||||
<li>Reset pots to the middle by right double clicking them in Simulator (<a href=https://github.com/opentx/opentx/issues/1939>#1939</a>)</li>
|
||||
<li>Minor fixes: <a href=https://github.com/opentx/opentx/issues/2153>#2153</a>,
|
||||
<li>Minor fixes: <a href=https://github.com/opentx/opentx/issues/2153>#2153</a>,
|
||||
<a href=https://github.com/opentx/opentx/issues/2138>#2138</a>,
|
||||
<a href=https://github.com/opentx/opentx/issues/2090>#2090</a>,
|
||||
<a href=https://github.com/opentx/opentx/issues/2122>#2122</a>
|
||||
@@ -297,13 +301,13 @@ Notice: version 2.1.4 was skipped by the OpenTX team to avoid confusion with FrS
|
||||
<ul>
|
||||
<li>Sound should be ok on all platforms</li>
|
||||
<li>Min/Max reviewed in Logical switches (for the whole telemetry)</li>
|
||||
<li>Various bug fixes</li>
|
||||
<li>Various bug fixes</li>
|
||||
</ul>
|
||||
|
||||
<h2>Version 2.0.3</h2>
|
||||
<ul>
|
||||
<li>EEPROM import bug on AdjustGVAR function</li>
|
||||
<li>Timers correctly displayed in logical switches tab</li>
|
||||
<li>Timers correctly displayed in logical switches tab</li>
|
||||
</ul>
|
||||
|
||||
<h2>Version 2.0.2</h2>
|
||||
|
||||
@@ -81,11 +81,14 @@ if(WIN32)
|
||||
set(WIN_EXECUTABLE_TYPE WIN32) # GUI (WinMain) app
|
||||
endif()
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc /LD /MP")
|
||||
if(NOT CLANG)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /LD /MP")
|
||||
endif()
|
||||
if(NOT WIN_USE_CONSOLE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS,5.01") # is this even needed?
|
||||
endif()
|
||||
elseif(MINGW)
|
||||
get_filename_component(MINGW_DIR ${CMAKE_CXX_COMPILER} DIRECTORY)
|
||||
# struct packing breaks on MinGW w/out -mno-ms-bitfields: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991 & http://stackoverflow.com/questions/24015852/struct-packing-and-alignment-with-mingw
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mno-ms-bitfields")
|
||||
endif()
|
||||
@@ -161,18 +164,9 @@ endif()
|
||||
|
||||
set(common_SRCS
|
||||
appdebugmessagehandler.cpp
|
||||
boards.cpp
|
||||
customdebug.cpp
|
||||
eeprominterface.cpp
|
||||
helpers.cpp
|
||||
radiodata.cpp
|
||||
translations.cpp
|
||||
firmwares/er9x/er9xeeprom.cpp
|
||||
firmwares/er9x/er9xinterface.cpp
|
||||
firmwares/ersky9x/ersky9xeeprom.cpp
|
||||
firmwares/ersky9x/ersky9xinterface.cpp
|
||||
firmwares/opentx/opentxeeprom.cpp
|
||||
firmwares/opentx/opentxinterface.cpp
|
||||
modeledit/node.cpp # used in simulator
|
||||
modeledit/edge.cpp # used by node
|
||||
)
|
||||
@@ -190,23 +184,35 @@ set(common_RESOURCES
|
||||
|
||||
qt5_wrap_cpp(common_SRCS ${common_MOC_HDRS})
|
||||
qt5_add_resources(common_RCC ${common_RESOURCES})
|
||||
#add_custom_target(gen_qrc DEPENDS ${common_RCC} ${companion_QM})
|
||||
|
||||
add_library(common ${common_SRCS} ${common_RCC})
|
||||
qt5_use_modules(common Core Xml Widgets)
|
||||
target_link_libraries(common PRIVATE simulation)
|
||||
#add_dependencies(common gen_qrc)
|
||||
|
||||
target_link_libraries(common
|
||||
firmwares
|
||||
storage
|
||||
simulation
|
||||
maxLibQtWidgets
|
||||
Qt5::Core
|
||||
Qt5::Xml
|
||||
Qt5::Widgets
|
||||
${PTHREAD_LIBRARY}
|
||||
${SDL_LIBRARY}
|
||||
${WIN_LINK_LIBRARIES}
|
||||
)
|
||||
|
||||
set(CPN_COMMON_LIB common)
|
||||
|
||||
############# Supporting libraries ###############
|
||||
|
||||
add_subdirectory(datamodels)
|
||||
add_subdirectory(firmwares)
|
||||
add_subdirectory(shared)
|
||||
add_subdirectory(modeledit)
|
||||
add_subdirectory(generaledit)
|
||||
add_subdirectory(simulation)
|
||||
add_subdirectory(storage)
|
||||
add_subdirectory(thirdparty/qcustomplot)
|
||||
add_subdirectory(thirdparty/maxlibqt/src/widgets)
|
||||
|
||||
############# Companion ###############
|
||||
|
||||
@@ -242,7 +248,8 @@ set(companion_SRCS
|
||||
radionotfound.cpp
|
||||
wizarddata.cpp
|
||||
wizarddialog.cpp
|
||||
multiprotocols.cpp
|
||||
styleeditdialog.cpp
|
||||
dialogs/filesyncdialog.cpp # TODO move to own lib with other dialogs
|
||||
)
|
||||
|
||||
set(companion_MOC_HDRS
|
||||
@@ -274,6 +281,9 @@ set(companion_MOC_HDRS
|
||||
modelprinter.h
|
||||
multimodelprinter.h
|
||||
modelslist.h
|
||||
styleeditdialog.h
|
||||
helpers_html.h
|
||||
dialogs/filesyncdialog.h
|
||||
)
|
||||
|
||||
set(companion_UIS
|
||||
@@ -294,18 +304,18 @@ set(companion_UIS
|
||||
flashfirmwaredialog.ui
|
||||
flasheepromdialog.ui
|
||||
radionotfound.ui
|
||||
styleeditdialog.ui
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set(icon_RC icon.rc)
|
||||
set(icon_RC images/winicons/icon.rc)
|
||||
endif()
|
||||
|
||||
qt5_wrap_ui(companion_SRCS ${companion_UIS})
|
||||
qt5_wrap_cpp(companion_SRCS ${companion_MOC_HDRS})
|
||||
|
||||
add_executable(${COMPANION_NAME} MACOSX_BUNDLE ${WIN_EXECUTABLE_TYPE} ${companion_SRCS} ${icon_RC})
|
||||
qt5_use_modules(${COMPANION_NAME} Core Widgets Network)
|
||||
target_link_libraries(${COMPANION_NAME} PRIVATE generaledit modeledit simulation ${CPN_COMMON_LIB} qcustomplot shared storage ${PTHREAD_LIBRARY} ${SDL_LIBRARY} ${WIN_LINK_LIBRARIES})
|
||||
target_link_libraries(${COMPANION_NAME} PRIVATE generaledit modeledit qcustomplot shared ${CPN_COMMON_LIB})
|
||||
|
||||
PrintTargetReport("${COMPANION_NAME}")
|
||||
|
||||
@@ -314,7 +324,7 @@ PrintTargetReport("${COMPANION_NAME}")
|
||||
set(simu_SRCS simulator.cpp )
|
||||
|
||||
add_executable(${SIMULATOR_NAME} MACOSX_BUNDLE ${WIN_EXECUTABLE_TYPE} ${simu_SRCS} ${icon_RC})
|
||||
target_link_libraries(${SIMULATOR_NAME} PRIVATE simulation ${CPN_COMMON_LIB} storage ${PTHREAD_LIBRARY} ${SDL_LIBRARY} ${WIN_LINK_LIBRARIES})
|
||||
target_link_libraries(${SIMULATOR_NAME} PRIVATE ${CPN_COMMON_LIB})
|
||||
|
||||
############# Install ####################
|
||||
|
||||
@@ -326,8 +336,10 @@ string(TOLOWER ${PCB} FLAVOUR)
|
||||
if(POLICY CMP0026)
|
||||
cmake_policy(SET CMP0026 OLD) # https://cmake.org/cmake/help/v3.0/policy/CMP0026.html
|
||||
endif()
|
||||
get_property(current_plugin TARGET opentx-${FLAVOUR}-simulator PROPERTY LOCATION)
|
||||
list(APPEND simulator_plugins "${current_plugin}")
|
||||
if(SIMU_TARGET)
|
||||
get_property(current_plugin TARGET opentx-${FLAVOUR}-simulator PROPERTY LOCATION)
|
||||
list(APPEND simulator_plugins "${current_plugin}")
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
|
||||
@@ -357,13 +369,6 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
|
||||
elseif(WIN32)
|
||||
|
||||
set(QT_DLL_DIR ${QT_LIB_DIR})
|
||||
set(INSTALL_TEMP_QTDLL_FILES Qt5Core Qt5Gui Qt5Widgets Qt5Xml Qt5Network Qt5PrintSupport Qt5Multimedia Qt5Svg)
|
||||
set(INSTALL_TEMP_ICUDLL_FILES icudt54.dll icuin54.dll icuuc54.dll)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(INSTALL_TEMP_QTDLL_SFX "d")
|
||||
endif()
|
||||
|
||||
if(NOT WIN_DO_FULL_INSTALL)
|
||||
# Just copy supporting DLLs to build folder
|
||||
set(INSTALL_DESTINATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
|
||||
@@ -377,89 +382,90 @@ elseif(WIN32)
|
||||
install(TARGETS ${SIMULATOR_NAME} DESTINATION ${INSTALL_DESTINATION})
|
||||
install(FILES ${simulator_plugins} DESTINATION "${INSTALL_DESTINATION}")
|
||||
# supporting utilities
|
||||
set(INSTALL_TEMP_FILES avrdude.exe avrdude.conf dfu-util.exe libusb0.dll libusb-1.0.dll)
|
||||
set(INSTALL_TEMP_FILES avrdude.exe avrdude.conf dfu-util.exe libusb0.dll libusb-1.0.dll license.txt)
|
||||
foreach(tmpfile ${INSTALL_TEMP_FILES})
|
||||
install(FILES "${COMPANION_SRC_DIRECTORY}/../targets/windows/${tmpfile}" DESTINATION ${INSTALL_DESTINATION})
|
||||
endforeach()
|
||||
endif() # WIN_DO_FULL_INSTALL
|
||||
|
||||
# Qt dlls
|
||||
foreach(tmpfile ${INSTALL_TEMP_QTDLL_FILES})
|
||||
install(FILES ${QT_DLL_DIR}/${tmpfile}${INSTALL_TEMP_QTDLL_SFX}.dll DESTINATION ${INSTALL_DESTINATION})
|
||||
endforeach()
|
||||
install(FILES ${QT_DLL_DIR}/../plugins/platforms/qwindows${INSTALL_TEMP_QTDLL_SFX}.dll DESTINATION ${INSTALL_DESTINATION}/platforms)
|
||||
# ICU dlls
|
||||
foreach(tmpfile ${INSTALL_TEMP_ICUDLL_FILES})
|
||||
# Qt5.7+ doesn't use icu dlls anymore, hence optional
|
||||
install(FILES ${QT_DLL_DIR}/${tmpfile}.dll DESTINATION ${INSTALL_DESTINATION} OPTIONAL)
|
||||
endforeach()
|
||||
# Qt dlls (using windeployqt)
|
||||
## Qt translations are already packaged into our custom qrc. Also don't need software rendering engines.
|
||||
set(wdqtopts --no-translations --no-opengl-sw --no-system-d3d-compiler --no-angle)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(wdqtopts ${wdqtopts} --release) # release builds aren't always properly detected with mingw
|
||||
endif()
|
||||
if(MSVC)
|
||||
set(wdqtopts ${wdqtopts} --no-compiler-runtime) # --compiler-runtime includes vcredist_x86, but we just copy the required DLLs manually
|
||||
endif()
|
||||
set(wdqtopts ${wdqtopts} -dir "${INSTALL_DESTINATION}" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${COMPANION_NAME}.exe" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${SIMULATOR_NAME}.exe")
|
||||
# Add installer command to execute windeployqt
|
||||
install(CODE "execute_process(COMMAND \"${QT_BIN_DIR}/windeployqt.exe\" ${wdqtopts})")
|
||||
|
||||
# SDL dll
|
||||
if(SDL_FOUND AND SDL_LIBRARY_PATH AND EXISTS "${SDL_LIBRARY_PATH}/SDL.dll")
|
||||
if(SDL_FOUND AND EXISTS "${SDL_LIBRARY_PATH}/SDL.dll")
|
||||
set(SDL_DIR ${SDL_LIBRARY_PATH}) # this is also used by NSIS installer script
|
||||
install(FILES ${SDL_DIR}/SDL.dll DESTINATION ${INSTALL_DESTINATION})
|
||||
elseif(SDL_FOUND)
|
||||
message(WARNING "Installer: SDL.dll not found!")
|
||||
message(WARNING "Installer: SDL.dll not found, set SDL_LIBRARY_PATH manually.")
|
||||
endif()
|
||||
|
||||
# libeay (SSL) dlls (used by QtNetwork) -- not strictly required but avoids possible issues with downloads and Qt warnings.
|
||||
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" WIN_PROGRAM_FILES)
|
||||
find_path(EAY_LIB_DIR libeay32.dll HINTS
|
||||
"${WIN_PROGRAM_FILES}/OpenSSL" "${WIN_PROGRAM_FILES}/OpenSSL-Win32"
|
||||
"C:/OpenSSL/" "C:/OpenSSL-Win32/"
|
||||
"${WIN_EXTRA_LIBS_PATH}" "${WIN_EXTRA_LIBS_PATH}/OpenSSL" "${WIN_EXTRA_LIBS_PATH}/OpenSSL-Win32"
|
||||
"${MINGW_DIR}/../opt/bin"
|
||||
"${PYTHON_DIRECTORY}/lib/site-packages/PyQt4"
|
||||
PATH_SUFFIXES bin
|
||||
DOC "Path to libeay32.dll and ssleay32.dll (OpenSSL)"
|
||||
)
|
||||
if (EAY_LIB_DIR)
|
||||
install(FILES "${EAY_LIB_DIR}/libeay32.dll" "${EAY_LIB_DIR}/ssleay32.dll" DESTINATION ${INSTALL_DESTINATION} OPTIONAL)
|
||||
else()
|
||||
message(WARNING "Installer: SSL libs not found, set EAY_LIB_DIR manually.")
|
||||
endif()
|
||||
|
||||
# C++/system dlls, depends on compiler
|
||||
if(MSVC)
|
||||
string(REPLACE "\\" "/" WIN_SYSDIR "$ENV{windir}")
|
||||
set(WIN_SYSDIR "${WIN_SYSDIR}/SysWOW64") # This would be "system32" for a 64-bit build or on x86... but how to tell?
|
||||
if(IS_DIRECTORY "${WIN_SYSDIR}")
|
||||
install(FILES "${WIN_SYSDIR}/msvcp140.dll" "${WIN_SYSDIR}/vcruntime140.dll" DESTINATION ${INSTALL_DESTINATION} OPTIONAL)
|
||||
file(TO_CMAKE_PATH "$ENV{windir}/SysWOW64" WIN_SYSDIR) # This would be "system32" for a 64-bit build or on x86... but how to tell?
|
||||
if (NOT EXISTS "${WIN_SYSDIR}")
|
||||
file(TO_CMAKE_PATH "$ENV{windir}/system32" WIN_SYSDIR) # Must be 32-bit Windows.
|
||||
endif()
|
||||
install(FILES "${WIN_SYSDIR}/msvcp140.dll" "${WIN_SYSDIR}/vcruntime140.dll" DESTINATION ${INSTALL_DESTINATION} OPTIONAL)
|
||||
if(WIN_PTHREAD_DLL)
|
||||
install(FILES "${WIN_PTHREAD_DLL}" DESTINATION ${INSTALL_DESTINATION})
|
||||
endif()
|
||||
elseif(MINGW)
|
||||
get_filename_component(MINGW_DIR ${CMAKE_CXX_COMPILER} PATH)
|
||||
if(IS_DIRECTORY ${MINGW_DIR})
|
||||
install(FILES "${MINGW_DIR}/libgcc_s_dw2-1.dll" "${MINGW_DIR}/libstdc++-6.dll" "${MINGW_DIR}/libwinpthread-1.dll" DESTINATION ${INSTALL_DESTINATION})
|
||||
set(MINGW_DIR "${MINGW_DIR}/../opt/bin")
|
||||
# SSL support
|
||||
install(FILES "${MINGW_DIR}/libeay32.dll" "${MINGW_DIR}/ssleay32.dll" DESTINATION ${INSTALL_DESTINATION} OPTIONAL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif() # WIN32 install
|
||||
|
||||
############# Packaging ####################
|
||||
|
||||
# Create Windows installer with NSIS (only works for MSVC for now)
|
||||
# Create Windows installer with NSIS
|
||||
if(WIN32)
|
||||
if(MSVC)
|
||||
set(COMPANION_NSI_IN_FILE companion-vs.nsi.in)
|
||||
set(SIMULATOR_NSI_IN_FILE simulator-vs.nsi.in)
|
||||
else()
|
||||
set(COMPANION_NSI_IN_FILE companion-msys.nsi.in)
|
||||
set(SIMULATOR_NSI_IN_FILE simulator-msys.nsi.in)
|
||||
endif()
|
||||
|
||||
set(SYSDIR "$ENV{windir}/system32")
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../targets/windows/${COMPANION_NSI_IN_FILE} ${PROJECT_BINARY_DIR}/companion/companion.nsi @ONLY)
|
||||
#configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../targets/windows/${SIMULATOR_NSI_IN_FILE} ${PROJECT_BINARY_DIR}/companion/simulator.nsi @ONLY)
|
||||
|
||||
find_program(NSIS_EXE makensis.exe PATHS
|
||||
"C:/Program Files/NSIS"
|
||||
"C:/Program Files (x86)/NSIS"
|
||||
"C:/Programs/NSIS"
|
||||
"${WIN_EXTRA_LIBS_PATH}/NSIS"
|
||||
)
|
||||
|
||||
if (NSIS_EXE)
|
||||
file(TO_NATIVE_PATH "${INSTALL_DESTINATION}" NSIS_DISTRO) # all files in here will be included in installer
|
||||
set(NSI_FILE "${PROJECT_BINARY_DIR}/companion/companion.nsi")
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../targets/windows/companion.nsi.in" "${NSI_FILE}" @ONLY)
|
||||
|
||||
add_custom_target(installer
|
||||
# The 'install' target prepares all the distro files, make sure it has been executed first.
|
||||
COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target install
|
||||
COMMAND "${NSIS_EXE}" "${NSI_FILE}"
|
||||
DEPENDS "${NSI_FILE}"
|
||||
COMMENT "Building Windows NSIS installer..."
|
||||
)
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/companion/companion-windows.exe
|
||||
COMMAND "${NSIS_EXE}" ARGS ${PROJECT_BINARY_DIR}/companion/companion.nsi
|
||||
DEPENDS companion simulator opentx-simulators ${PROJECT_BINARY_DIR}/companion/companion.nsi
|
||||
COMMENT "Companion Windows NSIS Installer")
|
||||
|
||||
# add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/companion/simulator-install.exe
|
||||
# COMMAND "${NSIS_EXE}" ARGS ${PROJECT_BINARY_DIR}/companion/simulator.nsi
|
||||
# DEPENDS simulator ${PROJECT_BINARY_DIR}/companion/simulator.nsi
|
||||
# COMMENT "Simulator Windows NSIS Installer")
|
||||
|
||||
add_custom_target(installer
|
||||
DEPENDS ${PROJECT_BINARY_DIR}/companion/companion-windows.exe
|
||||
# DEPENDS ${PROJECT_BINARY_DIR}/companion/simulator-windows.exe
|
||||
SOURCES ${PROJECT_BINARY_DIR}/companion/companion.nsi
|
||||
# SOURCES ${PROJECT_BINARY_DIR}/companion/simulator.nsi
|
||||
)
|
||||
endif()
|
||||
|
||||
set(CPACK_PACKAGE_NAME "companion${C9X_NAME_SUFFIX}")
|
||||
@@ -528,9 +534,9 @@ IF(APPLE)
|
||||
get_filename_component(AVRDUDECONF_ABSOLUTE_PATH ${AVRDUDE_CONF} REALPATH)
|
||||
install(PROGRAMS ${DFU_UTIL_ABSOLUTE_PATH} ${AVRDUDE_ABSOLUTE_PATH} DESTINATION ${companion_res_dir} COMPONENT Runtime)
|
||||
install(FILES ${AVRDUDECONF_ABSOLUTE_PATH} DESTINATION ${companion_res_dir} COMPONENT Runtime)
|
||||
|
||||
|
||||
set(bundle_tools_path "\${CMAKE_INSTALL_PREFIX}/${companion_res_dir}/dfu-util;\${CMAKE_INSTALL_PREFIX}/${companion_res_dir}/avrdude")
|
||||
|
||||
|
||||
|
||||
# Include depencies (adding frameworks, fixing the embbeded libraries)
|
||||
# I get write errors without setting BU_CHMOD_BUNDLE_ITEMS even though it is
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "mainwindow.h"
|
||||
#include "appdata.h"
|
||||
#include "helpers.h"
|
||||
#include "storage.h"
|
||||
#if defined(JOYSTICKS)
|
||||
#include "joystick.h"
|
||||
#include "joystickdialog.h"
|
||||
@@ -30,17 +31,17 @@
|
||||
|
||||
AppPreferencesDialog::AppPreferencesDialog(QWidget * parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::AppPreferencesDialog)
|
||||
ui(new Ui::AppPreferencesDialog),
|
||||
updateLock(false),
|
||||
mainWinHasDirtyChild(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
updateLock=false;
|
||||
setWindowIcon(CompanionIcon("apppreferences.png"));
|
||||
|
||||
initSettings();
|
||||
connect(ui->downloadVerCB, SIGNAL(currentIndexChanged(int)), this, SLOT(baseFirmwareChanged()));
|
||||
connect(ui->downloadVerCB, SIGNAL(currentIndexChanged(int)), this, SLOT(onBaseFirmwareChanged()));
|
||||
connect(ui->opt_appDebugLog, &QCheckBox::toggled, this, &AppPreferencesDialog::toggleAppLogSettings);
|
||||
connect(ui->opt_fwTraceLog, &QCheckBox::toggled, this, &AppPreferencesDialog::toggleAppLogSettings);
|
||||
connect(this, SIGNAL(accepted()), this, SLOT(writeValues()));
|
||||
|
||||
#if !defined(JOYSTICKS)
|
||||
ui->joystickCB->hide();
|
||||
@@ -58,18 +59,25 @@ AppPreferencesDialog::~AppPreferencesDialog()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::writeValues()
|
||||
void AppPreferencesDialog::setMainWinHasDirtyChild(bool value)
|
||||
{
|
||||
mainWinHasDirtyChild = value;
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::accept()
|
||||
{
|
||||
Profile & profile = g.currentProfile();
|
||||
|
||||
g.autoCheckApp(ui->autoCheckCompanion->isChecked());
|
||||
g.OpenTxBranch(DownloadBranchType(ui->OpenTxBranch->currentIndex()));
|
||||
g.OpenTxBranch(AppData::DownloadBranchType(ui->OpenTxBranch->currentIndex()));
|
||||
g.autoCheckFw(ui->autoCheckFirmware->isChecked());
|
||||
g.showSplash(ui->showSplash->isChecked());
|
||||
g.simuSW(ui->simuSW->isChecked());
|
||||
g.removeModelSlots(ui->opt_removeBlankSlots->isChecked());
|
||||
g.newModelAction(ui->opt_newMdl_useWizard->isChecked() ? 1 : ui->opt_newMdl_useEditor->isChecked() ? 2 : 0);
|
||||
g.newModelAction(ui->opt_newMdl_useWizard->isChecked() ? AppData::MODEL_ACT_WIZARD : ui->opt_newMdl_useEditor->isChecked() ? AppData::MODEL_ACT_EDITOR : AppData::MODEL_ACT_NONE);
|
||||
g.historySize(ui->historySize->value());
|
||||
g.backLight(ui->backLightColor->currentIndex());
|
||||
g.profile[g.id()].volumeGain(round(ui->volumeGain->value() * 10.0));
|
||||
profile.volumeGain(round(ui->volumeGain->value() * 10.0));
|
||||
g.libDir(ui->libraryPath->text());
|
||||
g.gePath(ui->ge_lineedit->text());
|
||||
g.embedSplashes(ui->splashincludeCB->currentIndex());
|
||||
@@ -87,30 +95,57 @@ void AppPreferencesDialog::writeValues()
|
||||
g.jsSupport(false);
|
||||
g.jsCtrl(0);
|
||||
}
|
||||
g.profile[g.id()].channelOrder(ui->channelorderCB->currentIndex());
|
||||
g.profile[g.id()].defaultMode(ui->stickmodeCB->currentIndex());
|
||||
g.profile[g.id()].renameFwFiles(ui->renameFirmware->isChecked());
|
||||
g.profile[g.id()].burnFirmware(ui->burnFirmware->isChecked());
|
||||
g.profile[g.id()].sdPath(ui->sdPath->text());
|
||||
g.profile[g.id()].pBackupDir(ui->profilebackupPath->text());
|
||||
g.profile[g.id()].penableBackup(ui->pbackupEnable->isChecked());
|
||||
g.profile[g.id()].splashFile(ui->SplashFileName->text());
|
||||
profile.channelOrder(ui->channelorderCB->currentIndex());
|
||||
profile.defaultMode(ui->stickmodeCB->currentIndex());
|
||||
profile.renameFwFiles(ui->renameFirmware->isChecked());
|
||||
profile.burnFirmware(ui->burnFirmware->isChecked());
|
||||
profile.sdPath(ui->sdPath->text());
|
||||
profile.pBackupDir(ui->profilebackupPath->text());
|
||||
profile.penableBackup(ui->pbackupEnable->isChecked());
|
||||
profile.splashFile(ui->SplashFileName->text());
|
||||
|
||||
// The profile name may NEVER be empty
|
||||
if (ui->profileNameLE->text().isEmpty())
|
||||
g.profile[g.id()].name(tr("My Radio"));
|
||||
profile.name(tr("My Radio"));
|
||||
else
|
||||
g.profile[g.id()].name(ui->profileNameLE->text());
|
||||
profile.name(ui->profileNameLE->text());
|
||||
|
||||
bool fwchange = false;
|
||||
Firmware * newFw = getFirmwareVariant(); // always !null
|
||||
// If a new fw type has been choosen, several things need to reset
|
||||
Firmware::setCurrentVariant(getFirmwareVariant());
|
||||
QString id = Firmware::getCurrentVariant()->getId();
|
||||
if (g.profile[g.id()].fwType() != id) {
|
||||
g.profile[g.id()].fwName("");
|
||||
g.profile[g.id()].initFwVariables();
|
||||
g.profile[g.id()].fwType(id);
|
||||
emit firmwareProfileChanged(g.id());
|
||||
if (Firmware::getCurrentVariant()->getId() != newFw->getId()) {
|
||||
// check if we're going to be converting to a new radio type and there are unsaved files in the main window
|
||||
if (mainWinHasDirtyChild && !Boards::isBoardCompatible(Firmware::getCurrentVariant()->getBoard(), newFw->getBoard())) {
|
||||
QString q = tr("<p><b>You cannot switch Radio Type or change Build Options while there are unsaved file changes. What do you wish to do?</b></p> <ul>" \
|
||||
"<li><i>Save All</i> - Save any open file(s) before saving Settings.<li>" \
|
||||
"<li><i>Reset</i> - Revert to the previous Radio Type and Build Options before saving Settings.</li>" \
|
||||
"<li><i>Cancel</i> - Return to the Settings editor dialog.</li></ul>");
|
||||
int resp = QMessageBox::question(this, windowTitle(), q, (QMessageBox::SaveAll | QMessageBox::Reset | QMessageBox::Cancel), QMessageBox::Cancel);
|
||||
if (resp == QMessageBox::SaveAll) {
|
||||
// signal main window to save files, need to do this before the fw actually changes
|
||||
emit firmwareProfileAboutToChange();
|
||||
}
|
||||
else if (resp == QMessageBox::Reset) {
|
||||
// bail out early before saving the radio type & firmware options
|
||||
QDialog::accept();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// we do not accept the dialog close
|
||||
return;
|
||||
}
|
||||
}
|
||||
Firmware::setCurrentVariant(newFw);
|
||||
profile.fwName("");
|
||||
profile.resetFwVariables();
|
||||
profile.fwType(newFw->getId());
|
||||
fwchange = true;
|
||||
}
|
||||
|
||||
QDialog::accept();
|
||||
|
||||
if (fwchange)
|
||||
emit firmwareProfileChanged(); // important to do this after the accepted() signal
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::on_snapshotPathButton_clicked()
|
||||
@@ -125,24 +160,33 @@ void AppPreferencesDialog::on_snapshotPathButton_clicked()
|
||||
|
||||
void AppPreferencesDialog::initSettings()
|
||||
{
|
||||
const Profile & profile = g.currentProfile();
|
||||
|
||||
ui->snapshotClipboardCKB->setChecked(g.snapToClpbrd());
|
||||
ui->burnFirmware->setChecked(g.profile[g.id()].burnFirmware());
|
||||
ui->burnFirmware->setChecked(profile.burnFirmware());
|
||||
ui->snapshotPath->setText(g.snapshotDir());
|
||||
ui->snapshotPath->setReadOnly(true);
|
||||
if (ui->snapshotClipboardCKB->isChecked()) {
|
||||
ui->snapshotPath->setDisabled(true);
|
||||
ui->snapshotPathButton->setDisabled(true);
|
||||
}
|
||||
|
||||
#if !defined(ALLOW_NIGHTLY_BUILDS)
|
||||
// TODO should we gray out nightly builds here?
|
||||
// remove nightly version option entirely unless it's the current one (because user might have nightly version also installed)
|
||||
if (g.OpenTxBranch() != AppData::BRANCH_NIGHTLY_UNSTABLE)
|
||||
ui->OpenTxBranch->removeItem(2);
|
||||
// if it's already selected, add a warning message
|
||||
else
|
||||
ui->updatesLayout->addWidget(new QLabel("<font color='red'>" % tr("Note: Nightly builds are not available in this version, Release/RC update channel will be used.") % "</font>", this));
|
||||
#endif
|
||||
ui->OpenTxBranch->setCurrentIndex(g.OpenTxBranch());
|
||||
|
||||
ui->autoCheckCompanion->setChecked(g.autoCheckApp());
|
||||
ui->autoCheckFirmware->setChecked(g.autoCheckFw());
|
||||
ui->showSplash->setChecked(g.showSplash());
|
||||
ui->historySize->setValue(g.historySize());
|
||||
ui->backLightColor->setCurrentIndex(g.backLight());
|
||||
ui->volumeGain->setValue(g.profile[g.id()].volumeGain() / 10.0);
|
||||
ui->volumeGain->setValue(profile.volumeGain() / 10.0);
|
||||
|
||||
if (IS_TARANIS(getCurrentBoard())) {
|
||||
ui->backLightColor->setEnabled(false);
|
||||
@@ -150,9 +194,9 @@ void AppPreferencesDialog::initSettings()
|
||||
|
||||
ui->simuSW->setChecked(g.simuSW());
|
||||
ui->opt_removeBlankSlots->setChecked(g.removeModelSlots());
|
||||
ui->opt_newMdl_useNone->setChecked(g.newModelAction() == 0);
|
||||
ui->opt_newMdl_useWizard->setChecked(g.newModelAction() == 1);
|
||||
ui->opt_newMdl_useEditor->setChecked(g.newModelAction() == 2);
|
||||
ui->opt_newMdl_useNone->setChecked(g.newModelAction() == AppData::MODEL_ACT_NONE);
|
||||
ui->opt_newMdl_useWizard->setChecked(g.newModelAction() == AppData::MODEL_ACT_WIZARD);
|
||||
ui->opt_newMdl_useEditor->setChecked(g.newModelAction() == AppData::MODEL_ACT_EDITOR);
|
||||
ui->libraryPath->setText(g.libDir());
|
||||
ui->ge_lineedit->setText(g.gePath());
|
||||
|
||||
@@ -204,15 +248,15 @@ void AppPreferencesDialog::initSettings()
|
||||
}
|
||||
#endif
|
||||
// Profile Tab Inits
|
||||
ui->channelorderCB->setCurrentIndex(g.profile[g.id()].channelOrder());
|
||||
ui->stickmodeCB->setCurrentIndex(g.profile[g.id()].defaultMode());
|
||||
ui->renameFirmware->setChecked(g.profile[g.id()].renameFwFiles());
|
||||
ui->sdPath->setText(g.profile[g.id()].sdPath());
|
||||
if (!g.profile[g.id()].pBackupDir().isEmpty()) {
|
||||
if (QDir(g.profile[g.id()].pBackupDir()).exists()) {
|
||||
ui->profilebackupPath->setText(g.profile[g.id()].pBackupDir());
|
||||
ui->channelorderCB->setCurrentIndex(profile.channelOrder());
|
||||
ui->stickmodeCB->setCurrentIndex(profile.defaultMode());
|
||||
ui->renameFirmware->setChecked(profile.renameFwFiles());
|
||||
ui->sdPath->setText(profile.sdPath());
|
||||
if (!profile.pBackupDir().isEmpty()) {
|
||||
if (QDir(profile.pBackupDir()).exists()) {
|
||||
ui->profilebackupPath->setText(profile.pBackupDir());
|
||||
ui->pbackupEnable->setEnabled(true);
|
||||
ui->pbackupEnable->setChecked(g.profile[g.id()].penableBackup());
|
||||
ui->pbackupEnable->setChecked(profile.penableBackup());
|
||||
} else {
|
||||
ui->pbackupEnable->setDisabled(true);
|
||||
}
|
||||
@@ -221,14 +265,14 @@ void AppPreferencesDialog::initSettings()
|
||||
ui->pbackupEnable->setDisabled(true);
|
||||
}
|
||||
|
||||
ui->profileNameLE->setText(g.profile[g.id()].name());
|
||||
ui->profileNameLE->setText(profile.name());
|
||||
|
||||
QString hwSettings;
|
||||
if (g.profile[g.id()].stickPotCalib() == "" ) {
|
||||
if (profile.stickPotCalib() == "" ) {
|
||||
hwSettings = tr("EMPTY: No radio settings stored in profile");
|
||||
}
|
||||
else {
|
||||
QString str = g.profile[g.id()].timeStamp();
|
||||
QString str = profile.timeStamp();
|
||||
if (str.isEmpty())
|
||||
hwSettings = tr("AVAILABLE: Radio settings of unknown age");
|
||||
else
|
||||
@@ -236,7 +280,7 @@ void AppPreferencesDialog::initSettings()
|
||||
}
|
||||
ui->lblGeneralSettings->setText(hwSettings);
|
||||
|
||||
QString currType = QStringList(g.profile[g.id()].fwType().split('-').mid(0, 2)).join('-');
|
||||
QString currType = QStringList(profile.fwType().split('-').mid(0, 2)).join('-');
|
||||
foreach(Firmware * firmware, Firmware::getRegisteredFirmwares()) {
|
||||
ui->downloadVerCB->addItem(firmware->getName(), firmware->getId());
|
||||
if (currType == firmware->getId()) {
|
||||
@@ -244,7 +288,7 @@ void AppPreferencesDialog::initSettings()
|
||||
}
|
||||
}
|
||||
|
||||
baseFirmwareChanged();
|
||||
onBaseFirmwareChanged();
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::on_libraryPathButton_clicked()
|
||||
@@ -344,7 +388,7 @@ void AppPreferencesDialog::on_joystickcalButton_clicked() {
|
||||
|
||||
void AppPreferencesDialog::on_sdPathButton_clicked()
|
||||
{
|
||||
QString fileName = QFileDialog::getExistingDirectory(this,tr("Select the folder replicating your SD structure"), g.profile[g.id()].sdPath());
|
||||
QString fileName = QFileDialog::getExistingDirectory(this,tr("Select the folder replicating your SD structure"), g.currentProfile().sdPath());
|
||||
if (!fileName.isEmpty()) {
|
||||
ui->sdPath->setText(fileName);
|
||||
}
|
||||
@@ -391,81 +435,47 @@ void AppPreferencesDialog::on_clearImageButton_clicked()
|
||||
ui->SplashFileName->clear();
|
||||
}
|
||||
|
||||
|
||||
void AppPreferencesDialog::showVoice(bool show)
|
||||
void AppPreferencesDialog::onBaseFirmwareChanged()
|
||||
{
|
||||
ui->voiceLabel->setVisible(show);
|
||||
ui->voiceCombo->setVisible(show);
|
||||
populateFirmwareOptions(getBaseFirmware());
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::baseFirmwareChanged()
|
||||
Firmware *AppPreferencesDialog::getBaseFirmware() const
|
||||
{
|
||||
QString selected_firmware = ui->downloadVerCB->currentData().toString();
|
||||
|
||||
foreach(Firmware * firmware, Firmware::getRegisteredFirmwares()) {
|
||||
if (firmware->getId() == selected_firmware) {
|
||||
populateFirmwareOptions(firmware);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Firmware::getFirmwareForId(ui->downloadVerCB->currentData().toString());
|
||||
}
|
||||
|
||||
Firmware * AppPreferencesDialog::getFirmwareVariant()
|
||||
Firmware * AppPreferencesDialog::getFirmwareVariant() const
|
||||
{
|
||||
QString selected_firmware = ui->downloadVerCB->currentData().toString();
|
||||
QString id = ui->downloadVerCB->currentData().toString();
|
||||
|
||||
foreach(Firmware * firmware, Firmware::getRegisteredFirmwares()) {
|
||||
QString id = firmware->getId();
|
||||
if (id == selected_firmware) {
|
||||
foreach(QCheckBox *cb, optionsCheckBoxes) {
|
||||
if (cb->isChecked()) {
|
||||
id += "-" + cb->text();
|
||||
}
|
||||
}
|
||||
|
||||
if (voice && voice->isChecked()) {
|
||||
id += "-tts" + ui->voiceCombo->currentText();
|
||||
}
|
||||
|
||||
if (ui->langCombo->count()) {
|
||||
id += "-" + ui->langCombo->currentText();
|
||||
}
|
||||
|
||||
return Firmware::getFirmwareForId(id);
|
||||
}
|
||||
foreach(QCheckBox *cb, optionsCheckBoxes.values()) {
|
||||
if (cb->isChecked())
|
||||
id += "-" + cb->text();
|
||||
}
|
||||
|
||||
// Should never occur...
|
||||
return Firmware::getDefaultVariant();
|
||||
if (ui->langCombo->count())
|
||||
id += "-" + ui->langCombo->currentText();
|
||||
|
||||
return Firmware::getFirmwareForId(id);
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::firmwareOptionChanged(bool state)
|
||||
void AppPreferencesDialog::onFirmwareOptionChanged(bool state)
|
||||
{
|
||||
QCheckBox *cb = qobject_cast<QCheckBox*>(sender());
|
||||
if (cb == voice) {
|
||||
showVoice(voice->isChecked());
|
||||
}
|
||||
Firmware * firmware=NULL;
|
||||
if (cb && state) {
|
||||
QVariant selected_firmware = ui->downloadVerCB->currentData();
|
||||
foreach(firmware, Firmware::getRegisteredFirmwares()) {
|
||||
if (firmware->getId() == selected_firmware) {
|
||||
foreach(QList<Option> opts, firmware->opts) {
|
||||
foreach(Option opt, opts) {
|
||||
if (cb->text() == opt.name) {
|
||||
foreach(Option other, opts) {
|
||||
if (other.name != opt.name) {
|
||||
foreach(QCheckBox *ocb, optionsCheckBoxes) {
|
||||
if (ocb->text() == other.name) {
|
||||
ocb->setChecked(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(cb && state))
|
||||
return;
|
||||
|
||||
// This de-selects any mutually exlusive options (that is, members of the same QList<Option> list).
|
||||
const Firmware::OptionsList & fwOpts = getBaseFirmware()->optionGroups();
|
||||
for (const Firmware::OptionsGroup & optGrp : fwOpts) {
|
||||
for (const Firmware::Option & opt : optGrp) {
|
||||
if (cb->text() == opt.name) {
|
||||
QCheckBox *ocb = nullptr;
|
||||
foreach(const Firmware::Option & other, optGrp)
|
||||
if (other.name != opt.name && (ocb = optionsCheckBoxes.value(other.name, nullptr)))
|
||||
ocb->setChecked(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -481,79 +491,67 @@ void AppPreferencesDialog::toggleAppLogSettings()
|
||||
|
||||
void AppPreferencesDialog::populateFirmwareOptions(const Firmware * firmware)
|
||||
{
|
||||
const Firmware * parent = firmware->getFirmwareBase();
|
||||
const Firmware * baseFw = firmware->getFirmwareBase();
|
||||
QStringList currVariant = Firmware::getCurrentVariant()->getId().split('-');
|
||||
const QString currLang = ui->langCombo->count() ? ui->langCombo->currentText() : currVariant.last();
|
||||
|
||||
updateLock = true;
|
||||
|
||||
QString id = Firmware::getCurrentVariant()->getId();
|
||||
ui->langCombo->clear();
|
||||
foreach(const char *lang, parent->languages) {
|
||||
for (const char *lang : baseFw->languageList()) {
|
||||
ui->langCombo->addItem(lang);
|
||||
if (id.endsWith(lang)) {
|
||||
if (currLang == lang) {
|
||||
ui->langCombo->setCurrentIndex(ui->langCombo->count() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
voice = NULL; // we will search for a voice checkbox
|
||||
if (optionsCheckBoxes.size()) {
|
||||
currVariant.clear();
|
||||
QMutableMapIterator<QString, QCheckBox *> it(optionsCheckBoxes);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
QCheckBox * cb = it.value();
|
||||
if (cb->isChecked())
|
||||
currVariant.append(it.key()); // keep previous selections
|
||||
ui->optionsLayout->removeWidget(cb);
|
||||
cb->deleteLater();
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
QWidget * prevFocus = ui->voiceCombo;
|
||||
foreach(QList<Option> opts, parent->opts) {
|
||||
foreach(Option opt, opts) {
|
||||
if (index >= optionsCheckBoxes.size()) {
|
||||
QCheckBox * checkbox = new QCheckBox(ui->profileTab);
|
||||
ui->optionsLayout->addWidget(checkbox, optionsCheckBoxes.count()/4, optionsCheckBoxes.count()%4, 1, 1);
|
||||
optionsCheckBoxes.push_back(checkbox);
|
||||
connect(checkbox, SIGNAL(toggled(bool)), this, SLOT(firmwareOptionChanged(bool)));
|
||||
if (prevFocus) {
|
||||
QWidget::setTabOrder(prevFocus, checkbox);
|
||||
}
|
||||
}
|
||||
|
||||
QCheckBox *cb = optionsCheckBoxes.at(index++);
|
||||
if (cb) {
|
||||
cb->show();
|
||||
cb->setText(opt.name);
|
||||
cb->setToolTip(opt.tooltip);
|
||||
cb->setCheckState(id.contains(opt.name) ? Qt::Checked : Qt::Unchecked);
|
||||
if (opt.name == QString("voice")) {
|
||||
voice = cb;
|
||||
}
|
||||
prevFocus = cb;
|
||||
}
|
||||
QWidget * prevFocus = ui->langCombo;
|
||||
for (const Firmware::OptionsGroup &optGrp : baseFw->optionGroups()) {
|
||||
for (const Firmware::Option &opt : optGrp) {
|
||||
QCheckBox * cb = new QCheckBox(ui->profileTab);
|
||||
cb->setText(opt.name);
|
||||
cb->setToolTip(opt.tooltip);
|
||||
cb->setChecked(currVariant.contains(opt.name));
|
||||
ui->optionsLayout->addWidget(cb, index / 4, index % 4);
|
||||
QWidget::setTabOrder(prevFocus, cb);
|
||||
// connect to duplicates check handler if this option is part of a group
|
||||
if (optGrp.size() > 1)
|
||||
connect(cb, &QCheckBox::toggled, this, &AppPreferencesDialog::onFirmwareOptionChanged);
|
||||
optionsCheckBoxes.insert(opt.name, cb);
|
||||
prevFocus = cb;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
for (; index<optionsCheckBoxes.size(); index++) {
|
||||
QCheckBox *cb = optionsCheckBoxes.at(index);
|
||||
cb->hide();
|
||||
cb->setCheckState(Qt::Unchecked);
|
||||
}
|
||||
|
||||
ui->voiceCombo->clear();
|
||||
foreach(const char *lang, parent->ttslanguages) {
|
||||
ui->voiceCombo->addItem(lang);
|
||||
if (id.contains(QString("-tts%1").arg(lang))) {
|
||||
ui->voiceCombo->setCurrentIndex(ui->voiceCombo->count() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
showVoice(voice && voice->isChecked());
|
||||
|
||||
// TODO: Remove once splash replacement supported on Horus
|
||||
// NOTE: 480x272 image causes issues on screens <800px high, needs a solution like scrolling once reinstated
|
||||
if (IS_HORUS(parent->getBoard())) {
|
||||
if (IS_HORUS(baseFw->getBoard())) {
|
||||
ui->widget_splashImage->hide();
|
||||
ui->SplashFileName->setText("");
|
||||
}
|
||||
else {
|
||||
ui->widget_splashImage->show();
|
||||
ui->SplashFileName->setText(g.profile[g.id()].splashFile());
|
||||
displayImage(g.profile[g.id()].splashFile());
|
||||
ui->SplashFileName->setText(g.currentProfile().splashFile());
|
||||
displayImage(g.currentProfile().splashFile());
|
||||
}
|
||||
|
||||
updateLock = false;
|
||||
QTimer::singleShot(50, this, SLOT(shrink()));
|
||||
QTimer::singleShot(50, this, &AppPreferencesDialog::shrink);
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::shrink()
|
||||
|
||||
@@ -38,33 +38,23 @@ class AppPreferencesDialog : public QDialog
|
||||
public:
|
||||
explicit AppPreferencesDialog(QWidget * parent = 0);
|
||||
~AppPreferencesDialog();
|
||||
|
||||
Joystick * joystick;
|
||||
|
||||
public slots:
|
||||
void accept() Q_DECL_OVERRIDE;
|
||||
void setMainWinHasDirtyChild(bool value);
|
||||
|
||||
signals:
|
||||
void firmwareProfileChanged(int profId);
|
||||
|
||||
private:
|
||||
QList<QCheckBox *> optionsCheckBoxes;
|
||||
bool updateLock;
|
||||
void showVoice(bool);
|
||||
void showVoice();
|
||||
void hideVoice();
|
||||
void populateLocale();
|
||||
void populateFirmwareOptions(const Firmware *);
|
||||
Firmware * getFirmwareVariant();
|
||||
QCheckBox * voice;
|
||||
|
||||
Ui::AppPreferencesDialog *ui;
|
||||
void initSettings();
|
||||
bool displayImage(const QString & fileName);
|
||||
void firmwareProfileChanged();
|
||||
void firmwareProfileAboutToChange(bool saveFiles = true);
|
||||
|
||||
protected slots:
|
||||
void shrink();
|
||||
void baseFirmwareChanged();
|
||||
void firmwareOptionChanged(bool state);
|
||||
void onBaseFirmwareChanged();
|
||||
void onFirmwareOptionChanged(bool state);
|
||||
void toggleAppLogSettings();
|
||||
|
||||
void writeValues();
|
||||
void on_libraryPathButton_clicked();
|
||||
void on_snapshotPathButton_clicked();
|
||||
void on_snapshotClipboardCKB_clicked();
|
||||
@@ -81,6 +71,18 @@ class AppPreferencesDialog : public QDialog
|
||||
void on_joystickChkB_clicked();
|
||||
void on_joystickcalButton_clicked();
|
||||
#endif
|
||||
|
||||
private:
|
||||
void initSettings();
|
||||
void populateFirmwareOptions(const Firmware *);
|
||||
Firmware * getBaseFirmware() const;
|
||||
Firmware * getFirmwareVariant() const;
|
||||
bool displayImage(const QString & fileName);
|
||||
|
||||
Ui::AppPreferencesDialog *ui;
|
||||
QMap<QString, QCheckBox *> optionsCheckBoxes;
|
||||
bool updateLock;
|
||||
bool mainWinHasDirtyChild;
|
||||
};
|
||||
|
||||
#endif // _APPPREFERENCESDIALOG_H_
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>863</width>
|
||||
<height>673</height>
|
||||
<width>741</width>
|
||||
<height>668</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -26,16 +26,6 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="sizePolicy">
|
||||
@@ -52,24 +42,37 @@
|
||||
<string>Radio Profile</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,0,0,0">
|
||||
<item row="8" column="2" colspan="2">
|
||||
<widget class="QPushButton" name="sdPathButton">
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
<item row="5" column="1">
|
||||
<widget class="QWidget" name="optionsWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="optionsLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="2" colspan="2">
|
||||
<widget class="QPushButton" name="ProfilebackupPathButton">
|
||||
<property name="toolTip">
|
||||
<string>The profile specific folder, if set, will override general Backup folder</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="4">
|
||||
<item row="7" column="0" colspan="4">
|
||||
<widget class="QWidget" name="widget_splashImage" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<property name="leftMargin">
|
||||
@@ -183,28 +186,19 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<item row="16" column="1">
|
||||
<widget class="QCheckBox" name="burnFirmware">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Profile Name</string>
|
||||
<string>Offer to write FW to Tx after download</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="profileNameLE"/>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="4">
|
||||
<widget class="Line" name="line_8">
|
||||
<property name="sizePolicy">
|
||||
@@ -218,319 +212,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Sans Serif</family>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Radio Type</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="downloadVerCB">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="langLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Menu Language</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1,1">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QComboBox" name="langCombo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="voiceLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Sans Serif</family>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Voice Language</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="voiceCombo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Set voice language.
|
||||
May be different from firmware language</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Build Options</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="4">
|
||||
<widget class="Line" name="splashSeparator">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="sdPathLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SD Structure path</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QLineEdit" name="sdPath">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="profilebackupPathLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The profile specific folder, if set, will override general Backup folder</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Backup folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QLineEdit" name="profilebackupPath">
|
||||
<property name="toolTip">
|
||||
<string>If set it will override the application general setting</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QCheckBox" name="pbackupEnable">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>if set, will override general backup enable</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable automatic backup before writing firmware</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>General Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QLabel" name="lblGeneralSettings">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">General Settings Label</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default Stick Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QComboBox" name="stickmodeCB">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Mode selection:
|
||||
|
||||
Mode 1:
|
||||
Left stick: Elevator, Rudder
|
||||
Right stick: Throttle, Aileron
|
||||
|
||||
Mode 2:
|
||||
Left stick: Throttle, Rudder
|
||||
Right stick: Elevator, Aileron
|
||||
|
||||
Mode 3:
|
||||
Left stick: Elevator, Aileron
|
||||
Right stick: Throttle, Rudder
|
||||
|
||||
Mode 4:
|
||||
Left stick: Throttle, Aileron
|
||||
Right stick: Elevator, Rudder
|
||||
|
||||
</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Mode 1 (RUD ELE THR AIL)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Mode 2 (RUD THR ELE AIL)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Mode 3 (AIL ELE THR RUD)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Mode 4 (AIL THR ELE RUD)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default Channel Order</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<item row="14" column="1">
|
||||
<widget class="QComboBox" name="channelorderCB">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
@@ -666,7 +348,30 @@ Mode 4:
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="downloadVerCB">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Build Options</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<widget class="QCheckBox" name="renameFirmware">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
@@ -679,8 +384,56 @@ Mode 4:
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<widget class="QCheckBox" name="burnFirmware">
|
||||
<item row="9" column="2" colspan="2">
|
||||
<widget class="QPushButton" name="sdPathButton">
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Profile Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="profileNameLE"/>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="profilebackupPathLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The profile specific folder, if set, will override general Backup folder</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Backup folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QLabel" name="lblGeneralSettings">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -688,24 +441,11 @@ Mode 4:
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Offer to write FW to Tx after download</string>
|
||||
<string notr="true">General Settings Label</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="1">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="4">
|
||||
<item row="8" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
@@ -724,34 +464,240 @@ Mode 4:
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QWidget" name="optionsWidget" native="true">
|
||||
<item row="13" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="optionsLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
<property name="text">
|
||||
<string>Default Stick Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<widget class="QComboBox" name="stickmodeCB">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Mode selection:
|
||||
|
||||
Mode 1:
|
||||
Left stick: Elevator, Rudder
|
||||
Right stick: Throttle, Aileron
|
||||
|
||||
Mode 2:
|
||||
Left stick: Throttle, Rudder
|
||||
Right stick: Elevator, Aileron
|
||||
|
||||
Mode 3:
|
||||
Left stick: Elevator, Aileron
|
||||
Right stick: Throttle, Rudder
|
||||
|
||||
Mode 4:
|
||||
Left stick: Throttle, Aileron
|
||||
Right stick: Elevator, Rudder
|
||||
|
||||
</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Mode 1 (RUD ELE THR AIL)</string>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Mode 2 (RUD THR ELE AIL)</string>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Mode 3 (AIL ELE THR RUD)</string>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Mode 4 (AIL THR ELE RUD)</string>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</layout>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default Channel Order</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QCheckBox" name="pbackupEnable">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>if set, will override general backup enable</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable automatic backup before writing firmware</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="4">
|
||||
<widget class="Line" name="splashSeparator">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QLineEdit" name="profilebackupPath">
|
||||
<property name="toolTip">
|
||||
<string>If set it will override the application general setting</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="sdPathLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SD Structure path</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="2" colspan="2">
|
||||
<widget class="QPushButton" name="ProfilebackupPathButton">
|
||||
<property name="toolTip">
|
||||
<string>The profile specific folder, if set, will override general Backup folder</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>General Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Sans Serif</family>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Radio Type</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="langLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Menu Language</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QLineEdit" name="sdPath">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="1">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="langCombo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -767,8 +713,8 @@ Mode 4:
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="7" column="1">
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="updatesLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoCheckFirmware">
|
||||
<property name="text">
|
||||
<string>Automatic check for OpenTX firmware updates</string>
|
||||
@@ -778,7 +724,7 @@ Mode 4:
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoCheckCompanion">
|
||||
<property name="text">
|
||||
<string>Automatic check for Companion updates</string>
|
||||
@@ -788,7 +734,7 @@ Mode 4:
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item>
|
||||
<widget class="QComboBox" name="OpenTxBranch">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
@@ -1464,14 +1410,22 @@ Mode 4:
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>tabWidget</tabstop>
|
||||
<tabstop>profileNameLE</tabstop>
|
||||
<tabstop>downloadVerCB</tabstop>
|
||||
<tabstop>langCombo</tabstop>
|
||||
<tabstop>voiceCombo</tabstop>
|
||||
<tabstop>sdPath</tabstop>
|
||||
<tabstop>sdPathButton</tabstop>
|
||||
<tabstop>profilebackupPath</tabstop>
|
||||
|
||||
@@ -57,7 +57,7 @@ burnConfigDialog::burnConfigDialog(QWidget *parent) :
|
||||
ui->label_sb1->hide();
|
||||
ui->label_sb3->hide();
|
||||
ui->samba_location->hide();
|
||||
ui->samba_port->hide();
|
||||
ui->samba_port->hide();
|
||||
ui->sb_browse->hide();
|
||||
}
|
||||
else if (IS_SKY9X(board)) {
|
||||
@@ -181,7 +181,7 @@ void burnConfigDialog::getSettings()
|
||||
ui->pushButton_3->setEnabled(true);
|
||||
} else {
|
||||
ui->pushButton_3->setDisabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void burnConfigDialog::putSettings()
|
||||
@@ -358,7 +358,7 @@ void burnConfigDialog::on_advCtrChkB_toggled(bool checked)
|
||||
else {
|
||||
ui->label_av3->show();
|
||||
ui->avrdude_mcu->show();
|
||||
QMessageBox::warning(this, tr("Companion"),
|
||||
QMessageBox::warning(this, CPN_STR_APP_NAME,
|
||||
tr("<b><u>WARNING!</u></b><br>Normally CPU type is automatically selected according to the chosen firmware.<br>If you change the CPU type the resulting eeprom could be inconsistent."),
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QMessageBox>
|
||||
#include <QSplashScreen>
|
||||
#if defined(JOYSTICKS) || defined(SIMU_AUDIO)
|
||||
#include <SDL.h>
|
||||
@@ -33,8 +34,10 @@
|
||||
#include "mainwindow.h"
|
||||
#include "version.h"
|
||||
#include "appdata.h"
|
||||
#include "simulatorinterface.h"
|
||||
#include "storage.h"
|
||||
#include "translations.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <QProxyStyle>
|
||||
@@ -51,6 +54,84 @@ class MyProxyStyle : public QProxyStyle
|
||||
};
|
||||
#endif
|
||||
|
||||
void importError()
|
||||
{
|
||||
QMessageBox::critical(nullptr, CPN_STR_APP_NAME, QCoreApplication::translate("Companion", "The saved settings could not be imported, please try again or continue with current settings."), QMessageBox::Ok, 0);
|
||||
}
|
||||
|
||||
void checkSettingsImport(bool force = false)
|
||||
{
|
||||
QString previousVersion;
|
||||
bool found;
|
||||
if (!(found = g.findPreviousVersionSettings(&previousVersion))) {
|
||||
found = QDir(CPN_SETTINGS_BACKUP_DIR).entryList(QStringList({"*.ini"}), QDir::Files).size() > 0;
|
||||
}
|
||||
if (!found && !force)
|
||||
return;
|
||||
|
||||
const QString impFileBtn = QCoreApplication::translate("Companion", "Import from File");
|
||||
const QString impPrevBtn = QCoreApplication::translate("Companion", "Import from v%1").arg(previousVersion);
|
||||
const QString impNoneBtn = QCoreApplication::translate("Companion", "Do not import");
|
||||
|
||||
QString msg;
|
||||
if (previousVersion.isEmpty()) {
|
||||
if (found)
|
||||
msg = QCoreApplication::translate("Companion", "We have found possible Companion settings backup file(s).\nDo you want to import settings from a file?");
|
||||
else
|
||||
msg = QCoreApplication::translate("Companion", "Import settings from a file, or start with current values.");
|
||||
}
|
||||
else {
|
||||
msg = QCoreApplication::translate("Companion", "We have found existing settings for Companion version: %1.\nDo you want to import them?\n\n" \
|
||||
"If you have a settings backup file, you may import that instead.").arg(previousVersion);
|
||||
}
|
||||
|
||||
const int ret = QMessageBox::question(nullptr, CPN_STR_APP_NAME, msg, impNoneBtn, impFileBtn, (previousVersion.isEmpty() ? QString() : impPrevBtn), 0, 0);
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
// Import from previous version
|
||||
if (ret == 2) {
|
||||
if (!g.importSettings(previousVersion)) {
|
||||
// very unlikely, but just in case of unexpected error, restart the import
|
||||
importError();
|
||||
checkSettingsImport();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Import from file
|
||||
bool err = false;
|
||||
QString impFile = CPN_SETTINGS_BACKUP_DIR;
|
||||
impFile = QFileDialog::getOpenFileName(nullptr, QCoreApplication::translate("Companion", "Select %1:").arg(CPN_STR_APP_SETTINGS_FILES), impFile, CPN_STR_APP_SETTINGS_FILTER);
|
||||
|
||||
if (!impFile.isEmpty() && QFileInfo(impFile).isReadable()) {
|
||||
QSettings fromSettings(impFile, QSettings::IniFormat);
|
||||
if (g.importSettings(&fromSettings)) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
importError();
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
// Restart the import prompt if user cancelled the file select dialog but we do have previous settings, or if we had a file import error.
|
||||
if (err || !previousVersion.isEmpty())
|
||||
checkSettingsImport();
|
||||
}
|
||||
|
||||
void printHelpText()
|
||||
{
|
||||
printf(qPrintable(QString(APP_COMPANION % " v%s\n\n")), VERSION);
|
||||
const char tmpl[] = " %s \t %s\n";
|
||||
printf(tmpl, "--export", QCoreApplication::translate("Companion", "Save application settings to file...").toUtf8().constData());
|
||||
printf(tmpl, "--import", QCoreApplication::translate("Companion", "Load application settings from file or previous version...").toUtf8().constData());
|
||||
printf(tmpl, "--defaults", QCoreApplication::translate("Companion", "Reset ALL application settings to default and remove radio profiles...").toUtf8().constData());
|
||||
printf(tmpl, "--quit ", QCoreApplication::translate("Companion", "Exit before settings initialization and application startup.").toUtf8().constData());
|
||||
printf(tmpl, "--version", QCoreApplication::translate("Companion", "Print version number and exit.").toUtf8().constData());
|
||||
printf(tmpl, "--help|-h", QCoreApplication::translate("Companion", "Print this help text.").toUtf8().constData());
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||
@@ -64,6 +145,19 @@ int main(int argc, char *argv[])
|
||||
app.setOrganizationDomain(COMPANY_DOMAIN);
|
||||
app.setAttribute(Qt::AA_DontShowIconsInMenus, false);
|
||||
|
||||
const QStringList args(QApplication::arguments());
|
||||
|
||||
if (args.contains("--help") || args.contains("-h") || args.contains("/?")) {
|
||||
printHelpText();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (args.contains("--version")) {
|
||||
printf("%s\n", VERSION);
|
||||
fflush(stdout);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Q_INIT_RESOURCE(companion);
|
||||
|
||||
if (AppDebugMessageHandler::instance())
|
||||
@@ -71,28 +165,45 @@ int main(int argc, char *argv[])
|
||||
|
||||
CustomDebug::setFilterRules();
|
||||
|
||||
if (!g.hasCurrentSettings()) {
|
||||
QString previousVersion;
|
||||
if (g.findPreviousVersionSettings(&previousVersion)) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText(QObject::tr("We have found existing settings for Companion version: %1.\nDo you want to import them?").arg(previousVersion));
|
||||
msgBox.setIcon(QMessageBox::Information);
|
||||
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
msgBox.setDefaultButton(QMessageBox::Yes);
|
||||
int ret = msgBox.exec();
|
||||
// handle settings export/import/reset via CLI
|
||||
|
||||
if (ret == QMessageBox::Yes)
|
||||
g.importSettings(previousVersion);
|
||||
bool doExport = args.contains("--export");
|
||||
bool doImport = args.contains("--import");
|
||||
bool doReset = args.contains("--defaults");
|
||||
|
||||
if (doExport)
|
||||
Helpers::exportAppSettings();
|
||||
|
||||
if (doReset) {
|
||||
char ok;
|
||||
printf("%s [Y/N] ", QCoreApplication::translate("Companion", "Reset ALL application settings to default values and remove radio profiles, are you sure?").toUtf8().constData());
|
||||
std::cin >> ok;
|
||||
if (ok != 'Y' && ok != 'y')
|
||||
exit(0);
|
||||
if (!doExport) {
|
||||
printf("%s [Y/N] ", QCoreApplication::translate("Companion", "Would you like to perform a backup first?").toUtf8().constData());
|
||||
std::cin >> ok;
|
||||
if (ok == 'Y' || ok == 'y')
|
||||
Helpers::exportAppSettings();
|
||||
}
|
||||
g.resetAllSettings();
|
||||
g.storeAllSettings();
|
||||
std::cout << QCoreApplication::translate("Companion", "Application settings were reset and saved.").toUtf8().constData() << std::endl;
|
||||
}
|
||||
g.init();
|
||||
|
||||
QStringList strl = QApplication::arguments();
|
||||
if (strl.contains("--version")) {
|
||||
printf("%s\n", VERSION);
|
||||
fflush(stdout);
|
||||
if (doImport)
|
||||
checkSettingsImport(true);
|
||||
|
||||
// give option to quit before settings init
|
||||
if (args.contains("--quit"))
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// end CLI handling
|
||||
|
||||
if (!doImport && g.isFirstUse())
|
||||
checkSettingsImport(false);
|
||||
|
||||
g.init();
|
||||
|
||||
QFile dbgLog;
|
||||
if (AppDebugMessageHandler::instance() && g.appDebugLog() && !g.appLogsDir().isEmpty() && QDir().mkpath(g.appLogsDir())) {
|
||||
@@ -126,9 +237,10 @@ int main(int argc, char *argv[])
|
||||
registerOpenTxFirmwares();
|
||||
SimulatorLoader::registerSimulators();
|
||||
|
||||
if (g.profile[g.id()].fwType().isEmpty()){
|
||||
g.profile[g.id()].fwType(Firmware::getDefaultVariant()->getId());
|
||||
g.profile[g.id()].fwName("");
|
||||
Profile & profile = g.currentProfile();
|
||||
if (profile.fwType().isEmpty()){
|
||||
profile.fwType(Firmware::getDefaultVariant()->getId());
|
||||
profile.fwName("");
|
||||
}
|
||||
|
||||
QString splashScreen;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/">
|
||||
<file>images/customize.png</file>
|
||||
<file>icon.png</file>
|
||||
<file alias="icon.png">images/icon.png</file>
|
||||
<file>../../CREDITS.txt</file>
|
||||
<file>../releasenotes.txt</file>
|
||||
<file>images/screenshot.png</file>
|
||||
@@ -136,6 +136,18 @@
|
||||
<file>images/simulator/X9E/right.png</file>
|
||||
<file>images/simulator/X9E/right_enter.png</file>
|
||||
<file>images/simulator/X9E/top.png</file>
|
||||
<file>images/simulator/XLITE/bottom.png</file>
|
||||
<file>images/simulator/XLITE/left.png</file>
|
||||
<file>images/simulator/XLITE/left_scrnshot.png</file>
|
||||
<file>images/simulator/XLITE/right.png</file>
|
||||
<file>images/simulator/XLITE/right_ent.png</file>
|
||||
<file>images/simulator/XLITE/top.png</file>
|
||||
<file>images/simulator/XLITE/right_exit.png</file>
|
||||
<file>images/simulator/XLITE/right_shift.png</file>
|
||||
<file>images/simulator/XLITE/right_right.png</file>
|
||||
<file>images/simulator/XLITE/right_left.png</file>
|
||||
<file>images/simulator/XLITE/right_up.png</file>
|
||||
<file>images/simulator/XLITE/right_down.png</file>
|
||||
<file>images/wizard/ailerons.png</file>
|
||||
<file>images/wizard/airbrakes.png</file>
|
||||
<file>images/wizard/elevons.png</file>
|
||||
@@ -235,6 +247,7 @@
|
||||
<file>images/library/10802.png</file>
|
||||
<file>themes/default/style.css</file>
|
||||
<file>themes/default/style-osx.css</file>
|
||||
<file>themes/default/modelprt.css</file>
|
||||
<file>themes/monochrome/16/paintbrush.png</file>
|
||||
<file>themes/monochrome/16/open.png</file>
|
||||
<file>themes/monochrome/16/edit.png</file>
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "appdata.h"
|
||||
#include "helpers.h"
|
||||
#include "modelslist.h"
|
||||
#include "styleeditdialog.h"
|
||||
#include <QPrinter>
|
||||
#include <QPrintDialog>
|
||||
|
||||
@@ -189,3 +190,10 @@ void CompareDialog::on_printFileButton_clicked()
|
||||
ui->textEdit->print(&printer);
|
||||
}
|
||||
}
|
||||
|
||||
void CompareDialog::on_styleButton_clicked()
|
||||
{
|
||||
StyleEditDialog *g = new StyleEditDialog(this, MODEL_PRINT_CSS);
|
||||
if (g->exec() == QDialog::Accepted)
|
||||
compare();
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ class CompareDialog : public QDialog
|
||||
void removeModelBtnClicked();
|
||||
void on_printButton_clicked();
|
||||
void on_printFileButton_clicked();
|
||||
void on_styleButton_clicked();
|
||||
|
||||
protected:
|
||||
virtual void closeEvent(QCloseEvent * event);
|
||||
|
||||
@@ -43,6 +43,9 @@
|
||||
<property name="text">
|
||||
<string>To compare models, drag and drop them anywhere in this window.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -65,6 +68,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="styleButton">
|
||||
<property name="text">
|
||||
<string>Style</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="printButton">
|
||||
<property name="text">
|
||||
|
||||
@@ -49,6 +49,12 @@
|
||||
#define CPN_MAX_MOUSE_ANALOGS 2
|
||||
#define CPN_MAX_ANALOGS (CPN_MAX_STICKS + CPN_MAX_POTS + CPN_MAX_MOUSE_ANALOGS)
|
||||
|
||||
#define CPN_STR_APP_NAME QCoreApplication::translate("Companion", "OpenTX Companion")
|
||||
#define CPN_STR_TTL_INFO QCoreApplication::translate("Companion", "Information") // shared Title Case words, eg. for a window title or section heading
|
||||
#define CPN_STR_TTL_WARNING QCoreApplication::translate("Companion", "Warning")
|
||||
#define CPN_STR_TTL_ERROR QCoreApplication::translate("Companion", "Error")
|
||||
#define CPN_STR_TTL_CONFIRM QCoreApplication::translate("Companion", "Please Confirm")
|
||||
|
||||
#define CPN_STR_FILES QCoreApplication::translate("Companion", "files")
|
||||
#define CPN_STR_RAD_MOD_SETTINGS QCoreApplication::translate("Companion", "Radio and Models settings")
|
||||
#define HEX_FILES_FILTER "HEX " % CPN_STR_FILES % " (*.hex);;"
|
||||
@@ -63,17 +69,15 @@
|
||||
#define EEPE_EEPROM_FILE_HEADER "EEPE EEPROM FILE"
|
||||
#define EEPE_MODEL_FILE_HEADER "EEPE MODEL FILE"
|
||||
|
||||
#define CPN_STR_APP_SETTINGS QCoreApplication::translate("Companion", "Application Settings")
|
||||
#define CPN_STR_APP_SETTINGS_FILES CPN_STR_APP_SETTINGS % " " % CPN_STR_FILES
|
||||
#define CPN_STR_APP_SETTINGS_FILTER CPN_STR_APP_SETTINGS_FILES % " (*.ini)"
|
||||
|
||||
#define CPN_STR_UNKNOWN_ITEM "???"
|
||||
|
||||
#define CPN_STR_SW_INDICATOR_UP QCoreApplication::translate("RawSwitch", "\xE2\x86\x91") // Switch up position indicator: Up arrow, or similar.
|
||||
#define CPN_STR_SW_INDICATOR_DN QCoreApplication::translate("RawSwitch", "\xE2\x86\x93") // Switch down position indicator: Down arrow, or similar.
|
||||
#define CPN_STR_SW_INDICATOR_NEUT QCoreApplication::translate("RawSwitch", "-") // Switch neutral (middle) position indicator.
|
||||
#define CPN_STR_SW_INDICATOR_REV QCoreApplication::translate("RawSwitch", "!") // Switch reversed logic (NOT) indicator.
|
||||
|
||||
enum DownloadBranchType {
|
||||
BRANCH_RELEASE_STABLE,
|
||||
BRANCH_RC_TESTING,
|
||||
BRANCH_NIGHTLY_UNSTABLE
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(DownloadBranchType)
|
||||
|
||||
#endif // _CONSTANTS_H_
|
||||
|
||||
@@ -74,7 +74,7 @@ bool Side::displayImage(QString fileName, Source pictSource)
|
||||
if (pictSource== PICT)
|
||||
*format = image.width()>WIDTH_9X ? LCDTARANIS : LCD9X;
|
||||
else if (pictSource == PROFILE)
|
||||
*format = (g.profile[g.id()].fwType().contains("x9")) ? LCDTARANIS : LCD9X;
|
||||
*format = (g.profile[g.id()].fwType().contains("x9")) ? LCDTARANIS : LCD9X;
|
||||
}
|
||||
|
||||
if (image.isNull()) {
|
||||
@@ -88,17 +88,17 @@ bool Side::displayImage(QString fileName, Source pictSource)
|
||||
|
||||
switch (pictSource) {
|
||||
case FW:
|
||||
fileNameEdit->setText(QObject::tr("FW: %1").arg(fileName));
|
||||
fileNameEdit->setText(CustomizeSplashDialog::tr("FW: %1").arg(fileName));
|
||||
*saveToFileName = fileName;
|
||||
*source = FW;
|
||||
break;
|
||||
case PICT:
|
||||
fileNameEdit->setText(QObject::tr("Pict: %1").arg(fileName));
|
||||
fileNameEdit->setText(CustomizeSplashDialog::tr("Pict: %1").arg(fileName));
|
||||
*saveToFileName = fileName;
|
||||
*source = PICT;
|
||||
break;
|
||||
case PROFILE:
|
||||
fileNameEdit->setText(QObject::tr("Profile image"));
|
||||
fileNameEdit->setText(CustomizeSplashDialog::tr("Profile image"));
|
||||
*saveToFileName = fileName;
|
||||
*source = PROFILE;
|
||||
break;
|
||||
@@ -158,7 +158,7 @@ CustomizeSplashDialog::CustomizeSplashDialog(QWidget *parent) :
|
||||
setWindowIcon(CompanionIcon("paintbrush.png"));
|
||||
ui->leftLibraryButton->setIcon(CompanionIcon("library.png"));
|
||||
ui->rightLibraryButton->setIcon(CompanionIcon("library.png"));
|
||||
|
||||
|
||||
left.imageLabel = ui->leftImageLabel;
|
||||
right.imageLabel = ui->rightImageLabel;
|
||||
left.fileNameEdit = ui->leftFileNameEdit;
|
||||
@@ -169,7 +169,7 @@ CustomizeSplashDialog::CustomizeSplashDialog(QWidget *parent) :
|
||||
right.libraryButton = ui->rightLibraryButton;
|
||||
left.invertButton = ui->leftInvertButton;
|
||||
right.invertButton = ui->rightInvertButton;
|
||||
|
||||
|
||||
left.loadFwButton = ui->leftLoadFwButton;
|
||||
right.loadFwButton = ui->rightLoadFwButton;
|
||||
left.loadPictButton = ui->leftLoadPictButton;
|
||||
@@ -203,7 +203,7 @@ void CustomizeSplashDialog::loadFirmware(Side side)
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Firmware File"), g.flashDir(), FLASH_FILES_FILTER);
|
||||
if (!fileName.isEmpty()) {
|
||||
if (!side.displayImage( fileName, FW ))
|
||||
QMessageBox::critical(this, tr("Error"), tr("Can not load embedded image from firmware file %1.").arg(fileName));
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Can not load embedded image from firmware file %1.").arg(fileName));
|
||||
else
|
||||
g.flashDir( QFileInfo(fileName).dir().absolutePath() );
|
||||
}
|
||||
@@ -223,7 +223,7 @@ void CustomizeSplashDialog::loadPicture(Side side)
|
||||
|
||||
if (!fileName.isEmpty()) {
|
||||
if (!side.displayImage( fileName, PICT ))
|
||||
QMessageBox::critical(this, tr("Error"), tr("Cannot load the image file %1.").arg(fileName));
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Cannot load the image file %1.").arg(fileName));
|
||||
else
|
||||
g.imagesDir( QFileInfo(fileName).dir().absolutePath() );
|
||||
}
|
||||
@@ -238,7 +238,7 @@ void CustomizeSplashDialog::loadProfile(Side side)
|
||||
|
||||
if (!fileName.isEmpty()) {
|
||||
if (!side.displayImage( fileName, PROFILE ))
|
||||
QMessageBox::critical(this, tr("Error"), tr("Cannot load profile image %1.").arg(fileName));
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Cannot load profile image %1.").arg(fileName));
|
||||
}
|
||||
side.markSourceButton();
|
||||
}
|
||||
@@ -252,7 +252,7 @@ void CustomizeSplashDialog::libraryButton_clicked( Side side )
|
||||
ld->exec();
|
||||
if (!fileName.isEmpty()) {
|
||||
if (!side.displayImage( fileName, UNDEFINED ))
|
||||
QMessageBox::critical(this, tr("Error"), tr("Cannot load the library image %1.").arg(fileName));
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Cannot load the library image %1.").arg(fileName));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
set(datamodels_SRCS
|
||||
rawitemdatamodels.cpp
|
||||
rawitemfilteredmodel.cpp
|
||||
)
|
||||
|
||||
set(datamodels_HDRS
|
||||
rawitemdatamodels.h
|
||||
rawitemfilteredmodel.h
|
||||
)
|
||||
|
||||
qt5_wrap_cpp(datamodels_SRCS ${datamodels_HDRS})
|
||||
|
||||
add_library(datamodels ${datamodels_SRCS} ${datamodels_HDRS})
|
||||
target_link_libraries(datamodels PRIVATE ${CPN_COMMON_LIB})
|
||||
|
||||
target_include_directories(datamodels
|
||||
PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"${COMPANION_SRC_DIRECTORY}"
|
||||
PUBLIC
|
||||
"${CMAKE_CURRENT_LIST_DIR}"
|
||||
)
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "rawitemdatamodels.h"
|
||||
#include "generalsettings.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "modeldata.h"
|
||||
|
||||
RawSourceItemModel::RawSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent) :
|
||||
AbstractRawItemDataModel(generalSettings, modelData, parent)
|
||||
{
|
||||
const Boards board = Boards(getCurrentBoard());
|
||||
Firmware * fw = getCurrentFirmware();
|
||||
const int anasCount = CPN_MAX_STICKS + board.getCapability(Board::Pots) + board.getCapability(Board::Sliders) + board.getCapability(Board::MouseAnalogs);
|
||||
|
||||
addItems(SOURCE_TYPE_NONE, RawSource::NoneGroup, 1);
|
||||
for (int i=0; i < fw->getCapability(LuaScripts); i++)
|
||||
addItems(SOURCE_TYPE_LUA_OUTPUT, RawSource::ScriptsGroup, fw->getCapability(LuaOutputsPerScript), i * 16);
|
||||
addItems(SOURCE_TYPE_VIRTUAL_INPUT, RawSource::InputsGroup, fw->getCapability(VirtualInputs));
|
||||
addItems(SOURCE_TYPE_STICK, RawSource::SourcesGroup, anasCount);
|
||||
addItems(SOURCE_TYPE_ROTARY_ENCODER, RawSource::SourcesGroup, fw->getCapability(RotaryEncoders));
|
||||
addItems(SOURCE_TYPE_TRIM, RawSource::TrimsGroup, board.getCapability(Board::NumTrims));
|
||||
addItems(SOURCE_TYPE_MAX, RawSource::SourcesGroup, 1);
|
||||
addItems(SOURCE_TYPE_SWITCH, RawSource::SwitchesGroup, board.getCapability(Board::Switches));
|
||||
addItems(SOURCE_TYPE_CUSTOM_SWITCH, RawSource::SwitchesGroup, fw->getCapability(LogicalSwitches));
|
||||
addItems(SOURCE_TYPE_CYC, RawSource::SourcesGroup, CPN_MAX_CYC);
|
||||
addItems(SOURCE_TYPE_PPM, RawSource::SourcesGroup, fw->getCapability(TrainerInputs));
|
||||
addItems(SOURCE_TYPE_CH, RawSource::SourcesGroup, fw->getCapability(Outputs));
|
||||
addItems(SOURCE_TYPE_SPECIAL, RawSource::TelemGroup, 5);
|
||||
addItems(SOURCE_TYPE_TELEMETRY, RawSource::TelemGroup, CPN_MAX_SENSORS * 3);
|
||||
addItems(SOURCE_TYPE_GVAR, RawSource::GVarsGroup, fw->getCapability(Gvars));
|
||||
}
|
||||
|
||||
void RawSourceItemModel::setDynamicItemData(QStandardItem * item, const RawSource & src) const
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
item->setText(src.toString(modelData, generalSettings, board));
|
||||
item->setData(src.isAvailable(modelData, generalSettings, board), IsAvailableRole);
|
||||
}
|
||||
|
||||
void RawSourceItemModel::addItems(const RawSourceType & type, const int group, const int count, const int start)
|
||||
{
|
||||
for (int i = start; i < start + count; i++) {
|
||||
const RawSource src = RawSource(type, i);
|
||||
QStandardItem * modelItem = new QStandardItem();
|
||||
modelItem->setData(src.toValue(), ItemIdRole);
|
||||
modelItem->setData(type, ItemTypeRole);
|
||||
modelItem->setData(group, ItemFlagsRole);
|
||||
setDynamicItemData(modelItem, src);
|
||||
appendRow(modelItem);
|
||||
}
|
||||
}
|
||||
|
||||
void RawSourceItemModel::update() const
|
||||
{
|
||||
for (int i=0; i < rowCount(); ++i)
|
||||
setDynamicItemData(item(i), RawSource(item(i)->data(ItemIdRole).toInt()));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// RawSwitchItemModel
|
||||
//
|
||||
|
||||
RawSwitchItemModel::RawSwitchItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent) :
|
||||
AbstractRawItemDataModel(generalSettings, modelData, parent)
|
||||
{
|
||||
Boards board = Boards(getCurrentBoard());
|
||||
Firmware * fw = getCurrentFirmware();
|
||||
|
||||
// Descending switch direction: NOT (!) switches
|
||||
addItems(SWITCH_TYPE_SENSOR, -CPN_MAX_SENSORS);
|
||||
addItems(SWITCH_TYPE_TELEMETRY, -1);
|
||||
addItems(SWITCH_TYPE_FLIGHT_MODE, -fw->getCapability(FlightModes));
|
||||
addItems(SWITCH_TYPE_VIRTUAL, -fw->getCapability(LogicalSwitches));
|
||||
addItems(SWITCH_TYPE_ROTARY_ENCODER, -fw->getCapability(RotaryEncoders));
|
||||
addItems(SWITCH_TYPE_TRIM, -board.getCapability(Board::NumTrimSwitches));
|
||||
addItems(SWITCH_TYPE_MULTIPOS_POT, -(board.getCapability(Board::MultiposPots) * board.getCapability(Board::MultiposPotsPositions)));
|
||||
addItems(SWITCH_TYPE_SWITCH, -board.getCapability(Board::SwitchPositions));
|
||||
|
||||
// Ascending switch direction (including zero)
|
||||
addItems(SWITCH_TYPE_TIMER_MODE, 5);
|
||||
addItems(SWITCH_TYPE_NONE, 1);
|
||||
addItems(SWITCH_TYPE_SWITCH, board.getCapability(Board::SwitchPositions));
|
||||
addItems(SWITCH_TYPE_MULTIPOS_POT, board.getCapability(Board::MultiposPots) * board.getCapability(Board::MultiposPotsPositions));
|
||||
addItems(SWITCH_TYPE_TRIM, board.getCapability(Board::NumTrimSwitches));
|
||||
addItems(SWITCH_TYPE_ROTARY_ENCODER, fw->getCapability(RotaryEncoders));
|
||||
addItems(SWITCH_TYPE_VIRTUAL, fw->getCapability(LogicalSwitches));
|
||||
addItems(SWITCH_TYPE_FLIGHT_MODE, fw->getCapability(FlightModes));
|
||||
addItems(SWITCH_TYPE_TELEMETRY, 1);
|
||||
addItems(SWITCH_TYPE_SENSOR, CPN_MAX_SENSORS);
|
||||
addItems(SWITCH_TYPE_ON, 1);
|
||||
addItems(SWITCH_TYPE_ONE, 1);
|
||||
}
|
||||
|
||||
void RawSwitchItemModel::setDynamicItemData(QStandardItem * item, const RawSwitch & rsw) const
|
||||
{
|
||||
const Board::Type board = getCurrentBoard();
|
||||
item->setText(rsw.toString(board, generalSettings, modelData));
|
||||
item->setData(rsw.isAvailable(modelData, generalSettings, board), IsAvailableRole);
|
||||
}
|
||||
|
||||
void RawSwitchItemModel::addItems(const RawSwitchType & type, int count)
|
||||
{
|
||||
// Most RawSwitch() indices are one-based (vs. typical zero); these are exceptions to the rule:
|
||||
const static QVector<int> rawSwitchIndexBaseZeroTypes = QVector<int>() << SWITCH_TYPE_NONE << SWITCH_TYPE_ON << SWITCH_TYPE_OFF << SWITCH_TYPE_TIMER_MODE;
|
||||
// handle exceptions in RawSwitch() index values
|
||||
const short rawIdxAdj = rawSwitchIndexBaseZeroTypes.contains(type) ? -1 : 0;
|
||||
|
||||
// determine cotext flags
|
||||
int context = RawSwitch::AllSwitchContexts;
|
||||
switch (type) {
|
||||
case SWITCH_TYPE_FLIGHT_MODE:
|
||||
context &= ~RawSwitch::MixesContext;
|
||||
// fallthrough
|
||||
case SWITCH_TYPE_VIRTUAL:
|
||||
case SWITCH_TYPE_SENSOR:
|
||||
context &= ~RawSwitch::GlobalFunctionsContext;
|
||||
break;
|
||||
|
||||
case SWITCH_TYPE_TIMER_MODE:
|
||||
context = RawSwitch::TimersContext;
|
||||
break;
|
||||
|
||||
case SWITCH_TYPE_NONE:
|
||||
context &= ~RawSwitch::TimersContext;
|
||||
break;
|
||||
|
||||
case SWITCH_TYPE_ON:
|
||||
case SWITCH_TYPE_ONE:
|
||||
context = RawSwitch::SpecialFunctionsContext | RawSwitch::GlobalFunctionsContext;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
int i = (count < 0 ? count : 1);
|
||||
count = (i < 0 ? 0 : count + i);
|
||||
for ( ; i < count; ++i) {
|
||||
RawSwitch rs(type, i + rawIdxAdj);
|
||||
QStandardItem * modelItem = new QStandardItem();
|
||||
modelItem->setData(rs.toValue(), ItemIdRole);
|
||||
modelItem->setData(type, ItemTypeRole);
|
||||
modelItem->setData(context, ItemFlagsRole);
|
||||
setDynamicItemData(modelItem, rs);
|
||||
appendRow(modelItem);
|
||||
}
|
||||
}
|
||||
|
||||
void RawSwitchItemModel::update() const
|
||||
{
|
||||
for (int i=0; i < rowCount(); ++i)
|
||||
setDynamicItemData(item(i), RawSwitch(item(i)->data(ItemIdRole).toInt()));
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RAWITEMDATAMODELS_H
|
||||
#define RAWITEMDATAMODELS_H
|
||||
|
||||
#include "rawsource.h"
|
||||
#include "rawswitch.h"
|
||||
|
||||
#include <QStandardItemModel>
|
||||
|
||||
class GeneralSettings;
|
||||
class ModelData;
|
||||
|
||||
class AbstractRawItemDataModel: public QStandardItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum DataRoles { ItemIdRole = Qt::UserRole, ItemTypeRole, ItemFlagsRole, IsAvailableRole };
|
||||
Q_ENUM(DataRoles)
|
||||
|
||||
explicit AbstractRawItemDataModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr) :
|
||||
QStandardItemModel(parent),
|
||||
generalSettings(generalSettings),
|
||||
modelData(modelData)
|
||||
{}
|
||||
|
||||
public slots:
|
||||
virtual void update() const = 0;
|
||||
|
||||
protected:
|
||||
const GeneralSettings * generalSettings;
|
||||
const ModelData * modelData;
|
||||
};
|
||||
|
||||
|
||||
class RawSourceItemModel: public AbstractRawItemDataModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RawSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void update() const override;
|
||||
|
||||
protected:
|
||||
void setDynamicItemData(QStandardItem * item, const RawSource & src) const;
|
||||
void addItems(const RawSourceType & type, const int group, const int count, const int start = 0);
|
||||
};
|
||||
|
||||
|
||||
class RawSwitchItemModel: public AbstractRawItemDataModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RawSwitchItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void update() const override;
|
||||
|
||||
protected:
|
||||
void setDynamicItemData(QStandardItem * item, const RawSwitch & rsw) const;
|
||||
void addItems(const RawSwitchType & type, int count);
|
||||
};
|
||||
|
||||
|
||||
#endif // RAWITEMDATAMODELS_H
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "rawitemfilteredmodel.h"
|
||||
#include "rawitemdatamodels.h"
|
||||
|
||||
RawItemFilteredModel::RawItemFilteredModel(QAbstractItemModel * sourceModel, int flags, QObject * parent) :
|
||||
QSortFilterProxyModel(parent),
|
||||
filterFlags(0)
|
||||
{
|
||||
setFilterRole(AbstractRawItemDataModel::IsAvailableRole);
|
||||
setFilterKeyColumn(0);
|
||||
setFilterFlags(flags);
|
||||
setDynamicSortFilter(true);
|
||||
setSourceModel(sourceModel);
|
||||
}
|
||||
|
||||
void RawItemFilteredModel::setFilterFlags(int flags)
|
||||
{
|
||||
if (filterFlags != flags) {
|
||||
filterFlags = flags;
|
||||
invalidateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
bool RawItemFilteredModel::filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const
|
||||
{
|
||||
const QModelIndex & srcIdx = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||
if (!srcIdx.isValid() || !sourceModel()->data(srcIdx, filterRole()).toBool())
|
||||
return false;
|
||||
|
||||
if (!filterFlags)
|
||||
return true;
|
||||
|
||||
bool ok;
|
||||
const int flags = sourceModel()->data(srcIdx, AbstractRawItemDataModel::ItemFlagsRole).toInt(&ok);
|
||||
return (ok && (!flags || (filterFlags & flags)));
|
||||
}
|
||||
|
||||
void RawItemFilteredModel::update() const
|
||||
{
|
||||
AbstractRawItemDataModel * model = qobject_cast<AbstractRawItemDataModel *>(sourceModel());
|
||||
if (model)
|
||||
model->update();
|
||||
}
|
||||
|
||||
|
||||
RawSourceFilterItemModel::RawSourceFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, int flags, QObject * parent) :
|
||||
RawItemFilteredModel(new RawSourceItemModel(generalSettings, modelData, parent), flags, parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RawSwitchFilterItemModel::RawSwitchFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, int context, QObject * parent) :
|
||||
RawItemFilteredModel(new RawSwitchItemModel(generalSettings, modelData, parent), context, parent)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RAWITEMFILTEREDMODEL_H
|
||||
#define RAWITEMFILTEREDMODEL_H
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class GeneralSettings;
|
||||
class ModelData;
|
||||
class RawSourceItemModel;
|
||||
class RawSwitchItemModel;
|
||||
|
||||
class RawItemFilteredModel: public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RawItemFilteredModel(QAbstractItemModel * sourceModel, int flags, QObject * parent = nullptr);
|
||||
explicit RawItemFilteredModel(QAbstractItemModel * sourceModel, QObject * parent = nullptr) : RawItemFilteredModel(sourceModel, 0, parent) {}
|
||||
|
||||
public slots:
|
||||
void setFilterFlags(int flags);
|
||||
void update() const;
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const override;
|
||||
|
||||
int filterFlags;
|
||||
};
|
||||
|
||||
|
||||
// The specialized "convenience" types below can go away once centralalized RawSource/RawSwitch item models are established.
|
||||
// These proxy classes will automatically create a source model of the corresponding type.
|
||||
|
||||
class RawSwitchFilterItemModel: public RawItemFilteredModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using RawItemFilteredModel::RawItemFilteredModel;
|
||||
|
||||
explicit RawSwitchFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, int context, QObject * parent = nullptr);
|
||||
};
|
||||
|
||||
|
||||
class RawSourceFilterItemModel: public RawItemFilteredModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using RawItemFilteredModel::RawItemFilteredModel;
|
||||
|
||||
explicit RawSourceFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, int flags, QObject * parent = nullptr);
|
||||
|
||||
explicit RawSourceFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr) :
|
||||
RawSourceFilterItemModel(generalSettings, modelData, 0, parent) {}
|
||||
};
|
||||
|
||||
#endif // RAWITEMFILTEREDMODEL_H
|
||||
@@ -0,0 +1,502 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "filesyncdialog.h"
|
||||
|
||||
#include "autobitsetcheckbox.h"
|
||||
#include "autocheckbox.h"
|
||||
#include "autocombobox.h"
|
||||
#include "autolineedit.h"
|
||||
#include "constants.h"
|
||||
#include "helpers.h"
|
||||
#include "progresswidget.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QComboBox>
|
||||
#include <QCompleter>
|
||||
#include <QCheckBox>
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QFileSystemModel>
|
||||
#include <QLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QMenu>
|
||||
#include <QSpinBox>
|
||||
|
||||
FileSyncDialog::FileSyncDialog(QWidget * parent, const SyncProcess::SyncOptions & syncOptions) :
|
||||
QDialog(parent),
|
||||
m_syncOptions(syncOptions),
|
||||
m_running(false)
|
||||
{
|
||||
setWindowTitle(tr("Synchronize Files"));
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setSizeGripEnabled(true);
|
||||
|
||||
setupUi();
|
||||
toggleExtraOptions(false);
|
||||
validate();
|
||||
updateRunningState();
|
||||
}
|
||||
|
||||
void FileSyncDialog::reject()
|
||||
{
|
||||
// override close event via window system close or esc. key
|
||||
if (m_running) {
|
||||
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Are you sure you wish to abort the sync?")) == QMessageBox::No)
|
||||
return;
|
||||
emit stopSync();
|
||||
// Force termination if the sync hasn't finished within 5s
|
||||
QElapsedTimer tim;
|
||||
tim.start();
|
||||
while (!tim.hasExpired(5000) && m_running)
|
||||
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 10);
|
||||
if (m_running)
|
||||
qWarning() << "Terminating thread while Sync process was still running.";
|
||||
}
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
// Create a widget with a line edit and folder select button and handles all interactions. Features autosuggest
|
||||
// path hints while typing, invalid paths shown in red.
|
||||
// This should probably be moved some place more reusable, esp. the QFileSystemModel.
|
||||
static QWidget * folderSelectorWidget(QLineEdit * le, QWidget * parent)
|
||||
{
|
||||
static QFileSystemModel fileModel;
|
||||
static bool init = false;
|
||||
if (!init) {
|
||||
init = true;
|
||||
fileModel.setFilter(QDir::Dirs);
|
||||
fileModel.setRootPath("/");
|
||||
}
|
||||
|
||||
QWidget * fsw = new QWidget(parent);
|
||||
//le = new QLineEdit(parent);
|
||||
QCompleter * fsc = new QCompleter(fsw);
|
||||
fsc->setModel(&fileModel);
|
||||
//fsc->setCompletionMode(QCompleter::InlineCompletion);
|
||||
le->setCompleter(fsc);
|
||||
|
||||
QToolButton * btn = new QToolButton(fsw);
|
||||
btn->setIcon(CompanionIcon("open.png"));
|
||||
QHBoxLayout * l = new QHBoxLayout(fsw);
|
||||
l->setContentsMargins(0,0,0,0);
|
||||
l->setSpacing(3);
|
||||
l->addWidget(le);
|
||||
l->addWidget(btn);
|
||||
|
||||
QObject::connect(btn, &QToolButton::clicked, [=]() {
|
||||
QString dir = QFileDialog::getExistingDirectory(parent, fsw->property("fileDialogTitle").toString(), le->text(), 0);
|
||||
if (!dir.isEmpty()) {
|
||||
le->setText(QDir::toNativeSeparators(dir));
|
||||
le->setFocus();
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(le, &QLineEdit::textChanged, [=](const QString & text) {
|
||||
if (QFile::exists(text))
|
||||
le->setStyleSheet("");
|
||||
else
|
||||
le->setStyleSheet("QLineEdit {color: red;}");
|
||||
});
|
||||
|
||||
return fsw;
|
||||
}
|
||||
|
||||
void FileSyncDialog::setupUi()
|
||||
{
|
||||
const QString srcArw = CPN_STR_SW_INDICATOR_UP % " ";
|
||||
const QString dstArw = CPN_STR_SW_INDICATOR_DN % " ";
|
||||
int row = 0;
|
||||
|
||||
CompanionIcon playIcon("play.png");
|
||||
playIcon.addImage("stop.png", QIcon::Normal, QIcon::On);
|
||||
|
||||
QLabel * lblSrc = new QLabel(tr("Source Folder:"), this);
|
||||
AutoLineEdit * leSrc = new AutoLineEdit(this, true);
|
||||
leSrc->setField(m_syncOptions.folderA);
|
||||
leSrc->setText(QDir::toNativeSeparators(m_syncOptions.folderA));
|
||||
QWidget * wdgSrc = folderSelectorWidget(leSrc, this);
|
||||
|
||||
QLabel * lblDst = new QLabel(tr("Destination Folder:"), this);
|
||||
AutoLineEdit * leDst = new AutoLineEdit(this, true);
|
||||
leDst->setField(m_syncOptions.folderB);
|
||||
leDst->setText(QDir::toNativeSeparators(m_syncOptions.folderB));
|
||||
QWidget * wdgDst = folderSelectorWidget(leDst, this);
|
||||
|
||||
AutoComboBox * syncDir = new AutoComboBox(this);
|
||||
syncDir->addItem(tr("%1%2 Both directions, to destination folder first").arg(dstArw, srcArw), SyncProcess::SYNC_A2B_B2A);
|
||||
syncDir->addItem(tr("%1%2 Both directions, to source folder first").arg(srcArw, dstArw), SyncProcess::SYNC_B2A_A2B);
|
||||
syncDir->addItem(tr(" %1 Only from source folder to destination folder").arg(dstArw), SyncProcess::SYNC_A2B);
|
||||
syncDir->addItem(tr(" %1 Only from destination folder to source folder").arg(srcArw), SyncProcess::SYNC_B2A);
|
||||
syncDir->setCurrentIndex(-1); // we set the default option later
|
||||
|
||||
AutoComboBox * copyMode = new AutoComboBox(this);
|
||||
copyMode->setToolTip(tr("How to handle overwriting files which already exist in the destination folder."));
|
||||
copyMode->addItem(tr("Copy only if newer and different (compare contents)"), SyncProcess::OVERWR_NEWER_IF_DIFF);
|
||||
copyMode->addItem(tr("Copy only if newer (do not compare contents)"), SyncProcess::OVERWR_NEWER_ALWAYS);
|
||||
copyMode->addItem(tr("Copy only if different (ignore file time stamps)"), SyncProcess::OVERWR_IF_DIFF);
|
||||
copyMode->addItem(tr("Always copy (force overwite existing files)"), SyncProcess::OVERWR_ALWAYS);
|
||||
copyMode->setField(m_syncOptions.compareType);
|
||||
|
||||
QSpinBox * maxSize = new QSpinBox(this);
|
||||
maxSize->setRange(0, 100 * 1024);
|
||||
maxSize->setAccelerated(true);
|
||||
maxSize->setSpecialValueText(tr("Any size"));
|
||||
maxSize->setToolTip(tr("Skip files larger than this size. Enter zero for unlimited."));
|
||||
maxSize->setGroupSeparatorShown(true);
|
||||
maxSize->setValue(0); // we set the real default value later
|
||||
|
||||
AutoComboBox * logLevel = new AutoComboBox(this);
|
||||
logLevel->setToolTip(tr("Minimum reporting level. Events of this type and of higher importance are shown.\n" \
|
||||
"WARNING: High log rates may make the user interface temporarily unresponsive."));
|
||||
logLevel->addItem(tr("Skipped"), QtDebugMsg);
|
||||
logLevel->addItem(tr("Created"), QtInfoMsg);
|
||||
logLevel->addItem(tr("Updated"), QtWarningMsg);
|
||||
//logLevel->addItem(tr("Item Deleted"), QtCriticalMsg); // unused
|
||||
logLevel->addItem(tr("Errors Only"), QtFatalMsg);
|
||||
logLevel->setField(m_syncOptions.logLevel);
|
||||
|
||||
AutoBitsetCheckBox * testRun = new AutoBitsetCheckBox(m_syncOptions.flags, SyncProcess::OPT_DRY_RUN, tr("Test-run only"), this);
|
||||
testRun->setToolTip(tr("Run as normal but do not actually copy anything. Useful for verifying results before real sync."));
|
||||
|
||||
// layout to hold size spinbox and checkbox option(s)
|
||||
QHBoxLayout * hlay1 = new QHBoxLayout();
|
||||
hlay1->addWidget(maxSize, 1);
|
||||
hlay1->addWidget(testRun);
|
||||
hlay1->addWidget(new QLabel(tr("Log Level:"), this));
|
||||
hlay1->addWidget(logLevel);
|
||||
|
||||
// "extra" options
|
||||
|
||||
QLabel * lbFilter = new QLabel(tr("Filters:"), this);
|
||||
lbFilter->setToolTip(tr("The \"Include\" filter will only copy files which match the pattern(s).\n" \
|
||||
"The \"Exclude\" filter will skip files matching the filter pattern(s).\n" \
|
||||
"The Include filter is evaluated first."));
|
||||
|
||||
AutoLineEdit * leFiltExc = new AutoLineEdit(this, true);
|
||||
leFiltExc->setField(m_syncOptions.excludeFilter);
|
||||
leFiltExc->setToolTip(tr("One or more file pattern(s) to exclude, separated by commas.\n" "Blank means exclude none. ?, *, and [...] wildcards accepted."));
|
||||
|
||||
AutoLineEdit * leFiltInc = new AutoLineEdit(this, true);
|
||||
leFiltInc->setField(m_syncOptions.includeFilter);
|
||||
leFiltInc->setToolTip(tr("One or more file pattern(s) to include, separated by commas.\n" "Blank means include all. ?, *, and [...] wildcards accepted."));
|
||||
|
||||
// layout to hold filter options
|
||||
QHBoxLayout * filtLo = new QHBoxLayout();
|
||||
filtLo->addWidget(new QLabel(tr("Include:"), this));
|
||||
filtLo->addWidget(leFiltInc, 1);
|
||||
filtLo->addWidget(new QLabel(tr("Exclude:"), this));
|
||||
filtLo->addWidget(leFiltExc, 1);
|
||||
|
||||
// file options
|
||||
QHBoxLayout * filOptsLo = new QHBoxLayout();
|
||||
filOptsLo->addWidget(new AutoBitsetCheckBox(m_syncOptions.dirFilterFlags, QDir::CaseSensitive, tr("Case sensitive"), this));
|
||||
filOptsLo->addWidget(new AutoBitsetCheckBox(m_syncOptions.dirFilterFlags, QDir::NoSymLinks, true, tr("Follow links"), this));
|
||||
filOptsLo->addWidget(new AutoBitsetCheckBox(m_syncOptions.dirFilterFlags, QDir::Hidden, tr("Include hidden"), this));
|
||||
|
||||
// folder options
|
||||
QHBoxLayout * dirOptsLo = new QHBoxLayout();
|
||||
dirOptsLo->addWidget(new AutoBitsetCheckBox(m_syncOptions.flags, SyncProcess::OPT_RECURSIVE, tr("Recursive"), this));
|
||||
dirOptsLo->addWidget(new AutoBitsetCheckBox(m_syncOptions.flags, SyncProcess::OPT_SKIP_DIR_LINKS, true, tr("Follow links"), this));
|
||||
dirOptsLo->addWidget(new AutoBitsetCheckBox(m_syncOptions.dirFilterFlags, QDir::Dirs, true, tr("Skip empty"), this));
|
||||
dirOptsLo->addWidget(new AutoBitsetCheckBox(m_syncOptions.dirFilterFlags, QDir::AllDirs, true, tr("Apply filters"), this));
|
||||
|
||||
// extra options container widget and layout
|
||||
ui_extraOptions = new QWidget(this);
|
||||
ui_extraOptions->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
|
||||
|
||||
QGridLayout * xOptsLay = new QGridLayout(ui_extraOptions);
|
||||
xOptsLay->setContentsMargins(0, 0, 0, 0);
|
||||
xOptsLay->addWidget(lbFilter, row, 0);
|
||||
xOptsLay->addLayout(filtLo, row++, 1);
|
||||
xOptsLay->addWidget(new QLabel(tr("Filter Options:"), this), row, 0);
|
||||
xOptsLay->addLayout(filOptsLo, row++, 1);
|
||||
xOptsLay->addWidget(new QLabel(tr("Folder Options:"), this), row, 0);
|
||||
xOptsLay->addLayout(dirOptsLo, row++, 1);
|
||||
|
||||
// status label
|
||||
ui_statusLabel = new QLabel(this);
|
||||
// progress widget
|
||||
ui_progress = new ProgressWidget(this);
|
||||
ui_progress->setMinimumWidth(0);
|
||||
ui_progress->setVisible(false);
|
||||
|
||||
// dialog buttons & menu
|
||||
|
||||
QMenu * optionsMenu = new QMenu(tr("Options"));
|
||||
QAction * xtrasAct = optionsMenu->addAction(CompanionIcon("fuses.png"), tr("Show extra options"), this, &FileSyncDialog::toggleExtraOptions);
|
||||
xtrasAct->setCheckable(true);
|
||||
connect(this, &FileSyncDialog::extraOptionsToggled, xtrasAct, &QAction::setChecked);
|
||||
optionsMenu->addAction(CompanionIcon("paintbrush.png"), tr("Reset to defaults"), this, &FileSyncDialog::resetOptions);
|
||||
|
||||
QToolButton * btnOpts = new QToolButton(this);
|
||||
btnOpts->setDefaultAction(xtrasAct);
|
||||
btnOpts->setMenu(optionsMenu);
|
||||
btnOpts->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
btnOpts->setPopupMode(QToolButton::MenuButtonPopup);
|
||||
btnOpts->setToolTip(xtrasAct->text());
|
||||
|
||||
ui_btnStartStop = new QToolButton(this);
|
||||
ui_btnStartStop->setCheckable(true);
|
||||
ui_btnStartStop->setIcon(playIcon);
|
||||
ui_btnStartStop->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
|
||||
ui_btnClose = new QToolButton(this);
|
||||
ui_btnClose->setText(tr("Close"));
|
||||
ui_btnClose->setToolButtonStyle(Qt::ToolButtonTextOnly);
|
||||
ui_btnClose->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
|
||||
|
||||
ui_buttonBox = new QDialogButtonBox(this);
|
||||
ui_buttonBox->addButton(btnOpts, QDialogButtonBox::ActionRole);
|
||||
ui_buttonBox->addButton(ui_btnStartStop, QDialogButtonBox::ActionRole);
|
||||
ui_buttonBox->addButton(ui_btnClose, QDialogButtonBox::RejectRole);
|
||||
|
||||
// The options group box.
|
||||
ui_optionsPanel = new QGroupBox(tr("Options"), this);
|
||||
QGridLayout * optsLay = new QGridLayout(ui_optionsPanel);
|
||||
row = 0;
|
||||
optsLay->addWidget(lblSrc, row, 0);
|
||||
optsLay->addWidget(wdgSrc, row++, 1);
|
||||
optsLay->addWidget(lblDst, row, 0);
|
||||
optsLay->addWidget(wdgDst, row++, 1);
|
||||
optsLay->addWidget(new QLabel(tr("Sync. Direction:"), this), row, 0);
|
||||
optsLay->addWidget(syncDir, row++, 1);
|
||||
optsLay->addWidget(new QLabel(tr("Existing Files:"), this), row, 0);
|
||||
optsLay->addWidget(copyMode, row++, 1);
|
||||
optsLay->addWidget(new QLabel(tr("Max. File Size:"), this), row, 0);
|
||||
optsLay->addLayout(hlay1, row++, 1);
|
||||
optsLay->addWidget(ui_extraOptions, row, 0, 1, 2);
|
||||
|
||||
// layout to hold warning label and button box
|
||||
QHBoxLayout * hlay2 = new QHBoxLayout();
|
||||
hlay2->addWidget(ui_statusLabel, 1);
|
||||
hlay2->addWidget(ui_buttonBox);
|
||||
|
||||
// Create main layout and add options, progress, buttons.
|
||||
QVBoxLayout * dlgL = new QVBoxLayout(this);
|
||||
dlgL->addWidget(ui_optionsPanel, 0, Qt::AlignTop);
|
||||
dlgL->addLayout(hlay2);
|
||||
dlgL->addWidget(ui_progress, 1);
|
||||
|
||||
// Connect all signal handlers
|
||||
|
||||
// source path
|
||||
connect(leSrc, &AutoLineEdit::textChanged, this, &FileSyncDialog::validate);
|
||||
// destination path
|
||||
connect(leDst, &AutoLineEdit::textChanged, this, &FileSyncDialog::validate);
|
||||
|
||||
// function to dis/enable the OVERWR_ALWAYS option depending on sync direction
|
||||
connect(syncDir, &AutoComboBox::currentDataChanged, [=](int dir) {
|
||||
int idx = copyMode->findData(SyncProcess::OVERWR_ALWAYS);
|
||||
int flg = (dir == SyncProcess::SYNC_A2B || dir == SyncProcess::SYNC_B2A) ? 33 : 0;
|
||||
if (!flg && idx == copyMode->currentIndex())
|
||||
copyMode->setCurrentIndex(copyMode->findData(SyncProcess::OVERWR_NEWER_IF_DIFF));
|
||||
copyMode->setItemData(idx, flg, Qt::UserRole - 1);
|
||||
});
|
||||
|
||||
// function to set magnitude of file size spinbox, KB or MB
|
||||
connect(maxSize, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), [=](int value) {
|
||||
const QSignalBlocker blocker(maxSize);
|
||||
int multi = maxSize->property("multi").isValid() ? maxSize->property("multi").toInt() : 0;
|
||||
if (value >= 10 * 1024 && multi != 1024 * 1024) {
|
||||
// KB -> MB
|
||||
multi = 1024 * 1024;
|
||||
maxSize->setValue(value / 1024);
|
||||
maxSize->setMaximum(100);
|
||||
maxSize->setSingleStep(1);
|
||||
maxSize->setSuffix(tr(" MB"));
|
||||
}
|
||||
else if ((value < 10 && multi != 1024) || !multi) {
|
||||
// MB -> KB
|
||||
if (multi)
|
||||
value *= 1024;
|
||||
multi = 1024;
|
||||
if (value == 9 * 1024)
|
||||
value += 1024 - 32; // avoid large jump when stepping from 10MB to 10,208KB
|
||||
maxSize->setMaximum(100 * 1024);
|
||||
maxSize->setValue(value);
|
||||
maxSize->setSingleStep(32);
|
||||
maxSize->setSuffix(tr(" KB"));
|
||||
}
|
||||
maxSize->setProperty("multi", multi);
|
||||
m_syncOptions.maxFileSize = value * multi;
|
||||
});
|
||||
|
||||
// we set these after connections are made because we want the signal processors to run
|
||||
syncDir->setField(m_syncOptions.direction);
|
||||
maxSize->setValue(m_syncOptions.maxFileSize / 1024);
|
||||
|
||||
// connect Reset action to all fields
|
||||
for (AutoLineEdit * a : ui_optionsPanel->findChildren<AutoLineEdit *>())
|
||||
connect(this, &FileSyncDialog::optionsWereReset, a, &AutoLineEdit::updateValue);
|
||||
for (AutoComboBox * a : ui_optionsPanel->findChildren<AutoComboBox *>())
|
||||
connect(this, &FileSyncDialog::optionsWereReset, a, &AutoComboBox::updateValue);
|
||||
for (AutoBitsetCheckBox * a : ui_optionsPanel->findChildren<AutoBitsetCheckBox *>())
|
||||
connect(this, &FileSyncDialog::optionsWereReset, a, &AutoBitsetCheckBox::updateValue);
|
||||
connect(this, &FileSyncDialog::optionsWereReset, [=]() { maxSize->setValue(m_syncOptions.maxFileSize / 1024); });
|
||||
|
||||
// React to name changes for source and destination path labels
|
||||
connect(this, &FileSyncDialog::folderNameAChanged, [=](const QString &text) {
|
||||
lblSrc->setText(text % ":");
|
||||
wdgSrc->setProperty("fileDialogTitle", text);
|
||||
});
|
||||
connect(this, &FileSyncDialog::folderNameBChanged, [=](const QString &text) {
|
||||
lblDst->setText(text % ":");
|
||||
wdgDst->setProperty("fileDialogTitle", text);
|
||||
});
|
||||
|
||||
// button actions
|
||||
connect(ui_btnStartStop, &QPushButton::clicked, this, &FileSyncDialog::toggleSync);
|
||||
connect(ui_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
connect(ui_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(ui_progress, &ProgressWidget::detailsToggled, this, &FileSyncDialog::adjustSizeDelayed);
|
||||
}
|
||||
|
||||
void FileSyncDialog::toggleSync(bool)
|
||||
{
|
||||
if (m_running) {
|
||||
setCursor(Qt::WaitCursor);
|
||||
emit stopSync();
|
||||
return;
|
||||
}
|
||||
|
||||
ui_progress->clearDetails();
|
||||
ui_progress->setInfo("");
|
||||
SyncProcess * syncProcess = new SyncProcess(m_syncOptions);
|
||||
|
||||
// move sync process to separate thread, we only use signals/slots from here on...
|
||||
QThread * syncThread = new QThread(this);
|
||||
syncProcess->moveToThread(syncThread);
|
||||
|
||||
// ...and quite a few of them!
|
||||
connect(this, &FileSyncDialog::startSync, syncProcess, &SyncProcess::run);
|
||||
connect(this, &FileSyncDialog::stopSync, syncProcess, &SyncProcess::stop);
|
||||
connect(syncProcess, &SyncProcess::started, this, &FileSyncDialog::onSyncStarted);
|
||||
connect(syncProcess, &SyncProcess::finished, this, &FileSyncDialog::onSyncFinished);
|
||||
connect(syncProcess, &SyncProcess::statusMessage, this, &FileSyncDialog::setStatusText);
|
||||
connect(syncProcess, &SyncProcess::statusUpdate, this, &FileSyncDialog::onStatusUpdate);
|
||||
connect(syncProcess, &SyncProcess::fileCountChanged, ui_progress, &ProgressWidget::setMaximum);
|
||||
connect(syncProcess, &SyncProcess::progressMessage, ui_progress, &ProgressWidget::addMessage);
|
||||
connect(syncProcess, &SyncProcess::finished, syncThread, &QThread::quit);
|
||||
connect(syncThread, &QThread::finished, syncThread, &QThread::deleteLater);
|
||||
connect(syncThread, &QThread::destroyed, syncProcess, &SyncProcess::deleteLater);
|
||||
|
||||
// go
|
||||
syncThread->start(QThread::LowPriority);
|
||||
emit startSync();
|
||||
}
|
||||
|
||||
void FileSyncDialog::onSyncStarted()
|
||||
{
|
||||
m_running = true;
|
||||
updateRunningState();
|
||||
}
|
||||
|
||||
void FileSyncDialog::onSyncFinished()
|
||||
{
|
||||
m_running = false;
|
||||
updateRunningState();
|
||||
if (parentWidget())
|
||||
QApplication::alert(parentWidget());
|
||||
}
|
||||
|
||||
void FileSyncDialog::updateRunningState()
|
||||
{
|
||||
ui_btnStartStop->setChecked(m_running);
|
||||
ui_optionsPanel->setEnabled(!m_running);
|
||||
ui_btnClose->setEnabled(!m_running);
|
||||
ui_btnStartStop->setText(m_running ? tr("Abort") : tr("Start"));
|
||||
if (m_running) {
|
||||
ui_progress->setVisible(true); // don't hide after run
|
||||
}
|
||||
else {
|
||||
setCursor(Qt::ArrowCursor); // in case we set a wait cursor upon abort request
|
||||
}
|
||||
}
|
||||
|
||||
void FileSyncDialog::onStatusUpdate(const SyncProcess::SyncStatus & stat)
|
||||
{
|
||||
static const QString reportTemplate = tr("Total: <b>%1</b>; Created: <b>%2</b>; Updated: <b>%3</b>; Skipped: <b>%4</b>; Errors: <font color=%6><b>%5</b></font>;");
|
||||
ui_progress->setInfo((stat.index < stat.count ? tr("Current: <b>%1</b> of ").arg(stat.index) : "") % reportTemplate.arg(stat.count).arg(stat.created).arg(stat.updated).arg(stat.skipped).arg(stat.errored).arg(stat.errored ? "red" : "black"));
|
||||
ui_progress->setValue(stat.index);
|
||||
}
|
||||
|
||||
void FileSyncDialog::setSyncOptions(const SyncProcess::SyncOptions & syncOptions)
|
||||
{
|
||||
m_syncOptions = syncOptions;
|
||||
emit optionsWereReset();
|
||||
}
|
||||
|
||||
void FileSyncDialog::resetOptions()
|
||||
{
|
||||
m_syncOptions.reset();
|
||||
emit optionsWereReset();
|
||||
}
|
||||
|
||||
void FileSyncDialog::toggleExtraOptions(bool show)
|
||||
{
|
||||
ui_extraOptions->setVisible(show);
|
||||
if (!ui_progress->detailsVisible())
|
||||
adjustSizeDelayed();
|
||||
m_extraOptionsVisible = show;
|
||||
emit extraOptionsToggled(show);
|
||||
}
|
||||
|
||||
void FileSyncDialog::setFolderNameA(const QString & name)
|
||||
{
|
||||
if (m_folderNameA != name) {
|
||||
m_folderNameA = name;
|
||||
emit folderNameAChanged(name);
|
||||
}
|
||||
}
|
||||
|
||||
void FileSyncDialog::setFolderNameB(const QString & name)
|
||||
{
|
||||
if (m_folderNameB != name) {
|
||||
m_folderNameB = name;
|
||||
emit folderNameBChanged(name);
|
||||
}
|
||||
}
|
||||
|
||||
void FileSyncDialog::setStatusText(const QString & text, int type)
|
||||
{
|
||||
ui_statusLabel->setText(text);
|
||||
ui_statusLabel->setStyleSheet(type != QtInfoMsg && type >= QtWarningMsg ? "QLabel { color: red; }:" : "");
|
||||
}
|
||||
|
||||
bool FileSyncDialog::validate()
|
||||
{
|
||||
QString msg;
|
||||
if (m_syncOptions.folderA.isEmpty() || !QFileInfo(m_syncOptions.folderA).exists())
|
||||
msg = tr("Source folder not found.");
|
||||
else if (m_syncOptions.folderB.isEmpty() || !QFileInfo(m_syncOptions.folderB).exists())
|
||||
msg = tr("Destination folder not found.");
|
||||
else if (QFileInfo(m_syncOptions.folderA).canonicalFilePath() == QFileInfo(m_syncOptions.folderB).canonicalFilePath())
|
||||
msg = tr("Source and destination folders are the same.");
|
||||
|
||||
setStatusText(msg, QtCriticalMsg);
|
||||
ui_btnStartStop->setEnabled(msg.isEmpty());
|
||||
return msg.isEmpty();
|
||||
}
|
||||
|
||||
void FileSyncDialog::adjustSizeDelayed()
|
||||
{
|
||||
QTimer::singleShot(0, [=]() { adjustSize(); });
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef FILESYNCDIALOG_H
|
||||
#define FILESYNCDIALOG_H
|
||||
|
||||
#include "process_sync.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QToolButton>
|
||||
|
||||
class ProgressWidget;
|
||||
|
||||
class FileSyncDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(SyncProcess::SyncOptions syncOptions READ syncOptions WRITE setSyncOptions RESET resetOptions NOTIFY optionsWereReset)
|
||||
Q_PROPERTY(bool extraOptionsVisible READ extraOptionsVisible WRITE toggleExtraOptions NOTIFY extraOptionsToggled)
|
||||
Q_PROPERTY(QString folderNameA READ folderNameA WRITE setFolderNameA NOTIFY folderNameAChanged)
|
||||
Q_PROPERTY(QString folderNameB READ folderNameB WRITE setFolderNameB NOTIFY folderNameBChanged)
|
||||
|
||||
public:
|
||||
FileSyncDialog(QWidget * parent = nullptr, const SyncProcess::SyncOptions & syncOptions = SyncProcess::SyncOptions());
|
||||
|
||||
inline SyncProcess::SyncOptions syncOptions() const { return m_syncOptions; }
|
||||
void setSyncOptions(const SyncProcess::SyncOptions & syncOptions);
|
||||
void resetOptions();
|
||||
|
||||
inline bool extraOptionsVisible() const { return m_extraOptionsVisible; }
|
||||
void toggleExtraOptions(bool show);
|
||||
|
||||
inline QString folderNameA() const { return m_folderNameA; }
|
||||
void setFolderNameA(const QString & name);
|
||||
|
||||
inline QString folderNameB() const { return m_folderNameB; }
|
||||
void setFolderNameB(const QString & name);
|
||||
|
||||
public slots:
|
||||
virtual void reject() override;
|
||||
void setStatusText(const QString & text, int type = QtWarningMsg);
|
||||
bool validate();
|
||||
|
||||
signals:
|
||||
void startSync();
|
||||
void stopSync();
|
||||
void folderNameAChanged(const QString & name);
|
||||
void folderNameBChanged(const QString & name);
|
||||
void extraOptionsToggled(bool show);
|
||||
void optionsWereReset();
|
||||
|
||||
private slots:
|
||||
void setupUi();
|
||||
void toggleSync(bool);
|
||||
void onSyncStarted();
|
||||
void onSyncFinished();
|
||||
void updateRunningState();
|
||||
void onStatusUpdate(const SyncProcess::SyncStatus & stat);
|
||||
void adjustSizeDelayed();
|
||||
|
||||
private:
|
||||
SyncProcess::SyncOptions m_syncOptions;
|
||||
QString m_folderNameA;
|
||||
QString m_folderNameB;
|
||||
bool m_running;
|
||||
bool m_extraOptionsVisible;
|
||||
|
||||
QGroupBox * ui_optionsPanel;
|
||||
QWidget * ui_extraOptions;
|
||||
ProgressWidget * ui_progress;
|
||||
QDialogButtonBox * ui_buttonBox;
|
||||
QToolButton * ui_btnStartStop;
|
||||
QToolButton * ui_btnClose;
|
||||
QLabel * ui_statusLabel;
|
||||
};
|
||||
|
||||
#endif // FILESYNCDIALOG_H
|
||||
@@ -20,13 +20,17 @@
|
||||
|
||||
#include "downloaddialog.h"
|
||||
#include "ui_downloaddialog.h"
|
||||
#include <QTime>
|
||||
#include "constants.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include <QTime>
|
||||
|
||||
downloadDialog::downloadDialog(QWidget *parent, QString src, QString tgt):
|
||||
QDialog(parent),
|
||||
ui(new Ui::downloadDialog),
|
||||
file(NULL)
|
||||
reply(nullptr),
|
||||
file(nullptr),
|
||||
aborted(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowIcon(CompanionIcon("fwpreferences.png"));
|
||||
@@ -41,7 +45,7 @@ downloadDialog::downloadDialog(QWidget *parent, QString src, QString tgt):
|
||||
|
||||
file = new QFile(tgt);
|
||||
if (!file->open(QIODevice::WriteOnly)) {
|
||||
QMessageBox::critical(this, "Companion",
|
||||
QMessageBox::critical(this, CPN_STR_APP_NAME,
|
||||
tr("Unable to save the file %1: %2.")
|
||||
.arg(tgt).arg(file->errorString()));
|
||||
QTimer::singleShot(0, this, SLOT(fileError()));
|
||||
@@ -60,29 +64,38 @@ downloadDialog::~downloadDialog()
|
||||
delete file;
|
||||
}
|
||||
|
||||
void downloadDialog::reject()
|
||||
{
|
||||
if (reply && reply->isRunning()) {
|
||||
aborted = true;
|
||||
reply->abort(); // this will call QNetworkReply::finished()
|
||||
return;
|
||||
}
|
||||
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void downloadDialog::httpFinished()
|
||||
{
|
||||
file->flush();
|
||||
file->close();
|
||||
file->flush();
|
||||
file->close();
|
||||
|
||||
bool ok = true;
|
||||
if (reply->error()) {
|
||||
file->remove();
|
||||
QMessageBox::information(this, tr("Companion"),
|
||||
tr("Download failed: %1.")
|
||||
.arg(reply->errorString()));
|
||||
ok = false;
|
||||
}
|
||||
const bool ok = !(reply->error() || aborted);
|
||||
if (!ok) {
|
||||
file->remove();
|
||||
if (!aborted)
|
||||
QMessageBox::information(this, CPN_STR_APP_NAME, tr("Download failed: %1.").arg(reply->errorString()));
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
reply = 0;
|
||||
delete file;
|
||||
file = NULL;
|
||||
reply->deleteLater();
|
||||
reply = nullptr;
|
||||
file->deleteLater();
|
||||
file = nullptr;
|
||||
|
||||
if (ok)
|
||||
accept();
|
||||
else
|
||||
reject();
|
||||
if (ok)
|
||||
accept();
|
||||
else
|
||||
reject();
|
||||
}
|
||||
|
||||
void downloadDialog::httpReadyRead()
|
||||
@@ -111,7 +124,7 @@ void downloadDialog::closeEvent( QCloseEvent * event)
|
||||
// Delay closing 2 seconds to avoid unpleasant flashing download dialogs
|
||||
QTime closeTime= QTime::currentTime().addSecs(2);
|
||||
while( QTime::currentTime() < closeTime )
|
||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
|
||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
|
||||
|
||||
event->accept();
|
||||
}
|
||||
|
||||
@@ -39,6 +39,9 @@ public:
|
||||
explicit downloadDialog(QWidget *parent = 0, QString src = "", QString tgt = "");
|
||||
~downloadDialog();
|
||||
|
||||
public slots:
|
||||
virtual void reject() override;
|
||||
|
||||
private slots:
|
||||
void fileError();
|
||||
void httpFinished();
|
||||
@@ -54,7 +57,7 @@ private:
|
||||
QNetworkAccessManager qnam;
|
||||
QNetworkReply *reply;
|
||||
QFile *file;
|
||||
|
||||
bool aborted;
|
||||
};
|
||||
|
||||
#endif // _DOWNLOADDIALOG_H_
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
set(firmwares_SRCS
|
||||
boards.cpp
|
||||
curvereference.cpp
|
||||
customfunctiondata.cpp
|
||||
eeprominterface.cpp
|
||||
generalsettings.cpp
|
||||
gvardata.cpp
|
||||
io_data.cpp
|
||||
logicalswitchdata.cpp
|
||||
modeldata.cpp
|
||||
moduledata.cpp
|
||||
multiprotocols.cpp
|
||||
radiodata.cpp
|
||||
radiodataconversionstate.cpp
|
||||
rawsource.cpp
|
||||
rawswitch.cpp
|
||||
sensordata.cpp
|
||||
telem_data.cpp
|
||||
er9x/er9xeeprom.cpp
|
||||
er9x/er9xinterface.cpp
|
||||
ersky9x/ersky9xeeprom.cpp
|
||||
ersky9x/ersky9xinterface.cpp
|
||||
opentx/opentxeeprom.cpp
|
||||
opentx/opentxinterface.cpp
|
||||
)
|
||||
|
||||
string(REPLACE ".cpp" ".h" firmwares_HDRS "${firmwares_SRCS}")
|
||||
|
||||
list(APPEND firmwares_HDRS
|
||||
eepromimportexport.h
|
||||
moduledata.h
|
||||
)
|
||||
|
||||
add_library(firmwares ${firmwares_SRCS} ${firmwares_HDRS})
|
||||
target_link_libraries(firmwares ${CPN_COMMON_LIB} Qt5::Core Qt5::Xml Qt5::Widgets)
|
||||
target_include_directories(firmwares
|
||||
PRIVATE
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
PUBLIC
|
||||
"${CMAKE_CURRENT_LIST_DIR}"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/er9x"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/ersky9x"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/opentx"
|
||||
)
|
||||
@@ -53,6 +53,34 @@ void Boards::setBoardType(const Type & board)
|
||||
m_boardType = BOARD_UNKNOWN;
|
||||
}
|
||||
|
||||
uint32_t Boards::getFourCC(Type board)
|
||||
{
|
||||
switch (board) {
|
||||
case BOARD_X12S:
|
||||
return 0x3478746F;
|
||||
case BOARD_X10:
|
||||
return 0x3778746F;
|
||||
case BOARD_TARANIS_XLITE:
|
||||
return 0x3978746F;
|
||||
case BOARD_TARANIS_X7:
|
||||
return 0x3678746F;
|
||||
case BOARD_TARANIS_X9E:
|
||||
return 0x3578746F;
|
||||
case BOARD_TARANIS_X9D:
|
||||
case BOARD_TARANIS_X9DP:
|
||||
return 0x3378746F;
|
||||
case BOARD_SKY9X:
|
||||
case BOARD_AR9X:
|
||||
case BOARD_9XRPRO:
|
||||
return 0x3278746F;
|
||||
case BOARD_MEGA2560:
|
||||
case BOARD_GRUVIN9X:
|
||||
return 0x3178746F;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const int Boards::getEEpromSize(Board::Type board)
|
||||
{
|
||||
switch (board) {
|
||||
@@ -68,11 +96,11 @@ const int Boards::getEEpromSize(Board::Type board)
|
||||
case BOARD_9XRPRO:
|
||||
case BOARD_AR9X:
|
||||
return EESIZE_9XRPRO;
|
||||
case BOARD_TARANIS_XLITE:
|
||||
case BOARD_TARANIS_X7:
|
||||
case BOARD_TARANIS_X9D:
|
||||
case BOARD_TARANIS_X9DP:
|
||||
case BOARD_TARANIS_X9E:
|
||||
case BOARD_FLAMENCO:
|
||||
return EESIZE_TARANIS;
|
||||
case BOARD_UNKNOWN:
|
||||
return EESIZE_MAX;
|
||||
@@ -96,11 +124,11 @@ const int Boards::getFlashSize(Type board)
|
||||
case BOARD_9XRPRO:
|
||||
case BOARD_AR9X:
|
||||
return FSIZE_9XRPRO;
|
||||
case BOARD_TARANIS_XLITE:
|
||||
case BOARD_TARANIS_X7:
|
||||
case BOARD_TARANIS_X9D:
|
||||
case BOARD_TARANIS_X9DP:
|
||||
case BOARD_TARANIS_X9E:
|
||||
case BOARD_TARANIS_X7:
|
||||
case BOARD_FLAMENCO:
|
||||
return FSIZE_TARANIS;
|
||||
case BOARD_X12S:
|
||||
case BOARD_X10:
|
||||
@@ -112,8 +140,21 @@ const int Boards::getFlashSize(Type board)
|
||||
}
|
||||
}
|
||||
|
||||
const SwitchInfo Boards::getSwitchInfo(Board::Type board, unsigned index)
|
||||
const SwitchInfo Boards::getSwitchInfo(Board::Type board, int index)
|
||||
{
|
||||
if (index < 0)
|
||||
return {SWITCH_NOT_AVAILABLE, CPN_STR_UNKNOWN_ITEM};
|
||||
|
||||
if (IS_TARANIS_XLITE(board)) {
|
||||
const Board::SwitchInfo switches[] = {
|
||||
{SWITCH_3POS, "SA"},
|
||||
{SWITCH_3POS, "SB"},
|
||||
{SWITCH_2POS, "SC"},
|
||||
{SWITCH_2POS, "SD"}
|
||||
};
|
||||
if (index < DIM(switches))
|
||||
return switches[index];
|
||||
}
|
||||
if (IS_TARANIS_X7(board)) {
|
||||
const Board::SwitchInfo switches[] = {
|
||||
{SWITCH_3POS, "SA"},
|
||||
@@ -164,7 +205,7 @@ const SwitchInfo Boards::getSwitchInfo(Board::Type board, unsigned index)
|
||||
return switches[index];
|
||||
}
|
||||
|
||||
return {SWITCH_NOT_AVAILABLE, "???"};
|
||||
return {SWITCH_NOT_AVAILABLE, CPN_STR_UNKNOWN_ITEM};
|
||||
}
|
||||
|
||||
const int Boards::getCapability(Board::Type board, Board::Capability capability)
|
||||
@@ -174,13 +215,19 @@ const int Boards::getCapability(Board::Type board, Board::Capability capability)
|
||||
return 4;
|
||||
|
||||
case Pots:
|
||||
if (IS_TARANIS_X7(board))
|
||||
if (IS_TARANIS_SMALL(board))
|
||||
return 2;
|
||||
else if (IS_TARANIS_X9E(board))
|
||||
return 4;
|
||||
else
|
||||
return 3;
|
||||
|
||||
case FactoryInstalledPots:
|
||||
if (IS_TARANIS_X9(board))
|
||||
return 2;
|
||||
else
|
||||
return getCapability(board, Pots);
|
||||
|
||||
case Sliders:
|
||||
if (IS_HORUS_X12S(board) || IS_TARANIS_X9E(board))
|
||||
return 4;
|
||||
@@ -195,11 +242,22 @@ const int Boards::getCapability(Board::Type board, Board::Capability capability)
|
||||
else
|
||||
return 0;
|
||||
|
||||
case MaxAnalogs:
|
||||
return getCapability(board, Board::Sticks) + getCapability(board, Board::Pots) + getCapability(board, Board::Sliders) + getCapability(board, Board::MouseAnalogs);
|
||||
|
||||
case MultiposPots:
|
||||
return IS_HORUS_OR_TARANIS(board) ? 3 : 0;
|
||||
|
||||
case MultiposPotsPositions:
|
||||
return IS_HORUS_OR_TARANIS(board) ? 6 : 0;
|
||||
|
||||
case Switches:
|
||||
if (IS_TARANIS_X9E(board))
|
||||
return 18;
|
||||
else if (IS_TARANIS_X7(board))
|
||||
return 6;
|
||||
else if (IS_TARANIS_XLITE(board))
|
||||
return 4;
|
||||
else if (IS_HORUS_OR_TARANIS(board))
|
||||
return 8;
|
||||
else
|
||||
@@ -233,20 +291,104 @@ const int Boards::getCapability(Board::Type board, Board::Capability capability)
|
||||
const QString Boards::getAxisName(int index)
|
||||
{
|
||||
const QString axes[] = {
|
||||
QObject::tr("Left Horizontal"),
|
||||
QObject::tr("Left Vertical"),
|
||||
QObject::tr("Right Vertical"),
|
||||
QObject::tr("Right Horizontal"),
|
||||
QObject::tr("Aux. 1"),
|
||||
QObject::tr("Aux. 2"),
|
||||
tr("Left Horizontal"),
|
||||
tr("Left Vertical"),
|
||||
tr("Right Vertical"),
|
||||
tr("Right Horizontal"),
|
||||
tr("Aux. 1"),
|
||||
tr("Aux. 2"),
|
||||
};
|
||||
if (index < (int)DIM(axes))
|
||||
return axes[index];
|
||||
else
|
||||
return QObject::tr("Unknown");
|
||||
return tr("Unknown");
|
||||
}
|
||||
|
||||
/* Currently unused
|
||||
const QString Boards::getAnalogInputName(Board::Type board, int index)
|
||||
{
|
||||
if (index < 0)
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
|
||||
if (index < getBoardCapability(board, Board::Sticks)) {
|
||||
const QString sticks[] = {
|
||||
tr("Rud"),
|
||||
tr("Ele"),
|
||||
tr("Thr"),
|
||||
tr("Ail")
|
||||
};
|
||||
return sticks[index];
|
||||
}
|
||||
|
||||
index -= getCapability(board, Board::Sticks);
|
||||
|
||||
if (IS_9X(board) || IS_2560(board) || IS_SKY9X(board)) {
|
||||
const QString pots[] = {
|
||||
"P1",
|
||||
"P2",
|
||||
"P3"
|
||||
};
|
||||
if (index < DIM(pots))
|
||||
return pots[index];
|
||||
}
|
||||
else if (IS_TARANIS_X9E(board)) {
|
||||
const QString pots[] = {
|
||||
"F1",
|
||||
"F2",
|
||||
"F3",
|
||||
"F4",
|
||||
"S1",
|
||||
"S2",
|
||||
"LS",
|
||||
"RS"
|
||||
};
|
||||
if (index < DIM(pots))
|
||||
return pots[index];
|
||||
}
|
||||
else if (IS_TARANIS(board)) {
|
||||
const QString pots[] = {
|
||||
"S1",
|
||||
"S2",
|
||||
"S3",
|
||||
"LS",
|
||||
"RS"
|
||||
};
|
||||
if (index < DIM(pots))
|
||||
return pots[index];
|
||||
}
|
||||
else if (IS_HORUS_X12S(board)) {
|
||||
const QString pots[] = {
|
||||
"S1",
|
||||
"6P",
|
||||
"S2",
|
||||
"L1",
|
||||
"L2",
|
||||
"LS",
|
||||
"RS",
|
||||
"JSx",
|
||||
"JSy"
|
||||
};
|
||||
if (index < DIM(pots))
|
||||
return pots[index];
|
||||
}
|
||||
else if (IS_HORUS_X10(board)) {
|
||||
const QString pots[] = {
|
||||
"S1",
|
||||
"6P",
|
||||
"S2",
|
||||
"LS",
|
||||
"RS"
|
||||
};
|
||||
if (index < DIM(pots))
|
||||
return pots[index];
|
||||
}
|
||||
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
|
||||
const bool Boards::isBoardCompatible(Type board1, Type board2)
|
||||
{
|
||||
return (getFourCC(board1) == getFourCC(board2));
|
||||
}
|
||||
|
||||
const QString Boards::getBoardName(Board::Type board)
|
||||
{
|
||||
@@ -260,7 +402,9 @@ const QString Boards::getBoardName(Board::Type board)
|
||||
case BOARD_MEGA2560:
|
||||
return "MEGA2560";
|
||||
case BOARD_TARANIS_X7:
|
||||
return "Taranis X7";
|
||||
return "Taranis X7/X7S";
|
||||
case BOARD_TARANIS_XLITE:
|
||||
return "Taranis X-Lite";
|
||||
case BOARD_TARANIS_X9D:
|
||||
return "Taranis X9D";
|
||||
case BOARD_TARANIS_X9DP:
|
||||
@@ -274,11 +418,10 @@ const QString Boards::getBoardName(Board::Type board)
|
||||
case BOARD_AR9X:
|
||||
return "AR9X";
|
||||
case BOARD_X12S:
|
||||
return "Horus";
|
||||
return "Horus X12S";
|
||||
case BOARD_X10:
|
||||
return "X10";
|
||||
return "Horus X10/X10S";
|
||||
default:
|
||||
return QObject::tr("Unknown");
|
||||
return tr("Unknown");
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef _BOARDS_H_
|
||||
#define _BOARDS_H_
|
||||
|
||||
#include <QtCore>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
@@ -42,9 +43,9 @@ namespace Board {
|
||||
BOARD_TARANIS_X9D,
|
||||
BOARD_TARANIS_X9DP,
|
||||
BOARD_TARANIS_X9E,
|
||||
BOARD_FLAMENCO,
|
||||
BOARD_X12S,
|
||||
BOARD_X10,
|
||||
BOARD_TARANIS_XLITE,
|
||||
BOARD_ENUM_COUNT
|
||||
};
|
||||
|
||||
@@ -108,8 +109,12 @@ namespace Board {
|
||||
enum Capability {
|
||||
Sticks,
|
||||
Pots,
|
||||
FactoryInstalledPots,
|
||||
Sliders,
|
||||
MouseAnalogs,
|
||||
MaxAnalogs,
|
||||
MultiposPots,
|
||||
MultiposPotsPositions,
|
||||
Switches,
|
||||
SwitchPositions,
|
||||
FactoryInstalledSwitches,
|
||||
@@ -137,6 +142,8 @@ namespace Board {
|
||||
|
||||
class Boards
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(Boards)
|
||||
|
||||
public:
|
||||
|
||||
Boards(Board::Type board)
|
||||
@@ -147,16 +154,23 @@ class Boards
|
||||
void setBoardType(const Board::Type & board);
|
||||
Board::Type getBoardType() const { return m_boardType; }
|
||||
|
||||
const int getEEpromSize() { return getEEpromSize(m_boardType); }
|
||||
const int getFlashSize() { return getFlashSize(m_boardType); }
|
||||
const Board::SwitchInfo getSwitchInfo(unsigned index) { return getSwitchInfo(m_boardType, index); }
|
||||
const int getCapability(Board::Capability capability) { return getCapability(m_boardType, capability); }
|
||||
const uint32_t getFourCC() const { return getFourCC(m_boardType); }
|
||||
const int getEEpromSize() const { return getEEpromSize(m_boardType); }
|
||||
const int getFlashSize() const { return getFlashSize(m_boardType); }
|
||||
const Board::SwitchInfo getSwitchInfo(int index) const { return getSwitchInfo(m_boardType, index); }
|
||||
const int getCapability(Board::Capability capability) const { return getCapability(m_boardType, capability); }
|
||||
const QString getAnalogInputName(int index) const { return getAnalogInputName(m_boardType, index); }
|
||||
const bool isBoardCompatible(Board::Type board2) const { return isBoardCompatible(m_boardType, board2); }
|
||||
|
||||
static uint32_t getFourCC(Board::Type board);
|
||||
static const int getEEpromSize(Board::Type board);
|
||||
static const int getFlashSize(Board::Type board);
|
||||
static const Board::SwitchInfo getSwitchInfo(Board::Type board, unsigned index);
|
||||
static const Board::SwitchInfo getSwitchInfo(Board::Type board, int index);
|
||||
static const int getCapability(Board::Type board, Board::Capability capability);
|
||||
static const QString getAxisName(int index);
|
||||
static const QString getAnalogInputName(Board::Type board, int index);
|
||||
static const bool isBoardCompatible(Board::Type board1, Board::Type board2);
|
||||
static const QString getBoardName(Board::Type board);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -165,27 +179,28 @@ class Boards
|
||||
|
||||
// temporary aliases for transition period, use Boards class instead.
|
||||
#define getBoardCapability(b__, c__) Boards::getCapability(b__, c__)
|
||||
#define getEEpromSize(b__) Boards::getEEpromSize(b__)
|
||||
#define getSwitchInfo(b__, i__) Boards::getSwitchInfo(b__, i__)
|
||||
|
||||
#define IS_9X(board) (board==Board::BOARD_STOCK || board==Board::BOARD_M128)
|
||||
#define IS_STOCK(board) (board==Board::BOARD_STOCK)
|
||||
#define IS_M128(board) (board==Board::BOARD_M128)
|
||||
#define IS_2560(board) (board==Board::BOARD_GRUVIN9X || board==Board::BOARD_MEGA2560)
|
||||
#define IS_SKY9X(board) (board==Board::BOARD_SKY9X || board==Board::BOARD_9XRPRO || board==Board::BOARD_AR9X)
|
||||
#define IS_9XRPRO(board) (board==Board::BOARD_9XRPRO)
|
||||
#define IS_TARANIS_XLITE(board) (board==Board::BOARD_TARANIS_XLITE)
|
||||
#define IS_TARANIS_X7(board) (board==Board::BOARD_TARANIS_X7)
|
||||
#define IS_TARANIS_X9(board) (board==Board::BOARD_TARANIS_X9D || board==Board::BOARD_TARANIS_X9DP || board==Board::BOARD_TARANIS_X9E)
|
||||
#define IS_TARANIS_X9D(board) (board==Board::BOARD_TARANIS_X9D || board==Board::BOARD_TARANIS_X9DP)
|
||||
#define IS_TARANIS_PLUS(board) (board==Board::BOARD_TARANIS_X9DP || board==Board::BOARD_TARANIS_X9E)
|
||||
#define IS_TARANIS_X9E(board) (board==Board::BOARD_TARANIS_X9E)
|
||||
#define IS_TARANIS(board) (IS_TARANIS_X9(board) || IS_TARANIS_X7(board))
|
||||
#define IS_TARANIS(board) (IS_TARANIS_X9(board) || IS_TARANIS_X7(board) || IS_TARANIS_XLITE(board))
|
||||
#define IS_TARANIS_SMALL(board) (board==Board::BOARD_TARANIS_X7 || board==Board::BOARD_TARANIS_XLITE)
|
||||
#define IS_TARANIS_NOT_X9E(board) (IS_TARANIS(board) && !IS_TARANIS_X9E(board))
|
||||
#define IS_HORUS_X12S(board) (board==Board::BOARD_X12S)
|
||||
#define IS_HORUS_X10(board) (board==Board::BOARD_X10)
|
||||
#define IS_HORUS(board) (IS_HORUS_X12S(board) || IS_HORUS_X10(board))
|
||||
#define IS_HORUS_OR_TARANIS(board) (IS_HORUS(board) || IS_TARANIS(board))
|
||||
#define IS_FLAMENCO(board) (board==Board::BOARD_FLAMENCO)
|
||||
#define IS_STM32(board) (IS_TARANIS(board) || IS_HORUS(board) || IS_FLAMENCO(board))
|
||||
#define IS_STM32(board) (IS_TARANIS(board) || IS_HORUS(board))
|
||||
#define IS_ARM(board) (IS_STM32(board) || IS_SKY9X(board))
|
||||
#define HAS_LARGE_LCD(board) (IS_HORUS(board) || (IS_TARANIS(board) && !IS_TARANIS_X7(board)))
|
||||
#define HAS_LARGE_LCD(board) (IS_HORUS(board) || IS_TARANIS_X9(board))
|
||||
|
||||
#endif // _BOARDS_H_
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "curvereference.h"
|
||||
|
||||
#include "helpers.h" // for Helpers::getAdjustmentString()
|
||||
#include "radiodata.h" // for ModelData
|
||||
|
||||
QString CurveReference::toString(const ModelData * model, bool verbose) const
|
||||
{
|
||||
if (value == 0) {
|
||||
return "----";
|
||||
}
|
||||
|
||||
QString ret;
|
||||
unsigned idx = abs(value) - 1;
|
||||
|
||||
switch(type) {
|
||||
case CURVE_REF_DIFF:
|
||||
ret = tr("Diff(%1)").arg(Helpers::getAdjustmentString(value, model));
|
||||
break;
|
||||
|
||||
case CURVE_REF_EXPO:
|
||||
ret = tr("Expo(%1)").arg(Helpers::getAdjustmentString(value, model));
|
||||
break;
|
||||
|
||||
case CURVE_REF_FUNC:
|
||||
ret = QString("x>0" "x<0" "|x|" "f>0" "f<0" "|f|").mid(3*(value-1), 3);
|
||||
if (verbose)
|
||||
ret = tr("Function(%1)").arg(ret);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (model)
|
||||
ret = model->curves[idx].nameToString(idx);
|
||||
else
|
||||
ret = CurveData().nameToString(idx);
|
||||
if (verbose)
|
||||
ret = tr("Curve(%1)").arg(ret);
|
||||
if (value < 0)
|
||||
ret.prepend(CPN_STR_SW_INDICATOR_REV);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef CURVEREFERENCE_H
|
||||
#define CURVEREFERENCE_H
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class ModelData;
|
||||
|
||||
class CurveReference {
|
||||
Q_DECLARE_TR_FUNCTIONS(CurveReference)
|
||||
|
||||
public:
|
||||
enum CurveRefType {
|
||||
CURVE_REF_DIFF,
|
||||
CURVE_REF_EXPO,
|
||||
CURVE_REF_FUNC,
|
||||
CURVE_REF_CUSTOM
|
||||
};
|
||||
|
||||
CurveReference() { clear(); }
|
||||
|
||||
CurveReference(CurveRefType type, int value):
|
||||
type(type),
|
||||
value(value)
|
||||
{
|
||||
}
|
||||
|
||||
void clear() { memset(this, 0, sizeof(CurveReference)); }
|
||||
|
||||
CurveRefType type;
|
||||
int value;
|
||||
|
||||
QString toString(const ModelData * model = NULL, bool verbose = true) const;
|
||||
};
|
||||
|
||||
#endif // CURVEREFERENCE_H
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "customfunctiondata.h"
|
||||
|
||||
#include "eeprominterface.h"
|
||||
#include "radiodata.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
|
||||
void CustomFunctionData::clear()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(CustomFunctionData));
|
||||
if (!getCurrentFirmware()->getCapability(SafetyChannelCustomFunction)) {
|
||||
func = FuncTrainer;
|
||||
}
|
||||
}
|
||||
|
||||
bool CustomFunctionData::isEmpty() const
|
||||
{
|
||||
return (swtch.type == SWITCH_TYPE_NONE);
|
||||
}
|
||||
|
||||
QString CustomFunctionData::nameToString(int index, bool globalContext) const
|
||||
{
|
||||
return RadioData::getElementName((globalContext ? tr("GF") : tr("SF")), index+1, 0, true);
|
||||
}
|
||||
|
||||
QString CustomFunctionData::funcToString(const ModelData * model) const
|
||||
{
|
||||
if (func >= FuncOverrideCH1 && func <= FuncOverrideCH32)
|
||||
return tr("Override %1").arg(RawSource(SOURCE_TYPE_CH, func).toString(model));
|
||||
else if (func == FuncTrainer)
|
||||
return tr("Trainer");
|
||||
else if (func == FuncTrainerRUD)
|
||||
return tr("Trainer RUD");
|
||||
else if (func == FuncTrainerELE)
|
||||
return tr("Trainer ELE");
|
||||
else if (func == FuncTrainerTHR)
|
||||
return tr("Trainer THR");
|
||||
else if (func == FuncTrainerAIL)
|
||||
return tr("Trainer AIL");
|
||||
else if (func == FuncInstantTrim)
|
||||
return tr("Instant Trim");
|
||||
else if (func == FuncPlaySound)
|
||||
return tr("Play Sound");
|
||||
else if (func == FuncPlayHaptic)
|
||||
return tr("Haptic");
|
||||
else if (func == FuncReset)
|
||||
return tr("Reset");
|
||||
else if (func >= FuncSetTimer1 && func <= FuncSetTimer3)
|
||||
return tr("Set Timer %1").arg(func-FuncSetTimer1+1);
|
||||
else if (func == FuncVario)
|
||||
return tr("Vario");
|
||||
else if (func == FuncPlayPrompt)
|
||||
return tr("Play Track");
|
||||
else if (func == FuncPlayBoth)
|
||||
return tr("Play Both");
|
||||
else if (func == FuncPlayValue)
|
||||
return tr("Play Value");
|
||||
else if (func == FuncPlayScript)
|
||||
return tr("Play Script");
|
||||
else if (func == FuncLogs)
|
||||
return tr("SD Logs");
|
||||
else if (func == FuncVolume)
|
||||
return tr("Volume");
|
||||
else if (func == FuncBacklight)
|
||||
return tr("Backlight");
|
||||
else if (func == FuncScreenshot)
|
||||
return tr("Screenshot");
|
||||
else if (func == FuncBackgroundMusic)
|
||||
return tr("Background Music");
|
||||
else if (func == FuncBackgroundMusicPause)
|
||||
return tr("Background Music Pause");
|
||||
else if (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast)
|
||||
return tr("Adjust %1").arg(RawSource(SOURCE_TYPE_GVAR, func-FuncAdjustGV1).toString(model));
|
||||
else if (func == FuncSetFailsafeInternalModule)
|
||||
return tr("SetFailsafe Int. Module");
|
||||
else if (func == FuncSetFailsafeExternalModule)
|
||||
return tr("SetFailsafe Ext. Module");
|
||||
else if (func == FuncRangeCheckInternalModule)
|
||||
return tr("RangeCheck Int. Module");
|
||||
else if (func == FuncRangeCheckExternalModule)
|
||||
return tr("RangeCheck Ext. Module");
|
||||
else if (func == FuncBindInternalModule)
|
||||
return tr("Bind Int. Module");
|
||||
else if (func == FuncBindExternalModule)
|
||||
return tr("Bind Ext. Module");
|
||||
else {
|
||||
return QString("???"); // Highlight unknown functions with output of question marks.(BTW should not happen that we do not know what a function is)
|
||||
}
|
||||
}
|
||||
|
||||
void CustomFunctionData::populateResetParams(const ModelData * model, QComboBox * b, unsigned int value = 0)
|
||||
{
|
||||
int val = 0;
|
||||
Firmware * firmware = Firmware::getCurrentVariant();
|
||||
Board::Type board = firmware->getBoard();
|
||||
|
||||
b->addItem(tr("Timer1"), val++);
|
||||
b->addItem(tr("Timer2"), val++);
|
||||
if (IS_ARM(board)) {
|
||||
b->addItem( tr("Timer3"), val++);
|
||||
}
|
||||
b->addItem(tr("Flight"), val++);
|
||||
b->addItem(tr("Telemetry"), val++);
|
||||
int reCount = firmware->getCapability(RotaryEncoders);
|
||||
if (reCount == 1) {
|
||||
b->addItem(tr("Rotary Encoder"), val++);
|
||||
}
|
||||
else if (reCount == 2) {
|
||||
b->addItem(tr("REa"), val++);
|
||||
b->addItem(tr("REb"), val++);
|
||||
}
|
||||
if ((int)value < b->count()) {
|
||||
b->setCurrentIndex(value);
|
||||
}
|
||||
if (model && IS_ARM(board)) {
|
||||
for (int i=0; i<CPN_MAX_SENSORS; ++i) {
|
||||
if (model->sensorData[i].isAvailable()) {
|
||||
RawSource item = RawSource(SOURCE_TYPE_TELEMETRY, 3*i);
|
||||
b->addItem(item.toString(model), val+i);
|
||||
if ((int)value == val+i) {
|
||||
b->setCurrentIndex(b->count()-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CustomFunctionData::populatePlaySoundParams(QStringList & qs)
|
||||
{
|
||||
qs <<"Beep 1" << "Beep 2" << "Beep 3" << "Warn1" << "Warn2" << "Cheep" << "Ratata" << "Tick" << "Siren" << "Ring" ;
|
||||
qs << "SciFi" << "Robot" << "Chirp" << "Tada" << "Crickt" << "AlmClk" ;
|
||||
}
|
||||
|
||||
void CustomFunctionData::populateHapticParams(QStringList & qs)
|
||||
{
|
||||
qs << "0" << "1" << "2" << "3";
|
||||
}
|
||||
|
||||
QString CustomFunctionData::paramToString(const ModelData * model) const
|
||||
{
|
||||
QStringList qs;
|
||||
if (func <= FuncInstantTrim) {
|
||||
return QString("%1").arg(param);
|
||||
}
|
||||
else if (func==FuncLogs) {
|
||||
return QString("%1").arg(param/10.0) + tr("s");
|
||||
}
|
||||
else if (func==FuncPlaySound) {
|
||||
CustomFunctionData::populatePlaySoundParams(qs);
|
||||
if (param>=0 && param<(int)qs.count())
|
||||
return qs.at(param);
|
||||
else
|
||||
return tr("<font color=red><b>Inconsistent parameter</b></font>");
|
||||
}
|
||||
else if (func==FuncPlayHaptic) {
|
||||
CustomFunctionData::populateHapticParams(qs);
|
||||
if (param>=0 && param<(int)qs.count())
|
||||
return qs.at(param);
|
||||
else
|
||||
return tr("<font color=red><b>Inconsistent parameter</b></font>");
|
||||
}
|
||||
else if (func==FuncReset) {
|
||||
QComboBox cb;
|
||||
CustomFunctionData::populateResetParams(model, &cb);
|
||||
int pos = cb.findData(param);
|
||||
if (pos >= 0)
|
||||
return cb.itemText(pos);
|
||||
else
|
||||
return tr("<font color=red><b>Inconsistent parameter</b></font>");
|
||||
}
|
||||
else if ((func==FuncVolume)|| (func==FuncPlayValue)) {
|
||||
RawSource item(param);
|
||||
return item.toString(model);
|
||||
}
|
||||
else if ((func==FuncPlayPrompt) || (func==FuncPlayBoth)) {
|
||||
if ( getCurrentFirmware()->getCapability(VoicesAsNumbers)) {
|
||||
return QString("%1").arg(param);
|
||||
}
|
||||
else {
|
||||
return paramarm;
|
||||
}
|
||||
}
|
||||
else if ((func>=FuncAdjustGV1) && (func<FuncCount)) {
|
||||
switch (adjustMode) {
|
||||
case FUNC_ADJUST_GVAR_CONSTANT:
|
||||
return tr("Value ")+QString("%1").arg(param);
|
||||
case FUNC_ADJUST_GVAR_SOURCE:
|
||||
case FUNC_ADJUST_GVAR_GVAR:
|
||||
return RawSource(param).toString();
|
||||
case FUNC_ADJUST_GVAR_INCDEC:
|
||||
if (param==0) return tr("Decr:") + " -1";
|
||||
else return tr("Incr:") + " +1";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
QString CustomFunctionData::repeatToString() const
|
||||
{
|
||||
if (repeatParam == -1) {
|
||||
return tr("played once, not during startup");
|
||||
}
|
||||
else if (repeatParam == 0) {
|
||||
return "";
|
||||
}
|
||||
else {
|
||||
unsigned int step = IS_ARM(getCurrentBoard()) ? 1 : 10;
|
||||
return tr("repeat(%1s)").arg(step*repeatParam);
|
||||
}
|
||||
}
|
||||
|
||||
QString CustomFunctionData::enabledToString() const
|
||||
{
|
||||
if ((func>=FuncOverrideCH1 && func<=FuncOverrideCH32) ||
|
||||
(func>=FuncAdjustGV1 && func<=FuncAdjustGVLast) ||
|
||||
(func==FuncReset) ||
|
||||
(func>=FuncSetTimer1 && func<=FuncSetTimer2) ||
|
||||
(func==FuncVolume) ||
|
||||
(func <= FuncInstantTrim)) {
|
||||
if (!enabled) {
|
||||
return tr("DISABLED");
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void CustomFunctionData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent(tr("CFN"), 8);
|
||||
cstate.setSubComp(nameToString(cstate.subCompIdx, (cstate.toModel() ? false : true)));
|
||||
swtch.convert(cstate);
|
||||
if (func == FuncVolume || func == FuncPlayValue || (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast && adjustMode == 1)) {
|
||||
param = RawSource(param).convert(cstate.withComponentField("PARAM")).toValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef CUSTOMFUNCTIONDATA_H
|
||||
#define CUSTOMFUNCTIONDATA_H
|
||||
|
||||
#include "boards.h"
|
||||
#include "constants.h"
|
||||
#include "rawswitch.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QComboBox>
|
||||
|
||||
class Firmware;
|
||||
class ModelData;
|
||||
class GeneralSettings;
|
||||
class RadioDataConversionState;
|
||||
|
||||
enum AssignFunc {
|
||||
FuncOverrideCH1 = 0,
|
||||
FuncOverrideCH32 = FuncOverrideCH1+CPN_MAX_CHNOUT-1,
|
||||
FuncTrainer,
|
||||
FuncTrainerRUD,
|
||||
FuncTrainerELE,
|
||||
FuncTrainerTHR,
|
||||
FuncTrainerAIL,
|
||||
FuncInstantTrim,
|
||||
FuncPlaySound,
|
||||
FuncPlayHaptic,
|
||||
FuncReset,
|
||||
FuncSetTimer1,
|
||||
FuncSetTimer2,
|
||||
FuncSetTimer3,
|
||||
FuncVario,
|
||||
FuncPlayPrompt,
|
||||
FuncPlayBoth,
|
||||
FuncPlayValue,
|
||||
FuncPlayScript,
|
||||
FuncLogs,
|
||||
FuncVolume,
|
||||
FuncBacklight,
|
||||
FuncScreenshot,
|
||||
FuncBackgroundMusic,
|
||||
FuncBackgroundMusicPause,
|
||||
FuncAdjustGV1,
|
||||
FuncAdjustGVLast = FuncAdjustGV1+CPN_MAX_GVARS-1,
|
||||
FuncSetFailsafeInternalModule,
|
||||
FuncSetFailsafeExternalModule,
|
||||
FuncRangeCheckInternalModule,
|
||||
FuncRangeCheckExternalModule,
|
||||
FuncBindInternalModule,
|
||||
FuncBindExternalModule,
|
||||
FuncCount,
|
||||
FuncReserve = -1
|
||||
};
|
||||
|
||||
enum GVarAdjustModes
|
||||
{
|
||||
FUNC_ADJUST_GVAR_CONSTANT,
|
||||
FUNC_ADJUST_GVAR_SOURCE,
|
||||
FUNC_ADJUST_GVAR_GVAR,
|
||||
FUNC_ADJUST_GVAR_INCDEC
|
||||
};
|
||||
|
||||
class CustomFunctionData {
|
||||
Q_DECLARE_TR_FUNCTIONS(CustomFunctionData)
|
||||
|
||||
public:
|
||||
CustomFunctionData(AssignFunc func=FuncOverrideCH1) { clear(); this->func = func; }
|
||||
RawSwitch swtch;
|
||||
AssignFunc func;
|
||||
int param;
|
||||
char paramarm[10];
|
||||
unsigned int enabled; // TODO perhaps not any more the right name
|
||||
unsigned int adjustMode;
|
||||
int repeatParam;
|
||||
|
||||
void clear();
|
||||
bool isEmpty() const;
|
||||
QString nameToString(int index, bool globalContext = false) const;
|
||||
QString funcToString(const ModelData * model = NULL) const;
|
||||
QString paramToString(const ModelData * model) const;
|
||||
QString repeatToString() const;
|
||||
QString enabledToString() const;
|
||||
|
||||
static void populateResetParams(const ModelData * model, QComboBox * b, unsigned int value);
|
||||
static void populatePlaySoundParams(QStringList & qs);
|
||||
static void populateHapticParams(QStringList & qs);
|
||||
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // CUSTOMFUNCTIONDATA_H
|
||||
@@ -22,9 +22,13 @@
|
||||
#define _EEPROMIMPORTEXPORT_H_
|
||||
|
||||
#include "customdebug.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QBitArray>
|
||||
|
||||
class DataField {
|
||||
Q_DECLARE_TR_FUNCTIONS(DataField)
|
||||
|
||||
public:
|
||||
DataField(DataField * parent, const char * name=""):
|
||||
parent(parent),
|
||||
@@ -382,8 +386,33 @@ class CharField: public DataField {
|
||||
bool truncate;
|
||||
};
|
||||
|
||||
int8_t char2idx(char c);
|
||||
char idx2char(int8_t idx);
|
||||
static const char specialCharsTab[] = "_-.,";
|
||||
static inline int8_t char2idx(char c)
|
||||
{
|
||||
if (c==' ') return 0;
|
||||
if (c>='A' && c<='Z') return 1+c-'A';
|
||||
if (c>='a' && c<='z') return -1-c+'a';
|
||||
if (c>='0' && c<='9') return 27+c-'0';
|
||||
for (int8_t i=0;;i++) {
|
||||
char cc = specialCharsTab[i];
|
||||
if (cc==0) return 0;
|
||||
if (cc==c) return 37+i;
|
||||
}
|
||||
}
|
||||
|
||||
#define ZCHAR_MAX 40
|
||||
static inline char idx2char(int8_t idx)
|
||||
{
|
||||
if (idx == 0) return ' ';
|
||||
if (idx < 0) {
|
||||
if (idx > -27) return 'a' - idx - 1;
|
||||
idx = -idx;
|
||||
}
|
||||
if (idx < 27) return 'A' + idx - 1;
|
||||
if (idx < 37) return '0' + idx - 27;
|
||||
if (idx <= ZCHAR_MAX) return specialCharsTab[idx-37];
|
||||
return ' ';
|
||||
}
|
||||
|
||||
template<int N>
|
||||
class ZCharField: public DataField {
|
||||
@@ -717,7 +746,7 @@ class ConversionField: public TransformedField {
|
||||
|
||||
if (table) {
|
||||
if (!table->exportValue(_field, _field)) {
|
||||
setError(error.isEmpty() ? QObject::tr("Conversion error on field %1").arg(name) : error);
|
||||
setError(error.isEmpty() ? DataField::tr("Conversion error on field %1").arg(name) : error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "eeprominterface.h"
|
||||
#include "firmwares/opentx/opentxeeprom.h"
|
||||
#include "firmwareinterface.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QMessageBox>
|
||||
#include <bitset>
|
||||
|
||||
float ValToTim(int value)
|
||||
{
|
||||
return ((value < -109 ? 129+value : (value < 7 ? (113+value)*5 : (53+value)*10))/10.0);
|
||||
}
|
||||
|
||||
int TimToVal(float value)
|
||||
{
|
||||
int temp;
|
||||
if (value>60) {
|
||||
temp=136+round((value-60));
|
||||
}
|
||||
else if (value>2) {
|
||||
temp=20+round((value-2.0)*2.0);
|
||||
}
|
||||
else {
|
||||
temp=round(value*10.0);
|
||||
}
|
||||
return (temp-129);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* EEpromInterface globals
|
||||
*/
|
||||
|
||||
// TODO: No globals
|
||||
|
||||
QList<EEPROMInterface *> eepromInterfaces;
|
||||
|
||||
void unregisterEEpromInterfaces()
|
||||
{
|
||||
foreach(EEPROMInterface * intf, eepromInterfaces) {
|
||||
// qDebug() << "UnregisterEepromInterfaces(): deleting " << QString::number( reinterpret_cast<uint64_t>(intf), 16 );
|
||||
delete intf;
|
||||
}
|
||||
OpenTxEepromCleanup();
|
||||
}
|
||||
|
||||
#if 0 // TODO: remove if unused, currently commented out in mdiChild.cpp
|
||||
// TODO: No GUI here, e.g. return string list instead
|
||||
void EEPROMInterface::showEepromErrors(QWidget *parent, const QString &title, const QString &mainMessage, unsigned long errorsFound)
|
||||
{
|
||||
std::bitset<NUM_ERRORS> errors((unsigned long long)errorsFound);
|
||||
QStringList errorsList;
|
||||
|
||||
errorsList << tr("Possible causes for this:");
|
||||
|
||||
if (errors.test(UNSUPPORTED_NEWER_VERSION)) { errorsList << tr("- Eeprom is from a newer version of OpenTX"); }
|
||||
if (errors.test(NOT_OPENTX)) { errorsList << tr("- Eeprom is not from OpenTX"); }
|
||||
if (errors.test(NOT_TH9X)) { errorsList << tr("- Eeprom is not from Th9X"); }
|
||||
if (errors.test(NOT_GRUVIN9X)) { errorsList << tr("- Eeprom is not from Gruvin9X"); }
|
||||
if (errors.test(NOT_ERSKY9X)) { errorsList << tr("- Eeprom is not from ErSky9X"); }
|
||||
if (errors.test(NOT_ER9X)) { errorsList << tr("- Eeprom is not from Er9X"); }
|
||||
if (errors.test(WRONG_SIZE)) { errorsList << tr("- Eeprom size is invalid"); }
|
||||
if (errors.test(WRONG_FILE_SYSTEM)) { errorsList << tr("- Eeprom file system is invalid"); }
|
||||
if (errors.test(UNKNOWN_BOARD)) { errorsList << tr("- Eeprom is from a unknown board"); }
|
||||
if (errors.test(WRONG_BOARD)) { errorsList << tr("- Eeprom is from the wrong board"); }
|
||||
if (errors.test(BACKUP_NOT_SUPPORTED)) { errorsList << tr("- Eeprom backup not supported"); }
|
||||
|
||||
if (errors.test(UNKNOWN_ERROR)) { errorsList << tr("- Something that couldn't be guessed, sorry"); }
|
||||
|
||||
if (errors.test(HAS_WARNINGS)) {
|
||||
errorsList << tr("Warning:");
|
||||
if (errors.test(WARNING_WRONG_FIRMWARE)) { errorsList << tr("- Your radio probably uses a wrong firmware,\n eeprom size is 4096 but only the first 2048 are used"); }
|
||||
}
|
||||
|
||||
QMessageBox msgBox(parent);
|
||||
msgBox.setWindowTitle(title);
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setText(mainMessage);
|
||||
msgBox.setInformativeText(errorsList.join("\n"));
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.exec();
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: No GUI here, e.g. return string list instead
|
||||
void EEPROMInterface::showEepromWarnings(QWidget *parent, const QString &title, unsigned long errorsFound)
|
||||
{
|
||||
std::bitset<NUM_ERRORS> errors((unsigned long long)errorsFound);
|
||||
QStringList warningsList;
|
||||
if (errors.test(WARNING_WRONG_FIRMWARE)) { warningsList << tr("- Your radio probably uses a wrong firmware,\n eeprom size is 4096 but only the first 2048 are used"); }
|
||||
if (errors.test(OLD_VERSION)) { warningsList << tr("- Your eeprom is from an old version of OpenTX, upgrading!\n To keep your original file as a backup, please choose File -> Save As specifying a different name."); }
|
||||
|
||||
QMessageBox msgBox(parent);
|
||||
msgBox.setWindowTitle(title);
|
||||
msgBox.setIcon(QMessageBox::Warning);
|
||||
msgBox.setText(tr("Warnings!"));
|
||||
msgBox.setInformativeText(warningsList.join("\n"));
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.exec();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Firmware
|
||||
*/
|
||||
|
||||
// static
|
||||
QVector<Firmware *> Firmware::registeredFirmwares;
|
||||
Firmware * Firmware::defaultVariant = NULL;
|
||||
Firmware * Firmware::currentVariant = NULL;
|
||||
|
||||
// static
|
||||
Firmware * Firmware::getFirmwareForId(const QString & id)
|
||||
{
|
||||
foreach(Firmware * firmware, registeredFirmwares) {
|
||||
Firmware * result = firmware->getFirmwareVariant(id);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return defaultVariant;
|
||||
}
|
||||
|
||||
unsigned int Firmware::getVariantNumber()
|
||||
{
|
||||
unsigned int result = 0;
|
||||
const Firmware * base = getFirmwareBase();
|
||||
QStringList options = id.mid(base->getId().length()+1).split("-", QString::SkipEmptyParts);
|
||||
foreach(QString option, options) {
|
||||
foreach(OptionsGroup group, base->opts) {
|
||||
foreach(Option opt, group) {
|
||||
if (opt.name == option) {
|
||||
result += opt.variant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Firmware::addLanguage(const char * lang)
|
||||
{
|
||||
languages.push_back(lang);
|
||||
}
|
||||
|
||||
//void Firmware::addTTSLanguage(const char * lang)
|
||||
//{
|
||||
// ttslanguages.push_back(lang);
|
||||
//}
|
||||
|
||||
void Firmware::addOption(const char * option, const QString & tooltip, unsigned variant)
|
||||
{
|
||||
addOption(Option(option, tooltip, variant));
|
||||
}
|
||||
|
||||
void Firmware::addOption(const Option & option)
|
||||
{
|
||||
addOptionsGroup({option});
|
||||
}
|
||||
|
||||
void Firmware::addOptionsGroup(const OptionsGroup & options)
|
||||
{
|
||||
this->opts.append(options);
|
||||
}
|
||||
@@ -21,15 +21,19 @@
|
||||
#ifndef _EEPROMINTERFACE_H_
|
||||
#define _EEPROMINTERFACE_H_
|
||||
|
||||
#include "boards.h"
|
||||
#include "macros.h"
|
||||
#include "radiodata.h"
|
||||
#include "../../radio/src/definitions.h"
|
||||
#include "simulatorinterface.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QStringList>
|
||||
#include <QList>
|
||||
#include <iostream>
|
||||
#include <QDebug>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
const uint8_t modn12x3[4][4]= {
|
||||
{1, 2, 3, 4},
|
||||
{1, 3, 2, 4},
|
||||
@@ -103,6 +107,8 @@ enum Capability {
|
||||
HasFailsafe,
|
||||
HasSoundMixer,
|
||||
NumModules,
|
||||
HasModuleR9MFlex,
|
||||
HasModuleR9MMini,
|
||||
PPMCenter,
|
||||
PPMUnitMicroseconds,
|
||||
SYMLimits,
|
||||
@@ -134,8 +140,6 @@ enum Capability {
|
||||
EnhancedCurves,
|
||||
HasFasOffset,
|
||||
HasMahPersistent,
|
||||
MultiposPots,
|
||||
MultiposPotsPositions,
|
||||
SimulatorVariant,
|
||||
MavlinkTelemetry,
|
||||
HasInputDiff,
|
||||
@@ -145,9 +149,10 @@ enum Capability {
|
||||
HasModelCategories
|
||||
};
|
||||
|
||||
class SimulatorInterface;
|
||||
class EEPROMInterface
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(EEPROMInterface)
|
||||
|
||||
public:
|
||||
|
||||
EEPROMInterface(Board::Type board):
|
||||
@@ -169,6 +174,9 @@ class EEPROMInterface
|
||||
|
||||
virtual int getSize(const GeneralSettings &) = 0;
|
||||
|
||||
//static void showEepromErrors(QWidget *parent, const QString &title, const QString &mainMessage, unsigned long errorsFound);
|
||||
static void showEepromWarnings(QWidget *parent, const QString &title, unsigned long errorsFound);
|
||||
|
||||
protected:
|
||||
|
||||
Board::Type board;
|
||||
@@ -179,13 +187,20 @@ class EEPROMInterface
|
||||
|
||||
};
|
||||
|
||||
/* EEPROM string conversion functions */
|
||||
void setEEPROMString(char *dst, const char *src, int size);
|
||||
void getEEPROMString(char *dst, const char *src, int size);
|
||||
|
||||
float ValToTim(int value);
|
||||
int TimToVal(float value);
|
||||
/* EEPROM string conversion function (used only by er9xeeprom and ersky9xeeprom) */
|
||||
inline void getEEPROMString(char *dst, const char *src, int size)
|
||||
{
|
||||
memcpy(dst, src, size);
|
||||
dst[size] = '\0';
|
||||
for (int i=size-1; i>=0; i--) {
|
||||
if (dst[i] == ' ')
|
||||
dst[i] = '\0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// (used only by er9xeeprom and ersky9xeeprom)
|
||||
inline int applyStickMode(int stick, unsigned int mode)
|
||||
{
|
||||
if (mode == 0 || mode > 4) {
|
||||
@@ -199,6 +214,9 @@ inline int applyStickMode(int stick, unsigned int mode)
|
||||
return stick;
|
||||
}
|
||||
|
||||
float ValToTim(int value);
|
||||
int TimToVal(float value);
|
||||
|
||||
void registerEEpromInterfaces();
|
||||
void unregisterEEpromInterfaces();
|
||||
void registerOpenTxFirmwares();
|
||||
@@ -226,42 +244,37 @@ enum EepromLoadErrors {
|
||||
NUM_ERRORS
|
||||
};
|
||||
|
||||
void ShowEepromErrors(QWidget *parent, const QString &title, const QString &mainMessage, unsigned long errorsFound);
|
||||
void ShowEepromWarnings(QWidget *parent, const QString &title, unsigned long errorsFound);
|
||||
|
||||
|
||||
struct Option {
|
||||
const char * name;
|
||||
QString tooltip;
|
||||
uint32_t variant;
|
||||
};
|
||||
|
||||
class Firmware {
|
||||
class Firmware
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(Firmware)
|
||||
|
||||
public:
|
||||
Firmware(const QString & id, const QString & name, Board::Type board):
|
||||
id(id),
|
||||
name(name),
|
||||
board(board),
|
||||
variantBase(0),
|
||||
base(NULL),
|
||||
eepromInterface(NULL)
|
||||
{
|
||||
}
|
||||
struct Option {
|
||||
const char * name = nullptr;
|
||||
QString tooltip;
|
||||
unsigned variant = 0;
|
||||
|
||||
Firmware(Firmware * base, const QString & id, const QString & name, Board::Type board):
|
||||
explicit Option(const char * name, const QString & description, unsigned variant = 0) :
|
||||
name(name), tooltip(description), variant(variant) { }
|
||||
};
|
||||
typedef QList<Option> OptionsGroup;
|
||||
typedef QList<OptionsGroup> OptionsList;
|
||||
|
||||
|
||||
explicit Firmware(const QString & id, const QString & name, Board::Type board) :
|
||||
Firmware(nullptr, id, name, board)
|
||||
{ }
|
||||
|
||||
explicit Firmware(Firmware * base, const QString & id, const QString & name, Board::Type board) :
|
||||
id(id),
|
||||
name(name),
|
||||
board(board),
|
||||
variantBase(0),
|
||||
base(base),
|
||||
eepromInterface(NULL)
|
||||
{
|
||||
}
|
||||
eepromInterface(nullptr)
|
||||
{ }
|
||||
|
||||
virtual ~Firmware()
|
||||
{
|
||||
}
|
||||
virtual ~Firmware() { }
|
||||
|
||||
inline const Firmware * getFirmwareBase() const
|
||||
{
|
||||
@@ -272,13 +285,15 @@ class Firmware {
|
||||
|
||||
unsigned int getVariantNumber();
|
||||
|
||||
virtual void addLanguage(const char *lang);
|
||||
virtual void addLanguage(const char * lang);
|
||||
|
||||
virtual void addTTSLanguage(const char *lang);
|
||||
//virtual void addTTSLanguage(const char * lang);
|
||||
|
||||
virtual void addOption(const char *option, QString tooltip="", uint32_t variant=0);
|
||||
virtual void addOption(const char * option, const QString & tooltip = QString(), unsigned variant = 0);
|
||||
|
||||
virtual void addOptions(Option options[]);
|
||||
virtual void addOption(const Option & option);
|
||||
|
||||
virtual void addOptionsGroup(const OptionsGroup & options);
|
||||
|
||||
virtual QString getStampUrl() = 0;
|
||||
|
||||
@@ -311,6 +326,16 @@ class Firmware {
|
||||
return id;
|
||||
}
|
||||
|
||||
QList<const char *> languageList() const
|
||||
{
|
||||
return languages;
|
||||
}
|
||||
|
||||
OptionsList optionGroups() const
|
||||
{
|
||||
return opts;
|
||||
}
|
||||
|
||||
virtual int getCapability(Capability) = 0;
|
||||
|
||||
virtual QString getAnalogInputName(unsigned int index) = 0;
|
||||
@@ -327,6 +352,7 @@ class Firmware {
|
||||
{
|
||||
return registeredFirmwares;
|
||||
}
|
||||
|
||||
static void addRegisteredFirmware(Firmware * fw)
|
||||
{
|
||||
registeredFirmwares.append(fw);
|
||||
@@ -345,17 +371,12 @@ class Firmware {
|
||||
{
|
||||
return currentVariant;
|
||||
}
|
||||
|
||||
static void setCurrentVariant(Firmware * value)
|
||||
{
|
||||
currentVariant = value;
|
||||
}
|
||||
|
||||
public:
|
||||
QList<const char *> languages;
|
||||
QList<const char *> ttslanguages;
|
||||
QList< QList<Option> > opts;
|
||||
|
||||
|
||||
protected:
|
||||
QString id;
|
||||
QString name;
|
||||
@@ -363,14 +384,13 @@ class Firmware {
|
||||
unsigned int variantBase;
|
||||
Firmware * base;
|
||||
EEPROMInterface * eepromInterface;
|
||||
QList<const char *> languages;
|
||||
//QList<const char *> ttslanguages;
|
||||
OptionsList opts;
|
||||
|
||||
static QVector<Firmware *> registeredFirmwares;
|
||||
static Firmware * defaultVariant;
|
||||
static Firmware * currentVariant;
|
||||
|
||||
private:
|
||||
Firmware();
|
||||
|
||||
};
|
||||
|
||||
inline Firmware * getCurrentFirmware()
|
||||
@@ -398,11 +418,7 @@ inline int calcRESXto100(int x)
|
||||
return divRoundClosest(x*100, 1024);
|
||||
}
|
||||
|
||||
#define CHECK_IN_ARRAY(T, index) ((unsigned int)index < DIM(T) ? T[(unsigned int)index] : "???")
|
||||
|
||||
extern QList<EEPROMInterface *> eepromInterfaces;
|
||||
|
||||
bool loadFile(RadioData & radioData, const QString & filename);
|
||||
|
||||
|
||||
#endif // _EEPROMINTERFACE_H_
|
||||
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "generalsettings.h"
|
||||
|
||||
#include "appdata.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
|
||||
const uint8_t chout_ar[] = { // First number is 0..23 -> template setup, Second is relevant channel out
|
||||
1,2,3,4 , 1,2,4,3 , 1,3,2,4 , 1,3,4,2 , 1,4,2,3 , 1,4,3,2,
|
||||
2,1,3,4 , 2,1,4,3 , 2,3,1,4 , 2,3,4,1 , 2,4,1,3 , 2,4,3,1,
|
||||
3,1,2,4 , 3,1,4,2 , 3,2,1,4 , 3,2,4,1 , 3,4,1,2 , 3,4,2,1,
|
||||
4,1,2,3 , 4,1,3,2 , 4,2,1,3 , 4,2,3,1 , 4,3,1,2 , 4,3,2,1
|
||||
};
|
||||
|
||||
bool GeneralSettings::switchPositionAllowedTaranis(int index) const
|
||||
{
|
||||
if (index == 0)
|
||||
return true;
|
||||
|
||||
div_t qr = div(abs(index)-1, 3);
|
||||
|
||||
if (index < 0 && switchConfig[qr.quot] != Board::SWITCH_3POS)
|
||||
return false;
|
||||
else if (qr.rem == 1)
|
||||
return switchConfig[qr.quot] == Board::SWITCH_3POS;
|
||||
else
|
||||
return switchConfig[qr.quot] != Board::SWITCH_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
bool GeneralSettings::switchSourceAllowedTaranis(int index) const
|
||||
{
|
||||
return switchConfig[index] != Board::SWITCH_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
bool GeneralSettings::isPotAvailable(int index) const
|
||||
{
|
||||
if (index<0 || index>getBoardCapability(getCurrentBoard(), Board::Pots)) return false;
|
||||
return potConfig[index] != Board::POT_NONE;
|
||||
}
|
||||
|
||||
bool GeneralSettings::isSliderAvailable(int index) const
|
||||
{
|
||||
if (index<0 || index>getBoardCapability(getCurrentBoard(), Board::Sliders)) return false;
|
||||
return sliderConfig[index] != Board::SLIDER_NONE;
|
||||
}
|
||||
|
||||
GeneralSettings::GeneralSettings()
|
||||
{
|
||||
memset(this, 0, sizeof(GeneralSettings));
|
||||
|
||||
contrast = 25;
|
||||
|
||||
for (int i=0; i < CPN_MAX_ANALOGS; ++i) {
|
||||
calibMid[i] = 0x200;
|
||||
calibSpanNeg[i] = 0x180;
|
||||
calibSpanPos[i] = 0x180;
|
||||
}
|
||||
|
||||
Firmware * firmware = Firmware::getCurrentVariant();
|
||||
Board::Type board = firmware->getBoard();
|
||||
|
||||
// vBatWarn is voltage in 100mV, vBatMin is in 100mV but with -9V offset, vBatMax has a -12V offset
|
||||
vBatWarn = 90;
|
||||
if (IS_TARANIS_X9E(board) || IS_HORUS_X12S(board)) {
|
||||
// NI-MH 9.6V
|
||||
vBatWarn = 87;
|
||||
vBatMin = -5; //8,5V
|
||||
vBatMax = -5; //11,5V
|
||||
}
|
||||
else if (IS_TARANIS_XLITE(board) || IS_HORUS_X10(board)) {
|
||||
// Lipo 2S
|
||||
vBatWarn = 66;
|
||||
vBatMin = -23; // 6.7V
|
||||
vBatMax = -37; // 8.3V
|
||||
}
|
||||
else if (IS_TARANIS(board)) {
|
||||
// NI-MH 7.2V, X9D, X9D+ and X7
|
||||
vBatWarn = 65;
|
||||
vBatMin = -30; //6V
|
||||
vBatMax = -40; //8V
|
||||
}
|
||||
|
||||
setDefaultControlTypes(board);
|
||||
|
||||
backlightMode = 3; // keys and sticks
|
||||
// backlightBright = 0; // 0 = 100%
|
||||
|
||||
if (IS_HORUS(board)) {
|
||||
backlightOffBright = 20;
|
||||
}
|
||||
|
||||
if (IS_ARM(board)) {
|
||||
speakerVolume = 12;
|
||||
}
|
||||
|
||||
if (IS_HORUS(board)) {
|
||||
strcpy(bluetoothName, "Horus");
|
||||
}
|
||||
else if (IS_TARANIS_X9E(board) || IS_TARANIS_SMALL(board)) {
|
||||
strcpy(bluetoothName, "Taranis");
|
||||
}
|
||||
|
||||
templateSetup = g.profile[g.sessionId()].channelOrder();
|
||||
stickMode = g.profile[g.sessionId()].defaultMode();
|
||||
|
||||
QString t_calib = g.profile[g.sessionId()].stickPotCalib();
|
||||
int potsnum = getBoardCapability(getCurrentBoard(), Board::Pots);
|
||||
if (!t_calib.isEmpty()) {
|
||||
QString t_trainercalib=g.profile[g.sessionId()].trainerCalib();
|
||||
int8_t t_txVoltageCalibration=(int8_t)g.profile[g.sessionId()].txVoltageCalibration();
|
||||
int8_t t_txCurrentCalibration=(int8_t)g.profile[g.sessionId()].txCurrentCalibration();
|
||||
int8_t t_PPM_Multiplier=(int8_t)g.profile[g.sessionId()].ppmMultiplier();
|
||||
uint8_t t_stickMode=(uint8_t)g.profile[g.sessionId()].gsStickMode();
|
||||
uint8_t t_vBatWarn=(uint8_t)g.profile[g.sessionId()].vBatWarn();
|
||||
QString t_DisplaySet=g.profile[g.sessionId()].display();
|
||||
QString t_BeeperSet=g.profile[g.sessionId()].beeper();
|
||||
QString t_HapticSet=g.profile[g.sessionId()].haptic();
|
||||
QString t_SpeakerSet=g.profile[g.sessionId()].speaker();
|
||||
QString t_CountrySet=g.profile[g.sessionId()].countryCode();
|
||||
|
||||
if ((t_calib.length()==(CPN_MAX_STICKS+potsnum)*12) && (t_trainercalib.length()==16)) {
|
||||
QString Byte;
|
||||
int16_t byte16;
|
||||
bool ok;
|
||||
for (int i=0; i<(CPN_MAX_STICKS+potsnum); i++) {
|
||||
Byte=t_calib.mid(i*12,4);
|
||||
byte16=(int16_t)Byte.toInt(&ok,16);
|
||||
if (ok)
|
||||
calibMid[i]=byte16;
|
||||
Byte=t_calib.mid(4+i*12,4);
|
||||
byte16=(int16_t)Byte.toInt(&ok,16);
|
||||
if (ok)
|
||||
calibSpanNeg[i]=byte16;
|
||||
Byte=t_calib.mid(8+i*12,4);
|
||||
byte16=(int16_t)Byte.toInt(&ok,16);
|
||||
if (ok)
|
||||
calibSpanPos[i]=byte16;
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
Byte=t_trainercalib.mid(i*4,4);
|
||||
byte16=(int16_t)Byte.toInt(&ok,16);
|
||||
if (ok)
|
||||
trainer.calib[i]=byte16;
|
||||
}
|
||||
txCurrentCalibration=t_txCurrentCalibration;
|
||||
txVoltageCalibration=t_txVoltageCalibration;
|
||||
vBatWarn=t_vBatWarn;
|
||||
PPM_Multiplier=t_PPM_Multiplier;
|
||||
stickMode = t_stickMode;
|
||||
}
|
||||
if ((t_DisplaySet.length()==6) && (t_BeeperSet.length()==4) && (t_HapticSet.length()==6) && (t_SpeakerSet.length()==6)) {
|
||||
uint8_t byte8u;
|
||||
int8_t byte8;
|
||||
bool ok;
|
||||
byte8=(int8_t)t_DisplaySet.mid(0,2).toInt(&ok,16);
|
||||
if (ok)
|
||||
optrexDisplay=(byte8==1 ? true : false);
|
||||
byte8u=(uint8_t)t_DisplaySet.mid(2,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
contrast=byte8u;
|
||||
byte8u=(uint8_t)t_DisplaySet.mid(4,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
backlightBright=byte8u;
|
||||
byte8=(int8_t)t_BeeperSet.mid(0,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
beeperMode=(BeeperMode)byte8;
|
||||
byte8=(int8_t)t_BeeperSet.mid(2,2).toInt(&ok,16);
|
||||
if (ok)
|
||||
beeperLength=byte8;
|
||||
byte8=(int8_t)t_HapticSet.mid(0,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
hapticMode=(BeeperMode)byte8;
|
||||
byte8=(int8_t)t_HapticSet.mid(2,2).toInt(&ok,16);
|
||||
if (ok)
|
||||
hapticStrength=byte8;
|
||||
byte8=(int8_t)t_HapticSet.mid(4,2).toInt(&ok,16);
|
||||
if (ok)
|
||||
hapticLength=byte8;
|
||||
byte8u=(uint8_t)t_SpeakerSet.mid(0,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
speakerMode=byte8u;
|
||||
byte8u=(uint8_t)t_SpeakerSet.mid(2,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
speakerPitch=byte8u;
|
||||
byte8u=(uint8_t)t_SpeakerSet.mid(4,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
speakerVolume=byte8u;
|
||||
if (t_CountrySet.length()==6) {
|
||||
byte8u=(uint8_t)t_CountrySet.mid(0,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
countryCode=byte8u;
|
||||
byte8u=(uint8_t)t_CountrySet.mid(2,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
imperial=byte8u;
|
||||
QString chars = t_CountrySet.mid(4, 2);
|
||||
ttsLanguage[0] = chars[0].toLatin1();
|
||||
ttsLanguage[1] = chars[1].toLatin1();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(themeName, "default");
|
||||
ThemeOptionData option1 = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0 };
|
||||
memcpy(&themeOptionValue[0], option1, sizeof(ThemeOptionData));
|
||||
ThemeOptionData option2 = { 0x03, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0 };
|
||||
memcpy(&themeOptionValue[1], option2, sizeof(ThemeOptionData));
|
||||
}
|
||||
|
||||
void GeneralSettings::setDefaultControlTypes(Board::Type board)
|
||||
{
|
||||
for (int i=0; i<getBoardCapability(board, Board::FactoryInstalledSwitches); i++) {
|
||||
switchConfig[i] = Boards::getSwitchInfo(board, i).config;
|
||||
}
|
||||
|
||||
// TODO: move to Boards, like with switches
|
||||
if (IS_HORUS(board)) {
|
||||
potConfig[0] = Board::POT_WITH_DETENT;
|
||||
potConfig[1] = Board::POT_MULTIPOS_SWITCH;
|
||||
potConfig[2] = Board::POT_WITH_DETENT;
|
||||
}
|
||||
else if (IS_TARANIS_XLITE(board)) {
|
||||
potConfig[0] = Board::POT_WITHOUT_DETENT;
|
||||
potConfig[1] = Board::POT_WITHOUT_DETENT;
|
||||
}
|
||||
else if (IS_TARANIS_X7(board)) {
|
||||
potConfig[0] = Board::POT_WITHOUT_DETENT;
|
||||
potConfig[1] = Board::POT_WITH_DETENT;
|
||||
}
|
||||
else if (IS_TARANIS(board)) {
|
||||
potConfig[0] = Board::POT_WITH_DETENT;
|
||||
potConfig[1] = Board::POT_WITH_DETENT;
|
||||
}
|
||||
else {
|
||||
potConfig[0] = Board::POT_WITHOUT_DETENT;
|
||||
potConfig[1] = Board::POT_WITHOUT_DETENT;
|
||||
potConfig[2] = Board::POT_WITHOUT_DETENT;
|
||||
}
|
||||
|
||||
if (IS_HORUS_X12S(board) || IS_TARANIS_X9E(board)) {
|
||||
sliderConfig[0] = Board::SLIDER_WITH_DETENT;
|
||||
sliderConfig[1] = Board::SLIDER_WITH_DETENT;
|
||||
sliderConfig[2] = Board::SLIDER_WITH_DETENT;
|
||||
sliderConfig[3] = Board::SLIDER_WITH_DETENT;
|
||||
}
|
||||
else if (IS_TARANIS_X9(board) || IS_HORUS_X10(board)) {
|
||||
sliderConfig[0] = Board::SLIDER_WITH_DETENT;
|
||||
sliderConfig[1] = Board::SLIDER_WITH_DETENT;
|
||||
}
|
||||
}
|
||||
|
||||
int GeneralSettings::getDefaultStick(unsigned int channel) const
|
||||
{
|
||||
if (channel >= CPN_MAX_STICKS)
|
||||
return -1;
|
||||
else
|
||||
return chout_ar[4*templateSetup + channel] - 1;
|
||||
}
|
||||
|
||||
RawSource GeneralSettings::getDefaultSource(unsigned int channel) const
|
||||
{
|
||||
int stick = getDefaultStick(channel);
|
||||
if (stick >= 0)
|
||||
return RawSource(SOURCE_TYPE_STICK, stick);
|
||||
else
|
||||
return RawSource(SOURCE_TYPE_NONE);
|
||||
}
|
||||
|
||||
int GeneralSettings::getDefaultChannel(unsigned int stick) const
|
||||
{
|
||||
for (int i=0; i<4; i++){
|
||||
if (getDefaultStick(i) == (int)stick)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void GeneralSettings::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
// Here we can add explicit conversions when moving from one board to another
|
||||
|
||||
cstate.setOrigin(tr("Radio Settings"));
|
||||
|
||||
setDefaultControlTypes(cstate.toType); // start with default switches/pots/sliders
|
||||
|
||||
// Try to intelligently copy any custom control names
|
||||
|
||||
// SE and SG are skipped on X7 board
|
||||
if (IS_TARANIS_X7(cstate.toType)) {
|
||||
if (IS_TARANIS_X9(cstate.fromType) || IS_HORUS(cstate.fromType)) {
|
||||
strncpy(switchName[4], switchName[5], sizeof(switchName[4]));
|
||||
strncpy(switchName[5], switchName[7], sizeof(switchName[5]));
|
||||
}
|
||||
}
|
||||
else if (IS_TARANIS_X7(cstate.fromType)) {
|
||||
if (IS_TARANIS_X9(cstate.toType) || IS_HORUS(cstate.toType)) {
|
||||
strncpy(switchName[5], switchName[4], sizeof(switchName[5]));
|
||||
strncpy(switchName[7], switchName[5], sizeof(switchName[7]));
|
||||
}
|
||||
}
|
||||
|
||||
// LS and RS sliders are after 2 aux sliders on X12 and X9E
|
||||
if ((IS_HORUS_X12S(cstate.toType) || IS_TARANIS_X9E(cstate.toType)) && !IS_HORUS_X12S(cstate.fromType) && !IS_TARANIS_X9E(cstate.fromType)) {
|
||||
strncpy(sliderName[0], sliderName[2], sizeof(sliderName[0]));
|
||||
strncpy(sliderName[1], sliderName[3], sizeof(sliderName[1]));
|
||||
}
|
||||
else if (!IS_TARANIS_X9E(cstate.toType) && !IS_HORUS_X12S(cstate.toType) && (IS_HORUS_X12S(cstate.fromType) || IS_TARANIS_X9E(cstate.fromType))) {
|
||||
strncpy(sliderName[2], sliderName[0], sizeof(sliderName[2]));
|
||||
strncpy(sliderName[3], sliderName[1], sizeof(sliderName[3]));
|
||||
}
|
||||
|
||||
if (IS_HORUS(cstate.toType)) {
|
||||
// 6P switch is only on Horus (by default)
|
||||
if (cstate.fromBoard.getCapability(Board::FactoryInstalledPots) == 2) {
|
||||
strncpy(potName[2], potName[1], sizeof(potName[2]));
|
||||
potName[1][0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_TARANIS(cstate.toType)) {
|
||||
// No S3 pot on Taranis boards by default
|
||||
if (cstate.fromBoard.getCapability(Board::FactoryInstalledPots) > 2)
|
||||
strncpy(potName[1], potName[2], sizeof(potName[1]));
|
||||
|
||||
contrast = qBound<int>(getCurrentFirmware()->getCapability(MinContrast), contrast, getCurrentFirmware()->getCapability(MaxContrast));
|
||||
}
|
||||
|
||||
// TODO: Would be nice at this point to have GUI pause and ask the user to set up any custom hardware they have on the destination radio.
|
||||
|
||||
// Convert all global functions (do this after HW adjustments)
|
||||
for (int i=0; i<CPN_MAX_SPECIAL_FUNCTIONS; i++) {
|
||||
customFn[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef GENERALSETTINGS_H
|
||||
#define GENERALSETTINGS_H
|
||||
|
||||
#include "boards.h"
|
||||
#include "constants.h"
|
||||
#include "customfunctiondata.h"
|
||||
#include "rawsource.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class Firmware;
|
||||
class ModelData;
|
||||
class GeneralSettings;
|
||||
class RadioDataConversionState;
|
||||
|
||||
enum UartModes {
|
||||
UART_MODE_NONE,
|
||||
UART_MODE_TELEMETRY_MIRROR,
|
||||
UART_MODE_TELEMETRY,
|
||||
UART_MODE_SBUS_TRAINER,
|
||||
UART_MODE_DEBUG
|
||||
};
|
||||
|
||||
class TrainerMix {
|
||||
public:
|
||||
TrainerMix() { clear(); }
|
||||
unsigned int src; // 0-7 = ch1-8
|
||||
RawSwitch swtch;
|
||||
int weight;
|
||||
unsigned int mode; // off, add-mode, subst-mode
|
||||
void clear() { memset(reinterpret_cast<void *>(this), 0, sizeof(TrainerMix)); }
|
||||
};
|
||||
|
||||
class TrainerData {
|
||||
public:
|
||||
TrainerData() { clear(); }
|
||||
int calib[4];
|
||||
TrainerMix mix[4];
|
||||
void clear() { memset(reinterpret_cast<void *>(this), 0, sizeof(TrainerData)); }
|
||||
};
|
||||
|
||||
class GeneralSettings {
|
||||
Q_DECLARE_TR_FUNCTIONS(GeneralSettings)
|
||||
|
||||
public:
|
||||
|
||||
enum BeeperMode {
|
||||
BEEPER_QUIET = -2,
|
||||
BEEPER_ALARMS_ONLY = -1,
|
||||
BEEPER_NOKEYS = 0,
|
||||
BEEPER_ALL = 1
|
||||
};
|
||||
|
||||
GeneralSettings();
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
|
||||
void setDefaultControlTypes(Board::Type board);
|
||||
int getDefaultStick(unsigned int channel) const;
|
||||
RawSource getDefaultSource(unsigned int channel) const;
|
||||
int getDefaultChannel(unsigned int stick) const;
|
||||
|
||||
unsigned int version;
|
||||
unsigned int variant;
|
||||
int calibMid[CPN_MAX_ANALOGS];
|
||||
int calibSpanNeg[CPN_MAX_ANALOGS];
|
||||
int calibSpanPos[CPN_MAX_ANALOGS];
|
||||
unsigned int currModelIndex;
|
||||
char currModelFilename[16+1];
|
||||
unsigned int contrast;
|
||||
unsigned int vBatWarn;
|
||||
int txVoltageCalibration;
|
||||
int txCurrentCalibration;
|
||||
int vBatMin;
|
||||
int vBatMax;
|
||||
int backlightMode;
|
||||
TrainerData trainer;
|
||||
unsigned int view; // main screen view // TODO enum
|
||||
bool disableThrottleWarning;
|
||||
bool fai;
|
||||
bool disableMemoryWarning;
|
||||
BeeperMode beeperMode;
|
||||
bool disableAlarmWarning;
|
||||
bool disableRssiPoweroffAlarm;
|
||||
unsigned int usbMode;
|
||||
BeeperMode hapticMode;
|
||||
unsigned int stickMode; // TODO enum
|
||||
int timezone;
|
||||
bool adjustRTC;
|
||||
bool optrexDisplay;
|
||||
unsigned int inactivityTimer;
|
||||
bool minuteBeep;
|
||||
bool preBeep;
|
||||
bool flashBeep;
|
||||
unsigned int splashMode;
|
||||
int splashDuration;
|
||||
unsigned int backlightDelay;
|
||||
unsigned int templateSetup; //RETA order according to chout_ar array
|
||||
int PPM_Multiplier;
|
||||
int hapticLength;
|
||||
unsigned int reNavigation;
|
||||
unsigned int stickReverse;
|
||||
unsigned int speakerPitch;
|
||||
int hapticStrength;
|
||||
unsigned int speakerMode;
|
||||
char ownerName[10+1];
|
||||
int beeperLength;
|
||||
unsigned int gpsFormat;
|
||||
int speakerVolume;
|
||||
unsigned int backlightBright;
|
||||
unsigned int backlightOffBright;
|
||||
int switchesDelay;
|
||||
int temperatureCalib;
|
||||
int temperatureWarn;
|
||||
unsigned int mAhWarn;
|
||||
unsigned int mAhUsed;
|
||||
unsigned int globalTimer;
|
||||
char bluetoothName[10+1];
|
||||
unsigned int bluetoothBaudrate;
|
||||
unsigned int bluetoothMode;
|
||||
unsigned int sticksGain;
|
||||
unsigned int rotarySteps;
|
||||
unsigned int countryCode;
|
||||
bool jitterFilter;
|
||||
unsigned int imperial;
|
||||
char ttsLanguage[2+1];
|
||||
int beepVolume;
|
||||
int wavVolume;
|
||||
int varioVolume;
|
||||
int varioPitch;
|
||||
int varioRange;
|
||||
int varioRepeat;
|
||||
int backgroundVolume;
|
||||
unsigned int mavbaud;
|
||||
unsigned int switchUnlockStates;
|
||||
unsigned int hw_uartMode; // UartModes
|
||||
unsigned int backlightColor;
|
||||
CustomFunctionData customFn[CPN_MAX_SPECIAL_FUNCTIONS];
|
||||
char switchName[CPN_MAX_SWITCHES][3+1];
|
||||
unsigned int switchConfig[CPN_MAX_SWITCHES];
|
||||
char stickName[CPN_MAX_STICKS][3+1];
|
||||
char potName[CPN_MAX_KNOBS][3+1];
|
||||
unsigned int potConfig[CPN_MAX_KNOBS];
|
||||
char sliderName[CPN_MAX_SLIDERS][3+1];
|
||||
unsigned int sliderConfig[CPN_MAX_SLIDERS];
|
||||
|
||||
char themeName[8+1];
|
||||
typedef uint8_t ThemeOptionData[8+1];
|
||||
ThemeOptionData themeOptionValue[5];
|
||||
|
||||
bool switchPositionAllowedTaranis(int index) const;
|
||||
bool switchSourceAllowedTaranis(int index) const;
|
||||
bool isPotAvailable(int index) const;
|
||||
bool isSliderAvailable(int index) const;
|
||||
};
|
||||
|
||||
|
||||
#endif // GENERALSETTINGS_H
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "gvardata.h"
|
||||
|
||||
#include "radiodata.h"
|
||||
|
||||
QString GVarData::unitToString() const
|
||||
{
|
||||
switch (unit) {
|
||||
case GVAR_UNIT_NUMBER:
|
||||
return tr("");
|
||||
case GVAR_UNIT_PERCENT:
|
||||
return tr("%");
|
||||
default:
|
||||
return tr("?"); // highlight unknown value
|
||||
}
|
||||
}
|
||||
|
||||
QString GVarData::precToString() const
|
||||
{
|
||||
switch (prec) {
|
||||
case GVAR_PREC_MUL10:
|
||||
return tr("0._");
|
||||
case GVAR_PREC_MUL1:
|
||||
return tr("0.0");
|
||||
default:
|
||||
return tr("?.?"); // highlight unknown value
|
||||
}
|
||||
}
|
||||
|
||||
QString GVarData::nameToString(int index) const
|
||||
{
|
||||
return RadioData::getElementName(tr("GV"), index + 1, name);
|
||||
}
|
||||
|
||||
int GVarData::multiplierSet()
|
||||
{
|
||||
return (prec == 0 ? 1 : 10);
|
||||
}
|
||||
|
||||
float GVarData::multiplierGet() const
|
||||
{
|
||||
return (prec == 0 ? 1 : 0.1);
|
||||
}
|
||||
|
||||
void GVarData::setMin(float val)
|
||||
{
|
||||
min = (val * multiplierSet()) - GVAR_MIN_VALUE;
|
||||
}
|
||||
|
||||
void GVarData::setMax(float val)
|
||||
{
|
||||
max = GVAR_MAX_VALUE - (val * multiplierSet());
|
||||
}
|
||||
|
||||
int GVarData::getMin() const
|
||||
{
|
||||
return GVAR_MIN_VALUE + min;
|
||||
}
|
||||
|
||||
int GVarData::getMax() const
|
||||
{
|
||||
return GVAR_MAX_VALUE - max;
|
||||
}
|
||||
|
||||
float GVarData::getMinPrec() const
|
||||
{
|
||||
return getMin() * multiplierGet();
|
||||
}
|
||||
|
||||
float GVarData::getMaxPrec() const
|
||||
{
|
||||
return getMax() * multiplierGet();
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef GVARDATA_H
|
||||
#define GVARDATA_H
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
#define GVAR_NAME_LEN 3
|
||||
#define GVAR_MAX_VALUE 1024
|
||||
#define GVAR_MIN_VALUE -GVAR_MAX_VALUE
|
||||
|
||||
class GVarData {
|
||||
Q_DECLARE_TR_FUNCTIONS(GVarData)
|
||||
|
||||
public:
|
||||
GVarData() { clear(); }
|
||||
|
||||
enum {
|
||||
GVAR_UNIT_NUMBER,
|
||||
GVAR_UNIT_PERCENT
|
||||
};
|
||||
|
||||
enum {
|
||||
GVAR_PREC_MUL10,
|
||||
GVAR_PREC_MUL1
|
||||
};
|
||||
|
||||
char name[GVAR_NAME_LEN+1];
|
||||
int min;
|
||||
int max;
|
||||
bool popup;
|
||||
unsigned int prec; // 0 0._ 1 0.0
|
||||
unsigned int unit; // 0 _ 1 %
|
||||
|
||||
void clear() {memset(this, 0, sizeof(GVarData)); }
|
||||
QString unitToString() const;
|
||||
QString precToString() const;
|
||||
QString nameToString(int index) const;
|
||||
int multiplierSet();
|
||||
float multiplierGet() const;
|
||||
void setMin(float val);
|
||||
void setMax(float val);
|
||||
int getMin() const;
|
||||
int getMax() const;
|
||||
float getMinPrec() const;
|
||||
float getMaxPrec() const;
|
||||
};
|
||||
|
||||
|
||||
#endif // GVARDATA_H
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "io_data.h"
|
||||
|
||||
#include "radiodata.h" // for RadioData::getElementName
|
||||
#include "radiodataconversionstate.h"
|
||||
|
||||
/*
|
||||
* ExpoData
|
||||
*/
|
||||
|
||||
void ExpoData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent(tr("INP"), 3);
|
||||
cstate.setSubComp(RawSource(SOURCE_TYPE_VIRTUAL_INPUT, chn).toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType) % tr(" (@%1)").arg(cstate.subCompIdx));
|
||||
srcRaw.convert(cstate);
|
||||
swtch.convert(cstate);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MixData
|
||||
*/
|
||||
|
||||
void MixData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent(tr("MIX"), 4);
|
||||
cstate.setSubComp(RawSource(SOURCE_TYPE_CH, destCh-1).toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType) % tr(" (@%1)").arg(cstate.subCompIdx));
|
||||
srcRaw.convert(cstate);
|
||||
swtch.convert(cstate);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* LimitData
|
||||
*/
|
||||
|
||||
QString LimitData::minToString() const
|
||||
{
|
||||
return QString::number((qreal)min/10);
|
||||
}
|
||||
|
||||
QString LimitData::maxToString() const
|
||||
{
|
||||
return QString::number((qreal)max/10);
|
||||
}
|
||||
|
||||
QString LimitData::revertToString() const
|
||||
{
|
||||
return revert ? tr("INV") : tr("NOR");
|
||||
}
|
||||
|
||||
QString LimitData::nameToString(int index) const
|
||||
{
|
||||
return RadioData::getElementName(tr("CH"), index + 1, name);
|
||||
}
|
||||
|
||||
QString LimitData::offsetToString() const
|
||||
{
|
||||
return QString::number((qreal)offset/10, 'f', 1);
|
||||
}
|
||||
|
||||
void LimitData::clear()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(LimitData));
|
||||
min = -1000;
|
||||
max = +1000;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CurveData
|
||||
*/
|
||||
|
||||
CurveData::CurveData()
|
||||
{
|
||||
clear(5);
|
||||
}
|
||||
|
||||
void CurveData::clear(int count)
|
||||
{
|
||||
memset(this, 0, sizeof(CurveData));
|
||||
this->count = count;
|
||||
}
|
||||
|
||||
bool CurveData::isEmpty() const
|
||||
{
|
||||
for (int i=0; i<count; i++) {
|
||||
if (points[i].y != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString CurveData::nameToString(const int idx) const
|
||||
{
|
||||
return RadioData::getElementName(tr("CV"), idx + 1, name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FlightModeData
|
||||
*/
|
||||
|
||||
void FlightModeData::clear(const int phase)
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(FlightModeData));
|
||||
if (phase != 0) {
|
||||
for (int idx=0; idx<CPN_MAX_GVARS; idx++) {
|
||||
gvars[idx] = 1025;
|
||||
}
|
||||
for (int idx=0; idx<CPN_MAX_ENCODERS; idx++) {
|
||||
rotaryEncoders[idx] = 1025;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString FlightModeData::nameToString(int index) const
|
||||
{
|
||||
return RadioData::getElementName(tr("FM"), index, name); // names are zero-based, FM0, FM1, etc
|
||||
}
|
||||
|
||||
void FlightModeData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent("FMD", 2);
|
||||
cstate.setSubComp(nameToString(cstate.subCompIdx));
|
||||
swtch.convert(cstate);
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef IO_DATA_H
|
||||
#define IO_DATA_H
|
||||
|
||||
#include "constants.h"
|
||||
#include "curvereference.h"
|
||||
#include "rawsource.h"
|
||||
#include "rawswitch.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class RadioDataConversionState;
|
||||
|
||||
enum InputMode {
|
||||
INPUT_MODE_NONE,
|
||||
INPUT_MODE_POS,
|
||||
INPUT_MODE_NEG,
|
||||
INPUT_MODE_BOTH
|
||||
};
|
||||
|
||||
class ExpoData {
|
||||
Q_DECLARE_TR_FUNCTIONS(ExpoData)
|
||||
|
||||
public:
|
||||
ExpoData() { clear(); }
|
||||
RawSource srcRaw;
|
||||
unsigned int scale;
|
||||
unsigned int mode; // InputMode
|
||||
unsigned int chn;
|
||||
RawSwitch swtch;
|
||||
unsigned int flightModes; // -5=!FP4, 0=normal, 5=FP4
|
||||
int weight;
|
||||
int offset;
|
||||
CurveReference curve;
|
||||
int carryTrim;
|
||||
char name[10+1];
|
||||
void clear() { memset(reinterpret_cast<void *>(this), 0, sizeof(ExpoData)); }
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
};
|
||||
|
||||
enum MltpxValue {
|
||||
MLTPX_ADD=0,
|
||||
MLTPX_MUL=1,
|
||||
MLTPX_REP=2
|
||||
};
|
||||
|
||||
#define MIXDATA_NAME_LEN 10
|
||||
|
||||
class MixData {
|
||||
Q_DECLARE_TR_FUNCTIONS(MixData)
|
||||
|
||||
public:
|
||||
MixData() { clear(); }
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
|
||||
unsigned int destCh; // 1..CPN_MAX_CHNOUT
|
||||
RawSource srcRaw;
|
||||
int weight;
|
||||
RawSwitch swtch;
|
||||
CurveReference curve; //0=symmetrisch
|
||||
unsigned int delayUp;
|
||||
unsigned int delayDown;
|
||||
unsigned int speedUp; // Servogeschwindigkeit aus Tabelle (10ms Cycle)
|
||||
unsigned int speedDown; // 0 nichts
|
||||
int carryTrim;
|
||||
bool noExpo;
|
||||
MltpxValue mltpx; // multiplex method 0=+ 1=* 2=replace
|
||||
unsigned int mixWarn; // mixer warning
|
||||
unsigned int flightModes; // -5=!FP4, 0=normal, 5=FP4
|
||||
int sOffset;
|
||||
char name[MIXDATA_NAME_LEN+1];
|
||||
|
||||
void clear() { memset(reinterpret_cast<void *>(this), 0, sizeof(MixData)); }
|
||||
};
|
||||
|
||||
class LimitData {
|
||||
Q_DECLARE_TR_FUNCTIONS(LimitData)
|
||||
|
||||
public:
|
||||
LimitData() { clear(); }
|
||||
int min;
|
||||
int max;
|
||||
bool revert;
|
||||
int offset;
|
||||
int ppmCenter;
|
||||
bool symetrical;
|
||||
char name[6+1];
|
||||
CurveReference curve;
|
||||
QString minToString() const;
|
||||
QString maxToString() const;
|
||||
QString offsetToString() const;
|
||||
QString revertToString() const;
|
||||
QString nameToString(int index) const;
|
||||
void clear();
|
||||
};
|
||||
|
||||
class CurvePoint {
|
||||
public:
|
||||
int8_t x;
|
||||
int8_t y;
|
||||
};
|
||||
|
||||
class CurveData {
|
||||
Q_DECLARE_TR_FUNCTIONS(CurveData)
|
||||
|
||||
public:
|
||||
enum CurveType {
|
||||
CURVE_TYPE_STANDARD,
|
||||
CURVE_TYPE_CUSTOM,
|
||||
CURVE_TYPE_LAST = CURVE_TYPE_CUSTOM
|
||||
};
|
||||
|
||||
CurveData();
|
||||
void clear(int count);
|
||||
bool isEmpty() const;
|
||||
QString nameToString(const int idx) const;
|
||||
|
||||
CurveType type;
|
||||
bool smooth;
|
||||
int count;
|
||||
CurvePoint points[CPN_MAX_POINTS];
|
||||
char name[6+1];
|
||||
};
|
||||
|
||||
class FlightModeData {
|
||||
Q_DECLARE_TR_FUNCTIONS(FlightModeData)
|
||||
|
||||
public:
|
||||
FlightModeData() { clear(0); }
|
||||
int trimMode[CPN_MAX_TRIMS];
|
||||
int trimRef[CPN_MAX_TRIMS];
|
||||
int trim[CPN_MAX_TRIMS];
|
||||
RawSwitch swtch;
|
||||
char name[10+1];
|
||||
unsigned int fadeIn;
|
||||
unsigned int fadeOut;
|
||||
int rotaryEncoders[CPN_MAX_ENCODERS];
|
||||
int gvars[CPN_MAX_GVARS];
|
||||
void clear(const int phase);
|
||||
QString nameToString(int index) const;
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
};
|
||||
|
||||
class SwashRingData {
|
||||
Q_DECLARE_TR_FUNCTIONS(SwashRingData)
|
||||
|
||||
public:
|
||||
SwashRingData() { clear(); }
|
||||
int elevatorWeight;
|
||||
int aileronWeight;
|
||||
int collectiveWeight;
|
||||
unsigned int type;
|
||||
RawSource collectiveSource;
|
||||
RawSource aileronSource;
|
||||
RawSource elevatorSource;
|
||||
unsigned int value;
|
||||
void clear() { memset(reinterpret_cast<void *>(this), 0, sizeof(SwashRingData)); }
|
||||
};
|
||||
|
||||
#endif // IO_DATA_H
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "logicalswitchdata.h"
|
||||
|
||||
#include "radiodata.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
#include "rawsource.h"
|
||||
#include "rawswitch.h"
|
||||
|
||||
bool LogicalSwitchData::isEmpty() const
|
||||
{
|
||||
return (func == 0);
|
||||
}
|
||||
|
||||
CSFunctionFamily LogicalSwitchData::getFunctionFamily() const
|
||||
{
|
||||
if (func == LS_FN_EDGE)
|
||||
return LS_FAMILY_EDGE;
|
||||
else if (func == LS_FN_TIMER)
|
||||
return LS_FAMILY_TIMER;
|
||||
else if (func == LS_FN_STICKY)
|
||||
return LS_FAMILY_STICKY;
|
||||
else if (func < LS_FN_AND || func > LS_FN_ELESS)
|
||||
return LS_FAMILY_VOFS;
|
||||
else if (func < LS_FN_EQUAL)
|
||||
return LS_FAMILY_VBOOL;
|
||||
else
|
||||
return LS_FAMILY_VCOMP;
|
||||
}
|
||||
|
||||
unsigned int LogicalSwitchData::getRangeFlags() const
|
||||
{
|
||||
int f = 0;
|
||||
|
||||
if (func == LS_FN_DPOS || func == LS_FN_DAPOS)
|
||||
f |= RANGE_DELTA_FUNCTION;
|
||||
|
||||
if (func == LS_FN_DAPOS || func == LS_FN_APOS || func == LS_FN_ANEG)
|
||||
f |= RANGE_ABS_FUNCTION;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
QString LogicalSwitchData::funcToString() const
|
||||
{
|
||||
switch (func) {
|
||||
case LS_FN_OFF:
|
||||
return tr("---");
|
||||
case LS_FN_VPOS:
|
||||
return tr("a>x");
|
||||
case LS_FN_VNEG:
|
||||
return tr("a<x");
|
||||
case LS_FN_APOS:
|
||||
return tr("|a|>x");
|
||||
case LS_FN_ANEG:
|
||||
return tr("|a|<x");
|
||||
case LS_FN_AND:
|
||||
return tr("AND");
|
||||
case LS_FN_OR:
|
||||
return tr("OR");
|
||||
case LS_FN_XOR:
|
||||
return tr("XOR");
|
||||
case LS_FN_EQUAL:
|
||||
return tr("a=b");
|
||||
case LS_FN_NEQUAL:
|
||||
return tr("a!=b");
|
||||
case LS_FN_GREATER:
|
||||
return tr("a>b");
|
||||
case LS_FN_LESS:
|
||||
return tr("a<b");
|
||||
case LS_FN_EGREATER:
|
||||
return tr("a>=b");
|
||||
case LS_FN_ELESS:
|
||||
return tr("a<=b");
|
||||
case LS_FN_DPOS:
|
||||
return tr("d>=x");
|
||||
case LS_FN_DAPOS:
|
||||
return tr("|d|>=x");
|
||||
case LS_FN_VEQUAL:
|
||||
return tr("a=x");
|
||||
case LS_FN_VALMOSTEQUAL:
|
||||
return tr("a~x");
|
||||
case LS_FN_TIMER:
|
||||
return tr("Timer");
|
||||
case LS_FN_STICKY:
|
||||
return tr("Sticky");
|
||||
case LS_FN_EDGE:
|
||||
return tr("Edge");
|
||||
default:
|
||||
return tr("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
QString LogicalSwitchData::nameToString(int index) const
|
||||
{
|
||||
return RadioData::getElementName(tr("L"), index + 1, NULL, true);
|
||||
}
|
||||
|
||||
void LogicalSwitchData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent(tr("LSW"), 7);
|
||||
cstate.setSubComp(RawSwitch(SWITCH_TYPE_VIRTUAL, cstate.subCompIdx + 1).toString(cstate.fromType, cstate.fromGS(), cstate.fromModel()));
|
||||
CSFunctionFamily family = getFunctionFamily();
|
||||
switch(family) {
|
||||
case LS_FAMILY_VOFS:
|
||||
val1 = RawSource(val1).convert(cstate.withComponentField("V1")).toValue();
|
||||
break;
|
||||
case LS_FAMILY_STICKY:
|
||||
case LS_FAMILY_VBOOL:
|
||||
val1 = RawSwitch(val1).convert(cstate.withComponentField("V1")).toValue();
|
||||
val2 = RawSwitch(val2).convert(cstate.withComponentField("V2")).toValue();
|
||||
break;
|
||||
case LS_FAMILY_EDGE:
|
||||
val1 = RawSwitch(val1).convert(cstate.withComponentField("V1")).toValue();
|
||||
break;
|
||||
case LS_FAMILY_VCOMP:
|
||||
val1 = RawSource(val1).convert(cstate.withComponentField("V1")).toValue();
|
||||
val2 = RawSource(val2).convert(cstate.withComponentField("V2")).toValue();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
andsw = RawSwitch(andsw).convert(cstate.withComponentField("AND")).toValue();
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef LOGICALSWITCHDATA_H
|
||||
#define LOGICALSWITCHDATA_H
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class RadioDataConversionState;
|
||||
|
||||
enum CSFunction {
|
||||
LS_FN_OFF,
|
||||
LS_FN_VPOS,
|
||||
LS_FN_VNEG,
|
||||
LS_FN_APOS,
|
||||
LS_FN_ANEG,
|
||||
LS_FN_AND,
|
||||
LS_FN_OR,
|
||||
LS_FN_XOR,
|
||||
LS_FN_EQUAL,
|
||||
LS_FN_NEQUAL,
|
||||
LS_FN_GREATER,
|
||||
LS_FN_LESS,
|
||||
LS_FN_EGREATER,
|
||||
LS_FN_ELESS,
|
||||
LS_FN_DPOS,
|
||||
LS_FN_DAPOS,
|
||||
LS_FN_VEQUAL, // added at the end to avoid everything renumbered
|
||||
LS_FN_VALMOSTEQUAL,
|
||||
LS_FN_TIMER,
|
||||
LS_FN_STICKY,
|
||||
LS_FN_EDGE,
|
||||
// later ... LS_FN_RANGE,
|
||||
LS_FN_MAX
|
||||
};
|
||||
|
||||
enum CSFunctionFamily {
|
||||
LS_FAMILY_VOFS,
|
||||
LS_FAMILY_VBOOL,
|
||||
LS_FAMILY_VCOMP,
|
||||
LS_FAMILY_TIMER,
|
||||
LS_FAMILY_STICKY,
|
||||
LS_FAMILY_EDGE,
|
||||
};
|
||||
|
||||
class LogicalSwitchData {
|
||||
Q_DECLARE_TR_FUNCTIONS(LogicalSwitchData)
|
||||
|
||||
public:
|
||||
LogicalSwitchData(unsigned int func=0)
|
||||
{
|
||||
clear();
|
||||
this->func = func;
|
||||
}
|
||||
unsigned int func;
|
||||
int val1;
|
||||
int val2;
|
||||
int val3;
|
||||
unsigned int delay;
|
||||
unsigned int duration;
|
||||
int andsw;
|
||||
|
||||
void clear() { memset(this, 0, sizeof(LogicalSwitchData)); }
|
||||
bool isEmpty() const;
|
||||
CSFunctionFamily getFunctionFamily() const;
|
||||
unsigned int getRangeFlags() const;
|
||||
QString funcToString() const;
|
||||
QString nameToString(int index) const;
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
};
|
||||
|
||||
#endif // LOGICALSWITCHDATA_H
|
||||
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "modeldata.h"
|
||||
|
||||
#include "eeprominterface.h"
|
||||
#include "generalsettings.h"
|
||||
#include "macros.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
|
||||
|
||||
QString removeAccents(const QString & str)
|
||||
{
|
||||
// UTF-8 ASCII Table
|
||||
static const QHash<QString, QVariant> map = {
|
||||
{"a", QRegularExpression("[áâãàä]")},
|
||||
{"A", QRegularExpression("[ÁÂÃÀÄ]")},
|
||||
{"e", QRegularExpression("[éèêě]")},
|
||||
{"E", QRegularExpression("[ÉÈÊĚ]")},
|
||||
{"o", QRegularExpression("[óôõö]")},
|
||||
{"O", QRegularExpression("[ÓÔÕÖ]")},
|
||||
{"u", QRegularExpression("[úü]")},
|
||||
{"U", QRegularExpression("[ÚÜ]")},
|
||||
{"i", "í"}, {"I", "Í"},
|
||||
{"c", "ç"}, {"C", "Ç"},
|
||||
{"y", "ý"}, {"Y", "Ý"},
|
||||
{"s", "š"}, {"S", "Š"},
|
||||
{"r", "ř"}, {"R", "Ř"}
|
||||
};
|
||||
|
||||
QString result(str);
|
||||
for (QHash<QString, QVariant>::const_iterator it = map.cbegin(), en = map.cend(); it != en; ++it) {
|
||||
if (it.value().canConvert<QRegularExpression>())
|
||||
result.replace(it.value().toRegularExpression(), it.key());
|
||||
else
|
||||
result.replace(it.value().toString(), it.key());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* TimerData
|
||||
*/
|
||||
|
||||
void TimerData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent(tr("TMR"), 1);
|
||||
cstate.setSubComp(tr("Timer %1").arg(cstate.subCompIdx + 1));
|
||||
mode.convert(cstate);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ModelData
|
||||
*/
|
||||
|
||||
ModelData::ModelData()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
ModelData::ModelData(const ModelData & src)
|
||||
{
|
||||
*this = src;
|
||||
}
|
||||
|
||||
ModelData & ModelData::operator = (const ModelData & src)
|
||||
{
|
||||
memcpy(reinterpret_cast<void *>(this), &src, sizeof(ModelData));
|
||||
return *this;
|
||||
}
|
||||
|
||||
ExpoData * ModelData::insertInput(const int idx)
|
||||
{
|
||||
memmove(&expoData[idx+1], &expoData[idx], (CPN_MAX_EXPOS-(idx+1))*sizeof(ExpoData));
|
||||
expoData[idx].clear();
|
||||
return &expoData[idx];
|
||||
}
|
||||
|
||||
bool ModelData::isInputValid(const unsigned int idx) const
|
||||
{
|
||||
for (int i=0; i<CPN_MAX_EXPOS; i++) {
|
||||
const ExpoData * expo = &expoData[i];
|
||||
if (expo->mode == 0) break;
|
||||
if (expo->chn == idx)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ModelData::hasExpos(uint8_t inputIdx) const
|
||||
{
|
||||
for (int i=0; i<CPN_MAX_EXPOS; i++) {
|
||||
const ExpoData & expo = expoData[i];
|
||||
if (expo.chn==inputIdx && expo.mode!=0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ModelData::hasMixes(uint8_t channelIdx) const
|
||||
{
|
||||
channelIdx += 1;
|
||||
for (int i=0; i<CPN_MAX_MIXERS; i++) {
|
||||
if (mixData[i].destCh == channelIdx) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QVector<const ExpoData *> ModelData::expos(int input) const
|
||||
{
|
||||
QVector<const ExpoData *> result;
|
||||
for (int i=0; i<CPN_MAX_EXPOS; i++) {
|
||||
const ExpoData * ed = &expoData[i];
|
||||
if ((int)ed->chn==input && ed->mode!=0) {
|
||||
result << ed;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QVector<const MixData *> ModelData::mixes(int channel) const
|
||||
{
|
||||
QVector<const MixData *> result;
|
||||
for (int i=0; i<CPN_MAX_MIXERS; i++) {
|
||||
const MixData * md = &mixData[i];
|
||||
if ((int)md->destCh == channel+1) {
|
||||
result << md;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ModelData::removeInput(const int idx, bool clearName)
|
||||
{
|
||||
unsigned int chn = expoData[idx].chn;
|
||||
|
||||
memmove(&expoData[idx], &expoData[idx+1], (CPN_MAX_EXPOS-(idx+1))*sizeof(ExpoData));
|
||||
expoData[CPN_MAX_EXPOS-1].clear();
|
||||
|
||||
//also remove input name if removing last line for this input
|
||||
if (clearName && !expos(chn).size())
|
||||
inputNames[chn][0] = 0;
|
||||
}
|
||||
|
||||
void ModelData::clearInputs()
|
||||
{
|
||||
for (int i=0; i<CPN_MAX_EXPOS; i++)
|
||||
expoData[i].clear();
|
||||
|
||||
//clear all input names
|
||||
if (getCurrentFirmware()->getCapability(VirtualInputs)) {
|
||||
for (int i=0; i<CPN_MAX_INPUTS; i++) {
|
||||
inputNames[i][0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelData::clearMixes()
|
||||
{
|
||||
for (int i=0; i<CPN_MAX_MIXERS; i++)
|
||||
mixData[i].clear();
|
||||
}
|
||||
|
||||
void ModelData::clear()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(ModelData));
|
||||
modelIndex = -1; // an invalid index, this is managed by the TreeView data model
|
||||
moduleData[0].protocol = PULSES_OFF;
|
||||
moduleData[1].protocol = PULSES_OFF;
|
||||
moduleData[0].channelsCount = 8;
|
||||
moduleData[1].channelsStart = 0;
|
||||
moduleData[1].channelsCount = 8;
|
||||
moduleData[0].ppm.delay = 300;
|
||||
moduleData[1].ppm.delay = 300;
|
||||
moduleData[2].ppm.delay = 300; // Trainer PPM
|
||||
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) {
|
||||
flightModeData[i].clear(i);
|
||||
}
|
||||
for (int i=0; i<CPN_MAX_GVARS; i++) {
|
||||
gvarData[i].clear();
|
||||
}
|
||||
clearInputs();
|
||||
clearMixes();
|
||||
for (int i=0; i<CPN_MAX_CHNOUT; i++)
|
||||
limitData[i].clear();
|
||||
for (int i=0; i<CPN_MAX_STICKS; i++)
|
||||
expoData[i].clear();
|
||||
for (int i=0; i<CPN_MAX_LOGICAL_SWITCHES; i++)
|
||||
logicalSw[i].clear();
|
||||
for (int i=0; i<CPN_MAX_SPECIAL_FUNCTIONS; i++)
|
||||
customFn[i].clear();
|
||||
for (int i=0; i<CPN_MAX_CURVES; i++)
|
||||
curves[i].clear(5);
|
||||
for (int i=0; i<CPN_MAX_TIMERS; i++)
|
||||
timers[i].clear();
|
||||
swashRingData.clear();
|
||||
frsky.clear();
|
||||
rssiAlarms.clear();
|
||||
for (int i=0; i<CPN_MAX_SENSORS; i++)
|
||||
sensorData[i].clear();
|
||||
|
||||
static const uint8_t blob[] = { 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x32, 0x50, 0x31, 0x00, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x42, 0x6d, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
memcpy(customScreenData[0], blob, sizeof(blob));
|
||||
}
|
||||
|
||||
bool ModelData::isEmpty() const
|
||||
{
|
||||
return !used;
|
||||
}
|
||||
|
||||
void ModelData::setDefaultInputs(const GeneralSettings & settings)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
if (IS_ARM(board)) {
|
||||
for (int i=0; i<CPN_MAX_STICKS; i++) {
|
||||
ExpoData * expo = &expoData[i];
|
||||
expo->chn = i;
|
||||
expo->mode = INPUT_MODE_BOTH;
|
||||
expo->srcRaw = settings.getDefaultSource(i);
|
||||
expo->weight = 100;
|
||||
strncpy(inputNames[i], removeAccents(expo->srcRaw.toString(this)).toLatin1().constData(), sizeof(inputNames[i])-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelData::setDefaultMixes(const GeneralSettings & settings)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
if (IS_ARM(board)) {
|
||||
setDefaultInputs(settings);
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_STICKS; i++) {
|
||||
MixData * mix = &mixData[i];
|
||||
mix->destCh = i+1;
|
||||
mix->weight = 100;
|
||||
if (IS_ARM(board)) {
|
||||
mix->srcRaw = RawSource(SOURCE_TYPE_VIRTUAL_INPUT, i);
|
||||
}
|
||||
else {
|
||||
mix->srcRaw = RawSource(SOURCE_TYPE_STICK, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelData::setDefaultValues(unsigned int id, const GeneralSettings & settings)
|
||||
{
|
||||
clear();
|
||||
used = true;
|
||||
sprintf(name, "MODEL%02d", id+1);
|
||||
for (int i=0; i<CPN_MAX_MODULES; i++) {
|
||||
moduleData[i].modelId = id+1;
|
||||
}
|
||||
setDefaultMixes(settings);
|
||||
}
|
||||
|
||||
int ModelData::getTrimValue(int phaseIdx, int trimIdx)
|
||||
{
|
||||
int result = 0;
|
||||
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) {
|
||||
FlightModeData & phase = flightModeData[phaseIdx];
|
||||
if (phase.trimMode[trimIdx] < 0) {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
if (phase.trimRef[trimIdx] == phaseIdx || phaseIdx == 0) {
|
||||
return result + phase.trim[trimIdx];
|
||||
}
|
||||
else {
|
||||
phaseIdx = phase.trimRef[trimIdx];
|
||||
if (phase.trimMode[trimIdx] != 0)
|
||||
result += phase.trim[trimIdx];
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ModelData::isGVarLinked(int phaseIdx, int gvarIdx)
|
||||
{
|
||||
return flightModeData[phaseIdx].gvars[gvarIdx] > 1024;
|
||||
}
|
||||
|
||||
int ModelData::getGVarFieldValue(int phaseIdx, int gvarIdx)
|
||||
{
|
||||
int idx = flightModeData[phaseIdx].gvars[gvarIdx];
|
||||
for (int i=0; idx>GVAR_MAX_VALUE && i<CPN_MAX_FLIGHT_MODES; i++) {
|
||||
int nextPhase = idx - GVAR_MAX_VALUE - 1;
|
||||
if (nextPhase >= phaseIdx) nextPhase += 1;
|
||||
phaseIdx = nextPhase;
|
||||
idx = flightModeData[phaseIdx].gvars[gvarIdx];
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
void ModelData::setTrimValue(int phaseIdx, int trimIdx, int value)
|
||||
{
|
||||
for (uint8_t i=0; i<CPN_MAX_FLIGHT_MODES; i++) {
|
||||
FlightModeData & phase = flightModeData[phaseIdx];
|
||||
int mode = phase.trimMode[trimIdx];
|
||||
int p = phase.trimRef[trimIdx];
|
||||
int & trim = phase.trim[trimIdx];
|
||||
if (mode < 0)
|
||||
return;
|
||||
if (p == phaseIdx || phaseIdx == 0) {
|
||||
trim = value;
|
||||
break;;
|
||||
}
|
||||
else if (mode == 0) {
|
||||
phaseIdx = p;
|
||||
}
|
||||
else {
|
||||
trim = value - getTrimValue(p, trimIdx);
|
||||
if (trim < -500)
|
||||
trim = -500;
|
||||
if (trim > 500)
|
||||
trim = 500;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelData::removeGlobalVar(int & var)
|
||||
{
|
||||
if (var >= 126 && var <= 130)
|
||||
var = flightModeData[0].gvars[var-126];
|
||||
else if (var <= -126 && var >= -130)
|
||||
var = - flightModeData[0].gvars[-126-var];
|
||||
}
|
||||
|
||||
ModelData ModelData::removeGlobalVars()
|
||||
{
|
||||
ModelData result = *this;
|
||||
|
||||
for (int i=0; i<CPN_MAX_MIXERS; i++) {
|
||||
removeGlobalVar(mixData[i].weight);
|
||||
removeGlobalVar(mixData[i].curve.value);
|
||||
removeGlobalVar(mixData[i].sOffset);
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_EXPOS; i++) {
|
||||
removeGlobalVar(expoData[i].weight);
|
||||
removeGlobalVar(expoData[i].curve.value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int ModelData::getChannelsMax(bool forceExtendedLimits) const
|
||||
{
|
||||
if (forceExtendedLimits || extendedLimits)
|
||||
return IS_HORUS_OR_TARANIS(getCurrentBoard()) ? 150 : 125;
|
||||
else
|
||||
return 100;
|
||||
}
|
||||
|
||||
bool ModelData::isAvailable(const RawSwitch & swtch) const
|
||||
{
|
||||
unsigned index = abs(swtch.index) - 1;
|
||||
|
||||
if (swtch.type == SWITCH_TYPE_VIRTUAL) {
|
||||
return logicalSw[index].func != LS_FN_OFF;
|
||||
}
|
||||
else if (swtch.type == SWITCH_TYPE_FLIGHT_MODE) {
|
||||
return index == 0 || flightModeData[index].swtch.type != SWITCH_TYPE_NONE;
|
||||
}
|
||||
else if (swtch.type == SWITCH_TYPE_SENSOR) {
|
||||
return strlen(sensorData[index].label) > 0;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
float ModelData::getGVarFieldValuePrec(int phaseIdx, int gvarIdx)
|
||||
{
|
||||
return getGVarFieldValue(phaseIdx, gvarIdx) * gvarData[gvarIdx].multiplierGet();
|
||||
}
|
||||
|
||||
void ModelData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
// Here we can add explicit conversions when moving from one board to another
|
||||
|
||||
QString origin = QString(name);
|
||||
if (origin.isEmpty())
|
||||
origin = QString::number(cstate.modelIdx+1);
|
||||
cstate.setOrigin(tr("Model: ") % origin);
|
||||
|
||||
cstate.setComponent("SET", 0);
|
||||
if (thrTraceSrc && (int)thrTraceSrc < cstate.fromBoard.getCapability(Board::Pots) + cstate.fromBoard.getCapability(Board::Sliders)) {
|
||||
cstate.setSubComp(tr("Throttle Source"));
|
||||
thrTraceSrc = RawSource(SOURCE_TYPE_STICK, (int)thrTraceSrc + 3).convert(cstate).index - 3;
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_TIMERS; i++) {
|
||||
timers[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_MIXERS; i++) {
|
||||
mixData[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_EXPOS; i++) {
|
||||
expoData[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_LOGICAL_SWITCHES; i++) {
|
||||
logicalSw[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_SPECIAL_FUNCTIONS; i++) {
|
||||
customFn[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) {
|
||||
flightModeData[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_MODULES; i++) {
|
||||
moduleData[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef MODELDATA_H
|
||||
#define MODELDATA_H
|
||||
|
||||
#include "constants.h"
|
||||
#include "customfunctiondata.h"
|
||||
#include "gvardata.h"
|
||||
#include "io_data.h"
|
||||
#include "logicalswitchdata.h"
|
||||
#include "moduledata.h"
|
||||
#include "sensordata.h"
|
||||
#include "telem_data.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class GeneralSettings;
|
||||
class RadioDataConversionState;
|
||||
|
||||
#define CHAR_FOR_NAMES " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-."
|
||||
#define CHAR_FOR_NAMES_REGEX "[ A-Za-z0-9_.-,]*"
|
||||
|
||||
class RSSIAlarmData {
|
||||
public:
|
||||
RSSIAlarmData() { clear(); }
|
||||
unsigned int level[2]; // AVR Only
|
||||
int warning;
|
||||
int critical;
|
||||
bool disabled;
|
||||
void clear() {
|
||||
this->level[0] = 2;
|
||||
this->level[1] = 3;
|
||||
this->warning = 45;
|
||||
this->critical = 42;
|
||||
this->disabled = false;
|
||||
}
|
||||
};
|
||||
|
||||
#define TIMER_NAME_LEN 8
|
||||
|
||||
class TimerData {
|
||||
Q_DECLARE_TR_FUNCTIONS(TimerData)
|
||||
|
||||
public:
|
||||
enum CountDownMode {
|
||||
COUNTDOWN_SILENT,
|
||||
COUNTDOWN_BEEPS,
|
||||
COUNTDOWN_VOICE,
|
||||
COUNTDOWN_HAPTIC
|
||||
};
|
||||
TimerData() { clear(); }
|
||||
RawSwitch mode;
|
||||
char name[TIMER_NAME_LEN+1];
|
||||
bool minuteBeep;
|
||||
unsigned int countdownBeep;
|
||||
unsigned int val;
|
||||
unsigned int persistent;
|
||||
int pvalue;
|
||||
void clear() { memset(reinterpret_cast<void *>(this), 0, sizeof(TimerData)); mode = RawSwitch(SWITCH_TYPE_TIMER_MODE, 0); }
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
};
|
||||
|
||||
#define CPN_MAX_SCRIPTS 9
|
||||
#define CPN_MAX_SCRIPT_INPUTS 10
|
||||
class ScriptData {
|
||||
public:
|
||||
ScriptData() { clear(); }
|
||||
char filename[10+1];
|
||||
char name[10+1];
|
||||
int inputs[CPN_MAX_SCRIPT_INPUTS];
|
||||
void clear() { memset(reinterpret_cast<void *>(this), 0, sizeof(ScriptData)); }
|
||||
};
|
||||
|
||||
/*
|
||||
* TODO ...
|
||||
*/
|
||||
#if 0
|
||||
class CustomScreenOptionData {
|
||||
public:
|
||||
|
||||
};
|
||||
|
||||
class CustomScreenZoneData {
|
||||
public:
|
||||
char widgetName[10+1];
|
||||
WidgetOptionData widgetOptions[5];
|
||||
};
|
||||
|
||||
class CustomScreenData {
|
||||
public:
|
||||
CustomScreenData();
|
||||
|
||||
char layoutName[10+1];
|
||||
CustomScreenZoneData zones[];
|
||||
CustomScreenOptionData options[];
|
||||
};
|
||||
#else
|
||||
typedef char CustomScreenData[610+1];
|
||||
typedef char TopbarData[216+1];
|
||||
#endif
|
||||
|
||||
enum TrainerMode {
|
||||
TRAINER_MODE_MASTER_TRAINER_JACK,
|
||||
TRAINER_MODE_SLAVE,
|
||||
TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE,
|
||||
TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE,
|
||||
TRAINER_MODE_MASTER_BATTERY_COMPARTMENT,
|
||||
};
|
||||
|
||||
class ModelData {
|
||||
Q_DECLARE_TR_FUNCTIONS(ModelData)
|
||||
|
||||
public:
|
||||
ModelData();
|
||||
ModelData(const ModelData & src);
|
||||
ModelData & operator = (const ModelData & src);
|
||||
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
|
||||
ExpoData * insertInput(const int idx);
|
||||
void removeInput(const int idx, bool clearName = true);
|
||||
|
||||
bool isInputValid(const unsigned int idx) const;
|
||||
bool hasExpos(uint8_t inputIdx) const;
|
||||
bool hasMixes(uint8_t output) const;
|
||||
|
||||
QVector<const ExpoData *> expos(int input) const;
|
||||
QVector<const MixData *> mixes(int channel) const;
|
||||
|
||||
bool used;
|
||||
int category;
|
||||
char name[15+1];
|
||||
char filename[16+1];
|
||||
int modelIndex; // Companion only, temporary index position managed by data model.
|
||||
|
||||
TimerData timers[CPN_MAX_TIMERS];
|
||||
bool noGlobalFunctions;
|
||||
bool thrTrim; // Enable Throttle Trim
|
||||
int trimInc; // Trim Increments
|
||||
unsigned int trimsDisplay;
|
||||
bool disableThrottleWarning;
|
||||
|
||||
unsigned int beepANACenter; // 1<<0->A1.. 1<<6->A7
|
||||
|
||||
bool extendedLimits; // TODO xml
|
||||
bool extendedTrims;
|
||||
bool throttleReversed;
|
||||
FlightModeData flightModeData[CPN_MAX_FLIGHT_MODES];
|
||||
MixData mixData[CPN_MAX_MIXERS];
|
||||
LimitData limitData[CPN_MAX_CHNOUT];
|
||||
|
||||
char inputNames[CPN_MAX_INPUTS][4+1];
|
||||
ExpoData expoData[CPN_MAX_EXPOS];
|
||||
|
||||
CurveData curves[CPN_MAX_CURVES];
|
||||
LogicalSwitchData logicalSw[CPN_MAX_LOGICAL_SWITCHES];
|
||||
CustomFunctionData customFn[CPN_MAX_SPECIAL_FUNCTIONS];
|
||||
SwashRingData swashRingData;
|
||||
unsigned int thrTraceSrc;
|
||||
uint64_t switchWarningStates;
|
||||
unsigned int switchWarningEnable;
|
||||
unsigned int potsWarningMode;
|
||||
bool potsWarningEnabled[CPN_MAX_POTS];
|
||||
int potPosition[CPN_MAX_POTS];
|
||||
bool displayChecklist;
|
||||
GVarData gvarData[CPN_MAX_GVARS];
|
||||
MavlinkData mavlink;
|
||||
unsigned int telemetryProtocol;
|
||||
FrSkyData frsky;
|
||||
RSSIAlarmData rssiAlarms;
|
||||
|
||||
char bitmap[10+1];
|
||||
|
||||
unsigned int trainerMode; // TrainerMode
|
||||
|
||||
ModuleData moduleData[CPN_MAX_MODULES+1/*trainer*/];
|
||||
|
||||
ScriptData scriptData[CPN_MAX_SCRIPTS];
|
||||
|
||||
SensorData sensorData[CPN_MAX_SENSORS];
|
||||
|
||||
unsigned int toplcdTimer;
|
||||
|
||||
CustomScreenData customScreenData[5];
|
||||
|
||||
TopbarData topbarData;
|
||||
|
||||
void clear();
|
||||
bool isEmpty() const;
|
||||
void setDefaultInputs(const GeneralSettings & settings);
|
||||
void setDefaultMixes(const GeneralSettings & settings);
|
||||
void setDefaultValues(unsigned int id, const GeneralSettings & settings);
|
||||
|
||||
int getTrimValue(int phaseIdx, int trimIdx);
|
||||
void setTrimValue(int phaseIdx, int trimIdx, int value);
|
||||
|
||||
bool isGVarLinked(int phaseIdx, int gvarIdx);
|
||||
int getGVarFieldValue(int phaseIdx, int gvarIdx);
|
||||
float getGVarFieldValuePrec(int phaseIdx, int gvarIdx);
|
||||
|
||||
ModelData removeGlobalVars();
|
||||
|
||||
void clearMixes();
|
||||
void clearInputs();
|
||||
|
||||
int getChannelsMax(bool forceExtendedLimits=false) const;
|
||||
|
||||
bool isAvailable(const RawSwitch & swtch) const;
|
||||
|
||||
protected:
|
||||
void removeGlobalVar(int & var);
|
||||
};
|
||||
|
||||
#endif // MODELDATA_H
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "moduledata.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "multiprotocols.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
|
||||
void ModuleData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
if (protocol == PULSES_PXX_R9M && (IS_TARANIS_XLITE(cstate.fromType) || IS_TARANIS_XLITE(cstate.toType))) {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
QString ModuleData::rfProtocolToString() const
|
||||
{
|
||||
switch (protocol) {
|
||||
case PULSES_MULTIMODULE:
|
||||
return Multiprotocols::protocolToString((int)multi.rfProtocol, multi.customProto);
|
||||
|
||||
default:
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
QString ModuleData::subTypeToString(int type) const
|
||||
{
|
||||
static const char * strings[] = {
|
||||
"FCC",
|
||||
"EU",
|
||||
"868MHz",
|
||||
"915MHz"
|
||||
};
|
||||
|
||||
if (type < 0)
|
||||
type = subType;
|
||||
|
||||
switch (protocol) {
|
||||
case PULSES_MULTIMODULE:
|
||||
return Multiprotocols::subTypeToString(multi.customProto ? MM_RF_CUSTOM_SELECTED : (int)multi.rfProtocol, (unsigned)type);
|
||||
|
||||
case PULSES_PXX_R9M:
|
||||
return CHECK_IN_ARRAY(strings, type);
|
||||
|
||||
default:
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
QString ModuleData::powerValueToString(Firmware * fw) const
|
||||
{
|
||||
const QStringList & strRef = powerValueStrings(subType, fw);
|
||||
// EU module with telemetry can only be < 100/200mW.
|
||||
if (pxx.sport_out && subType == MODULE_SUBTYPE_R9M_EU && pxx.power > 1)
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
|
||||
return strRef.value(pxx.power, CPN_STR_UNKNOWN_ITEM);
|
||||
}
|
||||
|
||||
// static
|
||||
QString ModuleData::indexToString(int index, Firmware * fw)
|
||||
{
|
||||
if (index < 0)
|
||||
return tr("Trainer Port");
|
||||
|
||||
if (fw->getCapability(NumModules) > 1) {
|
||||
if (IS_HORUS_OR_TARANIS(fw->getBoard()))
|
||||
return index == 0 ? tr("Internal Radio System") : tr("External Radio Module");
|
||||
if (index > 0)
|
||||
return tr("Extra Radio System");
|
||||
}
|
||||
return tr("Radio System");
|
||||
}
|
||||
|
||||
// static
|
||||
QString ModuleData::protocolToString(unsigned protocol)
|
||||
{
|
||||
static const char * strings[] = {
|
||||
"OFF",
|
||||
"PPM",
|
||||
"Silverlit A", "Silverlit B", "Silverlit C",
|
||||
"CTP1009",
|
||||
"LP45", "DSM2", "DSMX",
|
||||
"PPM16", "PPMsim",
|
||||
"FrSky XJT (D16)", "FrSky XJT (D8)", "FrSky XJT (LR12)", "FrSky DJT",
|
||||
"Crossfire",
|
||||
"DIY Multiprotocol Module",
|
||||
"FrSky R9M Module",
|
||||
"SBUS output at VBat"
|
||||
};
|
||||
|
||||
return CHECK_IN_ARRAY(strings, protocol);
|
||||
}
|
||||
|
||||
// static
|
||||
QStringList ModuleData::powerValueStrings(int subType, Firmware * fw)
|
||||
{
|
||||
static const QStringList strings[] = {
|
||||
{ tr("10mW - 16CH"), tr("100mW - 16CH"), tr("500mW - 16CH"), tr("Auto <= 1W - 16CH") }, // full-size FCC
|
||||
{ tr("25mW - 8CH"), tr("25mW - 16CH"), tr("200mW - 16CH (no telemetry)"), tr("500mW - 16CH (no telemetry)") }, // full-size EU
|
||||
{ tr("100mW - 16CH") }, // mini FCC
|
||||
{ tr("25mW - 8CH"), tr("25mW - 16CH"), tr("100mW - 16CH (no telemetry)") } // mini EU
|
||||
};
|
||||
int strIdx = 0;
|
||||
if (subType == MODULE_SUBTYPE_R9M_EU)
|
||||
strIdx += 1;
|
||||
if (fw->getCapability(HasModuleR9MMini))
|
||||
strIdx += 2;
|
||||
return strings[strIdx];
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef MODULEDATA_H
|
||||
#define MODULEDATA_H
|
||||
|
||||
#include "constants.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class Firmware;
|
||||
class RadioDataConversionState;
|
||||
|
||||
enum PulsesProtocol {
|
||||
PULSES_OFF,
|
||||
PULSES_PPM,
|
||||
PULSES_SILV_A,
|
||||
PULSES_SILV_B,
|
||||
PULSES_SILV_C,
|
||||
PULSES_CTP1009,
|
||||
PULSES_LP45,
|
||||
PULSES_DSM2,
|
||||
PULSES_DSMX,
|
||||
PULSES_PPM16,
|
||||
PULSES_PPMSIM,
|
||||
PULSES_PXX_XJT_X16,
|
||||
PULSES_PXX_XJT_D8,
|
||||
PULSES_PXX_XJT_LR12,
|
||||
PULSES_PXX_DJT,
|
||||
PULSES_CROSSFIRE,
|
||||
PULSES_MULTIMODULE,
|
||||
PULSES_PXX_R9M,
|
||||
PULSES_SBUS,
|
||||
PULSES_PROTOCOL_LAST
|
||||
};
|
||||
|
||||
enum MultiModuleRFProtocols {
|
||||
MM_RF_PROTO_FLYSKY=0,
|
||||
MM_RF_PROTO_FIRST=MM_RF_PROTO_FLYSKY,
|
||||
MM_RF_PROTO_HUBSAN,
|
||||
MM_RF_PROTO_FRSKY,
|
||||
MM_RF_PROTO_HISKY,
|
||||
MM_RF_PROTO_V2X2,
|
||||
MM_RF_PROTO_DSM2,
|
||||
MM_RF_PROTO_DEVO,
|
||||
MM_RF_PROTO_YD717,
|
||||
MM_RF_PROTO_KN,
|
||||
MM_RF_PROTO_SYMAX,
|
||||
MM_RF_PROTO_SLT,
|
||||
MM_RF_PROTO_CX10,
|
||||
MM_RF_PROTO_CG023,
|
||||
MM_RF_PROTO_BAYANG,
|
||||
MM_RF_PROTO_ESky,
|
||||
MM_RF_PROTO_MT99XX,
|
||||
MM_RF_PROTO_MJXQ,
|
||||
MM_RF_PROTO_SHENQI,
|
||||
MM_RF_PROTO_FY326,
|
||||
MM_RF_PROTO_SFHSS,
|
||||
MM_RF_PROTO_J6PRO,
|
||||
MM_RF_PROTO_FQ777,
|
||||
MM_RF_PROTO_ASSAN,
|
||||
MM_RF_PROTO_HONTAI,
|
||||
MM_RF_PROTO_OLRS,
|
||||
MM_RF_PROTO_FS_AFHDS2A,
|
||||
MM_RF_PROTO_Q2X2,
|
||||
MM_RF_PROTO_WK_2X01,
|
||||
MM_RF_PROTO_Q303,
|
||||
MM_RF_PROTO_GW008,
|
||||
MM_RF_PROTO_DM002,
|
||||
MM_RF_PROTO_CABELL,
|
||||
MM_RF_PROTO_ESKY150,
|
||||
MM_RF_PROTO_H83D,
|
||||
MM_RF_PROTO_CORONA,
|
||||
MM_RF_PROTO_CFLIE,
|
||||
MM_RF_PROTO_HITEC,
|
||||
MM_RF_PROTO_WFLY,
|
||||
MM_RF_PROTO_BUGS,
|
||||
MM_RF_PROTO_BUGS_MINI,
|
||||
MM_RF_PROTO_TRAXXAS,
|
||||
MM_RF_PROTO_NCC1701,
|
||||
MM_RF_PROTO_E01X,
|
||||
MM_RF_PROTO_V911S,
|
||||
MM_RF_PROTO_GD00X,
|
||||
MM_RF_PROTO_LAST = MM_RF_PROTO_GD00X
|
||||
};
|
||||
|
||||
enum TrainerProtocol {
|
||||
TRAINER_MASTER_JACK,
|
||||
TRAINER_SLAVE_JACK,
|
||||
TRAINER_MASTER_SBUS_MODULE,
|
||||
TRAINER_MASTER_CPPM_MODULE,
|
||||
TRAINER_MASTER_SBUS_BATT_COMPARTMENT
|
||||
};
|
||||
|
||||
enum R9MSubTypes {
|
||||
MODULE_SUBTYPE_R9M_FCC,
|
||||
MODULE_SUBTYPE_R9M_EU,
|
||||
MODULE_SUBTYPE_R9M_EUPLUS,
|
||||
MODULE_SUBTYPE_R9M_AUPLUS,
|
||||
MODULE_SUBTYPE_R9M_LAST=MODULE_SUBTYPE_R9M_AUPLUS
|
||||
};
|
||||
|
||||
class ModuleData {
|
||||
Q_DECLARE_TR_FUNCTIONS(ModuleData)
|
||||
|
||||
public:
|
||||
ModuleData() { clear(); }
|
||||
unsigned int modelId;
|
||||
int protocol;
|
||||
unsigned int subType;
|
||||
bool invertedSerial;
|
||||
unsigned int channelsStart;
|
||||
int channelsCount; // 0=8 channels
|
||||
unsigned int failsafeMode;
|
||||
int failsafeChannels[CPN_MAX_CHNOUT];
|
||||
|
||||
|
||||
struct {
|
||||
int delay;
|
||||
bool pulsePol; // false = positive
|
||||
bool outputType; // false = open drain, true = push pull
|
||||
int frameLength;
|
||||
} ppm;
|
||||
|
||||
struct {
|
||||
unsigned int rfProtocol;
|
||||
bool autoBindMode;
|
||||
bool lowPowerMode;
|
||||
bool customProto;
|
||||
int optionValue;
|
||||
} multi;
|
||||
|
||||
struct {
|
||||
int power; // 0 10 mW, 1 100 mW, 2 500 mW, 3 1W
|
||||
bool receiver_telem_off; // false = receiver telem enabled
|
||||
bool receiver_channel_9_16; // false = pwm out 1-8, true 9-16
|
||||
bool external_antenna; // false = internal antenna, true = external antenna
|
||||
bool sport_out;
|
||||
} pxx;
|
||||
|
||||
|
||||
void clear() { memset(this, 0, sizeof(ModuleData)); }
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
QString polarityToString() const { return ppm.pulsePol ? tr("Positive") : tr("Negative"); }
|
||||
QString rfProtocolToString() const;
|
||||
QString subTypeToString(int type = -1) const;
|
||||
QString powerValueToString(Firmware * fw) const;
|
||||
static QString indexToString(int index, Firmware * fw);
|
||||
static QString protocolToString(unsigned protocol);
|
||||
static QStringList powerValueStrings(int subType, Firmware * fw);
|
||||
};
|
||||
|
||||
#endif // MODULEDATA_H
|
||||
@@ -37,27 +37,32 @@ static const QStringList STR_SUBTYPE_CUSTOM ({
|
||||
STR_MULTI_SUBTYPE " 4", STR_MULTI_SUBTYPE " 5", STR_MULTI_SUBTYPE " 6", STR_MULTI_SUBTYPE " 7"
|
||||
});
|
||||
static const QStringList STR_SUBTYPE_FLYSKY {"Standard", "V9x9", "V6x6", "V912", "CX20"};
|
||||
static const QStringList STR_SUBTYPE_HUBSAN {"H107", "H301", "H501"};
|
||||
static const QStringList STR_SUBTYPE_FRSKY {"D16", "D8", "D16 8ch", "V8", "D16 EU-LBT", "D16 EU-LBT 8ch"};
|
||||
static const QStringList STR_SUBTYPE_HISKY {"HiSky", "HK310"};
|
||||
static const QStringList STR_SUBTYPE_V2X2 {"V2x2", "JXD506"};
|
||||
static const QStringList STR_SUBTYPE_HISKY {"Standard", "HK310"};
|
||||
static const QStringList STR_SUBTYPE_V2X2 {"Standard", "JXD506"};
|
||||
static const QStringList STR_SUBTYPE_DSM {"DSM2 22ms", "DSM2 11ms", "DSMX 22ms", "DSMX 11ms"};
|
||||
static const QStringList STR_SUBTYPE_YD717 {"YD717", "Skywalker", "Syma X2", "XINXUN", "NIHUI"};
|
||||
static const QStringList STR_SUBTYPE_SYMAX {"Standard", "Syma X5C"};
|
||||
static const QStringList STR_SUBTYPE_SLT {"SLT", "Vista"};
|
||||
static const QStringList STR_SUBTYPE_CX10 {"Green", "Blue", "DM007", "-", "JC3015a", "JC3015b", "MK33041", "Q242"};
|
||||
static const QStringList STR_SUBTYPE_CG023 {"CG023", "YD829"};
|
||||
static const QStringList STR_SUBTYPE_BAYANG {"Bayang", "H8S3D", "X16 AH", "IRDRONE"};
|
||||
static const QStringList STR_SUBTYPE_YD717 {"Standard", "Skywalker", "Syma X4", "XINXUN", "NIHUI"};
|
||||
static const QStringList STR_SUBTYPE_KN {"WLtoys", "FeiLun"};
|
||||
static const QStringList STR_SUBTYPE_SYMAX {"Standard", "Syma X5C"};
|
||||
static const QStringList STR_SUBTYPE_SLT {"V1 (6 Channel)", "V2 (8 Channel)", "Q100", "Q200", "MR100"};
|
||||
static const QStringList STR_SUBTYPE_CX10 {"Green", "Blue", "DM007", "-", "JC3015a", "JC3015b", "MK33041"};
|
||||
static const QStringList STR_SUBTYPE_CG023 {"Standard", "YD829"};
|
||||
static const QStringList STR_SUBTYPE_BAYANG {"Standard", "H8S3D", "X16 AH", "IRDRONE"};
|
||||
static const QStringList STR_SUBTYPE_MT99 {"MT99", "H7", "YZ", "LS", "FY805"};
|
||||
static const QStringList STR_SUBTYPE_MJXQ {"WLH08", "X600", "X800", "H26D", "E010", "H26WH"};
|
||||
static const QStringList STR_SUBTYPE_FY326 {"FY326", "FY319"};
|
||||
static const QStringList STR_SUBTYPE_HONTAI {"Standard", "JJRC X1", "X5C1 Clone"};
|
||||
static const QStringList STR_SUBTYPE_FY326 {"Standard", "FY319"};
|
||||
static const QStringList STR_SUBTYPE_HONTAI {"Standard", "JJRC X1", "X5C1 Clone", "FQ777_951"};
|
||||
static const QStringList STR_SUBTYPE_AFHDS2A {"PWM and IBUS", "PPM and IBUS", "PWM and SBUS", "PPM and SBUS"};
|
||||
static const QStringList STR_SUBTYPE_Q2X2 {"Q222", "Q242", "Q282"};
|
||||
static const QStringList STR_SUBTYPE_WK2x01 {"WK2801", "WK2401", "W6_5_1", "W6_6_1", "W6_HEL", "W6_HEL_I"};
|
||||
static const QStringList STR_SUBTYPE_Q303 {"Q303", "CX35", "CX10D", "CX10WD"};
|
||||
static const QStringList STR_SUBTYPE_CABELL {"CABELL V3","C TELEM","-","-","-","-","F_SAFE","UNBIND"};
|
||||
static const QStringList STR_SUBTYPE_H83D {"H8_3D","H20H","H20Mini","H30Mini"};
|
||||
static const QStringList STR_SUBTYPE_Q303 {"Standard", "CX35", "CX10D", "CX10WD"};
|
||||
static const QStringList STR_SUBTYPE_CABELL {"Cabell V3", "Cab V3 Telem", "-", "-", "-", "-", "Set FailSafe", "Unbind"};
|
||||
static const QStringList STR_SUBTYPE_H83D {"H8 Mini 3D", "H20H", "H20 Mini", "H30 Mini"};
|
||||
static const QStringList STR_SUBTYPE_CORONA {"V1", "V2", "Flydream V3"};
|
||||
static const QStringList STR_SUBTYPE_HITEC {"Optima", "Optima Hub Telem", "Minima"};
|
||||
static const QStringList STR_SUBTYPE_E01X {"E012", "E015"};
|
||||
|
||||
static const QStringList NO_SUBTYPE {STR_MULTI_DEFAULT};
|
||||
|
||||
|
||||
@@ -65,7 +70,7 @@ static const QStringList NO_SUBTYPE {STR_MULTI_DEFAULT};
|
||||
|
||||
const Multiprotocols multiProtocols {
|
||||
{MM_RF_PROTO_FLYSKY, 4, false, STR_SUBTYPE_FLYSKY, nullptr},
|
||||
{MM_RF_PROTO_HUBSAN, 0, false, NO_SUBTYPE, STR_MULTI_VIDFREQ},
|
||||
{MM_RF_PROTO_HUBSAN, 2, false, STR_SUBTYPE_HUBSAN, STR_MULTI_VIDFREQ},
|
||||
{MM_RF_PROTO_FRSKY, 5, false, STR_SUBTYPE_FRSKY, STR_MULTI_RFTUNE},
|
||||
{MM_RF_PROTO_HISKY, 1, false, STR_SUBTYPE_HISKY, nullptr},
|
||||
{MM_RF_PROTO_V2X2, 1, false, STR_SUBTYPE_V2X2, nullptr},
|
||||
@@ -73,15 +78,15 @@ const Multiprotocols multiProtocols {
|
||||
{MM_RF_PROTO_YD717, 4, false, STR_SUBTYPE_YD717, nullptr},
|
||||
{MM_RF_PROTO_KN, 1, false, STR_SUBTYPE_KN, nullptr},
|
||||
{MM_RF_PROTO_SYMAX, 1, false, STR_SUBTYPE_SYMAX, nullptr},
|
||||
{MM_RF_PROTO_SLT, 1, false, STR_SUBTYPE_SLT, nullptr},
|
||||
{MM_RF_PROTO_CX10, 7, false, STR_SUBTYPE_CX10, nullptr},
|
||||
{MM_RF_PROTO_SLT, 4, false, STR_SUBTYPE_SLT, nullptr},
|
||||
{MM_RF_PROTO_CX10, 6, false, STR_SUBTYPE_CX10, nullptr},
|
||||
{MM_RF_PROTO_CG023, 1, false, STR_SUBTYPE_CG023, nullptr},
|
||||
{MM_RF_PROTO_BAYANG, 3, false, STR_SUBTYPE_BAYANG, STR_MULTI_TELEMETRY},
|
||||
{MM_RF_PROTO_MT99XX, 4, false, STR_SUBTYPE_MT99, nullptr},
|
||||
{MM_RF_PROTO_MJXQ, 5, false, STR_SUBTYPE_MJXQ, nullptr},
|
||||
{MM_RF_PROTO_FY326, 1, false, STR_SUBTYPE_FY326, nullptr},
|
||||
{MM_RF_PROTO_SFHSS, 0, true, NO_SUBTYPE, STR_MULTI_RFTUNE},
|
||||
{MM_RF_PROTO_HONTAI, 2, false, STR_SUBTYPE_HONTAI, nullptr},
|
||||
{MM_RF_PROTO_HONTAI, 3, false, STR_SUBTYPE_HONTAI, nullptr},
|
||||
{MM_RF_PROTO_OLRS, 0, false, NO_SUBTYPE, STR_MULTI_RFPOWER},
|
||||
{MM_RF_PROTO_FS_AFHDS2A, 3, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ},
|
||||
{MM_RF_PROTO_Q2X2, 2, false, STR_SUBTYPE_Q2X2, nullptr},
|
||||
@@ -89,6 +94,9 @@ const Multiprotocols multiProtocols {
|
||||
{MM_RF_PROTO_Q303, 3, false, STR_SUBTYPE_Q303, nullptr},
|
||||
{MM_RF_PROTO_CABELL, 7, false, STR_SUBTYPE_CABELL, STR_MULTI_OPTION},
|
||||
{MM_RF_PROTO_H83D, 3, false, STR_SUBTYPE_H83D, nullptr},
|
||||
{MM_RF_PROTO_CORONA, 2, false, STR_SUBTYPE_CORONA, STR_MULTI_RFTUNE},
|
||||
{MM_RF_PROTO_HITEC, 2, false, STR_SUBTYPE_HITEC, STR_MULTI_RFTUNE},
|
||||
{MM_RF_PROTO_E01X, 1, false, STR_SUBTYPE_E01X, nullptr},
|
||||
{MM_RF_CUSTOM_SELECTED, 7, true, STR_SUBTYPE_CUSTOM, STR_MULTI_OPTION},
|
||||
|
||||
// Sentinel and default for protocols not listed above (MM_RF_CUSTOM is 0xff)
|
||||
@@ -122,3 +130,25 @@ const Multiprotocols::MultiProtocolDefinition & Multiprotocols::getProtocol(int
|
||||
Q_ASSERT(protocols.rbegin()->protocol == 0xfe);
|
||||
return *protocols.rbegin();
|
||||
}
|
||||
|
||||
// static
|
||||
QString Multiprotocols::protocolToString(int protocol, bool custom)
|
||||
{
|
||||
static const QStringList strings({
|
||||
"FlySky", "Hubsan", "FrSky", "Hisky", "V2x2", "DSM", "Devo", "YD717", "KN", "SymaX", "SLT", "CX10", "CG023",
|
||||
"Bayang", "ESky", "MT99XX", "MJXQ", "Shenqi", "FY326", "SFHSS", "J6 PRO","FQ777","Assan","Hontai","Open LRS",
|
||||
"FlySky AFHDS2A", "Q2x2", "Walkera", "Q303", "GW008", "DM002", "Cabell", "ESky 150", "H8 3D", "Corona", "CFlie",
|
||||
"Hitec", "Wfly", "Bugs", "Bugs Mini", "Traxxas", "NCC-1701-A", "E01X", "V911S", "GD00X"
|
||||
});
|
||||
|
||||
if (protocol == MM_RF_CUSTOM_SELECTED || custom)
|
||||
return tr("Custom - proto %1)").arg(protocol);
|
||||
else
|
||||
return strings.value(protocol, CPN_STR_UNKNOWN_ITEM);
|
||||
}
|
||||
|
||||
// static
|
||||
QString Multiprotocols::subTypeToString(int protocol, unsigned subType)
|
||||
{
|
||||
return tr(qPrintable(multiProtocols.getProtocol(protocol).subTypeStrings.value(subType, CPN_STR_UNKNOWN_ITEM)));
|
||||
}
|
||||
@@ -22,14 +22,14 @@
|
||||
#define OPENTX_MULTI_H
|
||||
|
||||
#include <vector>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QStringList>
|
||||
#include <QtCore>
|
||||
|
||||
#define MM_RF_CUSTOM_SELECTED 0xff
|
||||
|
||||
class Multiprotocols
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(Multiprotocols)
|
||||
|
||||
public:
|
||||
|
||||
struct radio_mm_definition {
|
||||
@@ -46,7 +46,7 @@ class Multiprotocols
|
||||
const QStringList subTypeStrings;
|
||||
const QString optionsstr;
|
||||
|
||||
unsigned int numSubytes() const
|
||||
unsigned int numSubTypes() const
|
||||
{
|
||||
return (unsigned int) subTypeStrings.length();
|
||||
}
|
||||
@@ -72,6 +72,8 @@ class Multiprotocols
|
||||
}
|
||||
|
||||
const MultiProtocolDefinition &getProtocol(int protocol) const;
|
||||
static QString protocolToString(int protocol, bool custom = false);
|
||||
static QString subTypeToString(int protocol, unsigned subType);
|
||||
|
||||
private:
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "boards.h"
|
||||
#include "helpers.h"
|
||||
#include "opentxeeprom.h"
|
||||
#include "customdebug.h"
|
||||
@@ -32,18 +33,18 @@ using namespace Board;
|
||||
|
||||
#define HAS_PERSISTENT_TIMERS(board) (IS_ARM(board) || IS_2560(board))
|
||||
#define MAX_VIEWS(board) (HAS_LARGE_LCD(board) ? 2 : 256)
|
||||
#define MAX_POTS(board, version) (IS_HORUS(board) ? 3 : (IS_TARANIS_X7(board) ? 2 : (IS_TARANIS(board) ? (IS_TARANIS_X9E(board) ? 4 : (version >= 216 ? 3 : 2)) : 3)))
|
||||
#define MAX_SLIDERS(board) (IS_HORUS(board) ? 4 : (IS_TARANIS_X7(board) ? 0 : (IS_TARANIS(board) ? (IS_TARANIS_X9E(board) ? 4 : 2) : 0)))
|
||||
#define MAX_MOUSE_ANALOGS(board) (IS_HORUS(board) ? 2 : 0)
|
||||
#define MAX_SWITCHES(board, version) (IS_HORUS(board) ? 8 : (IS_TARANIS_X7(board) ? 6 : (IS_TARANIS(board) ? (IS_TARANIS_X9E(board) ? 18 : 8) : 7)))
|
||||
#define MAX_SWITCH_SLOTS(board, version) (IS_TARANIS_X9E(board) ? 32 : 8)
|
||||
#define MAX_SWITCHES_POSITION(board, version) (IS_TARANIS_X7(board) ? 6*3 : (IS_TARANIS_X9E(board) ? 18*3 : (IS_HORUS_OR_TARANIS(board) ? 8*3 : 9)))
|
||||
#define MAX_POTS(board, version) (IS_TARANIS_NOT_X9E(board) && version < 216 ? 2 : Boards::getCapability(board, Board::Pots))
|
||||
#define MAX_SLIDERS(board) (IS_HORUS_X10(board) ? 4 : (Boards::getCapability(board, Board::Sliders))) //TODO need to be remove when x10 eeprom gets fixed
|
||||
#define MAX_MOUSE_ANALOGS(board) (IS_HORUS_X10(board) ? 2 : (Boards::getCapability(board, Board::MouseAnalogs))) //TODO need to be remove when x10 eeprom gets fixed
|
||||
#define MAX_SWITCHES(board, version) (Boards::getCapability(board, Board::Switches))
|
||||
#define MAX_SWITCH_SLOTS(board, version) (IS_TARANIS_X9E(board) ? 32 : 8) // bitsize of swconfig_t / 2 (see radio/src/datastructs.h)
|
||||
#define MAX_SWITCHES_POSITION(board, version) (Boards::getCapability(board, Board::SwitchPositions))
|
||||
#define MAX_ROTARY_ENCODERS(board) (IS_2560(board) ? 2 : (IS_SKY9X(board) ? 1 : 0))
|
||||
#define MAX_FLIGHT_MODES(board, version) (IS_ARM(board) ? 9 : (IS_DBLRAM(board, version) ? 6 : 5))
|
||||
#define MAX_TIMERS(board, version) ((IS_ARM(board) && version >= 217) ? 3 : 2)
|
||||
#define MAX_MIXERS(board, version) (IS_ARM(board) ? 64 : 32)
|
||||
#define MAX_CHANNELS(board, version) (IS_ARM(board) ? 32 : 16)
|
||||
#define MAX_TRIMS(board) (IS_HORUS(board) ? 6 : 4)
|
||||
#define MAX_TRIMS(board) (Boards::getCapability(board, Board::NumTrims))
|
||||
#define MAX_EXPOS(board, version) (IS_ARM(board) ? ((IS_HORUS_OR_TARANIS(board) && version >= 216) ? 64 : 32) : (IS_DBLRAM(board, version) ? 16 : 14))
|
||||
#define MAX_LOGICAL_SWITCHES(board, version) (IS_ARM(board) ? (version >= 218 ? 64 : 32) : ((IS_DBLEEPROM(board, version) && version<217) ? 15 : 12))
|
||||
#define MAX_CUSTOM_FUNCTIONS(board, version) (IS_ARM(board) ? (version >= 216 ? 64 : 32) : (IS_DBLEEPROM(board, version) ? 24 : 16))
|
||||
@@ -348,11 +349,11 @@ class SourcesConversionTable: public ConversionTable {
|
||||
|
||||
for (int i=0; i<TELEMETRY_SOURCE_ACC; i++) {
|
||||
if (version < 216) {
|
||||
if (i==TELEMETRY_SOURCE_TX_TIME || i==TELEMETRY_SOURCE_SWR || i==TELEMETRY_SOURCE_A3 || i==TELEMETRY_SOURCE_A4 || i==TELEMETRY_SOURCE_ASPEED || i==TELEMETRY_SOURCE_DTE || i==TELEMETRY_SOURCE_CELL_MIN || i==TELEMETRY_SOURCE_CELLS_MIN || i==TELEMETRY_SOURCE_VFAS_MIN)
|
||||
if (i==TELEMETRY_SOURCE_TX_TIME || i==TELEMETRY_SOURCE_RAS || i==TELEMETRY_SOURCE_A3 || i==TELEMETRY_SOURCE_A4 || i==TELEMETRY_SOURCE_ASPEED || i==TELEMETRY_SOURCE_DTE || i==TELEMETRY_SOURCE_CELL_MIN || i==TELEMETRY_SOURCE_CELLS_MIN || i==TELEMETRY_SOURCE_VFAS_MIN)
|
||||
continue;
|
||||
}
|
||||
if (!IS_ARM(board)) {
|
||||
if (i==TELEMETRY_SOURCE_TX_TIME || i==TELEMETRY_SOURCE_SWR || i==TELEMETRY_SOURCE_A3 || i==TELEMETRY_SOURCE_A4 || i==TELEMETRY_SOURCE_A3_MIN || i==TELEMETRY_SOURCE_A4_MIN)
|
||||
if (i==TELEMETRY_SOURCE_TX_TIME || i==TELEMETRY_SOURCE_RAS || i==TELEMETRY_SOURCE_A3 || i==TELEMETRY_SOURCE_A4 || i==TELEMETRY_SOURCE_A3_MIN || i==TELEMETRY_SOURCE_A4_MIN)
|
||||
continue;
|
||||
}
|
||||
addConversion(RawSource(SOURCE_TYPE_TELEMETRY, i), val++);
|
||||
@@ -433,8 +434,8 @@ template <int N>
|
||||
class SwitchField: public ConversionField< SignedField<N> > {
|
||||
public:
|
||||
SwitchField(DataField * parent, RawSwitch & sw, Board::Type board, unsigned int version, unsigned long flags=0):
|
||||
ConversionField< SignedField<N> >(parent, _switch, SwitchesConversionTable::getInstance(board, version, flags), QObject::tr("Switch").toLatin1(),
|
||||
QObject::tr("Switch ").toLatin1() + sw.toString(board) + QObject::tr(" cannot be exported on this board!").toLatin1()),
|
||||
ConversionField< SignedField<N> >(parent, _switch, SwitchesConversionTable::getInstance(board, version, flags), DataField::tr("Switch").toLatin1(),
|
||||
DataField::tr("Switch ").toLatin1() + sw.toString(board) + DataField::tr(" cannot be exported on this board!").toLatin1()),
|
||||
sw(sw),
|
||||
_switch(0),
|
||||
board(board)
|
||||
@@ -486,7 +487,7 @@ class TelemetrySourcesConversionTable: public ConversionTable {
|
||||
if (IS_ARM(board) && version >= 217)
|
||||
addConversion(1+TELEMETRY_SOURCE_TIMER3, val++);
|
||||
if (IS_ARM(board) && version >= 216)
|
||||
addConversion(1+TELEMETRY_SOURCE_SWR, val++);
|
||||
addConversion(1+TELEMETRY_SOURCE_RAS, val++);
|
||||
addConversion(1+TELEMETRY_SOURCE_RSSI_TX, val++);
|
||||
addConversion(1+TELEMETRY_SOURCE_RSSI_RX, val++);
|
||||
if (IS_ARM(board) && version >= 216)
|
||||
@@ -597,7 +598,7 @@ class SourceField: public ConversionField< UnsignedField<N> > {
|
||||
public:
|
||||
SourceField(DataField * parent, RawSource & source, Board::Type board, unsigned int version, unsigned int variant, unsigned long flags=0):
|
||||
ConversionField< UnsignedField<N> >(parent, _source, SourcesConversionTable::getInstance(board, version, variant, flags),
|
||||
"Source", QObject::tr("Source %1 cannot be exported on this board!").arg(source.toString())),
|
||||
DataField::tr("Source").toLatin1(), DataField::tr("Source %1 cannot be exported on this board!").arg(source.toString())),
|
||||
source(source),
|
||||
_source(0)
|
||||
{
|
||||
@@ -1569,14 +1570,14 @@ class CurvesField: public TransformedField {
|
||||
if (IS_STM32(board) && version >= 216) {
|
||||
offset += (curve->type == CurveData::CURVE_TYPE_CUSTOM ? curve->count * 2 - 2 : curve->count);
|
||||
if (offset > maxPoints) {
|
||||
setError(QObject::tr("OpenTX only accepts %1 points in all curves").arg(maxPoints));
|
||||
setError(DataField::tr("OpenTX only accepts %1 points in all curves").arg(maxPoints));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
offset += (curve->type == CurveData::CURVE_TYPE_CUSTOM ? curve->count * 2 - 2 : curve->count) - 5;
|
||||
if (offset > maxPoints - 5 * maxCurves) {
|
||||
setError(QObject::tr("OpenTx only accepts %1 points in all curves").arg(maxPoints));
|
||||
setError(DataField::tr("OpenTx only accepts %1 points in all curves").arg(maxPoints));
|
||||
break;
|
||||
}
|
||||
_curves[i] = offset;
|
||||
@@ -2154,11 +2155,11 @@ class ArmCustomFunctionField: public TransformedField {
|
||||
|
||||
if (version >= 218) {
|
||||
internalField.Append(new SwitchField<9>(this, fn.swtch, board, version));
|
||||
internalField.Append(new ConversionField< UnsignedField<7> >(this, _func, &functionsConversionTable, "Function", ::QObject::tr("OpenTX on this board doesn't accept this function")));
|
||||
internalField.Append(new ConversionField< UnsignedField<7> >(this, _func, &functionsConversionTable, "Function", DataField::tr("OpenTX on this board doesn't accept this function")));
|
||||
}
|
||||
else {
|
||||
internalField.Append(new SwitchField<8>(this, fn.swtch, board, version));
|
||||
internalField.Append(new ConversionField< UnsignedField<8> >(this, _func, &functionsConversionTable, "Function", ::QObject::tr("OpenTX on this board doesn't accept this function")));
|
||||
internalField.Append(new ConversionField< UnsignedField<8> >(this, _func, &functionsConversionTable, "Function", DataField::tr("OpenTX on this board doesn't accept this function")));
|
||||
}
|
||||
|
||||
if (IS_TARANIS(board) && version >= 216)
|
||||
@@ -2394,7 +2395,7 @@ class AvrCustomFunctionField: public TransformedField {
|
||||
{
|
||||
if (version >= 217 && IS_2560(board)) {
|
||||
internalField.Append(new SwitchField<8>(this, fn.swtch, board, version));
|
||||
internalField.Append(new ConversionField< UnsignedField<8> >(this, (unsigned int &)fn.func, &functionsConversionTable, "Function", ::QObject::tr("OpenTX on this board doesn't accept this function")));
|
||||
internalField.Append(new ConversionField< UnsignedField<8> >(this, (unsigned int &)fn.func, &functionsConversionTable, "Function", DataField::tr("OpenTX on this board doesn't accept this function")));
|
||||
internalField.Append(new UnsignedField<2>(this, fn.adjustMode));
|
||||
internalField.Append(new UnsignedField<4>(this, _union_param));
|
||||
internalField.Append(new UnsignedField<1>(this, _active));
|
||||
@@ -2402,18 +2403,18 @@ class AvrCustomFunctionField: public TransformedField {
|
||||
}
|
||||
else if (version >= 216) {
|
||||
internalField.Append(new SwitchField<6>(this, fn.swtch, board, version));
|
||||
internalField.Append(new ConversionField< UnsignedField<4> >(this, (unsigned int &)fn.func, &functionsConversionTable, "Function", ::QObject::tr("OpenTX on this board doesn't accept this function")));
|
||||
internalField.Append(new ConversionField< UnsignedField<4> >(this, (unsigned int &)fn.func, &functionsConversionTable, "Function", DataField::tr("OpenTX on this board doesn't accept this function")));
|
||||
internalField.Append(new UnsignedField<5>(this, _union_param));
|
||||
internalField.Append(new UnsignedField<1>(this, _active));
|
||||
}
|
||||
else if (version >= 213) {
|
||||
internalField.Append(new SwitchField<8>(this, fn.swtch, board, version));
|
||||
internalField.Append(new UnsignedField<3>(this, _union_param));
|
||||
internalField.Append(new ConversionField< UnsignedField<5> >(this, (unsigned int &)fn.func, &functionsConversionTable, "Function", ::QObject::tr("OpenTX on this board doesn't accept this function")));
|
||||
internalField.Append(new ConversionField< UnsignedField<5> >(this, (unsigned int &)fn.func, &functionsConversionTable, "Function", DataField::tr("OpenTX on this board doesn't accept this function")));
|
||||
}
|
||||
else {
|
||||
internalField.Append(new SwitchField<8>(this, fn.swtch, board, version));
|
||||
internalField.Append(new ConversionField< UnsignedField<7> >(this, (unsigned int &)fn.func, &functionsConversionTable, "Function", ::QObject::tr("OpenTX on this board doesn't accept this function")));
|
||||
internalField.Append(new ConversionField< UnsignedField<7> >(this, (unsigned int &)fn.func, &functionsConversionTable, "Function", DataField::tr("OpenTX on this board doesn't accept this function")));
|
||||
internalField.Append(new BoolField<1>(this, (bool &)fn.enabled));
|
||||
}
|
||||
internalField.Append(new UnsignedField<8>(this, _param));
|
||||
@@ -3137,7 +3138,7 @@ OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsig
|
||||
if (IS_ARM(board))
|
||||
internalField.Append(new UnsignedField<3>(this, modelData.telemetryProtocol));
|
||||
else
|
||||
internalField.Append(new ConversionField< UnsignedField<3> >(this, (unsigned int &)modelData.moduleData[0].protocol, &protocolsConversionTable, "Protocol", ::QObject::tr("OpenTX doesn't accept this telemetry protocol")));
|
||||
internalField.Append(new ConversionField< UnsignedField<3> >(this, (unsigned int &)modelData.moduleData[0].protocol, &protocolsConversionTable, "Protocol", DataField::tr("OpenTX doesn't accept this telemetry protocol")));
|
||||
|
||||
internalField.Append(new BoolField<1>(this, modelData.thrTrim));
|
||||
|
||||
@@ -3150,7 +3151,7 @@ OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsig
|
||||
internalField.Append(new SpareBitsField<4>(this));
|
||||
}
|
||||
else {
|
||||
internalField.Append(new ConversionField< SignedField<4> >(this, modelData.moduleData[0].channelsCount, &channelsConversionTable, "Channels number", ::QObject::tr("OpenTX doesn't allow this number of channels")));
|
||||
internalField.Append(new ConversionField< SignedField<4> >(this, modelData.moduleData[0].channelsCount, &channelsConversionTable, "Channels number", DataField::tr("OpenTX doesn't allow this number of channels")));
|
||||
}
|
||||
|
||||
if (version >= 216)
|
||||
@@ -3272,7 +3273,7 @@ OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsig
|
||||
internalField.Append(new UnsignedField<2>(this, modelData.potsWarningMode));
|
||||
}
|
||||
else {
|
||||
internalField.Append(new ConversionField< SignedField<8> >(this, modelData.moduleData[1].protocol, &protocolsConversionTable, "Protocol", ::QObject::tr("OpenTX doesn't accept this radio protocol")));
|
||||
internalField.Append(new ConversionField< SignedField<8> >(this, modelData.moduleData[1].protocol, &protocolsConversionTable, "Protocol", DataField::tr("OpenTX doesn't accept this radio protocol")));
|
||||
internalField.Append(new UnsignedField<8>(this, modelData.trainerMode));
|
||||
}
|
||||
}
|
||||
@@ -3284,14 +3285,14 @@ OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsig
|
||||
}
|
||||
else if (version >= 216) {
|
||||
modulesCount = 3;
|
||||
internalField.Append(new ConversionField< SignedField<8> >(this, modelData.moduleData[0].protocol, &protocolsConversionTable, "Protocol", ::QObject::tr("OpenTX doesn't accept this radio protocol")));
|
||||
internalField.Append(new ConversionField< SignedField<8> >(this, modelData.moduleData[0].protocol, &protocolsConversionTable, "Protocol", DataField::tr("OpenTX doesn't accept this radio protocol")));
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ARM(board) && version >= 215) {
|
||||
for (int module=0; module<modulesCount; module++) {
|
||||
if (version >= 217) {
|
||||
internalField.Append(new ConversionField<SignedField<4> >(this, modelData.moduleData[module].protocol, &protocolsConversionTable, "Protocol", ::QObject::tr("OpenTX doesn't accept this radio protocol")));
|
||||
internalField.Append(new ConversionField<SignedField<4> >(this, modelData.moduleData[module].protocol, &protocolsConversionTable, "Protocol", DataField::tr("OpenTX doesn't accept this radio protocol")));
|
||||
internalField.Append(new SignedField<4>(this, subprotocols[module]));
|
||||
}
|
||||
else {
|
||||
@@ -3835,7 +3836,7 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type
|
||||
internalField.Append(new ZCharField<10>(this, generalData.bluetoothName, "Bluetooth name"));
|
||||
}
|
||||
else if (IS_TARANIS_X9E(board) && version >= 217) {
|
||||
internalField.Append(new BoolField<8>(this, generalData.bluetoothEnable));
|
||||
internalField.Append(new UnsignedField<8>(this, generalData.bluetoothMode));
|
||||
internalField.Append(new ZCharField<10>(this, generalData.bluetoothName, "Bluetooth name"));
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#define M128_VARIANT 0x8000
|
||||
#define TARANIS_X9E_VARIANT 0x8000
|
||||
#define TARANIS_X7_VARIANT 0x4000
|
||||
#define TARANIS_XLITE_VARIANT 0x2000
|
||||
|
||||
#define SIMU_STOCK_VARIANTS (GVARS_VARIANT|FRSKY_VARIANT)
|
||||
#define SIMU_M128_VARIANTS (M128_VARIANT|SIMU_STOCK_VARIANTS)
|
||||
|
||||
@@ -22,19 +22,14 @@
|
||||
#include "opentxeeprom.h"
|
||||
#include "rlefile.h"
|
||||
#include "appdata.h"
|
||||
#include "constants.h"
|
||||
|
||||
#include <bitset>
|
||||
#include <QMessageBox>
|
||||
#include <QTime>
|
||||
#include <QUrl>
|
||||
#include <companion/src/storage/storage.h>
|
||||
|
||||
using namespace Board;
|
||||
|
||||
const char * const OPENTX_FIRMWARE_DOWNLOAD_URL[] = {
|
||||
"https://downloads.open-tx.org/2.2/release/firmware",
|
||||
"https://downloads.open-tx.org/2.2/rc/firmware",
|
||||
"https://downloads.open-tx.org/2.2/nightlies/firmware"
|
||||
};
|
||||
#include "storage.h" // does this need to be last include?
|
||||
|
||||
#define FILE_TYP_GENERAL 1
|
||||
#define FILE_TYP_MODEL 2
|
||||
@@ -44,12 +39,9 @@ const char * const OPENTX_FIRMWARE_DOWNLOAD_URL[] = {
|
||||
/// convert model number 0..MAX_MODELS-1 int fileId
|
||||
#define FILE_MODEL(n) (1+n)
|
||||
|
||||
template<typename T, size_t N>
|
||||
inline
|
||||
size_t SizeOfArray(T(&)[N])
|
||||
{
|
||||
return N;
|
||||
}
|
||||
using namespace Board;
|
||||
|
||||
QList<OpenTxEepromInterface *> opentxEEpromInterfaces;
|
||||
|
||||
OpenTxEepromInterface::OpenTxEepromInterface(OpenTxFirmware * firmware):
|
||||
EEPROMInterface(firmware->getBoard()),
|
||||
@@ -82,14 +74,14 @@ const char * OpenTxEepromInterface::getName()
|
||||
return "OpenTX for FrSky Taranis X9E";
|
||||
case BOARD_TARANIS_X7:
|
||||
return "OpenTX for FrSky Taranis X7";
|
||||
case BOARD_TARANIS_XLITE:
|
||||
return "OpenTX for FrSky Taranis X-Lite";
|
||||
case BOARD_SKY9X:
|
||||
return "OpenTX for Sky9x board / 9X";
|
||||
case BOARD_9XRPRO:
|
||||
return "OpenTX for 9XR-PRO";
|
||||
case BOARD_AR9X:
|
||||
return "OpenTX for ar9x board / 9X";
|
||||
case BOARD_FLAMENCO:
|
||||
return "OpenTX for Flamenco experimental";
|
||||
case BOARD_X12S:
|
||||
return "OpenTX for FrSky Horus";
|
||||
case BOARD_X10:
|
||||
@@ -143,7 +135,7 @@ bool OpenTxEepromInterface::saveToByteArray(const T & src, QByteArray & data, ui
|
||||
// manager.Dump();
|
||||
manager.Export(raw);
|
||||
data.resize(8);
|
||||
*((uint32_t*)&data.data()[0]) = StorageFormat::getFourCC(board);
|
||||
*((uint32_t*)&data.data()[0]) = Boards::getFourCC(board);
|
||||
data[4] = version;
|
||||
data[5] = 'M';
|
||||
*((uint16_t*)&data.data()[6]) = raw.size();
|
||||
@@ -166,12 +158,12 @@ template <class T, class M>
|
||||
bool OpenTxEepromInterface::loadFromByteArray(T & dest, const QByteArray & data)
|
||||
{
|
||||
uint32_t fourcc = *((uint32_t*)&data.data()[0]);
|
||||
if (StorageFormat::getFourCC(board) != fourcc) {
|
||||
if (Boards::getFourCC(board) != fourcc) {
|
||||
if (IS_HORUS(board) && fourcc == 0x3178396F) {
|
||||
qDebug() << QString().sprintf("%s: Deprecated fourcc used %x vs %x", getName(), fourcc, StorageFormat::getFourCC(board));
|
||||
qDebug() << QString().sprintf("%s: Deprecated fourcc used %x vs %x", getName(), fourcc, Boards::getFourCC(board));
|
||||
}
|
||||
else {
|
||||
qDebug() << QString().sprintf("%s: Wrong fourcc %x vs %x", getName(), fourcc, StorageFormat::getFourCC(board));
|
||||
qDebug() << QString().sprintf("%s: Wrong fourcc %x vs %x", getName(), fourcc, Boards::getFourCC(board));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -236,7 +228,7 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t *
|
||||
if (version_error == OLD_VERSION) {
|
||||
errors.set(version_error);
|
||||
errors.set(HAS_WARNINGS);
|
||||
ShowEepromWarnings(NULL, QObject::tr("Warning"), errors.to_ulong());
|
||||
showEepromWarnings(NULL, CPN_STR_TTL_WARNING, errors.to_ulong());
|
||||
}
|
||||
else if (version_error == NOT_OPENTX) {
|
||||
dbg << " not open9x";
|
||||
@@ -287,7 +279,7 @@ void OpenTxEepromInterface::showErrors(const QString & title, const QStringList
|
||||
{
|
||||
QString msg;
|
||||
if (errors.empty()) {
|
||||
msg = QObject::tr("Unknown error");
|
||||
msg = tr("Unknown error");
|
||||
}
|
||||
else {
|
||||
int noErrorsToDisplay = std::min((int)errors.size(), 10);
|
||||
@@ -295,12 +287,12 @@ void OpenTxEepromInterface::showErrors(const QString & title, const QStringList
|
||||
msg += " -" + errors.at(n) + "\n";
|
||||
}
|
||||
if (noErrorsToDisplay < errors.size()) {
|
||||
msg += QObject::tr(" ... plus %1 errors").arg(errors.size() - noErrorsToDisplay) + "\n" + msg;
|
||||
msg += tr(" ... plus %1 errors").arg(errors.size() - noErrorsToDisplay) + "\n" + msg;
|
||||
}
|
||||
}
|
||||
|
||||
QMessageBox::warning(NULL,
|
||||
QObject::tr("Error"),
|
||||
CPN_STR_TTL_ERROR,
|
||||
title + "\n" + msg);
|
||||
}
|
||||
|
||||
@@ -325,6 +317,9 @@ int OpenTxEepromInterface::save(uint8_t * eeprom, const RadioData & radioData, u
|
||||
else if (IS_TARANIS_X7(board)) {
|
||||
variant |= TARANIS_X7_VARIANT;
|
||||
}
|
||||
else if (IS_TARANIS_XLITE(board)) {
|
||||
variant |= TARANIS_XLITE_VARIANT;
|
||||
}
|
||||
|
||||
OpenTxGeneralData generator((GeneralSettings &)radioData.generalSettings, board, version, variant);
|
||||
// generator.Dump();
|
||||
@@ -332,7 +327,7 @@ int OpenTxEepromInterface::save(uint8_t * eeprom, const RadioData & radioData, u
|
||||
generator.Export(data);
|
||||
int sz = efile->writeRlc2(FILE_GENERAL, FILE_TYP_GENERAL, (const uint8_t *)data.constData(), data.size());
|
||||
if (sz == 0 || generator.errors().count() > 0) {
|
||||
showErrors(QObject::tr("Cannot write radio settings"), generator.errors());
|
||||
showErrors(tr("Cannot write radio settings"), generator.errors());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -344,7 +339,7 @@ int OpenTxEepromInterface::save(uint8_t * eeprom, const RadioData & radioData, u
|
||||
generator.Export(data);
|
||||
int sz = efile->writeRlc2(FILE_MODEL(i), FILE_TYP_MODEL, (const uint8_t *)data.constData(), data.size());
|
||||
if (sz == 0 || generator.errors().count() > 0) {
|
||||
showErrors(QObject::tr("Cannot write model %1").arg(radioData.models[i].name), generator.errors());
|
||||
showErrors(tr("Cannot write model %1").arg(radioData.models[i].name), generator.errors());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -364,7 +359,8 @@ int OpenTxEepromInterface::getSize(const ModelData &model)
|
||||
QByteArray tmp(Boards::getEEpromSize(Board::BOARD_UNKNOWN), 0);
|
||||
efile->EeFsCreate((uint8_t *) tmp.data(), Boards::getEEpromSize(Board::BOARD_UNKNOWN), board, 255/*version max*/);
|
||||
|
||||
OpenTxModelData open9xModel((ModelData &) model, board, 255/*version max*/, getCurrentFirmware()->getVariantNumber());
|
||||
ModelData srcCopy(model); // work on a copy of model data, because Export() may modify it!
|
||||
OpenTxModelData open9xModel(srcCopy, board, 255/*version max*/, getCurrentFirmware()->getVariantNumber());
|
||||
|
||||
QByteArray eeprom;
|
||||
open9xModel.Export(eeprom);
|
||||
@@ -383,7 +379,8 @@ int OpenTxEepromInterface::getSize(const GeneralSettings &settings)
|
||||
QByteArray tmp(Boards::getEEpromSize(Board::BOARD_UNKNOWN), 0);
|
||||
efile->EeFsCreate((uint8_t *) tmp.data(), Boards::getEEpromSize(Board::BOARD_UNKNOWN), board, 255);
|
||||
|
||||
OpenTxGeneralData open9xGeneral((GeneralSettings &) settings, board, 255, getCurrentFirmware()->getVariantNumber());
|
||||
GeneralSettings srcCopy(settings); // work on a copy of settings data, because Export() may modify it!
|
||||
OpenTxGeneralData open9xGeneral(srcCopy, board, 255, getCurrentFirmware()->getVariantNumber());
|
||||
// open9xGeneral.Dump();
|
||||
|
||||
QByteArray eeprom;
|
||||
@@ -535,7 +532,7 @@ int OpenTxFirmware::getCapability(::Capability capability)
|
||||
case SoundPitch:
|
||||
return 1;
|
||||
case Haptic:
|
||||
return (IS_2560(board) || IS_SKY9X(board) || IS_TARANIS_PLUS(board) || IS_TARANIS_X7(board) || IS_TARANIS_X9E(board) || IS_HORUS(board) || id.contains("haptic"));
|
||||
return (IS_2560(board) || IS_SKY9X(board) || IS_TARANIS_PLUS(board) || IS_TARANIS_SMALL(board) || IS_TARANIS_X9E(board) || IS_HORUS(board) || id.contains("haptic"));
|
||||
case ModelTrainerEnable:
|
||||
if (IS_HORUS_OR_TARANIS(board))
|
||||
return 1;
|
||||
@@ -544,7 +541,7 @@ int OpenTxFirmware::getCapability(::Capability capability)
|
||||
case MaxVolume:
|
||||
return (IS_ARM(board) ? 23 : 7);
|
||||
case MaxContrast:
|
||||
if (IS_TARANIS_X7(board))
|
||||
if (IS_TARANIS_SMALL(board))
|
||||
return 30;
|
||||
else
|
||||
return 45;
|
||||
@@ -611,6 +608,10 @@ int OpenTxFirmware::getCapability(::Capability capability)
|
||||
return (IS_ARM(board) ? 32 : 0);
|
||||
case NumModules:
|
||||
return (IS_ARM(board) ? 2 : 1);
|
||||
case HasModuleR9MFlex:
|
||||
return id.contains("flexr9m");
|
||||
case HasModuleR9MMini:
|
||||
return IS_TARANIS_XLITE(board) && !id.contains("stdr9m");
|
||||
case HasPPMStart:
|
||||
return (IS_ARM(board) ? true : false);
|
||||
case HastxCurrentCalibration:
|
||||
@@ -632,7 +633,7 @@ int OpenTxFirmware::getCapability(::Capability capability)
|
||||
case LcdWidth:
|
||||
if (IS_HORUS(board))
|
||||
return 480;
|
||||
else if (IS_TARANIS_X7(board))
|
||||
else if (IS_TARANIS_SMALL(board))
|
||||
return 128;
|
||||
else if (IS_TARANIS(board))
|
||||
return 212;
|
||||
@@ -646,7 +647,7 @@ int OpenTxFirmware::getCapability(::Capability capability)
|
||||
case LcdDepth:
|
||||
if (IS_HORUS(board))
|
||||
return 16;
|
||||
else if (IS_TARANIS_X7(board))
|
||||
else if (IS_TARANIS_SMALL(board))
|
||||
return 1;
|
||||
else if (IS_TARANIS(board))
|
||||
return 4;
|
||||
@@ -681,10 +682,6 @@ int OpenTxFirmware::getCapability(::Capability capability)
|
||||
return (IS_STOCK(board) ? false : true);
|
||||
case HasMahPersistent:
|
||||
return (IS_ARM(board) ? true : false);
|
||||
case MultiposPots:
|
||||
return IS_HORUS_OR_TARANIS(board) ? 3 : 0;
|
||||
case MultiposPotsPositions:
|
||||
return IS_HORUS_OR_TARANIS(board) ? 6 : 0;
|
||||
case SimulatorVariant:
|
||||
if (board == BOARD_STOCK)
|
||||
return SIMU_STOCK_VARIANTS;
|
||||
@@ -694,6 +691,8 @@ int OpenTxFirmware::getCapability(::Capability capability)
|
||||
return TARANIS_X9E_VARIANT;
|
||||
else if (IS_TARANIS_X7(board))
|
||||
return TARANIS_X7_VARIANT;
|
||||
else if (IS_TARANIS_XLITE(board))
|
||||
return TARANIS_XLITE_VARIANT;
|
||||
else
|
||||
return 0;
|
||||
case MavlinkTelemetry:
|
||||
@@ -716,76 +715,7 @@ int OpenTxFirmware::getCapability(::Capability capability)
|
||||
|
||||
QString OpenTxFirmware::getAnalogInputName(unsigned int index)
|
||||
{
|
||||
if ((int)index < getBoardCapability(board, Board::Sticks)) {
|
||||
const QString sticks[] = {
|
||||
QObject::tr("Rud"),
|
||||
QObject::tr("Ele"),
|
||||
QObject::tr("Thr"),
|
||||
QObject::tr("Ail")
|
||||
};
|
||||
return sticks[index];
|
||||
}
|
||||
|
||||
index -= getBoardCapability(board, Board::Sticks);
|
||||
|
||||
if (IS_9X(board) || IS_2560(board) || IS_SKY9X(board)) {
|
||||
const QString pots[] = {
|
||||
QObject::tr("P1"),
|
||||
QObject::tr("P2"),
|
||||
QObject::tr("P3")
|
||||
};
|
||||
return CHECK_IN_ARRAY(pots, index);
|
||||
}
|
||||
else if (IS_TARANIS_X9E(board)) {
|
||||
const QString pots[] = {
|
||||
QObject::tr("F1"),
|
||||
QObject::tr("F2"),
|
||||
QObject::tr("F3"),
|
||||
QObject::tr("F4"),
|
||||
QObject::tr("S1"),
|
||||
QObject::tr("S2"),
|
||||
QObject::tr("LS"),
|
||||
QObject::tr("RS")
|
||||
};
|
||||
return CHECK_IN_ARRAY(pots, index);
|
||||
}
|
||||
else if (IS_TARANIS(board)) {
|
||||
const QString pots[] = {
|
||||
QObject::tr("S1"),
|
||||
QObject::tr("S2"),
|
||||
QObject::tr("S3"),
|
||||
QObject::tr("LS"),
|
||||
QObject::tr("RS")
|
||||
};
|
||||
return CHECK_IN_ARRAY(pots, index);
|
||||
}
|
||||
else if (IS_HORUS_X12S(board)) {
|
||||
const QString pots[] = {
|
||||
QObject::tr("S1"),
|
||||
QObject::tr("6P"),
|
||||
QObject::tr("S2"),
|
||||
QObject::tr("L1"),
|
||||
QObject::tr("L2"),
|
||||
QObject::tr("LS"),
|
||||
QObject::tr("RS"),
|
||||
QObject::tr("JSx"),
|
||||
QObject::tr("JSy")
|
||||
};
|
||||
return CHECK_IN_ARRAY(pots, index);
|
||||
}
|
||||
else if (IS_HORUS_X10(board)) {
|
||||
const QString pots[] = {
|
||||
QObject::tr("S1"),
|
||||
QObject::tr("6P"),
|
||||
QObject::tr("S2"),
|
||||
QObject::tr("LS"),
|
||||
QObject::tr("RS")
|
||||
};
|
||||
return CHECK_IN_ARRAY(pots, index);
|
||||
}
|
||||
else {
|
||||
return "???";
|
||||
}
|
||||
return Boards::getAnalogInputName(board, index);
|
||||
}
|
||||
|
||||
QTime OpenTxFirmware::getMaxTimerStart()
|
||||
@@ -947,9 +877,14 @@ EepromLoadErrors OpenTxEepromInterface::checkVersion(unsigned int version)
|
||||
// M128 revert because too much RAM used!
|
||||
case 216:
|
||||
// A lot of things (first github release)
|
||||
if (IS_2560(board) || IS_M128(board)) {
|
||||
return OLD_VERSION;
|
||||
}
|
||||
case 217:
|
||||
// 3 logical switches removed on M128 / gruvin9x boards
|
||||
return OLD_VERSION;
|
||||
if (IS_ARM(board)) {
|
||||
return OLD_VERSION;
|
||||
}
|
||||
case 218:
|
||||
break;
|
||||
default:
|
||||
@@ -961,6 +896,7 @@ EepromLoadErrors OpenTxEepromInterface::checkVersion(unsigned int version)
|
||||
|
||||
bool OpenTxEepromInterface::checkVariant(unsigned int version, unsigned int variant)
|
||||
{
|
||||
bool variantError = false;
|
||||
if (board == BOARD_M128 && !(variant & M128_VARIANT)) {
|
||||
if (version == 212) {
|
||||
uint8_t tmp[1000];
|
||||
@@ -973,28 +909,34 @@ bool OpenTxEepromInterface::checkVariant(unsigned int version, unsigned int vari
|
||||
}
|
||||
}
|
||||
}
|
||||
qWarning() << " wrong variant (" << variant << ")";
|
||||
return false;
|
||||
variantError = true;
|
||||
}
|
||||
else if (IS_TARANIS_X9E(board)) {
|
||||
if (variant != TARANIS_X9E_VARIANT) {
|
||||
qWarning() << " wrong variant (" << variant << ")";
|
||||
return false;
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_TARANIS_X7(board)) {
|
||||
if (variant != TARANIS_X7_VARIANT) {
|
||||
qWarning() << " wrong variant (" << variant << ")";
|
||||
return false;
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_TARANIS_XLITE(board)) {
|
||||
if (variant != TARANIS_XLITE_VARIANT) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_TARANIS(board)) {
|
||||
if (variant != 0) {
|
||||
qWarning() << " wrong variant (" << variant << ")";
|
||||
return false;
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (variantError) {
|
||||
qWarning() << " wrong variant (" << variant << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1100,405 +1042,170 @@ unsigned long OpenTxEepromInterface::loadBackup(RadioData &radioData, const uint
|
||||
|
||||
QString OpenTxFirmware::getFirmwareBaseUrl()
|
||||
{
|
||||
return OPENTX_FIRMWARE_DOWNLOAD_URL[g.boundedOpenTxBranch()];
|
||||
return g.openTxCurrentDownloadBranchUrl() % QStringLiteral("firmware/");
|
||||
}
|
||||
|
||||
QString OpenTxFirmware::getFirmwareUrl()
|
||||
{
|
||||
QString url = getFirmwareBaseUrl();
|
||||
QByteArray data = QUrl::toPercentEncoding(id);
|
||||
|
||||
if (IS_ARM(board))
|
||||
url.append(QString("/getfw.php?fw=%1.bin").arg((QString) data));
|
||||
else
|
||||
url.append(QString("/getfw.php?fw=%1.hex").arg((QString) data));
|
||||
return url;
|
||||
return getFirmwareBaseUrl() % QString("getfw.php?fw=%1.bin").arg(QString(QUrl::toPercentEncoding(id)));
|
||||
}
|
||||
|
||||
QString OpenTxFirmware::getReleaseNotesUrl()
|
||||
{
|
||||
QString url = getFirmwareBaseUrl();
|
||||
url.append("/releasenotes.txt");
|
||||
return url;
|
||||
return getFirmwareBaseUrl() % QStringLiteral("releasenotes.txt");
|
||||
}
|
||||
|
||||
QString OpenTxFirmware::getStampUrl()
|
||||
{
|
||||
QString url = getFirmwareBaseUrl();
|
||||
url.append("/stamp-opentx.txt");
|
||||
return url;
|
||||
return getFirmwareBaseUrl() % QStringLiteral("stamp-opentx.txt");
|
||||
}
|
||||
|
||||
void addOpenTxCommonOptions(OpenTxFirmware * firmware)
|
||||
{
|
||||
firmware->addOption("ppmus", QObject::tr("Channel values displayed in us"));
|
||||
firmware->addOption("nooverridech", QObject::tr("No OverrideCH functions available"));
|
||||
Option fai_options[] = {{"faichoice", QObject::tr("Possibility to enable FAI MODE (no telemetry) at field")},
|
||||
{"faimode", QObject::tr("FAI MODE (no telemetry) always enabled")},
|
||||
{NULL}};
|
||||
firmware->addOptions(fai_options);
|
||||
}
|
||||
|
||||
void addOpenTxArmOptions(OpenTxFirmware * firmware)
|
||||
{
|
||||
firmware->addOption("multimodule", QObject::tr("Support for the DIY-Multiprotocol-TX-Module"));
|
||||
firmware->addOption("eu", QObject::tr("Removes D8 FrSky protocol support which is not legal for use in the EU on radios sold after Jan 1st, 2015"));
|
||||
}
|
||||
// Firmware registrations
|
||||
// NOTE: "recognized" build options are defined in /radio/util/fwoptions.py
|
||||
|
||||
void addOpenTxFrskyOptions(OpenTxFirmware * firmware)
|
||||
{
|
||||
addOpenTxCommonOptions(firmware);
|
||||
addOpenTxArmOptions(firmware);
|
||||
firmware->addOption("noheli", QObject::tr("Disable HELI menu and cyclic mix support"));
|
||||
firmware->addOption("nogvars", QObject::tr("Disable Global variables"));
|
||||
firmware->addOption("lua", QObject::tr("Enable Lua custom scripts screen"));
|
||||
firmware->addOption("luac", QObject::tr("Enable Lua compiler"));
|
||||
}
|
||||
|
||||
void addOpenTxTaranisOptions(OpenTxFirmware * firmware)
|
||||
{
|
||||
addOpenTxFrskyOptions(firmware);
|
||||
firmware->addOption("internalppm", QObject::tr("Support for PPM internal module hack"));
|
||||
firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
|
||||
}
|
||||
|
||||
void addOpenTxLcdOptions(OpenTxFirmware * firmware)
|
||||
{
|
||||
Option lcd_options[] = {
|
||||
{"ST7565P", QObject::tr("ST7565P LCD or compatible")},
|
||||
{"ST7565R", QObject::tr("ST7565R LCD or compatible")},
|
||||
{"ERC12864FSF", QObject::tr("ERC12864FSF LCD")},
|
||||
{"ST7920", QObject::tr("ST7920 LCD")},
|
||||
{"KS108", QObject::tr("KS108 LCD")},
|
||||
{NULL}
|
||||
};
|
||||
firmware->addOptions(lcd_options);
|
||||
}
|
||||
|
||||
void addOpenTxVoiceOptions(OpenTxFirmware * firmware)
|
||||
{
|
||||
Option voice_options[] = {
|
||||
{"WTV20", QObject::tr("WTV20 voice module")},
|
||||
{"JQ6500", QObject::tr("JQ6500 voice module")},
|
||||
{NULL}
|
||||
};
|
||||
firmware->addOptions(voice_options);
|
||||
}
|
||||
|
||||
QList<OpenTxEepromInterface *> opentxEEpromInterfaces;
|
||||
|
||||
void registerOpenTxFirmware(OpenTxFirmware * firmware)
|
||||
void registerOpenTxFirmware(OpenTxFirmware * firmware, bool deprecated = false)
|
||||
{
|
||||
OpenTxEepromInterface * eepromInterface = new OpenTxEepromInterface(firmware);
|
||||
firmware->setEEpromInterface(eepromInterface);
|
||||
opentxEEpromInterfaces.push_back(eepromInterface);
|
||||
eepromInterfaces.push_back(eepromInterface);
|
||||
Firmware::addRegisteredFirmware(firmware);
|
||||
if (!deprecated)
|
||||
Firmware::addRegisteredFirmware(firmware);
|
||||
}
|
||||
|
||||
void addOpenTxCommonOptions(OpenTxFirmware * firmware)
|
||||
{
|
||||
static const Firmware::OptionsGroup fai_options = {
|
||||
Firmware::Option("faichoice", Firmware::tr("Possibility to enable FAI MODE (no telemetry) at field")),
|
||||
Firmware::Option("faimode", Firmware::tr("FAI MODE (no telemetry) always enabled"))
|
||||
};
|
||||
firmware->addOption("ppmus", Firmware::tr("Channel values displayed in us"));
|
||||
firmware->addOptionsGroup(fai_options);
|
||||
firmware->addOption("nooverridech", Firmware::tr("No OverrideCH functions available"));
|
||||
}
|
||||
|
||||
void addOpenTxRfOptions(OpenTxFirmware * firmware, bool flex = true)
|
||||
{
|
||||
static const Firmware::Option opt_eu("eu", Firmware::tr("Removes D8 FrSky protocol support which is not legal for use in the EU on radios sold after Jan 1st, 2015"));
|
||||
static const Firmware::Option opt_fl("flexr9m", Firmware::tr("Enable non certified firmwares"));
|
||||
firmware->addOption("multimodule", Firmware::tr("Support for the DIY-Multiprotocol-TX-Module"));
|
||||
if (flex)
|
||||
firmware->addOptionsGroup({opt_eu, opt_fl});
|
||||
else
|
||||
firmware->addOption(opt_eu);
|
||||
}
|
||||
|
||||
void addOpenTxFontOptions(OpenTxFirmware * firmware)
|
||||
{
|
||||
firmware->addOption("sqt5font", Firmware::tr("Use alternative SQT5 font"));
|
||||
}
|
||||
|
||||
void addOpenTxFrskyOptions(OpenTxFirmware * firmware)
|
||||
{
|
||||
addOpenTxCommonOptions(firmware);
|
||||
firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support"));
|
||||
firmware->addOption("nogvars", Firmware::tr("Disable Global variables"));
|
||||
firmware->addOption("lua", Firmware::tr("Enable Lua custom scripts screen"));
|
||||
firmware->addOption("luac", Firmware::tr("Enable Lua compiler"));
|
||||
addOpenTxRfOptions(firmware);
|
||||
}
|
||||
|
||||
void addOpenTxTaranisOptions(OpenTxFirmware * firmware, bool intppm = true)
|
||||
{
|
||||
addOpenTxFrskyOptions(firmware);
|
||||
if (intppm)
|
||||
firmware->addOption("internalppm", Firmware::tr("Support for PPM internal module hack"));
|
||||
addOpenTxFontOptions(firmware);
|
||||
}
|
||||
|
||||
void addOpenTxArm9xOptions(OpenTxFirmware * firmware, bool dblkeys = true)
|
||||
{
|
||||
addOpenTxCommonOptions(firmware);
|
||||
firmware->addOption("heli", Firmware::tr("Enable HELI menu and cyclic mix support"));
|
||||
firmware->addOption("gvars", Firmware::tr("Global variables"), GVARS_VARIANT);
|
||||
firmware->addOption("potscroll", Firmware::tr("Pots use in menus navigation"));
|
||||
firmware->addOption("autosource", Firmware::tr("In model setup menus automatically set source by moving the control"));
|
||||
firmware->addOption("autoswitch", Firmware::tr("In model setup menus automatically set switch by moving the control"));
|
||||
firmware->addOption("nographics", Firmware::tr("No graphical check boxes and sliders"));
|
||||
firmware->addOption("battgraph", Firmware::tr("Battery graph"));
|
||||
firmware->addOption("nobold", Firmware::tr("Don't use bold font for highlighting active items"));
|
||||
//firmware->addOption("bluetooth", Firmware::tr("Bluetooth interface"));
|
||||
if (dblkeys)
|
||||
firmware->addOption("dblkeys", Firmware::tr("Enable resetting values by pressing up and down at the same time"));
|
||||
addOpenTxFontOptions(firmware);
|
||||
addOpenTxRfOptions(firmware, true);
|
||||
}
|
||||
|
||||
void registerOpenTxFirmwares()
|
||||
{
|
||||
OpenTxFirmware * firmware;
|
||||
|
||||
Option ext_options[] = {{"frsky", QObject::tr("Support for frsky telemetry mod"), FRSKY_VARIANT},
|
||||
{"telemetrez", QObject::tr("Support for telemetry easy board"), FRSKY_VARIANT},
|
||||
{"jeti", QObject::tr("Support for jeti telemetry mod"), 0},
|
||||
{"ardupilot", QObject::tr("Support for receiving ardupilot data"), 0},
|
||||
{"nmea", QObject::tr("Support for receiving NMEA data"), 0},
|
||||
{"mavlink", QObject::tr("Support for MAVLINK devices"), MAVLINK_VARIANT},
|
||||
{NULL}};
|
||||
Option extr_options[] = {{"frsky", QObject::tr("Support for frsky telemetry mod"), FRSKY_VARIANT},
|
||||
{"jeti", QObject::tr("Support for jeti telemetry mod"), 0},
|
||||
{"ardupilot", QObject::tr("Support for receiving ardupilot data"), 0},
|
||||
{"nmea", QObject::tr("Support for receiving NMEA data"), 0},
|
||||
{"mavlink", QObject::tr("Support for MAVLINK devices"), MAVLINK_VARIANT},
|
||||
{NULL}};
|
||||
Option nav_options[] = {{"rotenc", QObject::tr("Rotary Encoder use in menus navigation")},
|
||||
{"potscroll", QObject::tr("Pots use in menus navigation")},
|
||||
{NULL}};
|
||||
Option dsm2_options[] = {{"DSM2", QObject::tr("Support for DSM2 modules"), 0},
|
||||
{"DSM2PPM", QObject::tr("Support for DSM2 modules using ppm instead of true serial"), 0},
|
||||
{NULL}};
|
||||
|
||||
/* FrSky Taranis X9D+ board */
|
||||
firmware = new OpenTxFirmware("opentx-x9d+", QObject::tr("FrSky Taranis X9D+"), BOARD_TARANIS_X9DP);
|
||||
firmware = new OpenTxFirmware("opentx-x9d+", Firmware::tr("FrSky Taranis X9D+"), BOARD_TARANIS_X9DP);
|
||||
firmware->addOption("noras", Firmware::tr("Disable RAS (SWR)"));
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* FrSky Taranis X9D board */
|
||||
firmware = new OpenTxFirmware("opentx-x9d", QObject::tr("FrSky Taranis X9D"), BOARD_TARANIS_X9D);
|
||||
firmware->addOption("haptic", QObject::tr("Haptic module installed"));
|
||||
firmware = new OpenTxFirmware("opentx-x9d", Firmware::tr("FrSky Taranis X9D"), BOARD_TARANIS_X9D);
|
||||
firmware->addOption("haptic", Firmware::tr("Haptic module installed"));
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* FrSky Taranis X9E board */
|
||||
firmware = new OpenTxFirmware("opentx-x9e", QObject::tr("FrSky Taranis X9E"), BOARD_TARANIS_X9E);
|
||||
firmware->addOption("shutdownconfirm", QObject::tr("Confirmation before radio shutdown"));
|
||||
firmware->addOption("horussticks", QObject::tr("Horus gimbals installed (Hall sensors)"));
|
||||
firmware = new OpenTxFirmware("opentx-x9e", Firmware::tr("FrSky Taranis X9E"), BOARD_TARANIS_X9E);
|
||||
firmware->addOption("shutdownconfirm", Firmware::tr("Confirmation before radio shutdown"));
|
||||
firmware->addOption("horussticks", Firmware::tr("Horus gimbals installed (Hall sensors)"));
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* FrSky X7 board */
|
||||
firmware = new OpenTxFirmware("opentx-x7", QObject::tr("FrSky Taranis X7 / X7S"), BOARD_TARANIS_X7);
|
||||
// No mixersmon for now
|
||||
addOpenTxFrskyOptions(firmware);
|
||||
firmware->addOption("internalppm", QObject::tr("Support for PPM internal module hack"));
|
||||
firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
|
||||
firmware = new OpenTxFirmware("opentx-x7", Firmware::tr("FrSky Taranis X7 / X7S"), BOARD_TARANIS_X7);
|
||||
addOpenTxTaranisOptions(firmware, false);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* FrSky X-Lite board */
|
||||
firmware = new OpenTxFirmware("opentx-xlite", Firmware::tr("FrSky Taranis X-Lite"), BOARD_TARANIS_XLITE);
|
||||
// firmware->addOption("stdr9m", Firmware::tr("Use JR-sized R9M module"));
|
||||
addOpenTxTaranisOptions(firmware, false);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* FrSky X10 board */
|
||||
firmware = new OpenTxFirmware("opentx-x10", QObject::tr("FrSky Horus X10 / X10S"), BOARD_X10);
|
||||
firmware = new OpenTxFirmware("opentx-x10", Firmware::tr("FrSky Horus X10 / X10S"), BOARD_X10);
|
||||
addOpenTxFrskyOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* FrSky Horus board */
|
||||
firmware = new OpenTxFirmware("opentx-x12s", QObject::tr("FrSky Horus X12S"), BOARD_X12S);
|
||||
/* FrSky X12 (Horus) board */
|
||||
firmware = new OpenTxFirmware("opentx-x12s", Firmware::tr("FrSky Horus X12S"), BOARD_X12S);
|
||||
addOpenTxFrskyOptions(firmware);
|
||||
firmware->addOption("pcbdev", QObject::tr("Use ONLY with first DEV pcb version"));
|
||||
firmware->addOption("pcbdev", Firmware::tr("Use ONLY with first DEV pcb version"));
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* 9XR-Pro */
|
||||
firmware = new OpenTxFirmware("opentx-9xrpro", QObject::tr("Turnigy 9XR-PRO"), BOARD_9XRPRO);
|
||||
firmware->addOption("heli", QObject::tr("Enable HELI menu and cyclic mix support"));
|
||||
firmware->addOption("nofp", QObject::tr("No flight modes"));
|
||||
firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
|
||||
firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
|
||||
firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
|
||||
firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
|
||||
firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
|
||||
firmware->addOption("battgraph", QObject::tr("Battery graph"));
|
||||
firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
|
||||
firmware->addOption("bluetooth", QObject::tr("Bluetooth interface"));
|
||||
firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
|
||||
addOpenTxArmOptions(firmware);
|
||||
addOpenTxCommonOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* 9XR board with M128 chip */
|
||||
firmware = new OpenTxFirmware("opentx-9xr128", QObject::tr("Turnigy 9XR with m128 chip"), BOARD_M128);
|
||||
firmware->addOptions(extr_options);
|
||||
firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
|
||||
firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
|
||||
firmware->addOption("nosplash", QObject::tr("No splash screen"));
|
||||
firmware->addOption("nofp", QObject::tr("No flight modes"));
|
||||
firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
|
||||
firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
|
||||
firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
|
||||
firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
|
||||
// NOT TESTED firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
|
||||
firmware->addOption("DSM2", QObject::tr("Support for DSM2 modules"));
|
||||
firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
|
||||
firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
|
||||
firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
|
||||
firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
|
||||
firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
|
||||
firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
|
||||
firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
|
||||
firmware->addOption("battgraph", QObject::tr("Battery graph"));
|
||||
firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
|
||||
firmware->addOption("thrtrace", QObject::tr("Enable the throttle trace in Statistics"));
|
||||
firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
|
||||
firmware->addOption("imperial", QObject::tr("Imperial units"));
|
||||
firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
|
||||
addOpenTxCommonOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* 9XR board */
|
||||
firmware = new OpenTxFirmware("opentx-9xr", QObject::tr("Turnigy 9XR"), BOARD_STOCK);
|
||||
firmware->addOptions(extr_options);
|
||||
firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
|
||||
firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
|
||||
firmware->addOption("nosplash", QObject::tr("No splash screen"));
|
||||
firmware->addOption("nofp", QObject::tr("No flight modes"));
|
||||
firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
|
||||
firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
|
||||
firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
|
||||
firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
|
||||
// NOT TESTED firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
|
||||
firmware->addOption("DSM2", QObject::tr("Support for DSM2 modules"));
|
||||
firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
|
||||
firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
|
||||
firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
|
||||
firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
|
||||
firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
|
||||
firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
|
||||
firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
|
||||
firmware->addOption("battgraph", QObject::tr("Battery graph"));
|
||||
firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
|
||||
firmware->addOption("thrtrace", QObject::tr("Enable the throttle trace in Statistics"));
|
||||
firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
|
||||
firmware->addOption("imperial", QObject::tr("Imperial units"));
|
||||
firmware->addOption("nowshh", QObject::tr("No Winged Shadow How High support"));
|
||||
firmware->addOption("novario", QObject::tr("No vario support"));
|
||||
firmware->addOption("nogps", QObject::tr("No GPS support"));
|
||||
firmware->addOption("nogauges", QObject::tr("No gauges in the custom telemetry screen"));
|
||||
firmware->addOption("stickrev", QObject::tr("Add support for reversing stick inputs (e.g. needed for FrSky gimbals)"));
|
||||
firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
|
||||
addOpenTxCommonOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* 9x board */
|
||||
firmware = new OpenTxFirmware("opentx-9x", QObject::tr("9X with stock board"), BOARD_STOCK);
|
||||
firmware->addOptions(ext_options);
|
||||
firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
|
||||
firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
|
||||
firmware->addOption("nosplash", QObject::tr("No splash screen"));
|
||||
firmware->addOption("nofp", QObject::tr("No flight modes"));
|
||||
firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
|
||||
firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
|
||||
firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
|
||||
firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
|
||||
// NOT TESTED firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
|
||||
firmware->addOption("DSM2", QObject::tr("Support for DSM2 modules"));
|
||||
firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
|
||||
firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
|
||||
firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
|
||||
firmware->addOptions(nav_options);
|
||||
firmware->addOption("sp22", QObject::tr("SmartieParts 2.2 Backlight support"));
|
||||
firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
|
||||
firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
|
||||
firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
|
||||
firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
|
||||
firmware->addOption("battgraph", QObject::tr("Battery graph"));
|
||||
firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
|
||||
firmware->addOption("thrtrace", QObject::tr("Enable the throttle trace in Statistics"));
|
||||
firmware->addOption("pgbar", QObject::tr("EEprom write progress bar"));
|
||||
firmware->addOption("imperial", QObject::tr("Imperial units"));
|
||||
firmware->addOption("nowshh", QObject::tr("No Winged Shadow How High support"));
|
||||
firmware->addOption("novario", QObject::tr("No vario support"));
|
||||
firmware->addOption("nogps", QObject::tr("No GPS support"));
|
||||
firmware->addOption("nogauges", QObject::tr("No gauges in the custom telemetry screen"));
|
||||
firmware->addOption("fasoffset", QObject::tr("Allow compensating for offset errors in FrSky FAS current sensors"));
|
||||
firmware->addOption("stickrev", QObject::tr("Add support for reversing stick inputs (e.g. needed for FrSky gimbals)"));
|
||||
firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
|
||||
addOpenTxCommonOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* 9x board with M128 chip */
|
||||
firmware = new OpenTxFirmware("opentx-9x128", QObject::tr("9X with stock board and m128 chip"), BOARD_M128);
|
||||
firmware->addOptions(ext_options);
|
||||
firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
|
||||
firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
|
||||
firmware->addOption("nosplash", QObject::tr("No splash screen"));
|
||||
firmware->addOption("nofp", QObject::tr("No flight modes"));
|
||||
firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
|
||||
firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
|
||||
firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
|
||||
firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
|
||||
// NOT TESTED firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
|
||||
firmware->addOption("DSM2", QObject::tr("Support for DSM2 modules"));
|
||||
firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
|
||||
firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
|
||||
firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
|
||||
firmware->addOptions(nav_options);
|
||||
firmware->addOption("sp22", QObject::tr("SmartieParts 2.2 Backlight support"));
|
||||
firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
|
||||
firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
|
||||
firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
|
||||
firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
|
||||
firmware->addOption("battgraph", QObject::tr("Battery graph"));
|
||||
firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
|
||||
firmware->addOption("thrtrace", QObject::tr("Enable the throttle trace in Statistics"));
|
||||
firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
|
||||
firmware->addOption("imperial", QObject::tr("Imperial units"));
|
||||
firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
|
||||
addOpenTxCommonOptions(firmware);
|
||||
firmware = new OpenTxFirmware("opentx-9xrpro", Firmware::tr("Turnigy 9XR-PRO"), BOARD_9XRPRO);
|
||||
addOpenTxArm9xOptions(firmware, false);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* ar9x board */
|
||||
firmware = new OpenTxFirmware("opentx-ar9x", QObject::tr("9X with AR9X board"), BOARD_AR9X);
|
||||
firmware->addOption("heli", QObject::tr("Enable HELI menu and cyclic mix support"));
|
||||
firmware->addOption("nofp", QObject::tr("No flight modes"));
|
||||
firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
|
||||
firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
|
||||
firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
|
||||
firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
|
||||
firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
|
||||
firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
|
||||
firmware->addOption("battgraph", QObject::tr("Battery graph"));
|
||||
firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
|
||||
firmware->addOption("bluetooth", QObject::tr("Bluetooth interface"));
|
||||
firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
|
||||
// firmware->addOption("rtc", QObject::tr("Optional RTC added"));
|
||||
// firmware->addOption("volume", QObject::tr("i2c volume control added"));
|
||||
addOpenTxArmOptions(firmware);
|
||||
addOpenTxCommonOptions(firmware);
|
||||
firmware = new OpenTxFirmware("opentx-ar9x", Firmware::tr("9X with AR9X board"), BOARD_AR9X);
|
||||
addOpenTxArm9xOptions(firmware);
|
||||
//firmware->addOption("rtc", Firmware::tr("Optional RTC added"));
|
||||
//firmware->addOption("volume", Firmware::tr("i2c volume control added"));
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* Sky9x board */
|
||||
firmware = new OpenTxFirmware("opentx-sky9x", QObject::tr("9X with Sky9x board"), BOARD_SKY9X);
|
||||
firmware->addOption("heli", QObject::tr("Enable HELI menu and cyclic mix support"));
|
||||
firmware->addOption("nofp", QObject::tr("No flight modes"));
|
||||
firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
|
||||
firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
|
||||
firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
|
||||
firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
|
||||
firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
|
||||
firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
|
||||
firmware->addOption("battgraph", QObject::tr("Battery graph"));
|
||||
firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
|
||||
firmware->addOption("bluetooth", QObject::tr("Bluetooth interface"));
|
||||
firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
|
||||
addOpenTxArmOptions(firmware);
|
||||
addOpenTxCommonOptions(firmware);
|
||||
firmware = new OpenTxFirmware("opentx-sky9x", Firmware::tr("9X with Sky9x board"), BOARD_SKY9X);
|
||||
addOpenTxArm9xOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* Gruvin9x board */
|
||||
firmware = new OpenTxFirmware("opentx-gruvin9x", QObject::tr("9X with Gruvin9x board"), BOARD_GRUVIN9X);
|
||||
firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
|
||||
firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
|
||||
firmware->addOption("nofp", QObject::tr("No flight modes"));
|
||||
firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
|
||||
firmware->addOption("sdcard", QObject::tr("Support for SD memory card"));
|
||||
firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
|
||||
firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
|
||||
firmware->addOptions(dsm2_options);
|
||||
firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
|
||||
firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
|
||||
firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
|
||||
firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
|
||||
firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
|
||||
firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
|
||||
firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
|
||||
firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
|
||||
firmware->addOption("battgraph", QObject::tr("Battery graph"));
|
||||
firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
|
||||
firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
|
||||
firmware->addOption("imperial", QObject::tr("Imperial units"));
|
||||
firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
|
||||
addOpenTxCommonOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* MEGA2560 board */
|
||||
firmware = new OpenTxFirmware("opentx-mega2560", QObject::tr("DIY MEGA2560 radio"), BOARD_MEGA2560);
|
||||
addOpenTxLcdOptions(firmware);
|
||||
firmware->addOption("PWR", QObject::tr("Power management by soft-off circuitry"));
|
||||
firmware->addOptions(ext_options);
|
||||
firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
|
||||
firmware->addOptions(dsm2_options);
|
||||
firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
|
||||
firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
|
||||
firmware->addOption("nofp", QObject::tr("No flight modes"));
|
||||
firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
|
||||
firmware->addOption("sdcard", QObject::tr("Support for SD memory card"));
|
||||
firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
|
||||
//firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
|
||||
addOpenTxVoiceOptions(firmware);
|
||||
firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
|
||||
firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
|
||||
firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
|
||||
firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
|
||||
firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
|
||||
firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
|
||||
firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
|
||||
firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
|
||||
firmware->addOption("battgraph", QObject::tr("Battery graph"));
|
||||
firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
|
||||
firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
|
||||
firmware->addOption("imperial", QObject::tr("Imperial units"));
|
||||
firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
|
||||
addOpenTxCommonOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
// These are kept only for import purposes, marked as deprecated to hide from UI.
|
||||
registerOpenTxFirmware(new OpenTxFirmware("opentx-9xr", Firmware::tr("Turnigy 9XR"), BOARD_STOCK), true);
|
||||
registerOpenTxFirmware(new OpenTxFirmware("opentx-9xr128", Firmware::tr("Turnigy 9XR with m128 chip"), BOARD_M128), true);
|
||||
registerOpenTxFirmware(new OpenTxFirmware("opentx-9x", Firmware::tr("9X with stock board"), BOARD_STOCK), true);
|
||||
registerOpenTxFirmware(new OpenTxFirmware("opentx-9x128", Firmware::tr("9X with stock board and m128 chip"), BOARD_M128), true);
|
||||
registerOpenTxFirmware(new OpenTxFirmware("opentx-gruvin9x", Firmware::tr("9X with Gruvin9x board"), BOARD_GRUVIN9X), true);
|
||||
registerOpenTxFirmware(new OpenTxFirmware("opentx-mega2560", Firmware::tr("DIY MEGA2560 radio"), BOARD_MEGA2560), true);
|
||||
|
||||
Firmware::setDefaultVariant(Firmware::getFirmwareForId("opentx-x9d+"));
|
||||
Firmware::setCurrentVariant(Firmware::getDefaultVariant());
|
||||
|
||||
@@ -23,11 +23,15 @@
|
||||
|
||||
#include "eeprominterface.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class RleFile;
|
||||
class OpenTxFirmware;
|
||||
|
||||
class OpenTxEepromInterface : public EEPROMInterface
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(OpenTxEepromInterface)
|
||||
|
||||
public:
|
||||
|
||||
OpenTxEepromInterface(OpenTxFirmware * firmware);
|
||||
@@ -35,17 +39,17 @@ class OpenTxEepromInterface : public EEPROMInterface
|
||||
virtual ~OpenTxEepromInterface();
|
||||
|
||||
virtual unsigned long load(RadioData &, const uint8_t * eeprom, int size);
|
||||
|
||||
|
||||
bool loadModelFromBackup(ModelData & model, const uint8_t * data, unsigned int size, uint8_t version, uint32_t variant);
|
||||
|
||||
|
||||
virtual unsigned long loadBackup(RadioData &, const uint8_t * eeprom, int esize, int index);
|
||||
|
||||
|
||||
virtual int save(uint8_t * eeprom, const RadioData & radioData, uint8_t version=0, uint32_t variant=0);
|
||||
|
||||
virtual int getSize(const ModelData &);
|
||||
|
||||
virtual int getSize(const GeneralSettings &);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
const char * getName();
|
||||
@@ -53,33 +57,35 @@ class OpenTxEepromInterface : public EEPROMInterface
|
||||
EepromLoadErrors checkVersion(unsigned int version);
|
||||
|
||||
bool checkVariant(unsigned int version, unsigned int variant);
|
||||
|
||||
|
||||
template <class T, class M>
|
||||
bool loadFromByteArray(T & dest, const QByteArray & data, uint8_t version, uint32_t variant=0);
|
||||
|
||||
|
||||
public:
|
||||
template <class T, class M>
|
||||
bool loadFromByteArray(T & dest, const QByteArray & data);
|
||||
|
||||
|
||||
template <class T, class M>
|
||||
bool saveToByteArray(const T & src, QByteArray & data, uint8_t version=0);
|
||||
|
||||
bool loadRadioSettingsFromRLE(GeneralSettings & settings, RleFile * rleFile, uint8_t version);
|
||||
|
||||
|
||||
bool loadModelFromRLE(ModelData & model, RleFile * rleFile, unsigned int index, uint8_t version, uint32_t variant);
|
||||
|
||||
void showErrors(const QString & title, const QStringList & errors);
|
||||
|
||||
|
||||
uint8_t getLastDataVersion(Board::Type board);
|
||||
|
||||
|
||||
RleFile * efile;
|
||||
|
||||
|
||||
OpenTxFirmware * firmware;
|
||||
|
||||
};
|
||||
|
||||
class OpenTxFirmware: public Firmware
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(OpenTxFirmware)
|
||||
|
||||
public:
|
||||
OpenTxFirmware(const QString & id, OpenTxFirmware * parent):
|
||||
Firmware(parent, id, parent->getName(), parent->getBoard())
|
||||
@@ -100,19 +106,6 @@ class OpenTxFirmware: public Firmware
|
||||
addLanguage("pl");
|
||||
addLanguage("pt");
|
||||
addLanguage("se");
|
||||
|
||||
addTTSLanguage("en");
|
||||
addTTSLanguage("cz");
|
||||
addTTSLanguage("de");
|
||||
addTTSLanguage("es");
|
||||
addTTSLanguage("fr");
|
||||
addTTSLanguage("hu");
|
||||
addTTSLanguage("it");
|
||||
addTTSLanguage("nl");
|
||||
addTTSLanguage("pl");
|
||||
addTTSLanguage("pt");
|
||||
addTTSLanguage("se");
|
||||
addTTSLanguage("sk");
|
||||
}
|
||||
|
||||
virtual Firmware * getFirmwareVariant(const QString & id);
|
||||
@@ -124,9 +117,9 @@ class OpenTxFirmware: public Firmware
|
||||
virtual QString getFirmwareUrl();
|
||||
|
||||
virtual int getCapability(Capability);
|
||||
|
||||
|
||||
virtual QString getAnalogInputName(unsigned int index);
|
||||
|
||||
|
||||
virtual QTime getMaxTimerStart();
|
||||
|
||||
virtual int isAvailable(PulsesProtocol proto, int port=0);
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "radiodata.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
#include "eeprominterface.h"
|
||||
|
||||
// static
|
||||
QString RadioData::getElementName(const QString & prefix, unsigned int index, const char * name, bool padding)
|
||||
{
|
||||
QString result = prefix;
|
||||
if (padding)
|
||||
result += QString("%1").arg(index, 2, 10, QChar('0'));
|
||||
else
|
||||
result += QString("%1").arg(index);
|
||||
if (name) {
|
||||
QString trimmed = QString(name).trimmed();
|
||||
if (trimmed.length() > 0) {
|
||||
result += ":" + QString(name).trimmed();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RadioData::RadioData()
|
||||
{
|
||||
models.resize(getCurrentFirmware()->getCapability(Models));
|
||||
}
|
||||
|
||||
void RadioData::setCurrentModel(unsigned int index)
|
||||
{
|
||||
generalSettings.currModelIndex = index;
|
||||
if (index < models.size()) {
|
||||
strcpy(generalSettings.currModelFilename, models[index].filename);
|
||||
}
|
||||
}
|
||||
|
||||
void RadioData::fixModelFilename(unsigned int index)
|
||||
{
|
||||
ModelData & model = models[index];
|
||||
QString filename(model.filename);
|
||||
bool ok = filename.endsWith(".bin");
|
||||
if (ok) {
|
||||
if (filename.startsWith("model") && filename.mid(5, filename.length()-9).toInt() > 0) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
for (unsigned i=0; i<index; i++) {
|
||||
if (strcmp(models[i].filename, model.filename) == 0) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
sprintf(model.filename, "model%d.bin", index+1);
|
||||
}
|
||||
}
|
||||
|
||||
void RadioData::fixModelFilenames()
|
||||
{
|
||||
for (unsigned int i=0; i<models.size(); i++) {
|
||||
fixModelFilename(i);
|
||||
}
|
||||
setCurrentModel(generalSettings.currModelIndex);
|
||||
}
|
||||
|
||||
QString RadioData::getNextModelFilename()
|
||||
{
|
||||
char filename[sizeof(ModelData::filename)];
|
||||
int index = 0;
|
||||
bool found = true;
|
||||
while (found) {
|
||||
sprintf(filename, "model%d.bin", ++index);
|
||||
found = false;
|
||||
for (unsigned int i=0; i<models.size(); i++) {
|
||||
if (strcmp(filename, models[i].filename) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
void RadioData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
generalSettings.convert(cstate.withModelIndex(-1));
|
||||
|
||||
for (unsigned i=0; i<models.size(); i++) {
|
||||
models[i].convert(cstate.withModelIndex(i));
|
||||
}
|
||||
|
||||
if (categories.size() == 0) {
|
||||
categories.push_back(CategoryData(qPrintable(tr("Models"))));
|
||||
for (unsigned i=0; i<models.size(); i++) {
|
||||
models[i].category = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_HORUS(cstate.toType)) {
|
||||
fixModelFilenames();
|
||||
}
|
||||
|
||||
// ensure proper number of model slots
|
||||
if (getCurrentFirmware()->getCapability(Models) && getCurrentFirmware()->getCapability(Models) != (int)models.size()) {
|
||||
models.resize(getCurrentFirmware()->getCapability(Models));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef _RADIODATA_H_
|
||||
#define _RADIODATA_H_
|
||||
|
||||
#include "generalsettings.h"
|
||||
#include "modeldata.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class RadioDataConversionState;
|
||||
|
||||
class CategoryData {
|
||||
public:
|
||||
CategoryData(const char * name) {
|
||||
strncpy(this->name, name, sizeof(CategoryData::name));
|
||||
}
|
||||
char name[15+1];
|
||||
};
|
||||
|
||||
class RadioData {
|
||||
Q_DECLARE_TR_FUNCTIONS(RadioData)
|
||||
|
||||
public:
|
||||
RadioData();
|
||||
|
||||
GeneralSettings generalSettings;
|
||||
std::vector<CategoryData> categories;
|
||||
std::vector<ModelData> models;
|
||||
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
|
||||
void setCurrentModel(unsigned int index);
|
||||
void fixModelFilenames();
|
||||
QString getNextModelFilename();
|
||||
|
||||
static QString getElementName(const QString & prefix, unsigned int index, const char * name = 0, bool padding = false);
|
||||
|
||||
protected:
|
||||
void fixModelFilename(unsigned int index);
|
||||
};
|
||||
|
||||
#endif // _RADIODATA_H_
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "radiodataconversionstate.h"
|
||||
#include "radiodata.h"
|
||||
|
||||
#include <QStandardItemModel>
|
||||
|
||||
RadioDataConversionState::RadioDataConversionState(Board::Type before, Board::Type after, RadioData * rdata) :
|
||||
fromType(before),
|
||||
toType(after),
|
||||
fromBoard(Boards(before)),
|
||||
toBoard(Boards(after)),
|
||||
rd(NULL),
|
||||
rdCopy(NULL),
|
||||
maxEventType(EVT_NONE),
|
||||
modelIdx(-1),
|
||||
subCompIdx(-1)
|
||||
{
|
||||
setRadioData(rdata);
|
||||
}
|
||||
|
||||
RadioDataConversionState::~RadioDataConversionState()
|
||||
{
|
||||
if (rdCopy)
|
||||
delete rdCopy;
|
||||
}
|
||||
|
||||
RadioDataConversionState & RadioDataConversionState::withModelIndex(int index)
|
||||
{
|
||||
modelIdx = index;
|
||||
subCompIdx = -1;
|
||||
setLogField(FLD_ORIGIN);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RadioDataConversionState & RadioDataConversionState::withComponentIndex(int index)
|
||||
{
|
||||
subCompIdx = index;
|
||||
setLogField(FLD_SUB_COMP);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RadioDataConversionState &RadioDataConversionState::withComponentField(const QString & name)
|
||||
{
|
||||
setLogField(FLD_COMP_FIELD, LogField(0, name));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool RadioDataConversionState::convert()
|
||||
{
|
||||
if (rd) {
|
||||
rd->convert(*this);
|
||||
return true;
|
||||
}
|
||||
|
||||
setErr(("No radio data to convert."));
|
||||
return false;
|
||||
}
|
||||
|
||||
void RadioDataConversionState::setRadioData(RadioData * rdata)
|
||||
{
|
||||
rd = rdata;
|
||||
if (rdCopy)
|
||||
delete rdCopy;
|
||||
rdCopy = new RadioData(*rdata);
|
||||
logCache = LogRecord();
|
||||
}
|
||||
|
||||
void RadioDataConversionState::setLogField(LogFieldType type, const LogField & data, bool clearRest)
|
||||
{
|
||||
if (type >= FLD_ENUM_COUNT)
|
||||
return;
|
||||
|
||||
logCache.fields[type].id = data.id;
|
||||
logCache.fields[type].name = data.name;
|
||||
if (clearRest && type + 1 < FLD_ENUM_COUNT)
|
||||
setLogField(LogFieldType(type + 1));
|
||||
}
|
||||
|
||||
void RadioDataConversionState::addLogEntry(EventType event, const QString & msg)
|
||||
{
|
||||
if (event != EVT_NONE) {
|
||||
setLogField(FLD_EVT_TYPE, LogField(event, eventTypeToString(event)), false);
|
||||
setLogField(FLD_MSG, LogField(event, msg), false);
|
||||
log.append(logCache);
|
||||
}
|
||||
maxEventType = qMax(event, maxEventType);
|
||||
logCache.fields[FLD_MSG].clear();
|
||||
}
|
||||
|
||||
void RadioDataConversionState::setInvalid(const LogField & item)
|
||||
{
|
||||
setLogField(FLD_ITM_BEFORE, item);
|
||||
addLogEntry(EVT_INV, tr("is invalid"));
|
||||
}
|
||||
|
||||
void RadioDataConversionState::setConverted(const LogField & from, const LogField & to)
|
||||
{
|
||||
setLogField(FLD_ITM_BEFORE, from);
|
||||
setLogField(FLD_ITM_AFTER, to);
|
||||
addLogEntry(EVT_CVRT, tr("converted to"));
|
||||
}
|
||||
|
||||
void RadioDataConversionState::setMoved(const LogField & from, const LogField & to)
|
||||
{
|
||||
setLogField(FLD_ITM_BEFORE, from);
|
||||
setLogField(FLD_ITM_AFTER, to);
|
||||
addLogEntry(EVT_INF, tr("verify is"));
|
||||
}
|
||||
|
||||
const ModelData * RadioDataConversionState::toModel() const
|
||||
{
|
||||
if (rd && modelIdx > -1 && modelIdx < (int)rd->models.size())
|
||||
return &rd->models[modelIdx];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const ModelData *RadioDataConversionState::fromModel() const
|
||||
{
|
||||
if (rdCopy && modelIdx > -1 && modelIdx < (int)rdCopy->models.size())
|
||||
return &rdCopy->models[modelIdx];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const GeneralSettings * RadioDataConversionState::toGS() const
|
||||
{
|
||||
if (rd)
|
||||
return &rd->generalSettings;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const GeneralSettings *RadioDataConversionState::fromGS() const
|
||||
{
|
||||
if (rdCopy)
|
||||
return &rdCopy->generalSettings;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool RadioDataConversionState::hasLogEntries(EventType logLevel) const
|
||||
{
|
||||
return (maxEventType >= logLevel);
|
||||
}
|
||||
|
||||
QString RadioDataConversionState::eventTypeToString(int type) const
|
||||
{
|
||||
// enum EventType { EVT_NONE, EVT_DBG, EVT_INF, EVT_WRN, EVT_CVRT, EVT_ERR, EVT_INV
|
||||
static const QStringList evtTypes = QStringList() << "" << tr("[DBG]") << tr("[NFO]") << tr("[WRN]") << tr("[CVT]") << tr("[ERR]") << tr("[INV]");
|
||||
return (type < evtTypes.size() ? evtTypes.at(type) : "");
|
||||
}
|
||||
|
||||
QString RadioDataConversionState::eventTypeToColor(int type) const
|
||||
{
|
||||
// enum EventType { EVT_NONE, EVT_DBG, EVT_INF, EVT_WRN, EVT_CVRT, EVT_ERR, EVT_INV
|
||||
static const QStringList evtColors = QStringList() << "black" << "dimgrey" << "black" << "#ea7104" << "#ea7104" << "red" << "red";
|
||||
return (type < evtColors.size() ? evtColors.at(type) : "black");
|
||||
}
|
||||
|
||||
QString RadioDataConversionState::getFieldName(int field) const
|
||||
{
|
||||
static const QStringList dataFields = QStringList() << tr("Event") << tr("Origin") << tr("Comp") << tr("Sub-Component") << tr("Field") << tr("Type") << tr("Old") << tr("Action") << tr("New");
|
||||
return (field < dataFields.size() ? dataFields.at(field) : "");
|
||||
}
|
||||
|
||||
QStandardItemModel * RadioDataConversionState::getLogModel(RadioDataConversionState::EventType logLevel, QObject * parent) const
|
||||
{
|
||||
QStandardItemModel * stdmdl = new QStandardItemModel(parent);
|
||||
const QString tooltip = "%1: %2 (ID: %3)";
|
||||
const int sortRole = Qt::UserRole + 1;
|
||||
const int seqdigits = floorf(logf(log.size()) / logf(10.0f)) + 1;
|
||||
|
||||
stdmdl->setSortRole(sortRole);
|
||||
|
||||
QStringList header;
|
||||
header << tr("Seq");
|
||||
for (int i=0; i < FLD_ENUM_COUNT; ++i)
|
||||
header << getFieldName(i);
|
||||
stdmdl->setHorizontalHeaderLabels(header);
|
||||
|
||||
QFont fnt("Courier");
|
||||
fnt.setStyleHint(QFont::TypeWriter);
|
||||
//fnt.setPointSize(fnt.pointSize()+1);
|
||||
|
||||
int row = 0;
|
||||
foreach (const LogRecord & lr, log) {
|
||||
if (lr.fields.at(FLD_EVT_TYPE).id < logLevel)
|
||||
continue;
|
||||
QBrush fg(QColor(eventTypeToColor(lr.fields.at(FLD_EVT_TYPE).id)));
|
||||
stdmdl->setItem(row, 0, new QStandardItem(QString("%1").arg(row+1, seqdigits, 10, QChar('0'))));
|
||||
stdmdl->item(row, 0)->setData(row, sortRole);
|
||||
stdmdl->item(row, 0)->setData(fnt, Qt::FontRole);
|
||||
for (int i=0; i < FLD_ENUM_COUNT; ++i) {
|
||||
QStandardItem * itm = new QStandardItem(lr.fields.at(i).name);
|
||||
itm->setData(lr.fields.at(i).id, sortRole);
|
||||
itm->setData(fnt, Qt::FontRole);
|
||||
itm->setData(tooltip.arg(getFieldName(i)).arg(lr.fields.at(i).name).arg(lr.fields.at(i).id), Qt::ToolTipRole);
|
||||
itm->setEditable(false);
|
||||
if (i == FLD_EVT_TYPE || i == FLD_MSG)
|
||||
itm->setForeground(fg);
|
||||
stdmdl->setItem(row, i+1, itm);
|
||||
}
|
||||
++row;
|
||||
}
|
||||
|
||||
return stdmdl;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RADIODATACONVERSIONSTATE_H
|
||||
#define RADIODATACONVERSIONSTATE_H
|
||||
|
||||
#include "boards.h"
|
||||
#include <QtCore>
|
||||
|
||||
class ModelData;
|
||||
class GeneralSettings;
|
||||
class RadioData;
|
||||
class QStandardItemModel;
|
||||
|
||||
class RadioDataConversionState
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(RadioDataConversionState)
|
||||
|
||||
public:
|
||||
enum EventType {
|
||||
EVT_NONE, // does not get logged
|
||||
EVT_DBG, // debug
|
||||
EVT_INF, // misc. info
|
||||
EVT_WRN, // misc. warning, place warning-level events after this and before EVT_ERR
|
||||
EVT_CVRT, // something was converted (A->B)
|
||||
EVT_ERR, // misc. error, place error-level events after this
|
||||
EVT_INV, // invalid, control/etc not available on destination radio
|
||||
};
|
||||
|
||||
enum LogFieldType {
|
||||
FLD_EVT_TYPE, // EventType
|
||||
FLD_ORIGIN, // General Settings or Model with name
|
||||
FLD_COMP, // Input/Mix/LS/CF/etc
|
||||
FLD_SUB_COMP, // Mix channel/Input line/LS number/etc
|
||||
FLD_COMP_FIELD, // optional item within subcomponent, eg. LS V1/V2/AND, etc
|
||||
FLD_ITM_TYPE, // Source/Switch
|
||||
FLD_ITM_BEFORE, // item before conversion
|
||||
FLD_MSG, // conversion details
|
||||
FLD_ITM_AFTER, // item after conversion
|
||||
FLD_ENUM_COUNT
|
||||
};
|
||||
|
||||
struct LogField {
|
||||
LogField(int id = 0, const QString & name = QString()) : id(id), name(name) {}
|
||||
void clear() { id = 0; name.clear(); }
|
||||
int id;
|
||||
QString name;
|
||||
};
|
||||
|
||||
struct LogRecord
|
||||
{
|
||||
LogRecord() { fields.resize(FLD_ENUM_COUNT); }
|
||||
QVector<LogField> fields; // collected data fields indexed by LogColumn value
|
||||
};
|
||||
|
||||
RadioDataConversionState(Board::Type before = Board::BOARD_UNKNOWN, Board::Type after = Board::BOARD_UNKNOWN, RadioData * rdata = NULL);
|
||||
~RadioDataConversionState();
|
||||
|
||||
RadioDataConversionState & withModelIndex(int index);
|
||||
RadioDataConversionState & withComponentIndex(int index);
|
||||
RadioDataConversionState & withComponentField(const QString & name);
|
||||
|
||||
bool convert();
|
||||
void setRadioData(RadioData * rdata);
|
||||
void setLogField(LogFieldType type, const LogField & data = LogField(), bool clearRest = true);
|
||||
inline void setOrigin(const QString & name = QString()) { setLogField(FLD_ORIGIN, LogField(modelIdx, name)); }
|
||||
inline void setSubComp(const QString & name = QString()) { setLogField(FLD_SUB_COMP, LogField(subCompIdx, name)); }
|
||||
inline void setComponent(const QString & name = QString(), int id = 0) { setLogField(FLD_COMP, LogField(id, name)); }
|
||||
inline void setItemType(const QString & name = QString(), int id = 0) { setLogField(FLD_ITM_TYPE, LogField(id, name)); }
|
||||
|
||||
void addLogEntry(EventType event, const QString & msg = QString());
|
||||
void setInvalid(const LogField & item);
|
||||
void setConverted(const LogField & from, const LogField & to);
|
||||
void setMoved(const LogField & from, const LogField & to);
|
||||
inline void setDbg(const QString & msg) { addLogEntry(EVT_DBG, msg); }
|
||||
inline void setInf(const QString & msg) { addLogEntry(EVT_INF, msg); }
|
||||
inline void setWrn(const QString & msg) { addLogEntry(EVT_WRN, msg); }
|
||||
inline void setErr(const QString & msg) { addLogEntry(EVT_ERR, msg); }
|
||||
|
||||
const ModelData * toModel() const;
|
||||
const ModelData * fromModel() const;
|
||||
const GeneralSettings * toGS() const;
|
||||
const GeneralSettings * fromGS() const;
|
||||
bool hasLogEntries(EventType logLevel = EVT_INF) const;
|
||||
|
||||
QString eventTypeToString(int type) const;
|
||||
QString eventTypeToColor(int type) const;
|
||||
QString getFieldName(int field) const;
|
||||
QStandardItemModel * getLogModel(EventType logLevel = EVT_INF, QObject *parent = Q_NULLPTR) const;
|
||||
|
||||
Board::Type fromType; // board type before conversion
|
||||
Board::Type toType; // board type after
|
||||
Boards fromBoard;
|
||||
Boards toBoard;
|
||||
RadioData * rd; // pointer to data struct being converted
|
||||
RadioData * rdCopy; // copy of original radio data before conversion
|
||||
QVector<LogRecord> log; // logged events
|
||||
LogRecord logCache; // buffer for holding event data before logging
|
||||
EventType maxEventType; // most severe event type recorded
|
||||
int modelIdx; // model index in radio data array, -1 if none
|
||||
int subCompIdx; // current row index within component (eg. model.mixData[componentIdx]), -1 if none
|
||||
};
|
||||
|
||||
#endif // RADIODATACONVERSIONSTATE_H
|
||||
@@ -0,0 +1,644 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "rawsource.h"
|
||||
|
||||
#include "eeprominterface.h"
|
||||
#include "radiodata.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
/*
|
||||
* RawSourceRange
|
||||
*/
|
||||
|
||||
float RawSourceRange::getValue(int value)
|
||||
{
|
||||
if (IS_ARM(getCurrentBoard()))
|
||||
return float(value) * step;
|
||||
else
|
||||
return min + float(value) * step;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RawSource
|
||||
*/
|
||||
|
||||
RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSettings & settings, unsigned int flags) const
|
||||
{
|
||||
RawSourceRange result;
|
||||
|
||||
Firmware * firmware = Firmware::getCurrentVariant();
|
||||
int board = firmware->getBoard();
|
||||
|
||||
switch (type) {
|
||||
case SOURCE_TYPE_TELEMETRY:
|
||||
if (IS_ARM(board)) {
|
||||
div_t qr = div(index, 3);
|
||||
const SensorData & sensor = model->sensorData[qr.quot];
|
||||
if (sensor.prec == 2)
|
||||
result.step = 0.01;
|
||||
else if (sensor.prec == 1)
|
||||
result.step = 0.1;
|
||||
else
|
||||
result.step = 1;
|
||||
result.min = -30000 * result.step;
|
||||
result.max = +30000 * result.step;
|
||||
result.decimals = sensor.prec;
|
||||
result.unit = sensor.unitString();
|
||||
}
|
||||
else {
|
||||
result.offset = -DBL_MAX;
|
||||
|
||||
switch (index) {
|
||||
case TELEMETRY_SOURCE_TX_BATT:
|
||||
result.step = 0.1;
|
||||
result.decimals = 1;
|
||||
result.max = 25.5;
|
||||
result.unit = tr("V");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_TX_TIME:
|
||||
result.step = 60;
|
||||
result.max = 24 * 60 * result.step - 60; // 23:59:00 with 1-minute resolution
|
||||
result.unit = tr("s");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_TIMER1:
|
||||
case TELEMETRY_SOURCE_TIMER2:
|
||||
case TELEMETRY_SOURCE_TIMER3:
|
||||
result.step = 5;
|
||||
result.max = 255 * result.step;
|
||||
result.unit = tr("s");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_RSSI_TX:
|
||||
case TELEMETRY_SOURCE_RSSI_RX:
|
||||
result.max = 100;
|
||||
result.offset = 128;
|
||||
break;
|
||||
case TELEMETRY_SOURCE_A1_MIN:
|
||||
case TELEMETRY_SOURCE_A2_MIN:
|
||||
case TELEMETRY_SOURCE_A3_MIN:
|
||||
case TELEMETRY_SOURCE_A4_MIN:
|
||||
if (model) result = model->frsky.channels[index-TELEMETRY_SOURCE_A1_MIN].getRange();
|
||||
break;
|
||||
case TELEMETRY_SOURCE_A1:
|
||||
case TELEMETRY_SOURCE_A2:
|
||||
case TELEMETRY_SOURCE_A3:
|
||||
case TELEMETRY_SOURCE_A4:
|
||||
if (model) result = model->frsky.channels[index-TELEMETRY_SOURCE_A1].getRange();
|
||||
break;
|
||||
case TELEMETRY_SOURCE_ALT:
|
||||
case TELEMETRY_SOURCE_ALT_MIN:
|
||||
case TELEMETRY_SOURCE_ALT_MAX:
|
||||
case TELEMETRY_SOURCE_GPS_ALT:
|
||||
result.step = 8;
|
||||
result.min = -500;
|
||||
result.max = 1540;
|
||||
if (firmware->getCapability(Imperial) || settings.imperial) {
|
||||
result.step = (result.step * 105) / 32;
|
||||
result.min = (result.min * 105) / 32;
|
||||
result.max = (result.max * 105) / 32;
|
||||
result.unit = tr("ft");
|
||||
}
|
||||
else {
|
||||
result.unit = tr("m");
|
||||
}
|
||||
break;
|
||||
case TELEMETRY_SOURCE_T1:
|
||||
case TELEMETRY_SOURCE_T1_MAX:
|
||||
case TELEMETRY_SOURCE_T2:
|
||||
case TELEMETRY_SOURCE_T2_MAX:
|
||||
result.min = -30;
|
||||
result.max = 225;
|
||||
result.unit = trUtf8("°C");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_HDG:
|
||||
result.step = 2;
|
||||
result.max = 360;
|
||||
result.offset = 256;
|
||||
result.unit = trUtf8("°");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_RPM:
|
||||
case TELEMETRY_SOURCE_RPM_MAX:
|
||||
result.step = 50;
|
||||
result.max = 12750;
|
||||
break;
|
||||
case TELEMETRY_SOURCE_FUEL:
|
||||
result.max = 100;
|
||||
result.unit = tr("%");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_ASPEED:
|
||||
case TELEMETRY_SOURCE_ASPEED_MAX:
|
||||
result.decimals = 1;
|
||||
result.step = 2.0;
|
||||
result.max = (2*255);
|
||||
if (firmware->getCapability(Imperial) || settings.imperial) {
|
||||
result.step *= 1.150779;
|
||||
result.max *= 1.150779;
|
||||
result.unit = tr("mph");
|
||||
}
|
||||
else {
|
||||
result.step *= 1.852;
|
||||
result.max *= 1.852;
|
||||
result.unit = tr("km/h");
|
||||
}
|
||||
break;
|
||||
case TELEMETRY_SOURCE_SPEED:
|
||||
case TELEMETRY_SOURCE_SPEED_MAX:
|
||||
result.step = 2;
|
||||
result.max = (2*255);
|
||||
if (firmware->getCapability(Imperial) || settings.imperial) {
|
||||
result.step *= 1.150779;
|
||||
result.max *= 1.150779;
|
||||
result.unit = tr("mph");
|
||||
}
|
||||
else {
|
||||
result.step *= 1.852;
|
||||
result.max *= 1.852;
|
||||
result.unit = tr("km/h");
|
||||
}
|
||||
break;
|
||||
case TELEMETRY_SOURCE_VERTICAL_SPEED:
|
||||
result.step = 0.1;
|
||||
result.min = -12.5;
|
||||
result.max = 13.0;
|
||||
result.decimals = 1;
|
||||
result.unit = tr("m/s");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_DTE:
|
||||
result.max = 30000;
|
||||
break;
|
||||
case TELEMETRY_SOURCE_DIST:
|
||||
case TELEMETRY_SOURCE_DIST_MAX:
|
||||
result.step = 8;
|
||||
result.max = 2040;
|
||||
result.unit = tr("m");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_CELL:
|
||||
case TELEMETRY_SOURCE_CELL_MIN:
|
||||
result.step = 0.02;
|
||||
result.max = 5.1;
|
||||
result.decimals = 2;
|
||||
result.unit = tr("V");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_CELLS_SUM:
|
||||
case TELEMETRY_SOURCE_CELLS_MIN:
|
||||
case TELEMETRY_SOURCE_VFAS:
|
||||
case TELEMETRY_SOURCE_VFAS_MIN:
|
||||
result.step = 0.1;
|
||||
result.max = 25.5;
|
||||
result.decimals = 1;
|
||||
result.unit = tr("V");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_CURRENT:
|
||||
case TELEMETRY_SOURCE_CURRENT_MAX:
|
||||
result.step = 0.5;
|
||||
result.max = 127.5;
|
||||
result.decimals = 1;
|
||||
result.unit = tr("A");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_CONSUMPTION:
|
||||
result.step = 100;
|
||||
result.max = 25500;
|
||||
result.unit = tr("mAh");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_POWER:
|
||||
case TELEMETRY_SOURCE_POWER_MAX:
|
||||
result.step = 5;
|
||||
result.max = 1275;
|
||||
result.unit = tr("W");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_ACCX:
|
||||
case TELEMETRY_SOURCE_ACCY:
|
||||
case TELEMETRY_SOURCE_ACCZ:
|
||||
result.step = 0.01;
|
||||
result.decimals = 2;
|
||||
result.max = 2.55;
|
||||
result.min = 0;
|
||||
result.unit = tr("g");
|
||||
break;
|
||||
default:
|
||||
result.max = 125;
|
||||
break;
|
||||
}
|
||||
|
||||
if (result.offset == -DBL_MAX) {
|
||||
result.offset = result.max - (127*result.step);
|
||||
}
|
||||
|
||||
if (flags & (RANGE_DELTA_FUNCTION | RANGE_ABS_FUNCTION)) {
|
||||
result.offset = 0;
|
||||
result.min = result.step * -127;
|
||||
result.max = result.step * 127;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SOURCE_TYPE_LUA_OUTPUT:
|
||||
result.max = 30000;
|
||||
result.min = -result.max;
|
||||
break;
|
||||
|
||||
case SOURCE_TYPE_TRIM:
|
||||
result.max = (model && model->extendedTrims ? firmware->getCapability(ExtendedTrimsRange) : firmware->getCapability(TrimsRange));
|
||||
result.min = -result.max;
|
||||
break;
|
||||
|
||||
case SOURCE_TYPE_GVAR: {
|
||||
GVarData gv = model->gvarData[index];
|
||||
result.step = gv.multiplierGet();
|
||||
result.decimals = gv.prec;
|
||||
result.max = gv.getMaxPrec();
|
||||
result.min = gv.getMinPrec();
|
||||
result.unit = gv.unitToString();
|
||||
break;
|
||||
}
|
||||
|
||||
case SOURCE_TYPE_SPECIAL:
|
||||
if (index == 0) { //Batt
|
||||
result.step = 0.1;
|
||||
result.decimals = 1;
|
||||
result.max = 25.5;
|
||||
result.unit = tr("V");
|
||||
}
|
||||
else if (index == 1) { //Time
|
||||
result.step = 60;
|
||||
result.max = 24 * 60 * result.step - 60; // 23:59:00 with 1-minute resolution
|
||||
result.unit = tr("s");
|
||||
}
|
||||
else { // Timers 1 - 3
|
||||
result.step = 1;
|
||||
result.max = 9 * 60 * 60 - 1; // 8:59:59 (to match firmware)
|
||||
result.min = -result.max;
|
||||
result.unit = tr("s");
|
||||
}
|
||||
break;
|
||||
|
||||
case SOURCE_TYPE_CH:
|
||||
result.max = model->getChannelsMax(false);
|
||||
result.min = -result.max;
|
||||
break;
|
||||
|
||||
default:
|
||||
result.max = 100;
|
||||
result.min = -result.max;
|
||||
break;
|
||||
}
|
||||
|
||||
if (flags & RANGE_ABS_FUNCTION) {
|
||||
result.min = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString RawSource::toString(const ModelData * model, const GeneralSettings * const generalSettings, Board::Type board) const
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN) {
|
||||
board = getCurrentBoard();
|
||||
}
|
||||
|
||||
static const QString trims[] = {
|
||||
tr("TrmR"), tr("TrmE"), tr("TrmT"), tr("TrmA"), tr("Trm5"), tr("Trm6")
|
||||
};
|
||||
|
||||
static const QString trims2[] = {
|
||||
tr("TrmH"), tr("TrmV")
|
||||
};
|
||||
|
||||
static const QString special[] = {
|
||||
tr("Batt"), tr("Time"), tr("Timer1"), tr("Timer2"), tr("Timer3"),
|
||||
};
|
||||
|
||||
static const QString telemetry[] = {
|
||||
tr("Batt"), tr("Time"), tr("Timer1"), tr("Timer2"), tr("Timer3"),
|
||||
tr("RAS"), tr("RSSI Tx"), tr("RSSI Rx"),
|
||||
tr("A1"), tr("A2"), tr("A3"), tr("A4"),
|
||||
tr("Alt"), tr("Rpm"), tr("Fuel"), tr("T1"), tr("T2"),
|
||||
tr("Speed"), tr("Dist"), tr("GPS Alt"),
|
||||
tr("Cell"), tr("Cells"), tr("Vfas"), tr("Curr"), tr("Cnsp"), tr("Powr"),
|
||||
tr("AccX"), tr("AccY"), tr("AccZ"),
|
||||
tr("Hdg "), tr("VSpd"), tr("AirSpeed"), tr("dTE"),
|
||||
tr("A1-"), tr("A2-"), tr("A3-"), tr("A4-"),
|
||||
tr("Alt-"), tr("Alt+"), tr("Rpm+"), tr("T1+"), tr("T2+"), tr("Speed+"), tr("Dist+"), tr("AirSpeed+"),
|
||||
tr("Cell-"), tr("Cells-"), tr("Vfas-"), tr("Curr+"), tr("Powr+"),
|
||||
tr("ACC"), tr("GPS Time"),
|
||||
};
|
||||
|
||||
static const QString rotary[] = { tr("REa"), tr("REb") };
|
||||
|
||||
if (index<0) {
|
||||
return tr("???");
|
||||
}
|
||||
|
||||
QString result;
|
||||
int genAryIdx = 0;
|
||||
switch (type) {
|
||||
case SOURCE_TYPE_NONE:
|
||||
return tr("----");
|
||||
|
||||
case SOURCE_TYPE_VIRTUAL_INPUT:
|
||||
{
|
||||
const char * name = NULL;
|
||||
if (model)
|
||||
name = model->inputNames[index];
|
||||
return RadioData::getElementName(tr("I", "as in Input"), index + 1, name);
|
||||
}
|
||||
|
||||
case SOURCE_TYPE_LUA_OUTPUT:
|
||||
return tr("LUA%1%2").arg(index/16+1).arg(QChar('a'+index%16));
|
||||
|
||||
case SOURCE_TYPE_STICK:
|
||||
if (generalSettings) {
|
||||
if (isPot(&genAryIdx))
|
||||
result = QString(generalSettings->potName[genAryIdx]);
|
||||
else if (isSlider(&genAryIdx))
|
||||
result = QString(generalSettings->sliderName[genAryIdx]);
|
||||
else if (isStick(&genAryIdx))
|
||||
result = QString(generalSettings->stickName[genAryIdx]);
|
||||
}
|
||||
if (result.isEmpty())
|
||||
result = Boards::getAnalogInputName(board, index);
|
||||
return result;
|
||||
|
||||
case SOURCE_TYPE_TRIM:
|
||||
return (Boards::getCapability(board, Board::NumTrims) == 2 ? CHECK_IN_ARRAY(trims2, index) : CHECK_IN_ARRAY(trims, index));
|
||||
|
||||
case SOURCE_TYPE_ROTARY_ENCODER:
|
||||
return CHECK_IN_ARRAY(rotary, index);
|
||||
|
||||
case SOURCE_TYPE_MAX:
|
||||
return tr("MAX");
|
||||
|
||||
case SOURCE_TYPE_SWITCH:
|
||||
if (generalSettings)
|
||||
result = QString(generalSettings->switchName[index]);
|
||||
if (result.isEmpty())
|
||||
result = Boards::getSwitchInfo(board, index).name;
|
||||
return result;
|
||||
|
||||
case SOURCE_TYPE_CUSTOM_SWITCH:
|
||||
return RawSwitch(SWITCH_TYPE_VIRTUAL, index+1).toString();
|
||||
|
||||
case SOURCE_TYPE_CYC:
|
||||
return tr("CYC%1").arg(index+1);
|
||||
|
||||
case SOURCE_TYPE_PPM:
|
||||
return RadioData::getElementName(tr("TR", "as in Trainer"), index + 1);
|
||||
|
||||
case SOURCE_TYPE_CH:
|
||||
if (model)
|
||||
return model->limitData[index].nameToString(index);
|
||||
else
|
||||
return LimitData().nameToString(index);
|
||||
|
||||
case SOURCE_TYPE_SPECIAL:
|
||||
return CHECK_IN_ARRAY(special, index);
|
||||
|
||||
case SOURCE_TYPE_TELEMETRY:
|
||||
if (IS_ARM(board)) {
|
||||
div_t qr = div(index, 3);
|
||||
if (model)
|
||||
result = model->sensorData[qr.quot].nameToString(qr.quot);
|
||||
else
|
||||
result = SensorData().nameToString(qr.quot);
|
||||
if (qr.rem)
|
||||
result += (qr.rem == 1 ? "-" : "+");
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return CHECK_IN_ARRAY(telemetry, index);
|
||||
}
|
||||
|
||||
case SOURCE_TYPE_GVAR:
|
||||
if (model)
|
||||
return model->gvarData[index].nameToString(index);
|
||||
else
|
||||
return GVarData().nameToString(index);
|
||||
|
||||
default:
|
||||
return tr("???");
|
||||
}
|
||||
}
|
||||
|
||||
bool RawSource::isStick(int * stickIndex, Board::Type board) const
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN)
|
||||
board = getCurrentBoard();
|
||||
|
||||
if (type == SOURCE_TYPE_STICK && index < Boards::getCapability(board, Board::Sticks)) {
|
||||
if (stickIndex)
|
||||
*stickIndex = index;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RawSource::isPot(int * potsIndex, Board::Type board) const
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN)
|
||||
board = getCurrentBoard();
|
||||
|
||||
Boards b(board);
|
||||
if (type == SOURCE_TYPE_STICK &&
|
||||
index >= b.getCapability(Board::Sticks) &&
|
||||
index < b.getCapability(Board::Sticks) + b.getCapability(Board::Pots)) {
|
||||
if (potsIndex)
|
||||
*potsIndex = index - b.getCapability(Board::Sticks);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RawSource::isSlider(int * sliderIndex, Board::Type board) const
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN)
|
||||
board = getCurrentBoard();
|
||||
|
||||
Boards b(board);
|
||||
if (type == SOURCE_TYPE_STICK &&
|
||||
index >= b.getCapability(Board::Sticks) + b.getCapability(Board::Pots) &&
|
||||
index < b.getCapability(Board::Sticks) + b.getCapability(Board::Pots) + b.getCapability(Board::Sliders)) {
|
||||
if (sliderIndex)
|
||||
*sliderIndex = index - b.getCapability(Board::Sticks) - b.getCapability(Board::Pots);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RawSource::isTimeBased(Board::Type board) const
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN)
|
||||
board = getCurrentBoard();
|
||||
|
||||
if (IS_ARM(board))
|
||||
return (type == SOURCE_TYPE_SPECIAL && index > 0);
|
||||
else
|
||||
return (type==SOURCE_TYPE_TELEMETRY && (index==TELEMETRY_SOURCE_TX_TIME || index==TELEMETRY_SOURCE_TIMER1 || index==TELEMETRY_SOURCE_TIMER2 || index==TELEMETRY_SOURCE_TIMER3));
|
||||
}
|
||||
|
||||
bool RawSource::isAvailable(const ModelData * const model, const GeneralSettings * const gs, Board::Type board) const
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN)
|
||||
board = getCurrentBoard();
|
||||
|
||||
Boards b(board);
|
||||
|
||||
if (type == SOURCE_TYPE_STICK && index >= b.getCapability(Board::MaxAnalogs))
|
||||
return false;
|
||||
|
||||
if (type == SOURCE_TYPE_SWITCH && index >= b.getCapability(Board::Switches))
|
||||
return false;
|
||||
|
||||
if (model) {
|
||||
if (type == SOURCE_TYPE_VIRTUAL_INPUT && !model->isInputValid(index))
|
||||
return false;
|
||||
|
||||
if (type == SOURCE_TYPE_CUSTOM_SWITCH && model->logicalSw[index].isEmpty())
|
||||
return false;
|
||||
|
||||
if (type == SOURCE_TYPE_TELEMETRY) {
|
||||
if (IS_ARM(board) && !model->sensorData[div(index, 3).quot].isAvailable()) {
|
||||
return false;
|
||||
}
|
||||
else if (!IS_ARM(board)) {
|
||||
Firmware * fw = getCurrentFirmware();
|
||||
if (type == (int)TELEMETRY_SOURCE_TX_TIME && !fw->getCapability(RtcTime))
|
||||
return false;
|
||||
|
||||
if (type == (int)TELEMETRY_SOURCE_RAS && !fw->getCapability(SportTelemetry))
|
||||
return false;
|
||||
|
||||
if (type == (int)TELEMETRY_SOURCE_TIMER3 && fw->getCapability(Timers) < 3)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gs) {
|
||||
int gsIdx = 0;
|
||||
if (type == SOURCE_TYPE_STICK && ((isPot(&gsIdx) && !gs->isPotAvailable(gsIdx)) || (isSlider(&gsIdx) && !gs->isSliderAvailable(gsIdx))))
|
||||
return false;
|
||||
|
||||
if (type == SOURCE_TYPE_SWITCH && IS_HORUS_OR_TARANIS(board) && !gs->switchSourceAllowedTaranis(index))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == SOURCE_TYPE_TRIM && index >= b.getCapability(Board::NumTrims))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RawSource RawSource::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setItemType(tr("SRC"), 1);
|
||||
RadioDataConversionState::EventType evt = RadioDataConversionState::EVT_NONE;
|
||||
RadioDataConversionState::LogField oldData(index, toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType));
|
||||
|
||||
if (type == SOURCE_TYPE_STICK) {
|
||||
if (cstate.toBoard.getCapability(Board::Sliders)) {
|
||||
if (index >= cstate.fromBoard.getCapability(Board::Sticks) + cstate.fromBoard.getCapability(Board::Pots)) {
|
||||
// 1st slider alignment
|
||||
index += cstate.toBoard.getCapability(Board::Pots) - cstate.fromBoard.getCapability(Board::Pots);
|
||||
}
|
||||
|
||||
if (isSlider(0, cstate.fromType)) {
|
||||
// LS and RS sliders are after 2 aux sliders on X12 and X9E
|
||||
if ((IS_HORUS_X12S(cstate.toType) || IS_TARANIS_X9E(cstate.toType)) && !IS_HORUS_X12S(cstate.fromType) && !IS_TARANIS_X9E(cstate.fromType)) {
|
||||
if (index >= 7) {
|
||||
index += 2; // LS/RS to LS/RS
|
||||
}
|
||||
}
|
||||
else if (!IS_TARANIS_X9E(cstate.toType) && !IS_HORUS_X12S(cstate.toType) && (IS_HORUS_X12S(cstate.fromType) || IS_TARANIS_X9E(cstate.fromType))) {
|
||||
if (index >= 7 && index <= 8) {
|
||||
index += 2; // aux sliders to spare analogs (which may not exist, this is validated later)
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
else if (index >= 9 && index <= 10) {
|
||||
index -= 2; // LS/RS to LS/RS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_TARANIS(cstate.toType) && IS_HORUS(cstate.fromType)) {
|
||||
if (index == 6)
|
||||
index = 5; // pot S2 to S2
|
||||
else if (index == 5)
|
||||
index = -1; // 6P on Horus doesn't exist on Taranis
|
||||
}
|
||||
else if (IS_HORUS(cstate.toType) && IS_TARANIS(cstate.fromType) && index == 5)
|
||||
{
|
||||
index = 6; // pot S2 to S2
|
||||
}
|
||||
|
||||
} // SOURCE_TYPE_STICK
|
||||
|
||||
if (type == SOURCE_TYPE_SWITCH) {
|
||||
// SWI to SWR don't exist on !X9E board
|
||||
if (!IS_TARANIS_X9E(cstate.toType) && IS_TARANIS_X9E(cstate.fromType)) {
|
||||
if (index >= 8) {
|
||||
index = index % 8;
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_TARANIS_X7(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_HORUS(cstate.fromType))) {
|
||||
// No SE and SG on X7 board
|
||||
if (index == 4 || index == 6) {
|
||||
index = 3; // SG and SE to SD
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
else if (index == 5) {
|
||||
index = 4; // SF to SF
|
||||
}
|
||||
else if (index == 7) {
|
||||
index = 5; // SH to SH
|
||||
}
|
||||
}
|
||||
// Compensate for SE and SG on X9/Horus board if converting from X7
|
||||
else if ((IS_TARANIS_X9(cstate.toType) || IS_HORUS(cstate.toType)) && IS_TARANIS_X7(cstate.fromType)) {
|
||||
if (index == 4) {
|
||||
index = 5; // SF to SF
|
||||
}
|
||||
else if (index == 5) {
|
||||
index = 7; // SH to SH
|
||||
}
|
||||
}
|
||||
} // SOURCE_TYPE_SWITCH
|
||||
|
||||
// final validation (we do not pass model to isAvailable() because we don't know what has or hasn't been converted)
|
||||
if (!isAvailable(NULL, cstate.toGS(), cstate.toType)) {
|
||||
cstate.setInvalid(oldData);
|
||||
index = -1; // TODO: better way to flag invalid sources?
|
||||
type = MAX_SOURCE_TYPE;
|
||||
}
|
||||
else if (evt == RadioDataConversionState::EVT_CVRT) {
|
||||
cstate.setConverted(oldData, RadioDataConversionState::LogField(index, toString(cstate.toModel(), cstate.toGS(), cstate.toType)));
|
||||
}
|
||||
else if (oldData.id != index) {
|
||||
// provide info by default if anything changed
|
||||
cstate.setMoved(oldData, RadioDataConversionState::LogField(index, toString(cstate.toModel(), cstate.toGS(), cstate.toType)));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RAWSOURCE_H
|
||||
#define RAWSOURCE_H
|
||||
|
||||
#include "boards.h"
|
||||
#include "constants.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class Firmware;
|
||||
class ModelData;
|
||||
class GeneralSettings;
|
||||
class RadioDataConversionState;
|
||||
|
||||
enum Switches {
|
||||
SWITCH_NONE,
|
||||
|
||||
SWITCH_THR = SWITCH_NONE+1,
|
||||
SWITCH_RUD,
|
||||
SWITCH_ELE,
|
||||
SWITCH_ID0,
|
||||
SWITCH_ID1,
|
||||
SWITCH_ID2,
|
||||
SWITCH_AIL,
|
||||
SWITCH_GEA,
|
||||
SWITCH_TRN,
|
||||
|
||||
SWITCH_SA0 = SWITCH_NONE+1,
|
||||
SWITCH_SA1,
|
||||
SWITCH_SA2,
|
||||
SWITCH_SB0,
|
||||
SWITCH_SB1,
|
||||
SWITCH_SB2,
|
||||
SWITCH_SC0,
|
||||
SWITCH_SC1,
|
||||
SWITCH_SC2,
|
||||
SWITCH_SD0,
|
||||
SWITCH_SD1,
|
||||
SWITCH_SD2,
|
||||
SWITCH_SE0,
|
||||
SWITCH_SE1,
|
||||
SWITCH_SE2,
|
||||
SWITCH_SF0,
|
||||
SWITCH_SF1,
|
||||
SWITCH_SG0,
|
||||
SWITCH_SG1,
|
||||
SWITCH_SG2,
|
||||
SWITCH_SH0,
|
||||
SWITCH_SH2,
|
||||
SWITCH_SI0,
|
||||
SWITCH_SI2,
|
||||
SWITCH_SJ0,
|
||||
SWITCH_SJ2,
|
||||
SWITCH_SK0,
|
||||
SWITCH_SK2,
|
||||
};
|
||||
|
||||
enum TimerModes {
|
||||
TMRMODE_NONE,
|
||||
TMRMODE_ABS,
|
||||
TMRMODE_THR,
|
||||
TMRMODE_THR_REL,
|
||||
TMRMODE_THR_TRG,
|
||||
TMRMODE_FIRST_SWITCH
|
||||
};
|
||||
|
||||
enum FailsafeModes {
|
||||
FAILSAFE_NOT_SET,
|
||||
FAILSAFE_HOLD,
|
||||
FAILSAFE_CUSTOM,
|
||||
FAILSAFE_NOPULSES,
|
||||
FAILSAFE_RECEIVER,
|
||||
FAILSAFE_LAST = FAILSAFE_RECEIVER
|
||||
};
|
||||
|
||||
enum HeliSwashTypes {
|
||||
HELI_SWASH_TYPE_NONE=0,
|
||||
HELI_SWASH_TYPE_120,
|
||||
HELI_SWASH_TYPE_120X,
|
||||
HELI_SWASH_TYPE_140,
|
||||
HELI_SWASH_TYPE_90
|
||||
};
|
||||
|
||||
enum TelemetrySource {
|
||||
TELEMETRY_SOURCE_TX_BATT,
|
||||
TELEMETRY_SOURCE_TX_TIME,
|
||||
TELEMETRY_SOURCE_TIMER1,
|
||||
TELEMETRY_SOURCE_TIMER2,
|
||||
TELEMETRY_SOURCE_TIMER3,
|
||||
TELEMETRY_SOURCE_RAS,
|
||||
TELEMETRY_SOURCE_RSSI_TX,
|
||||
TELEMETRY_SOURCE_RSSI_RX,
|
||||
TELEMETRY_SOURCE_A1,
|
||||
TELEMETRY_SOURCE_A2,
|
||||
TELEMETRY_SOURCE_A3,
|
||||
TELEMETRY_SOURCE_A4,
|
||||
TELEMETRY_SOURCE_ALT,
|
||||
TELEMETRY_SOURCE_RPM,
|
||||
TELEMETRY_SOURCE_FUEL,
|
||||
TELEMETRY_SOURCE_T1,
|
||||
TELEMETRY_SOURCE_T2,
|
||||
TELEMETRY_SOURCE_SPEED,
|
||||
TELEMETRY_SOURCE_DIST,
|
||||
TELEMETRY_SOURCE_GPS_ALT,
|
||||
TELEMETRY_SOURCE_CELL,
|
||||
TELEMETRY_SOURCE_CELLS_SUM,
|
||||
TELEMETRY_SOURCE_VFAS,
|
||||
TELEMETRY_SOURCE_CURRENT,
|
||||
TELEMETRY_SOURCE_CONSUMPTION,
|
||||
TELEMETRY_SOURCE_POWER,
|
||||
TELEMETRY_SOURCE_ACCX,
|
||||
TELEMETRY_SOURCE_ACCY,
|
||||
TELEMETRY_SOURCE_ACCZ,
|
||||
TELEMETRY_SOURCE_HDG,
|
||||
TELEMETRY_SOURCE_VERTICAL_SPEED,
|
||||
TELEMETRY_SOURCE_ASPEED,
|
||||
TELEMETRY_SOURCE_DTE,
|
||||
TELEMETRY_SOURCE_A1_MIN,
|
||||
TELEMETRY_SOURCE_A2_MIN,
|
||||
TELEMETRY_SOURCE_A3_MIN,
|
||||
TELEMETRY_SOURCE_A4_MIN,
|
||||
TELEMETRY_SOURCE_ALT_MIN,
|
||||
TELEMETRY_SOURCE_ALT_MAX,
|
||||
TELEMETRY_SOURCE_RPM_MAX,
|
||||
TELEMETRY_SOURCE_T1_MAX,
|
||||
TELEMETRY_SOURCE_T2_MAX,
|
||||
TELEMETRY_SOURCE_SPEED_MAX,
|
||||
TELEMETRY_SOURCE_DIST_MAX,
|
||||
TELEMETRY_SOURCE_ASPEED_MAX,
|
||||
TELEMETRY_SOURCE_CELL_MIN,
|
||||
TELEMETRY_SOURCE_CELLS_MIN,
|
||||
TELEMETRY_SOURCE_VFAS_MIN,
|
||||
TELEMETRY_SOURCE_CURRENT_MAX,
|
||||
TELEMETRY_SOURCE_POWER_MAX,
|
||||
TELEMETRY_SOURCE_ACC,
|
||||
TELEMETRY_SOURCE_GPS_TIME,
|
||||
TELEMETRY_SOURCES_STATUS_COUNT = TELEMETRY_SOURCE_GPS_TIME+1,
|
||||
TELEMETRY_SOURCES_DISPLAY_COUNT = TELEMETRY_SOURCE_POWER_MAX+1,
|
||||
TELEMETRY_SOURCES_COUNT = TELEMETRY_SOURCE_POWER_MAX+1,
|
||||
TELEMETRY_SOURCE_RESERVE = -1
|
||||
};
|
||||
|
||||
#define TM_HASTELEMETRY 0x01
|
||||
#define TM_HASOFFSET 0x02
|
||||
#define TM_HASWSHH 0x04
|
||||
|
||||
enum RawSourceType {
|
||||
SOURCE_TYPE_NONE,
|
||||
SOURCE_TYPE_VIRTUAL_INPUT,
|
||||
SOURCE_TYPE_LUA_OUTPUT,
|
||||
SOURCE_TYPE_STICK, // and POTS
|
||||
SOURCE_TYPE_ROTARY_ENCODER,
|
||||
SOURCE_TYPE_TRIM,
|
||||
SOURCE_TYPE_MAX,
|
||||
SOURCE_TYPE_SWITCH,
|
||||
SOURCE_TYPE_CUSTOM_SWITCH,
|
||||
SOURCE_TYPE_CYC,
|
||||
SOURCE_TYPE_PPM,
|
||||
SOURCE_TYPE_CH,
|
||||
SOURCE_TYPE_GVAR,
|
||||
SOURCE_TYPE_SPECIAL,
|
||||
SOURCE_TYPE_TELEMETRY,
|
||||
MAX_SOURCE_TYPE
|
||||
};
|
||||
|
||||
class RawSourceRange
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(RawSourceRange)
|
||||
|
||||
public:
|
||||
RawSourceRange():
|
||||
decimals(0),
|
||||
min(0.0),
|
||||
max(0.0),
|
||||
step(1.0),
|
||||
offset(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
float getValue(int value);
|
||||
|
||||
int decimals;
|
||||
double min;
|
||||
double max;
|
||||
double step;
|
||||
double offset;
|
||||
QString unit;
|
||||
};
|
||||
|
||||
#define RANGE_DELTA_FUNCTION 1
|
||||
#define RANGE_ABS_FUNCTION 2
|
||||
|
||||
class RawSource {
|
||||
Q_DECLARE_TR_FUNCTIONS(RawSource)
|
||||
|
||||
public:
|
||||
enum SourceGroups {
|
||||
NoneGroup = 0x001,
|
||||
SourcesGroup = 0x002,
|
||||
TrimsGroup = 0x004,
|
||||
SwitchesGroup = 0x008,
|
||||
GVarsGroup = 0x010,
|
||||
TelemGroup = 0x020,
|
||||
InputsGroup = 0x040,
|
||||
ScriptsGroup = 0x080,
|
||||
|
||||
InputSourceGroups = NoneGroup | SourcesGroup | TrimsGroup | SwitchesGroup | InputsGroup,
|
||||
AllSourceGroups = InputSourceGroups | GVarsGroup | TelemGroup | ScriptsGroup
|
||||
};
|
||||
|
||||
RawSource():
|
||||
type(SOURCE_TYPE_NONE),
|
||||
index(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit RawSource(int value):
|
||||
type(RawSourceType(abs(value)/65536)),
|
||||
index(value >= 0 ? abs(value)%65536 : -(abs(value)%65536))
|
||||
{
|
||||
}
|
||||
|
||||
RawSource(RawSourceType type, int index=0):
|
||||
type(type),
|
||||
index(index)
|
||||
{
|
||||
}
|
||||
|
||||
inline const int toValue() const
|
||||
{
|
||||
return index >= 0 ? (type * 65536 + index) : -(type * 65536 - index);
|
||||
}
|
||||
|
||||
RawSource convert(RadioDataConversionState & cstate);
|
||||
QString toString(const ModelData * model = NULL, const GeneralSettings * const generalSettings = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
|
||||
RawSourceRange getRange(const ModelData * model, const GeneralSettings & settings, unsigned int flags=0) const;
|
||||
bool isStick(int * potsIndex = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
|
||||
bool isPot(int * potsIndex = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
|
||||
bool isSlider(int * sliderIndex = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
|
||||
bool isTimeBased(Board::Type board = Board::BOARD_UNKNOWN) const;
|
||||
bool isAvailable(const ModelData * const model = NULL, const GeneralSettings * const gs = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
|
||||
|
||||
bool operator == ( const RawSource & other) {
|
||||
return (this->type == other.type) && (this->index == other.index);
|
||||
}
|
||||
|
||||
bool operator != ( const RawSource & other) {
|
||||
return (this->type != other.type) || (this->index != other.index);
|
||||
}
|
||||
|
||||
RawSourceType type;
|
||||
int index;
|
||||
};
|
||||
|
||||
#endif // RAWSOURCE_H
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "rawswitch.h"
|
||||
|
||||
#include "eeprominterface.h"
|
||||
#include "radiodata.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
|
||||
QString RawSwitch::toString(Board::Type board, const GeneralSettings * const generalSettings, const ModelData * const modelData) const
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN) {
|
||||
board = getCurrentBoard();
|
||||
}
|
||||
|
||||
static const QString switches9X[] = {
|
||||
QString("THR"), QString("RUD"), QString("ELE"),
|
||||
QString("ID0"), QString("ID1"), QString("ID2"),
|
||||
QString("AIL"), QString("GEA"), QString("TRN")
|
||||
};
|
||||
|
||||
static const QString trimsSwitches[] = {
|
||||
tr("RudTrim Left"), tr("RudTrim Right"),
|
||||
tr("EleTrim Down"), tr("EleTrim Up"),
|
||||
tr("ThrTrim Down"), tr("ThrTrim Up"),
|
||||
tr("AilTrim Left"), tr("AilTrim Right"),
|
||||
tr("Trim 5 Down"), tr("Trim 5 Up"),
|
||||
tr("Trim 6 Down"), tr("Trim 6 Up")
|
||||
};
|
||||
|
||||
static const QString trimsSwitches2[] = {
|
||||
tr("TrmH Left"), tr("TrmH Right"),
|
||||
tr("TrmV Down"), tr("TrmV Up")
|
||||
};
|
||||
|
||||
static const QString rotaryEncoders[] = {
|
||||
tr("REa"), tr("REb")
|
||||
};
|
||||
|
||||
static const QString timerModes[] = {
|
||||
tr("OFF"), tr("ON"),
|
||||
tr("THs"), tr("TH%"), tr("THt")
|
||||
};
|
||||
|
||||
const QStringList directionIndicators = QStringList()
|
||||
<< CPN_STR_SW_INDICATOR_UP
|
||||
<< CPN_STR_SW_INDICATOR_NEUT
|
||||
<< CPN_STR_SW_INDICATOR_DN;
|
||||
|
||||
if (index < 0) {
|
||||
return CPN_STR_SW_INDICATOR_REV % RawSwitch(type, -index).toString(board, generalSettings, modelData);
|
||||
}
|
||||
else {
|
||||
QString swName;
|
||||
div_t qr;
|
||||
switch(type) {
|
||||
case SWITCH_TYPE_SWITCH:
|
||||
if (IS_HORUS_OR_TARANIS(board)) {
|
||||
qr = div(index-1, 3);
|
||||
if (generalSettings)
|
||||
swName = QString(generalSettings->switchName[qr.quot]);
|
||||
if (swName.isEmpty())
|
||||
swName = Boards::getSwitchInfo(board, qr.quot).name;
|
||||
return swName + directionIndicators.at(qr.rem > -1 && qr.rem < directionIndicators.size() ? qr.rem : 1);
|
||||
}
|
||||
else {
|
||||
return CHECK_IN_ARRAY(switches9X, index - 1);
|
||||
}
|
||||
|
||||
case SWITCH_TYPE_VIRTUAL:
|
||||
if (modelData)
|
||||
return modelData->logicalSw[index].nameToString(index-1);
|
||||
else
|
||||
return LogicalSwitchData().nameToString(index-1);
|
||||
|
||||
case SWITCH_TYPE_MULTIPOS_POT:
|
||||
if (!Boards::getCapability(board, Board::MultiposPotsPositions))
|
||||
return tr("???");
|
||||
qr = div(index - 1, Boards::getCapability(board, Board::MultiposPotsPositions));
|
||||
if (generalSettings && qr.quot < (int)DIM(generalSettings->potConfig))
|
||||
swName = QString(generalSettings->potName[qr.quot]);
|
||||
if (swName.isEmpty())
|
||||
swName = Boards::getAnalogInputName(board, qr.quot + Boards::getCapability(board, Board::Sticks));
|
||||
return swName + "_" + QString::number(qr.rem + 1);
|
||||
|
||||
case SWITCH_TYPE_TRIM:
|
||||
return (Boards::getCapability(board, Board::NumTrims) == 2 ? CHECK_IN_ARRAY(trimsSwitches2, index-1) : CHECK_IN_ARRAY(trimsSwitches, index-1));
|
||||
|
||||
case SWITCH_TYPE_ROTARY_ENCODER:
|
||||
return CHECK_IN_ARRAY(rotaryEncoders, index-1);
|
||||
|
||||
case SWITCH_TYPE_ON:
|
||||
return tr("ON");
|
||||
|
||||
case SWITCH_TYPE_OFF:
|
||||
return tr("OFF");
|
||||
|
||||
case SWITCH_TYPE_ONE:
|
||||
return tr("One");
|
||||
|
||||
case SWITCH_TYPE_FLIGHT_MODE:
|
||||
if (modelData)
|
||||
return modelData->flightModeData[index-1].nameToString(index - 1);
|
||||
else
|
||||
return FlightModeData().nameToString(index - 1);
|
||||
|
||||
case SWITCH_TYPE_NONE:
|
||||
return tr("----");
|
||||
|
||||
case SWITCH_TYPE_TIMER_MODE:
|
||||
return CHECK_IN_ARRAY(timerModes, index);
|
||||
|
||||
case SWITCH_TYPE_SENSOR:
|
||||
if (modelData)
|
||||
return modelData->sensorData[index-1].nameToString(index-1);
|
||||
else
|
||||
return SensorData().nameToString(index-1);
|
||||
|
||||
case SWITCH_TYPE_TELEMETRY:
|
||||
return tr("Telemetry");
|
||||
|
||||
default:
|
||||
return tr("???");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RawSwitch::isAvailable(const ModelData * const model, const GeneralSettings * const gs, Board::Type board) const
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN)
|
||||
board = getCurrentBoard();
|
||||
|
||||
Boards b(board);
|
||||
|
||||
if (type == SWITCH_TYPE_SWITCH && abs(index) > b.getCapability(Board::SwitchPositions))
|
||||
return false;
|
||||
|
||||
if (type == SWITCH_TYPE_TRIM && abs(index) > b.getCapability(Board::NumTrimSwitches))
|
||||
return false;
|
||||
|
||||
if (gs) {
|
||||
if (type == SWITCH_TYPE_SWITCH && IS_HORUS_OR_TARANIS(board) && !gs->switchPositionAllowedTaranis(abs(index)))
|
||||
return false;
|
||||
|
||||
if (type == SWITCH_TYPE_MULTIPOS_POT) {
|
||||
int pot = div(abs(index) - 1, b.getCapability(Board::MultiposPotsPositions)).quot;
|
||||
if (!gs->isPotAvailable(pot) || gs->potConfig[pot] != Board::POT_MULTIPOS_SWITCH)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (model && !model->isAvailable(*this))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RawSwitch RawSwitch::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
if (!index)
|
||||
return *this;
|
||||
|
||||
cstate.setItemType(tr("SW"), 2);
|
||||
RadioDataConversionState::EventType evt = RadioDataConversionState::EVT_NONE;
|
||||
RadioDataConversionState::LogField oldData(index, toString(cstate.fromType, cstate.fromGS(), cstate.fromModel()));
|
||||
|
||||
if (type == SWITCH_TYPE_SWITCH) {
|
||||
int srcIdx = div(abs(index)-1, 3).quot; // raw source index
|
||||
int delta = 0;
|
||||
|
||||
// SWI to SWR don't exist on !X9E board
|
||||
if (!IS_TARANIS_X9E(cstate.toType) && IS_TARANIS_X9E(cstate.fromType)) {
|
||||
if (srcIdx > 7) {
|
||||
index %= 24;
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
}
|
||||
|
||||
// No SE and SG on X7 board
|
||||
if (IS_TARANIS_X7(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_HORUS(cstate.fromType))) {
|
||||
if (srcIdx == 4 || srcIdx == 5) {
|
||||
delta = 3; // SE to SD & SF to SF
|
||||
if (srcIdx == 4)
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
else if (srcIdx == 6) {
|
||||
delta = 9; // SG to SD
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
else if (srcIdx == 7) {
|
||||
delta = 6; // SH to SH
|
||||
}
|
||||
}
|
||||
// Compensate for SE and SG on X9/Horus board if converting from X7
|
||||
else if ((IS_TARANIS_X9(cstate.toType) || IS_HORUS(cstate.toType)) && IS_TARANIS_X7(cstate.fromType)) {
|
||||
if (srcIdx == 4) {
|
||||
delta = -3; // SF to SF
|
||||
}
|
||||
else if (srcIdx == 5) {
|
||||
delta = -6; // SH to SH
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
delta = -delta; // invert for !switch
|
||||
}
|
||||
|
||||
index -= delta;
|
||||
|
||||
} // SWITCH_TYPE_SWITCH
|
||||
|
||||
// final validation (we do not pass model to isAvailable() because we don't know what has or hasn't been converted)
|
||||
if (!isAvailable(NULL, cstate.toGS(), cstate.toType)) {
|
||||
cstate.setInvalid(oldData);
|
||||
type = MAX_SWITCH_TYPE; // TODO: better way to flag invalid switches?
|
||||
}
|
||||
else if (evt == RadioDataConversionState::EVT_CVRT) {
|
||||
cstate.setConverted(oldData, RadioDataConversionState::LogField(index, toString(cstate.toType, cstate.toGS(), cstate.toModel())));
|
||||
}
|
||||
else if (oldData.id != index) {
|
||||
// provide info by default if anything changed
|
||||
cstate.setMoved(oldData, RadioDataConversionState::LogField(index, toString(cstate.toType, cstate.toGS(), cstate.toModel())));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RAWSWITCH_H
|
||||
#define RAWSWITCH_H
|
||||
|
||||
#include "boards.h"
|
||||
#include "constants.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class Firmware;
|
||||
class ModelData;
|
||||
class GeneralSettings;
|
||||
class RadioDataConversionState;
|
||||
|
||||
enum RawSwitchType {
|
||||
SWITCH_TYPE_NONE,
|
||||
SWITCH_TYPE_SWITCH,
|
||||
SWITCH_TYPE_VIRTUAL,
|
||||
SWITCH_TYPE_MULTIPOS_POT,
|
||||
SWITCH_TYPE_TRIM,
|
||||
SWITCH_TYPE_ROTARY_ENCODER,
|
||||
SWITCH_TYPE_ON,
|
||||
SWITCH_TYPE_OFF,
|
||||
SWITCH_TYPE_ONE,
|
||||
SWITCH_TYPE_FLIGHT_MODE,
|
||||
SWITCH_TYPE_TIMER_MODE,
|
||||
SWITCH_TYPE_TELEMETRY,
|
||||
SWITCH_TYPE_SENSOR,
|
||||
MAX_SWITCH_TYPE
|
||||
};
|
||||
|
||||
class RawSwitch {
|
||||
Q_DECLARE_TR_FUNCTIONS(RawSwitch)
|
||||
|
||||
public:
|
||||
enum SwitchContext
|
||||
{
|
||||
LogicalSwitchesContext = 0x01,
|
||||
SpecialFunctionsContext = 0x02,
|
||||
GlobalFunctionsContext = 0x04,
|
||||
TimersContext = 0x08,
|
||||
MixesContext = 0x10,
|
||||
|
||||
AllModelContexts = SpecialFunctionsContext | LogicalSwitchesContext | TimersContext | MixesContext,
|
||||
AllSwitchContexts = AllModelContexts | GlobalFunctionsContext
|
||||
};
|
||||
|
||||
RawSwitch():
|
||||
type(SWITCH_TYPE_NONE),
|
||||
index(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit RawSwitch(int value):
|
||||
type(RawSwitchType(abs(value)/256)),
|
||||
index(value >= 0 ? abs(value)%256 : -(abs(value)%256))
|
||||
{
|
||||
}
|
||||
|
||||
RawSwitch(RawSwitchType type, int index=0):
|
||||
type(type),
|
||||
index(index)
|
||||
{
|
||||
}
|
||||
|
||||
inline const int toValue() const
|
||||
{
|
||||
return index >= 0 ? (type * 256 + index) : -(type * 256 - index);
|
||||
}
|
||||
|
||||
RawSwitch convert(RadioDataConversionState & cstate);
|
||||
QString toString(Board::Type board = Board::BOARD_UNKNOWN, const GeneralSettings * const generalSettings = NULL, const ModelData * const modelData = NULL) const;
|
||||
bool isAvailable(const ModelData * const model = NULL, const GeneralSettings * const gs = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
|
||||
|
||||
bool operator== ( const RawSwitch& other) {
|
||||
return (this->type == other.type) && (this->index == other.index);
|
||||
}
|
||||
|
||||
bool operator!= ( const RawSwitch& other) {
|
||||
return (this->type != other.type) || (this->index != other.index);
|
||||
}
|
||||
|
||||
|
||||
RawSwitchType type;
|
||||
int index;
|
||||
};
|
||||
|
||||
#endif // RAWSWITCH_H
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "sensordata.h"
|
||||
|
||||
#include "radiodata.h"
|
||||
|
||||
void SensorData::updateUnit()
|
||||
{
|
||||
if (type == TELEM_TYPE_CALCULATED) {
|
||||
if (formula == TELEM_FORMULA_CONSUMPTION)
|
||||
unit = UNIT_MAH;
|
||||
}
|
||||
}
|
||||
|
||||
QString SensorData::unitString() const
|
||||
{
|
||||
switch (unit) {
|
||||
case UNIT_VOLTS:
|
||||
return tr("V");
|
||||
case UNIT_AMPS:
|
||||
return tr("A");
|
||||
case UNIT_MILLIAMPS:
|
||||
return tr("mA");
|
||||
case UNIT_KTS:
|
||||
return tr("kts");
|
||||
case UNIT_METERS_PER_SECOND:
|
||||
return tr("m/s");
|
||||
case UNIT_KMH:
|
||||
return tr("km/h");
|
||||
case UNIT_MPH:
|
||||
return tr("mph");
|
||||
case UNIT_METERS:
|
||||
return tr("m");
|
||||
case UNIT_FEET:
|
||||
return tr("f");
|
||||
case UNIT_CELSIUS:
|
||||
return trUtf8("°C");
|
||||
case UNIT_FAHRENHEIT:
|
||||
return trUtf8("°F");
|
||||
case UNIT_PERCENT:
|
||||
return tr("%");
|
||||
case UNIT_MAH:
|
||||
return tr("mAh");
|
||||
case UNIT_WATTS:
|
||||
return tr("W");
|
||||
case UNIT_MILLIWATTS:
|
||||
return tr("mW");
|
||||
case UNIT_DB:
|
||||
return tr("dB");
|
||||
case UNIT_RPMS:
|
||||
return tr("rpms");
|
||||
case UNIT_G:
|
||||
return tr("g");
|
||||
case UNIT_DEGREE:
|
||||
return trUtf8("°");
|
||||
case UNIT_RADIANS:
|
||||
return trUtf8("Rad");
|
||||
case UNIT_HOURS:
|
||||
return tr("hours");
|
||||
case UNIT_MINUTES:
|
||||
return tr("minutes");
|
||||
case UNIT_SECONDS:
|
||||
return tr("seconds");
|
||||
case UNIT_CELLS:
|
||||
return tr("V");
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
QString SensorData::nameToString(int index) const
|
||||
{
|
||||
return RadioData::getElementName(tr("TELE"), index + 1, label);
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef SENSORDATA_H
|
||||
#define SENSORDATA_H
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
#define CPN_MAX_SENSORS 32
|
||||
|
||||
class SensorData {
|
||||
Q_DECLARE_TR_FUNCTIONS(SensorData)
|
||||
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
TELEM_TYPE_CUSTOM,
|
||||
TELEM_TYPE_CALCULATED
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TELEM_FORMULA_ADD,
|
||||
TELEM_FORMULA_AVERAGE,
|
||||
TELEM_FORMULA_MIN,
|
||||
TELEM_FORMULA_MAX,
|
||||
TELEM_FORMULA_MULTIPLY,
|
||||
TELEM_FORMULA_TOTALIZE,
|
||||
TELEM_FORMULA_CELL,
|
||||
TELEM_FORMULA_CONSUMPTION,
|
||||
TELEM_FORMULA_DIST,
|
||||
TELEM_FORMULA_LAST = TELEM_FORMULA_DIST
|
||||
};
|
||||
|
||||
enum {
|
||||
TELEM_CELL_INDEX_LOWEST,
|
||||
TELEM_CELL_INDEX_1,
|
||||
TELEM_CELL_INDEX_2,
|
||||
TELEM_CELL_INDEX_3,
|
||||
TELEM_CELL_INDEX_4,
|
||||
TELEM_CELL_INDEX_5,
|
||||
TELEM_CELL_INDEX_6,
|
||||
TELEM_CELL_INDEX_HIGHEST,
|
||||
TELEM_CELL_INDEX_DELTA,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
UNIT_RAW,
|
||||
UNIT_VOLTS,
|
||||
UNIT_AMPS,
|
||||
UNIT_MILLIAMPS,
|
||||
UNIT_KTS,
|
||||
UNIT_METERS_PER_SECOND,
|
||||
UNIT_FEET_PER_SECOND,
|
||||
UNIT_KMH,
|
||||
UNIT_MPH,
|
||||
UNIT_METERS,
|
||||
UNIT_FEET,
|
||||
UNIT_CELSIUS,
|
||||
UNIT_FAHRENHEIT,
|
||||
UNIT_PERCENT,
|
||||
UNIT_MAH,
|
||||
UNIT_WATTS,
|
||||
UNIT_MILLIWATTS,
|
||||
UNIT_DB,
|
||||
UNIT_RPMS,
|
||||
UNIT_G,
|
||||
UNIT_DEGREE,
|
||||
UNIT_RADIANS,
|
||||
UNIT_MILLILITERS,
|
||||
UNIT_FLOZ,
|
||||
UNIT_HOURS,
|
||||
UNIT_MINUTES,
|
||||
UNIT_SECONDS,
|
||||
// FrSky format used for these fields, could be another format in the future
|
||||
UNIT_FIRST_VIRTUAL,
|
||||
UNIT_CELLS = UNIT_FIRST_VIRTUAL,
|
||||
UNIT_DATETIME,
|
||||
UNIT_GPS,
|
||||
UNIT_GPS_LONGITUDE,
|
||||
UNIT_GPS_LATITUDE,
|
||||
UNIT_GPS_LONGITUDE_EW,
|
||||
UNIT_GPS_LATITUDE_NS,
|
||||
UNIT_DATETIME_YEAR,
|
||||
UNIT_DATETIME_DAY_MONTH,
|
||||
UNIT_DATETIME_HOUR_MIN,
|
||||
UNIT_DATETIME_SEC
|
||||
};
|
||||
|
||||
SensorData() { clear(); }
|
||||
unsigned int type; // custom / formula
|
||||
unsigned int id;
|
||||
unsigned int subid;
|
||||
unsigned int instance;
|
||||
unsigned int persistentValue;
|
||||
unsigned int formula;
|
||||
char label[4+1];
|
||||
unsigned int unit;
|
||||
unsigned int prec;
|
||||
bool autoOffset;
|
||||
bool filter;
|
||||
bool logs;
|
||||
bool persistent;
|
||||
bool onlyPositive;
|
||||
|
||||
// for custom sensors
|
||||
unsigned int ratio;
|
||||
int offset;
|
||||
|
||||
// for consumption
|
||||
unsigned int amps;
|
||||
|
||||
// for cell
|
||||
unsigned int source;
|
||||
unsigned int index;
|
||||
|
||||
// for calculations
|
||||
int sources[4];
|
||||
|
||||
// for GPS dist
|
||||
unsigned int gps;
|
||||
unsigned int alt;
|
||||
|
||||
bool isAvailable() const { return strlen(label) > 0; }
|
||||
void updateUnit();
|
||||
QString unitString() const;
|
||||
QString nameToString(int index) const;
|
||||
void clear() { memset(this, 0, sizeof(SensorData)); }
|
||||
};
|
||||
|
||||
#endif // SENSORDATA_H
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "telem_data.h"
|
||||
|
||||
#include "eeprominterface.h" // for getCurrentBoard()
|
||||
|
||||
float FrSkyChannelData::getRatio() const
|
||||
{
|
||||
if (type==0 || type==1 || type==2)
|
||||
return float(ratio << multiplier) / 10.0;
|
||||
else
|
||||
return ratio << multiplier;
|
||||
}
|
||||
|
||||
RawSourceRange FrSkyChannelData::getRange() const
|
||||
{
|
||||
RawSourceRange result;
|
||||
float ratio = getRatio();
|
||||
if (type==0 || type==1 || type==2)
|
||||
result.decimals = 2;
|
||||
else
|
||||
result.decimals = 0;
|
||||
result.step = ratio / 255;
|
||||
result.min = offset * result.step;
|
||||
result.max = ratio + result.min;
|
||||
result.unit = tr("V");
|
||||
return result;
|
||||
}
|
||||
|
||||
void FrSkyScreenData::clear()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(FrSkyScreenData));
|
||||
if (!IS_ARM(getCurrentBoard())) {
|
||||
type = TELEMETRY_SCREEN_NUMBERS;
|
||||
}
|
||||
}
|
||||
|
||||
void FrSkyData::clear()
|
||||
{
|
||||
usrProto = 0;
|
||||
voltsSource = 0;
|
||||
altitudeSource = 0;
|
||||
currentSource = 0;
|
||||
varioMin = 0;
|
||||
varioCenterMin = 0; // if increment in 0.2m/s = 3.0m/s max
|
||||
varioCenterMax = 0;
|
||||
varioMax = 0;
|
||||
mAhPersistent = 0;
|
||||
storedMah = 0;
|
||||
fasOffset = 0;
|
||||
for (int i=0; i<4; i++)
|
||||
screens[i].clear();
|
||||
varioSource = 2/*VARIO*/;
|
||||
blades = 2;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef TELEMETRYDATA_H
|
||||
#define TELEMETRYDATA_H
|
||||
|
||||
#include "rawsource.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class FrSkyAlarmData {
|
||||
Q_DECLARE_TR_FUNCTIONS(FrSkyAlarmData)
|
||||
|
||||
public:
|
||||
FrSkyAlarmData() { clear(); }
|
||||
unsigned int level; // 0=none, 1=Yellow, 2=Orange, 3=Red
|
||||
unsigned int greater; // 0=LT(<), 1=GT(>)
|
||||
unsigned int value; // 0.1V steps EG. 6.6 Volts = 66. 25.1V = 251, etc.
|
||||
|
||||
void clear() { memset(this, 0, sizeof(FrSkyAlarmData)); }
|
||||
|
||||
static QString alarmLevelName(int alarm)
|
||||
{
|
||||
switch (alarm) {
|
||||
case 1:
|
||||
return tr("Yellow");
|
||||
case 2:
|
||||
return tr("Orange");
|
||||
case 3:
|
||||
return tr("Red");
|
||||
default:
|
||||
return "----";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class FrSkyChannelData {
|
||||
Q_DECLARE_TR_FUNCTIONS(FrSkyChannelData)
|
||||
|
||||
public:
|
||||
FrSkyChannelData() { clear(); }
|
||||
unsigned int ratio; // 0.0 means not used, 0.1V steps EG. 6.6 Volts = 66. 25.1V = 251, etc.
|
||||
unsigned int type; // future use: 0=volts, 1=ml...
|
||||
int offset;
|
||||
unsigned int multiplier;
|
||||
FrSkyAlarmData alarms[2];
|
||||
|
||||
float getRatio() const;
|
||||
RawSourceRange getRange() const;
|
||||
void clear() { memset(reinterpret_cast<void *>(this), 0, sizeof(FrSkyChannelData)); }
|
||||
|
||||
static QString unitString(int units)
|
||||
{
|
||||
switch(units) {
|
||||
case 1:
|
||||
return QCoreApplication::translate("FrSkyChannelData", "---");
|
||||
default:
|
||||
return QCoreApplication::translate("FrSkyChannelData", "V");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct FrSkyBarData {
|
||||
RawSource source;
|
||||
int barMin; // minimum for bar display
|
||||
int barMax; // ditto for max display (would usually = ratio)
|
||||
};
|
||||
|
||||
struct FrSkyLineData {
|
||||
RawSource source[3];
|
||||
};
|
||||
|
||||
struct TelemetryScriptData {
|
||||
char filename[8+1];
|
||||
};
|
||||
|
||||
enum TelemetryScreenEnum {
|
||||
TELEMETRY_SCREEN_NONE,
|
||||
TELEMETRY_SCREEN_NUMBERS,
|
||||
TELEMETRY_SCREEN_BARS,
|
||||
TELEMETRY_SCREEN_SCRIPT
|
||||
};
|
||||
|
||||
class FrSkyScreenData {
|
||||
public:
|
||||
FrSkyScreenData() { clear(); }
|
||||
|
||||
typedef struct {
|
||||
FrSkyBarData bars[4];
|
||||
FrSkyLineData lines[4];
|
||||
TelemetryScriptData script;
|
||||
} FrSkyScreenBody;
|
||||
|
||||
unsigned int type;
|
||||
FrSkyScreenBody body;
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
enum TelemetryVarioSources {
|
||||
TELEMETRY_VARIO_SOURCE_ALTI,
|
||||
TELEMETRY_VARIO_SOURCE_ALTI_PLUS,
|
||||
TELEMETRY_VARIO_SOURCE_VSPEED,
|
||||
TELEMETRY_VARIO_SOURCE_A1,
|
||||
TELEMETRY_VARIO_SOURCE_A2,
|
||||
TELEMETRY_VARIO_SOURCE_DTE,
|
||||
};
|
||||
|
||||
enum TelemetryVoltsSources {
|
||||
TELEMETRY_VOLTS_SOURCE_A1,
|
||||
TELEMETRY_VOLTS_SOURCE_A2,
|
||||
TELEMETRY_VOLTS_SOURCE_A3,
|
||||
TELEMETRY_VOLTS_SOURCE_A4,
|
||||
TELEMETRY_VOLTS_SOURCE_FAS,
|
||||
TELEMETRY_VOLTS_SOURCE_CELLS
|
||||
};
|
||||
|
||||
enum TelemetryCurrentSources {
|
||||
TELEMETRY_CURRENT_SOURCE_NONE,
|
||||
TELEMETRY_CURRENT_SOURCE_A1,
|
||||
TELEMETRY_CURRENT_SOURCE_A2,
|
||||
TELEMETRY_CURRENT_SOURCE_A3,
|
||||
TELEMETRY_CURRENT_SOURCE_A4,
|
||||
TELEMETRY_CURRENT_SOURCE_FAS
|
||||
};
|
||||
|
||||
class FrSkyData {
|
||||
public:
|
||||
FrSkyData() { clear(); }
|
||||
FrSkyChannelData channels[4];
|
||||
unsigned int usrProto;
|
||||
int blades;
|
||||
unsigned int voltsSource;
|
||||
unsigned int altitudeSource;
|
||||
unsigned int currentSource;
|
||||
FrSkyScreenData screens[4];
|
||||
unsigned int varioSource;
|
||||
bool varioCenterSilent;
|
||||
int varioMin;
|
||||
int varioCenterMin; // if increment in 0.2m/s = 3.0m/s max
|
||||
int varioCenterMax;
|
||||
int varioMax;
|
||||
bool mAhPersistent;
|
||||
unsigned int storedMah;
|
||||
int fasOffset;
|
||||
bool ignoreSensorIds;
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
class MavlinkData {
|
||||
public:
|
||||
MavlinkData() { clear();}
|
||||
unsigned int rc_rssi_scale;
|
||||
unsigned int pc_rssi_en;
|
||||
void clear() { memset(this, 0, sizeof(MavlinkData)); }
|
||||
};
|
||||
|
||||
#endif // TELEMETRYDATA_H
|
||||
@@ -118,7 +118,7 @@ int FlashEEpromDialog::getEEpromVersion(const QString & filename)
|
||||
result = radioData->generalSettings.version;
|
||||
}
|
||||
else {
|
||||
QMessageBox::warning(this, tr("Error"), storage.error());
|
||||
QMessageBox::warning(this, CPN_STR_TTL_ERROR, storage.error());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -163,7 +163,7 @@ bool FlashEEpromDialog::patchCalibration()
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
QMessageBox::critical(this, tr("Warning"), tr("Wrong radio calibration data in profile, Settings not patched"));
|
||||
QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Wrong radio calibration data in profile, Settings not patched"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -208,7 +208,7 @@ bool FlashEEpromDialog::patchHardwareSettings()
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
QMessageBox::critical(this, tr("Warning"), tr("Wrong radio setting data in profile, Settings not patched"));
|
||||
QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Wrong radio setting data in profile, Settings not patched"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -233,13 +233,13 @@ void FlashEEpromDialog::on_burnButton_clicked()
|
||||
return;
|
||||
}
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
QMessageBox::warning(this, tr("Error"), tr("Cannot write file %1:\n%2.").arg(filename).arg(file.errorString()));
|
||||
QMessageBox::warning(this, CPN_STR_TTL_ERROR, tr("Cannot write file %1:\n%2.").arg(filename).arg(file.errorString()));
|
||||
return;
|
||||
}
|
||||
QTextStream outputStream(&file);
|
||||
long result = file.write((char*)eeprom, eeprom_size);
|
||||
if (result != eeprom_size) {
|
||||
QMessageBox::warning(this, tr("Error"), tr("Error writing file %1:\n%2.").arg(filename).arg(file.errorString()));
|
||||
QMessageBox::warning(this, CPN_STR_TTL_ERROR, tr("Error writing file %1:\n%2.").arg(filename).arg(file.errorString()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -277,16 +277,16 @@ void FlashEEpromDialog::on_burnButton_clicked()
|
||||
if (convertEEprom(filename, compatEEprom, firmwareFilename)) {
|
||||
int compatVersion = getEEpromVersion(compatEEprom);
|
||||
if ((compatVersion / 100) != (eepromVersion / 100)) {
|
||||
QMessageBox::warning(this, tr("Warning"), tr("The radio firmware belongs to another product family, check file and preferences!"));
|
||||
QMessageBox::warning(this, CPN_STR_TTL_WARNING, tr("The radio firmware belongs to another product family, check file and preferences!"));
|
||||
return;
|
||||
}
|
||||
else if (compatVersion < eepromVersion) {
|
||||
QMessageBox::warning(this, tr("Warning"), tr("The radio firmware is outdated, please upgrade!"));
|
||||
QMessageBox::warning(this, CPN_STR_TTL_WARNING, tr("The radio firmware is outdated, please upgrade!"));
|
||||
return;
|
||||
}
|
||||
filename = compatEEprom;
|
||||
}
|
||||
else if (QMessageBox::question(this, "Error", tr("Cannot check Models and Settings compatibility! Continue anyway?"), QMessageBox::Yes|QMessageBox::No) == QMessageBox::No) {
|
||||
else if (QMessageBox::question(this, CPN_STR_TTL_ERROR, tr("Cannot check Models and Settings compatibility! Continue anyway?"), QMessageBox::Yes|QMessageBox::No) == QMessageBox::No) {
|
||||
return;
|
||||
}
|
||||
qunlink(firmwareFilename);
|
||||
|
||||
@@ -142,7 +142,7 @@ void FlashFirmwareDialog::on_firmwareLoad_clicked()
|
||||
if (!fileName.isEmpty()) {
|
||||
fwName = fileName;
|
||||
if (!fwName.isEmpty() && !fwName.endsWith(".dfu") && !FirmwareInterface(fwName).isValid()) {
|
||||
QMessageBox::warning(this, tr("Warning"), tr("%1 may not be a valid firmware file").arg(fwName));
|
||||
QMessageBox::warning(this, CPN_STR_TTL_WARNING, tr("%1 may not be a valid firmware file").arg(fwName));
|
||||
}
|
||||
updateUI();
|
||||
}
|
||||
@@ -152,10 +152,10 @@ void FlashFirmwareDialog::on_useFirmwareSplash_clicked()
|
||||
{
|
||||
FirmwareInterface firmware(fwName);
|
||||
if (!firmware.isValid()) {
|
||||
QMessageBox::warning(this, tr("Error"), tr( "The firmware file is not valid." ));
|
||||
QMessageBox::warning(this, CPN_STR_TTL_ERROR, tr( "The firmware file is not valid." ));
|
||||
}
|
||||
else if (!firmware.hasSplash()) {
|
||||
QMessageBox::warning(this, tr("Error"), tr( "There is no start screen image in the firmware file." ));
|
||||
QMessageBox::warning(this, CPN_STR_TTL_ERROR, tr( "There is no start screen image in the firmware file." ));
|
||||
}
|
||||
else {
|
||||
imageSource = FIRMWARE;
|
||||
@@ -169,7 +169,7 @@ void FlashFirmwareDialog::on_useProfileSplash_clicked()
|
||||
if (!fileName.isEmpty()) {
|
||||
QImage image(fileName);
|
||||
if (image.isNull()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Profile image %1 is invalid.").arg(fileName));
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Profile image %1 is invalid.").arg(fileName));
|
||||
}
|
||||
else {
|
||||
imageSource = PROFILE;
|
||||
@@ -189,12 +189,12 @@ void FlashFirmwareDialog::on_useExternalSplash_clicked()
|
||||
g.imagesDir( QFileInfo(fileName).dir().absolutePath() );
|
||||
QImage image(fileName);
|
||||
if (image.isNull()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Image could not be loaded from %1").arg(fileName));
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Image could not be loaded from %1").arg(fileName));
|
||||
}
|
||||
else{
|
||||
imageSource = EXTERNAL;
|
||||
imageFile = fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
updateUI();
|
||||
}
|
||||
@@ -207,7 +207,7 @@ void FlashFirmwareDialog::on_useLibrarySplash_clicked()
|
||||
if (!fileName.isEmpty()) {
|
||||
QImage image(fileName);
|
||||
if (image.isNull()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("The library image could not be loaded"));
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("The library image could not be loaded"));
|
||||
}
|
||||
else {
|
||||
imageSource = LIBRARY;
|
||||
@@ -234,7 +234,7 @@ void FlashFirmwareDialog::on_burnButton_clicked()
|
||||
image = pixmap->toImage().scaled(ui->splash->width(), ui->splash->height());
|
||||
}
|
||||
if (image.isNull()) {
|
||||
QMessageBox::critical(this, tr("Warning"), tr("Splash image not found"));
|
||||
QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Splash image not found"));
|
||||
return;
|
||||
}
|
||||
// write the customized firmware
|
||||
@@ -247,7 +247,7 @@ void FlashFirmwareDialog::on_burnButton_clicked()
|
||||
FirmwareInterface firmware(fwName);
|
||||
firmware.setSplash(image);
|
||||
if (firmware.save(tempFile) <= 0) {
|
||||
QMessageBox::critical(this, tr("Warning"), tr("Cannot save customized firmware"));
|
||||
QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Cannot save customized firmware"));
|
||||
return;
|
||||
}
|
||||
startFlash(tempFile);
|
||||
@@ -304,7 +304,7 @@ void FlashFirmwareDialog::startFlash(const QString &filename)
|
||||
backupPath = g.profile[g.id()].pBackupDir();
|
||||
if (backupPath.isEmpty()) {
|
||||
backupPath=g.backupDir();
|
||||
}
|
||||
}
|
||||
backupFilename = backupPath + "/backup-" + QDateTime().currentDateTime().toString("yyyy-MM-dd-HHmmss") + ".bin";
|
||||
result = readEeprom(backupFilename, progressDialog.progress());
|
||||
sleep(2);
|
||||
|
||||
@@ -24,12 +24,6 @@
|
||||
#include "helpers.h"
|
||||
#include "appdata.h"
|
||||
|
||||
const char * const OPENTX_SDCARD_DOWNLOAD_URL[] = {
|
||||
"https://downloads.open-tx.org/2.2/release/sdcard/",
|
||||
"https://downloads.open-tx.org/2.2/rc/sdcard/",
|
||||
"https://downloads.open-tx.org/2.2/nightlies/sdcard/"
|
||||
};
|
||||
|
||||
FirmwarePreferencesDialog::FirmwarePreferencesDialog(QWidget * parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::FirmwarePreferencesDialog)
|
||||
@@ -37,6 +31,9 @@ FirmwarePreferencesDialog::FirmwarePreferencesDialog(QWidget * parent) :
|
||||
ui->setupUi(this);
|
||||
setWindowIcon(CompanionIcon("fwpreferences.png"));
|
||||
initSettings();
|
||||
MainWindow * mw = qobject_cast<MainWindow *>(this->parent());
|
||||
if (mw)
|
||||
connect(mw, &MainWindow::firmwareDownloadCompleted, this, &FirmwarePreferencesDialog::initSettings);
|
||||
}
|
||||
|
||||
FirmwarePreferencesDialog::~FirmwarePreferencesDialog()
|
||||
@@ -46,34 +43,35 @@ FirmwarePreferencesDialog::~FirmwarePreferencesDialog()
|
||||
|
||||
void FirmwarePreferencesDialog::initSettings()
|
||||
{
|
||||
ui->fwTypeLbl->setText(g.profile[g.id()].fwType());
|
||||
int version = g.fwRev.get(g.profile[g.id()].fwType());
|
||||
if (version > 0) {
|
||||
ui->fwTypeLbl->setText(g.currentProfile().fwType());
|
||||
int version = g.fwRev.get(g.currentProfile().fwType());
|
||||
if (version > 0)
|
||||
ui->lastRevisionLbl->setText(index2version(version));
|
||||
}
|
||||
else
|
||||
ui->lastRevisionLbl->setText(tr("Unknown"));
|
||||
}
|
||||
|
||||
void FirmwarePreferencesDialog::on_checkFWUpdates_clicked()
|
||||
{
|
||||
MainWindow * mw = qobject_cast<MainWindow *>(this->parent());
|
||||
mw->checkForFirmwareUpdate();
|
||||
initSettings();
|
||||
if (mw)
|
||||
mw->checkForFirmwareUpdate();
|
||||
}
|
||||
|
||||
void FirmwarePreferencesDialog::on_fw_dnld_clicked()
|
||||
{
|
||||
MainWindow * mw = qobject_cast<MainWindow *>(this->parent());
|
||||
mw->dowloadLastFirmwareUpdate();
|
||||
initSettings();
|
||||
if (mw)
|
||||
mw->dowloadLastFirmwareUpdate();
|
||||
}
|
||||
|
||||
void FirmwarePreferencesDialog::on_sd_dnld_clicked()
|
||||
{
|
||||
QString url = OPENTX_SDCARD_DOWNLOAD_URL[g.boundedOpenTxBranch()];
|
||||
QString url = g.openTxCurrentDownloadBranchUrl() % QStringLiteral("sdcard/");
|
||||
QString fwType = g.profile[g.id()].fwType();
|
||||
QStringList list = fwType.split("-");
|
||||
QString firmware = QString("%1-%2").arg(list[0]).arg(list[1]);
|
||||
if (g.boundedOpenTxBranch() != BRANCH_NIGHTLY_UNSTABLE) {
|
||||
if (g.boundedOpenTxBranch() != AppData::BRANCH_NIGHTLY_UNSTABLE) {
|
||||
url.append(QString("%1/").arg(firmware));
|
||||
}
|
||||
QDesktopServices::openUrl(url);
|
||||
|
||||
@@ -28,5 +28,4 @@ qt5_wrap_ui(generaledit_SRCS ${generaledit_UIS})
|
||||
qt5_wrap_cpp(generaledit_SRCS ${generaledit_HDRS})
|
||||
|
||||
add_library(generaledit ${generaledit_SRCS})
|
||||
qt5_use_modules(generaledit Widgets Xml Multimedia)
|
||||
target_link_libraries(generaledit PRIVATE ${CPN_COMMON_LIB})
|
||||
target_link_libraries(generaledit PRIVATE ${CPN_COMMON_LIB} Qt5::Multimedia)
|
||||
|
||||
@@ -41,7 +41,7 @@ CalibrationPanel::CalibrationPanel(QWidget * parent, GeneralSettings & generalSe
|
||||
tableWidget->setFrameStyle(QFrame::NoFrame | QFrame::Plain);
|
||||
tableWidget->setStyleSheet("QTableWidget {background-color: transparent;}");
|
||||
QStringList headerLabels;
|
||||
headerLabels << QObject::tr("Negative span") << QObject::tr("Mid value") << QObject::tr("Positive span");
|
||||
headerLabels << tr("Negative span") << tr("Mid value") << tr("Positive span");
|
||||
tableWidget->setHorizontalHeaderLabels(headerLabels);
|
||||
|
||||
int rows = CPN_MAX_STICKS + getBoardCapability(getCurrentBoard(), Board::Pots) + getBoardCapability(getCurrentBoard(), Board::Sliders) + getBoardCapability(getCurrentBoard(), Board::MouseAnalogs);
|
||||
|
||||
@@ -151,7 +151,7 @@ void GeneralEdit::on_calretrieve_PB_clicked()
|
||||
}
|
||||
generalSettings.PPM_Multiplier=PPM_Multiplier;
|
||||
} else {
|
||||
QMessageBox::critical(this, tr("Warning"), tr("Wrong data in profile, radio calibration was not retrieved"));
|
||||
QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Wrong data in profile, radio calibration was not retrieved"));
|
||||
}
|
||||
if (hwtypes.length()==numSwPots) {
|
||||
QString Byte;
|
||||
@@ -193,7 +193,7 @@ void GeneralEdit::on_calretrieve_PB_clicked()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
QMessageBox::critical(this, tr("Warning"), tr("Wrong data in profile, Switch/pot config not retrieved"));
|
||||
QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Wrong data in profile, Switch/pot config not retrieved"));
|
||||
}
|
||||
if ((DisplaySet.length()==6) && (BeeperSet.length()==4) && (HapticSet.length()==6) && (SpeakerSet.length()==6)) {
|
||||
generalSettings.stickMode=GSStickMode;
|
||||
@@ -234,7 +234,7 @@ void GeneralEdit::on_calretrieve_PB_clicked()
|
||||
}
|
||||
}
|
||||
else {
|
||||
QMessageBox::critical(this, tr("Warning"), tr("Wrong data in profile, hw related parameters were not retrieved"));
|
||||
QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Wrong data in profile, hw related parameters were not retrieved"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,7 +256,7 @@ void GeneralEdit::on_calstore_PB_clicked()
|
||||
QString hwtypes=g.profile[profile_id].controlTypes();
|
||||
QString controlNames=g.profile[profile_id].controlNames();
|
||||
if (!(calib.isEmpty())) {
|
||||
int ret = QMessageBox::question(this, "Companion",
|
||||
int ret = QMessageBox::question(this, CPN_STR_APP_NAME,
|
||||
tr("Do you want to store calibration in %1 profile<br>overwriting existing calibration?").arg(name) ,
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
if (ret == QMessageBox::No) {
|
||||
@@ -311,6 +311,6 @@ void GeneralEdit::on_calstore_PB_clicked()
|
||||
|
||||
QDateTime dateTime = QDateTime::currentDateTime();
|
||||
g.profile[profile_id].timeStamp(dateTime.toString("yyyy-MM-dd hh:mm"));
|
||||
QMessageBox::information(this, "Companion", tr("Calibration and HW parameters saved."));
|
||||
QMessageBox::information(this, CPN_STR_APP_NAME, tr("Calibration and HW parameters saved."));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ ui(new Ui::GeneralSetup)
|
||||
ui->BLBright_SB->setDisabled(true);
|
||||
ui->label_BLBright->hide();
|
||||
}
|
||||
|
||||
|
||||
if (!IS_HORUS(firmware->getBoard())) {
|
||||
ui->OFFBright_SB->hide();
|
||||
ui->OFFBright_SB->setDisabled(true);
|
||||
@@ -311,7 +311,7 @@ GeneralSetupPanel::~GeneralSetupPanel()
|
||||
void GeneralSetupPanel::populateBacklightCB()
|
||||
{
|
||||
QComboBox * b = ui->backlightswCB;
|
||||
QString strings[] = { QObject::tr("OFF"), QObject::tr("Keys"), QObject::tr("Sticks"), QObject::tr("Keys + Sticks"), QObject::tr("ON"), NULL };
|
||||
QString strings[] = { tr("OFF"), tr("Keys"), tr("Sticks"), tr("Keys + Sticks"), tr("ON"), NULL };
|
||||
|
||||
b->clear();
|
||||
for (int i=0; !strings[i].isNull(); i++) {
|
||||
@@ -325,8 +325,8 @@ void GeneralSetupPanel::populateBacklightCB()
|
||||
void GeneralSetupPanel::populateVoiceLangCB()
|
||||
{
|
||||
QComboBox * b = ui->voiceLang_CB;
|
||||
QString strings[] = { QObject::tr("English"), QObject::tr("Dutch"), QObject::tr("French"), QObject::tr("Italian"), QObject::tr("German"), QObject::tr("Czech"), QObject::tr("Slovak"), QObject::tr("Spanish"), QObject::tr("Polish"), QObject::tr("Portuguese"), QObject::tr("Swedish"), QObject::tr("Hungarian"), NULL};
|
||||
QString langcode[] = { "en", "nl","fr", "it", "de", "cz", "sk", "es", "pl", "pt", "se", "hu", NULL};
|
||||
QString strings[] = { tr("English"), tr("Dutch"), tr("French"), tr("Italian"), tr("German"), tr("Czech"), tr("Slovak"), tr("Spanish"), tr("Polish"), tr("Portuguese"), tr("Russian"), tr("Swedish"), tr("Hungarian"), NULL};
|
||||
QString langcode[] = { "en", "nl","fr", "it", "de", "cz", "sk", "es", "pl", "pt", "ru", "se", "hu", NULL};
|
||||
|
||||
b->clear();
|
||||
for (int i=0; strings[i]!=NULL; i++) {
|
||||
@@ -389,7 +389,7 @@ void GeneralSetupPanel::updateVarioPitchRange()
|
||||
|
||||
void GeneralSetupPanel::populateRotEncCB(int reCount)
|
||||
{
|
||||
QString strings[] = { QObject::tr("No"), QObject::tr("RotEnc A"), QObject::tr("Rot Enc B"), QObject::tr("Rot Enc C"), QObject::tr("Rot Enc D"), QObject::tr("Rot Enc E")};
|
||||
QString strings[] = { tr("No"), tr("RotEnc A"), tr("Rot Enc B"), tr("Rot Enc C"), tr("Rot Enc D"), tr("Rot Enc E")};
|
||||
QComboBox * b = ui->re_CB;
|
||||
|
||||
b->clear();
|
||||
@@ -429,8 +429,8 @@ void GeneralSetupPanel::setValues()
|
||||
void GeneralSetupPanel::on_faimode_CB_stateChanged(int)
|
||||
{
|
||||
if (ui->faimode_CB->isChecked()) {
|
||||
int ret = QMessageBox::question(this, "Companion",
|
||||
tr("If you enable FAI, you loose the vario, the play functions, the telemetry screen.\nThis function cannot be disabled by the radio.\nAre you sure ?") ,
|
||||
int ret = QMessageBox::question(this, CPN_STR_APP_NAME,
|
||||
tr("If you enable FAI, only RSSI and RxBt sensors will keep working.\nThis function cannot be disabled by the radio.\nAre you sure ?") ,
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
if (ret==QMessageBox::Yes) {
|
||||
generalSettings.fai = true;
|
||||
|
||||
@@ -577,7 +577,7 @@
|
||||
<item row="15" column="1">
|
||||
<widget class="QCheckBox" name="faimode_CB">
|
||||
<property name="toolTip">
|
||||
<string>If you enable FAI, you loose the vario, the play functions, the telemetry screen. This function cannot be disabled by the radio.</string>
|
||||
<string>If you enable FAI, only RSSI and RxBt sensors will keep working. This function cannot be disabled by the radio.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
|
||||
@@ -143,7 +143,7 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
|
||||
setupSwitchType(16, ui->sqLabel, ui->sqName, ui->sqType);
|
||||
setupSwitchType(17, ui->srLabel, ui->srName, ui->srType);
|
||||
|
||||
if (IS_TARANIS(board) && !IS_TARANIS_X7(board)) {
|
||||
if (IS_TARANIS(board) && !IS_TARANIS_SMALL(board)) {
|
||||
ui->serialPortMode->setCurrentIndex(generalSettings.hw_uartMode);
|
||||
}
|
||||
else {
|
||||
@@ -157,8 +157,16 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
|
||||
ui->txCurrentCalibrationLabel->hide();
|
||||
}
|
||||
|
||||
if (IS_TARANIS_X9E(board) || IS_HORUS(board)) {
|
||||
ui->bluetoothEnable->setChecked(generalSettings.bluetoothEnable);
|
||||
if (IS_TARANIS_X7(board) || IS_TARANIS_XLITE(board)|| IS_TARANIS_X9E(board) || IS_HORUS(board)) {
|
||||
ui->bluetoothMode->addItem(tr("OFF"), 0);
|
||||
if (IS_TARANIS_X9E(board)) {
|
||||
ui->bluetoothMode->addItem(tr("Enabled"), 1);
|
||||
}
|
||||
else {
|
||||
ui->bluetoothMode->addItem(tr("Telemetry"), 1);
|
||||
ui->bluetoothMode->addItem(tr("Trainer"), 2);
|
||||
}
|
||||
ui->bluetoothMode->setField(generalSettings.bluetoothMode, this);
|
||||
ui->bluetoothName->setField(generalSettings.bluetoothName, 10, this);
|
||||
}
|
||||
else {
|
||||
@@ -238,12 +246,6 @@ void HardwarePanel::on_txCurrentCalibration_editingFinished()
|
||||
}
|
||||
}
|
||||
|
||||
void HardwarePanel::on_bluetoothEnable_stateChanged(int)
|
||||
{
|
||||
generalSettings.bluetoothEnable = ui->bluetoothEnable->isChecked();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void HardwarePanel::setValues()
|
||||
{
|
||||
ui->txVoltageCalibration->setValue((double)generalSettings.txVoltageCalibration/10);
|
||||
|
||||
@@ -48,7 +48,6 @@ class HardwarePanel : public GeneralPanel
|
||||
|
||||
void on_txCurrentCalibration_editingFinished();
|
||||
void on_txVoltageCalibration_editingFinished();
|
||||
void on_bluetoothEnable_stateChanged(int);
|
||||
void on_filterEnable_stateChanged();
|
||||
|
||||
void on_serialPortMode_currentIndexChanged(int index);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>470</width>
|
||||
<height>1095</height>
|
||||
<height>1419</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -149,15 +149,6 @@
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="2">
|
||||
@@ -168,15 +159,6 @@
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="34" column="1">
|
||||
@@ -899,15 +881,6 @@
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="2">
|
||||
@@ -918,15 +891,6 @@
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="2">
|
||||
@@ -937,15 +901,6 @@
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="2">
|
||||
@@ -956,15 +911,6 @@
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="2">
|
||||
@@ -975,15 +921,6 @@
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="2">
|
||||
@@ -994,15 +931,6 @@
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
@@ -1013,15 +941,6 @@
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
@@ -1032,15 +951,6 @@
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="32" column="0">
|
||||
@@ -1099,8 +1009,8 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="bluetoothEnable">
|
||||
<property name="text">
|
||||
<widget class="AutoComboBox" name="bluetoothMode">
|
||||
<property name="text" stdset="0">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
|
||||
@@ -29,9 +29,11 @@
|
||||
#include "appdata.h"
|
||||
#include "macros.h"
|
||||
#include "helpers.h"
|
||||
#include "simulatorinterface.h"
|
||||
#include "simulatormainwindow.h"
|
||||
#include "storage/sdcard.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
|
||||
@@ -74,6 +76,42 @@ const QColor colors[CPN_MAX_CURVES] = {
|
||||
QColor(255,127,0),
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* CompanionIcon
|
||||
*/
|
||||
|
||||
static QString iconThemeFolder(int theme_set)
|
||||
{
|
||||
switch(theme_set) {
|
||||
case 0:
|
||||
return QStringLiteral("classic");
|
||||
case 2:
|
||||
return QStringLiteral("monowhite");
|
||||
case 3:
|
||||
return QStringLiteral("monochrome");
|
||||
case 4:
|
||||
return QStringLiteral("monoblue");
|
||||
default:
|
||||
return QStringLiteral("yerico");
|
||||
}
|
||||
}
|
||||
|
||||
CompanionIcon::CompanionIcon(const QString &baseimage)
|
||||
{
|
||||
addImage(baseimage);
|
||||
}
|
||||
|
||||
void CompanionIcon::addImage(const QString & baseimage, Mode mode, State state)
|
||||
{
|
||||
const QString theme = iconThemeFolder(g.theme());
|
||||
addFile(":/themes/"+theme+"/16/"+baseimage, QSize(16,16), mode, state);
|
||||
addFile(":/themes/"+theme+"/24/"+baseimage, QSize(24,24), mode, state);
|
||||
addFile(":/themes/"+theme+"/32/"+baseimage, QSize(32,32), mode, state);
|
||||
addFile(":/themes/"+theme+"/48/"+baseimage, QSize(48,48), mode, state);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* GVarGroup
|
||||
*/
|
||||
@@ -86,6 +124,9 @@ GVarGroup::GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBo
|
||||
dsb(dynamic_cast<QDoubleSpinBox *>(weightSB)),
|
||||
weightCB(weightCB),
|
||||
weight(weight),
|
||||
deflt(deflt),
|
||||
mini(mini),
|
||||
maxi(maxi),
|
||||
step(step),
|
||||
lock(true)
|
||||
{
|
||||
@@ -101,31 +142,7 @@ GVarGroup::GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBo
|
||||
}
|
||||
}
|
||||
|
||||
int val;
|
||||
|
||||
if (weight>maxi || weight<mini) {
|
||||
val = deflt;
|
||||
weightGV->setChecked(true);
|
||||
weightSB->hide();
|
||||
weightCB->show();
|
||||
}
|
||||
else {
|
||||
val = weight;
|
||||
weightGV->setChecked(false);
|
||||
weightSB->show();
|
||||
weightCB->hide();
|
||||
}
|
||||
|
||||
if (sb) {
|
||||
sb->setMinimum(mini);
|
||||
sb->setMaximum(maxi);
|
||||
sb->setValue(val);
|
||||
}
|
||||
else {
|
||||
dsb->setMinimum(mini*step);
|
||||
dsb->setMaximum(maxi*step);
|
||||
dsb->setValue(val*step);
|
||||
}
|
||||
setWeight(weight);
|
||||
|
||||
connect(weightSB, SIGNAL(editingFinished()), this, SLOT(valuesChanged()));
|
||||
|
||||
@@ -156,6 +173,43 @@ void GVarGroup::valuesChanged()
|
||||
}
|
||||
}
|
||||
|
||||
void GVarGroup::setWeight(int val)
|
||||
{
|
||||
lock = true;
|
||||
|
||||
int tval;
|
||||
|
||||
if (val>maxi || val<mini) {
|
||||
tval = deflt;
|
||||
weightGV->setChecked(true);
|
||||
weightSB->hide();
|
||||
weightCB->setCurrentIndex(weightCB->findData(val));
|
||||
if (weightCB->currentIndex() == -1)
|
||||
weightCB->setCurrentIndex(getCurrentFirmware()->getCapability(Gvars));
|
||||
weightCB->show();
|
||||
}
|
||||
else {
|
||||
tval = val;
|
||||
weightGV->setChecked(false);
|
||||
weightSB->show();
|
||||
weightCB->hide();
|
||||
}
|
||||
|
||||
if (sb) {
|
||||
sb->setMinimum(mini);
|
||||
sb->setMaximum(maxi);
|
||||
sb->setValue(tval);
|
||||
}
|
||||
else {
|
||||
dsb->setMinimum(mini*step);
|
||||
dsb->setMaximum(maxi*step);
|
||||
dsb->setValue(tval*step);
|
||||
}
|
||||
|
||||
lock = false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CurveGroup
|
||||
*/
|
||||
@@ -318,6 +372,7 @@ void CurveGroup::valuesChanged()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Helpers namespace functions
|
||||
*/
|
||||
@@ -363,16 +418,22 @@ QString Helpers::getAdjustmentString(int16_t val, const ModelData * model, bool
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO: Move lookup to GVarData class (w/out combobox)
|
||||
void Helpers::populateGvarUseCB(QComboBox * b, unsigned int phase)
|
||||
{
|
||||
b->addItem(QObject::tr("Own value"));
|
||||
b->addItem(QCoreApplication::translate("GVarData", "Own value"));
|
||||
for (int i=0; i<getCurrentFirmware()->getCapability(FlightModes); i++) {
|
||||
if (i != (int)phase) {
|
||||
b->addItem(QObject::tr("Flight mode %1 value").arg(i));
|
||||
b->addItem(QCoreApplication::translate("GVarData", "Flight mode %1 value").arg(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool caseInsensitiveLessThan(const QString &s1, const QString &s2)
|
||||
{
|
||||
return s1.toLower() < s2.toLower();
|
||||
}
|
||||
|
||||
void Helpers::populateFileComboBox(QComboBox * b, const QSet<QString> & set, const QString & current)
|
||||
{
|
||||
b->clear();
|
||||
@@ -404,232 +465,22 @@ void Helpers::getFileComboBoxValue(QComboBox * b, char * dest, int length)
|
||||
}
|
||||
}
|
||||
|
||||
void Helpers::addRawSourceItems(QStandardItemModel * itemModel, const RawSourceType & type, int count, const GeneralSettings * const generalSettings,
|
||||
const ModelData * const model, const int start, const QList<int> exclude)
|
||||
void Helpers::exportAppSettings(QWidget * dlgParent)
|
||||
{
|
||||
for (int i = start; i < start + count; i++) {
|
||||
if (exclude.contains(i))
|
||||
continue;
|
||||
static QString lastExpFile = CPN_SETTINGS_INI_PATH.arg(QDateTime::currentDateTime().toString("dd-MMM-yy"));
|
||||
const QString expFile = QFileDialog::getSaveFileName(dlgParent, QCoreApplication::translate("Companion", "Select or create a file for exported Settings:"), lastExpFile, CPN_STR_APP_SETTINGS_FILTER);
|
||||
if (expFile.isEmpty())
|
||||
return;
|
||||
|
||||
RawSource src = RawSource(type, i);
|
||||
if (model) {
|
||||
if (type == SOURCE_TYPE_VIRTUAL_INPUT && !model->isInputValid(i))
|
||||
continue;
|
||||
}
|
||||
if (generalSettings) {
|
||||
int genAryIdx = 0;
|
||||
if (type == SOURCE_TYPE_STICK && ((src.isPot(&genAryIdx) && !generalSettings->isPotAvailable(genAryIdx)) || (src.isSlider(&genAryIdx) && !generalSettings->isSliderAvailable(genAryIdx))))
|
||||
continue;
|
||||
}
|
||||
|
||||
QStandardItem * modelItem = new QStandardItem(src.toString(model, generalSettings));
|
||||
modelItem->setData(src.toValue(), Qt::UserRole);
|
||||
itemModel->appendRow(modelItem);
|
||||
|
||||
if (type == SOURCE_TYPE_SWITCH && generalSettings && IS_HORUS_OR_TARANIS(getCurrentBoard()) && !generalSettings->switchSourceAllowedTaranis(i)) {
|
||||
modelItem->setData(0, Qt::UserRole - 1); // trick to disable an item
|
||||
}
|
||||
lastExpFile = expFile;
|
||||
QString resultMsg;
|
||||
if (g.exportSettingsToFile(expFile, resultMsg)) {
|
||||
QMessageBox::information(dlgParent, CPN_STR_APP_NAME, resultMsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QStandardItemModel * Helpers::getRawSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const model, unsigned int flags)
|
||||
{
|
||||
QStandardItemModel * itemModel = new QStandardItemModel();
|
||||
Boards board = Boards(getCurrentBoard());
|
||||
Firmware * fw = getCurrentFirmware();
|
||||
|
||||
if (flags & POPULATE_NONE) {
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_NONE, 1, generalSettings, model);
|
||||
}
|
||||
|
||||
if (flags & POPULATE_SCRIPT_OUTPUTS) {
|
||||
for (int i=0; i < getCurrentFirmware()->getCapability(LuaScripts); i++) {
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_LUA_OUTPUT, fw->getCapability(LuaOutputsPerScript), generalSettings, model, i * 16);
|
||||
}
|
||||
}
|
||||
|
||||
if (model && (flags & POPULATE_VIRTUAL_INPUTS)) {
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_VIRTUAL_INPUT, fw->getCapability(VirtualInputs), generalSettings, model);
|
||||
}
|
||||
|
||||
if (flags & POPULATE_SOURCES) {
|
||||
int totalSources = CPN_MAX_STICKS + board.getCapability(Board::Pots) + board.getCapability(Board::Sliders) + board.getCapability(Board::MouseAnalogs);
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_STICK, totalSources, generalSettings, model);
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_ROTARY_ENCODER, fw->getCapability(RotaryEncoders), generalSettings, model);
|
||||
}
|
||||
|
||||
if (flags & POPULATE_TRIMS) {
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_TRIM, board.getCapability(Board::NumTrims), generalSettings, model);
|
||||
}
|
||||
|
||||
if (flags & POPULATE_SOURCES) {
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_MAX, 1, generalSettings, model);
|
||||
}
|
||||
|
||||
if (flags & POPULATE_SWITCHES) {
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_SWITCH, board.getCapability(Board::Switches), generalSettings, model);
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_CUSTOM_SWITCH, fw->getCapability(LogicalSwitches), generalSettings, model);
|
||||
}
|
||||
|
||||
if (flags & POPULATE_SOURCES) {
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_CYC, CPN_MAX_CYC, generalSettings, model);
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_PPM, fw->getCapability(TrainerInputs), generalSettings, model);
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_CH, fw->getCapability(Outputs), generalSettings, model);
|
||||
}
|
||||
|
||||
if (flags & POPULATE_TELEMETRY) {
|
||||
if (IS_ARM(board.getBoardType())) {
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_SPECIAL, 5, generalSettings, model);
|
||||
|
||||
if (model) {
|
||||
QList<int> exclude;
|
||||
for (int i=0; i < CPN_MAX_SENSORS * 3; ++i) {
|
||||
//this conditon must be false if we populate Global Functions where model = 0
|
||||
if (!model->sensorData[div(i, 3).quot].isAvailable())
|
||||
exclude << i;
|
||||
}
|
||||
if (exclude.size() < CPN_MAX_SENSORS * 3)
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_TELEMETRY, CPN_MAX_SENSORS * 3, generalSettings, model, 0, exclude);
|
||||
}
|
||||
}
|
||||
else {
|
||||
QList<int> exclude;
|
||||
if (!fw->getCapability(RtcTime))
|
||||
exclude << TELEMETRY_SOURCE_TX_TIME;
|
||||
if (!fw->getCapability(SportTelemetry))
|
||||
exclude << TELEMETRY_SOURCE_SWR;
|
||||
if (!IS_ARM(board.getBoardType()))
|
||||
exclude << TELEMETRY_SOURCE_TIMER3;
|
||||
int count = ((flags & POPULATE_TELEMETRYEXT) ? TELEMETRY_SOURCES_STATUS_COUNT : TELEMETRY_SOURCES_COUNT);
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_TELEMETRY, count, generalSettings, model, 0, exclude);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & POPULATE_GVARS) {
|
||||
addRawSourceItems(itemModel, SOURCE_TYPE_GVAR, fw->getCapability(Gvars), generalSettings, model);
|
||||
}
|
||||
|
||||
return itemModel;
|
||||
}
|
||||
|
||||
QString image2qstring(QImage image)
|
||||
{
|
||||
if (image.isNull())
|
||||
return "";
|
||||
QBuffer buffer;
|
||||
image.save(&buffer, "PNG");
|
||||
QString ImageStr;
|
||||
int b=0;
|
||||
int size=buffer.data().size();
|
||||
for (int j = 0; j < size; j++) {
|
||||
b=buffer.data().at(j);
|
||||
ImageStr += QString("%1").arg(b&0xff, 2, 16, QChar('0'));
|
||||
}
|
||||
return ImageStr;
|
||||
}
|
||||
|
||||
int findmult(float value, float base)
|
||||
{
|
||||
int vvalue = value*10;
|
||||
int vbase = base*10;
|
||||
vvalue--;
|
||||
|
||||
int mult = 0;
|
||||
for (int i=8; i>=0; i--) {
|
||||
if (vvalue/vbase >= (1<<i)) {
|
||||
mult = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mult;
|
||||
}
|
||||
|
||||
QString getFrSkyAlarmType(int alarm)
|
||||
{
|
||||
switch (alarm) {
|
||||
case 1:
|
||||
return QObject::tr("Yellow");
|
||||
case 2:
|
||||
return QObject::tr("Orange");
|
||||
case 3:
|
||||
return QObject::tr("Red");
|
||||
default:
|
||||
return "----";
|
||||
}
|
||||
}
|
||||
|
||||
QString getFrSkyUnits(int units)
|
||||
{
|
||||
switch(units) {
|
||||
case 1:
|
||||
return QObject::tr("---");
|
||||
default:
|
||||
return "V";
|
||||
}
|
||||
}
|
||||
|
||||
QString getFrSkyProtocol(int protocol)
|
||||
{
|
||||
switch(protocol) {
|
||||
case 2:
|
||||
if ((getCurrentFirmware()->getCapability(Telemetry) & TM_HASWSHH))
|
||||
return QObject::tr("Winged Shadow How High");
|
||||
else
|
||||
return QObject::tr("Winged Shadow How High (not supported)");
|
||||
case 1:
|
||||
return QObject::tr("FrSky Sensor Hub");
|
||||
default:
|
||||
return QObject::tr("None");
|
||||
}
|
||||
}
|
||||
|
||||
QString getFrSkyMeasure(int units)
|
||||
{
|
||||
switch(units) {
|
||||
case 1:
|
||||
return QObject::tr("Imperial");
|
||||
default:
|
||||
return QObject::tr("Metric");
|
||||
}
|
||||
}
|
||||
|
||||
QString getFrSkySrc(int index)
|
||||
{
|
||||
return RawSource(SOURCE_TYPE_TELEMETRY, index-1).toString();
|
||||
}
|
||||
|
||||
QString getTheme()
|
||||
{
|
||||
int theme_set = g.theme();
|
||||
QString Theme;
|
||||
switch(theme_set) {
|
||||
case 0:
|
||||
Theme="classic";
|
||||
break;
|
||||
case 2:
|
||||
Theme="monowhite";
|
||||
break;
|
||||
case 3:
|
||||
Theme="monochrome";
|
||||
break;
|
||||
case 4:
|
||||
Theme="monoblue";
|
||||
break;
|
||||
default:
|
||||
Theme="yerico";
|
||||
break;
|
||||
}
|
||||
return Theme;
|
||||
}
|
||||
|
||||
CompanionIcon::CompanionIcon(const QString &baseimage)
|
||||
{
|
||||
static QString theme = getTheme();
|
||||
addFile(":/themes/"+theme+"/16/"+baseimage, QSize(16,16));
|
||||
addFile(":/themes/"+theme+"/24/"+baseimage, QSize(24,24));
|
||||
addFile(":/themes/"+theme+"/32/"+baseimage, QSize(32,32));
|
||||
addFile(":/themes/"+theme+"/48/"+baseimage, QSize(48,48));
|
||||
resultMsg.append("\n" % QCoreApplication::translate("Companion", "Press the 'Retry' button to choose another file."));
|
||||
if (QMessageBox::warning(dlgParent, CPN_STR_APP_NAME, resultMsg, QMessageBox::Cancel, QMessageBox::Retry) == QMessageBox::Retry)
|
||||
exportAppSettings(dlgParent);
|
||||
}
|
||||
|
||||
void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
|
||||
@@ -637,8 +488,8 @@ void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
|
||||
QString fwId = SimulatorLoader::findSimulatorByFirmwareName(getCurrentFirmware()->getId());
|
||||
if (fwId.isEmpty()) {
|
||||
QMessageBox::warning(NULL,
|
||||
QObject::tr("Warning"),
|
||||
QObject::tr("Simulator for this firmware is not yet available"));
|
||||
CPN_STR_TTL_WARNING,
|
||||
QCoreApplication::translate("Companion", "Simulator for this firmware is not yet available"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -662,15 +513,15 @@ void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
|
||||
QString resultMsg;
|
||||
if (dialog->getExitStatus(&resultMsg)) {
|
||||
if (resultMsg.isEmpty())
|
||||
resultMsg = QObject::tr("Uknown error during Simulator startup.");
|
||||
QMessageBox::critical(NULL, QObject::tr("Simulator Error"), resultMsg);
|
||||
resultMsg = QCoreApplication::translate("Companion", "Uknown error during Simulator startup.");
|
||||
QMessageBox::critical(NULL, QCoreApplication::translate("Companion", "Simulator Error"), resultMsg);
|
||||
dialog->deleteLater();
|
||||
}
|
||||
else if (dialog->setRadioData(simuData)) {
|
||||
dialog->show();
|
||||
}
|
||||
else {
|
||||
QMessageBox::critical(NULL, QObject::tr("Data Load Error"), QObject::tr("Error occurred while starting simulator."));
|
||||
QMessageBox::critical(NULL, QCoreApplication::translate("Companion", "Data Load Error"), QCoreApplication::translate("Companion", "Error occurred while starting simulator."));
|
||||
dialog->deleteLater();
|
||||
}
|
||||
}
|
||||
@@ -737,7 +588,7 @@ const QString index2version(int index)
|
||||
if (nightly > 0 && nightly < 900) {
|
||||
result += "N" + QString::number(nightly);
|
||||
}
|
||||
else if (nightly >= 900 && nightly < 1000) {
|
||||
else if (nightly >= 900 && nightly < 999) {
|
||||
result += "RC" + QString::number(nightly-900);
|
||||
}
|
||||
}
|
||||
@@ -794,11 +645,6 @@ QSet<QString> getFilesSet(const QString &path, const QStringList &filter, int ma
|
||||
return result;
|
||||
}
|
||||
|
||||
bool caseInsensitiveLessThan(const QString &s1, const QString &s2)
|
||||
{
|
||||
return s1.toLower() < s2.toLower();
|
||||
}
|
||||
|
||||
bool GpsGlitchFilter::isGlitch(GpsCoord coord)
|
||||
{
|
||||
if ((fabs(coord.latitude) < 0.1) && (fabs(coord.longitude) < 0.1)) {
|
||||
|
||||
@@ -52,11 +52,10 @@ extern const QColor colors[CPN_MAX_CURVES];
|
||||
|
||||
#define TRIM_MODE_NONE 0x1F // 0b11111
|
||||
|
||||
QString getTheme();
|
||||
|
||||
class CompanionIcon: public QIcon {
|
||||
public:
|
||||
CompanionIcon(const QString &baseimage);
|
||||
void addImage(const QString &baseimage, Mode mode = Normal, State state = Off);
|
||||
};
|
||||
|
||||
class GVarGroup: public QObject {
|
||||
@@ -66,6 +65,8 @@ class GVarGroup: public QObject {
|
||||
public:
|
||||
GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBox * weightCB, int & weight, const ModelData & model, const int deflt, const int mini, const int maxi, const double step=1.0, bool allowGVars=true);
|
||||
|
||||
void setWeight(int val);
|
||||
|
||||
signals:
|
||||
void valueChanged();
|
||||
|
||||
@@ -80,6 +81,9 @@ class GVarGroup: public QObject {
|
||||
QDoubleSpinBox *dsb;
|
||||
QComboBox *weightCB;
|
||||
int & weight;
|
||||
int deflt;
|
||||
int mini;
|
||||
int maxi;
|
||||
double step;
|
||||
bool lock;
|
||||
};
|
||||
@@ -113,45 +117,20 @@ class CurveGroup : public QObject {
|
||||
int lastType;
|
||||
};
|
||||
|
||||
|
||||
#define POPULATE_NONE (1<<0)
|
||||
#define POPULATE_SOURCES (1<<1)
|
||||
#define POPULATE_TRIMS (1<<2)
|
||||
#define POPULATE_SWITCHES (1<<3)
|
||||
#define POPULATE_GVARS (1<<4)
|
||||
#define POPULATE_TELEMETRY (1<<5)
|
||||
#define POPULATE_TELEMETRYEXT (1<<6)
|
||||
#define POPULATE_VIRTUAL_INPUTS (1<<7)
|
||||
#define POPULATE_SCRIPT_OUTPUTS (1<<8)
|
||||
|
||||
#define GVARS_VARIANT 0x0001
|
||||
#define FRSKY_VARIANT 0x0002
|
||||
|
||||
namespace Helpers
|
||||
{
|
||||
void addRawSourceItems(QStandardItemModel * itemModel, const RawSourceType & type, int count, const GeneralSettings * const generalSettings = NULL,
|
||||
const ModelData * const model = NULL, const int start = 0, const QList<int> exclude = QList<int>());
|
||||
QStandardItemModel * getRawSourceItemModel(const GeneralSettings * const generalSettings = NULL, const ModelData * const model = NULL, unsigned int flags = 0);
|
||||
|
||||
void populateGvarUseCB(QComboBox *b, unsigned int phase);
|
||||
void populateGVCB(QComboBox & b, int value, const ModelData & model);
|
||||
QString getAdjustmentString(int16_t val, const ModelData * model = NULL, bool sign = false);
|
||||
|
||||
void populateFileComboBox(QComboBox * b, const QSet<QString> & set, const QString & current);
|
||||
void getFileComboBoxValue(QComboBox * b, char * dest, int length);
|
||||
|
||||
void exportAppSettings(QWidget * dlgParent = nullptr);
|
||||
|
||||
} // namespace Helpers
|
||||
|
||||
// TODO : move to Helpers namespace
|
||||
|
||||
QString image2qstring(QImage image);
|
||||
int findmult(float value, float base);
|
||||
|
||||
/* FrSky helpers */
|
||||
QString getFrSkyAlarmType(int alarm);
|
||||
QString getFrSkyUnits(int units);
|
||||
QString getFrSkyProtocol(int protocol);
|
||||
QString getFrSkyMeasure(int units);
|
||||
QString getFrSkySrc(int index);
|
||||
// TODO : move globals to Helpers namespace
|
||||
|
||||
void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx);
|
||||
|
||||
@@ -161,14 +140,6 @@ QPixmap makePixMap(const QImage & image);
|
||||
int version2index(const QString & version);
|
||||
const QString index2version(int index);
|
||||
|
||||
class QTimeS : public QTime
|
||||
{
|
||||
public:
|
||||
QTimeS(int s) { int h = s/3600; s %= 3600; int m = s/60; s %=60; setHMS(h, m, s); }
|
||||
QTimeS(const QTime & q) : QTime(q) {}
|
||||
int seconds() const { return hour()*3600 + minute()*60 + second(); }
|
||||
};
|
||||
|
||||
bool qunlink(const QString & fileName);
|
||||
|
||||
QString generateProcessUniqueTempFileName(const QString & fileName);
|
||||
@@ -177,8 +148,14 @@ bool isTempFileName(const QString & fileName);
|
||||
QString getSoundsPath(const GeneralSettings &generalSettings);
|
||||
QSet<QString> getFilesSet(const QString &path, const QStringList &filter, int maxLen);
|
||||
|
||||
bool caseInsensitiveLessThan(const QString &s1, const QString &s2);
|
||||
|
||||
class QTimeS : public QTime
|
||||
{
|
||||
public:
|
||||
QTimeS(int s) { int h = s/3600; s %= 3600; int m = s/60; s %=60; setHMS(h, m, s); }
|
||||
QTimeS(const QTime & q) : QTime(q) {}
|
||||
int seconds() const { return hour()*3600 + minute()*60 + second(); }
|
||||
};
|
||||
|
||||
class GpsCoord
|
||||
{
|
||||
|
||||
@@ -18,34 +18,212 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "helpers.h"
|
||||
#include "helpers_html.h"
|
||||
#include <QStringList>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
|
||||
QString tdAlign(const QString &s, const QString &align, const QString &color, bool bold)
|
||||
QString tdAlign(const QString & s, const QString & align, const QString & color, bool bold)
|
||||
{
|
||||
QString str = s;
|
||||
if (bold) str = "<b>" + str + "</b>";
|
||||
if (!color.isEmpty()) str = "<font color=" + color + ">" + str + "</font>";
|
||||
return "<td align=" + align + ">" + str + "</td>";
|
||||
if (!color.isEmpty()) str = "<font color='" + color + "'>" + str + "</font>";
|
||||
return "<td align='" + align + "'>" + str + "</td>";
|
||||
}
|
||||
|
||||
QString doTC(const QString &s, const QString &color, bool bold)
|
||||
QString doTC(const QString & s, const QString & color, bool bold)
|
||||
{
|
||||
return tdAlign(s, "center", color, bold);
|
||||
}
|
||||
|
||||
QString doTR(const QString &s, const QString &color, bool bold)
|
||||
QString doTR(const QString & s, const QString & color, bool bold)
|
||||
{
|
||||
return tdAlign(s, "right", color, bold);
|
||||
}
|
||||
|
||||
QString doTL(const QString &s, const QString &color, bool bold)
|
||||
QString doTL(const QString & s, const QString & color, bool bold)
|
||||
{
|
||||
return tdAlign(s, "left", color, bold);
|
||||
}
|
||||
|
||||
QString fv(const QString &name, const QString &value, const QString &color)
|
||||
QString fv(const QString & name, const QString & value, const QString & color)
|
||||
{
|
||||
return "<b>" + name + ": </b><font color=" +color + ">" + value + "</font><br>";
|
||||
return "<b>" + name + ": </b><font color='" + color + "'>" + value + "</font><br>";
|
||||
}
|
||||
|
||||
QString doTableCell(const QString & s, const unsigned int width, const QString & align, const QString & color, bool bold)
|
||||
{
|
||||
QString prfx = "<td";
|
||||
if (width)
|
||||
prfx.append(QString(" width='%1%'").arg(QString::number(width)));
|
||||
if (!align.isEmpty())
|
||||
prfx.append(QString(" align='%1'").arg(align));
|
||||
prfx.append(">");
|
||||
|
||||
QString str = s;
|
||||
if (bold)
|
||||
str = "<b>" + str + "</b>";
|
||||
if (!color.isEmpty())
|
||||
str = QString("<font color='%1'>%2</font>").arg(color).arg(str);
|
||||
|
||||
str = prfx + str + "</td>";
|
||||
return str;
|
||||
}
|
||||
|
||||
QString doTableRow(const QStringList & strl, const unsigned int width, const QString & align, const QString & color, bool bold)
|
||||
{
|
||||
QString str;
|
||||
for (int i=0; i<strl.count(); i++) {
|
||||
str.append(doTableCell(strl.at(i), width, align, color, bold));
|
||||
}
|
||||
return "<tr>" + str + "</tr>";
|
||||
}
|
||||
|
||||
QString doTableBlankRow()
|
||||
{
|
||||
return "<tr></tr>";
|
||||
}
|
||||
|
||||
Stylesheet::Stylesheet(const QString & name):
|
||||
mName(name)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
Stylesheet::Stylesheet(const QString & name, const StyleType styleType):
|
||||
mName(name)
|
||||
{
|
||||
init();
|
||||
mResult = load(styleType);
|
||||
}
|
||||
|
||||
Stylesheet::~Stylesheet()
|
||||
{
|
||||
}
|
||||
|
||||
void Stylesheet::init()
|
||||
{
|
||||
mResult = false;
|
||||
mErrormsg = "";
|
||||
mText = "";
|
||||
QStringList p = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
|
||||
mCustomPath = p[0];
|
||||
mCustomFile = p[0] + "/" + mName;
|
||||
mDefaultFile = THEMES_DEFAULT_PATH + mName;
|
||||
}
|
||||
|
||||
bool Stylesheet::load(const StyleType styleType)
|
||||
{
|
||||
mResult = false;
|
||||
switch (styleType) {
|
||||
case STYLE_TYPE_NONE:
|
||||
case STYLE_TYPE_DEFAULT:
|
||||
mResult = read(mDefaultFile);
|
||||
case STYLE_TYPE_CUSTOM:
|
||||
mResult = read(mCustomFile);
|
||||
case STYLE_TYPE_EFFECTIVE:
|
||||
mResult = read(mCustomFile);
|
||||
if(!mResult)
|
||||
mResult = read(mDefaultFile);
|
||||
}
|
||||
return mResult;
|
||||
}
|
||||
|
||||
bool Stylesheet::read(const QString & path)
|
||||
{
|
||||
mResult = false;
|
||||
mText = "";
|
||||
|
||||
QFile file(path);
|
||||
if (file.exists()) {
|
||||
if (file.open(QFile::ReadOnly | QFile::Text)) {
|
||||
QTextStream in(&file);
|
||||
if (in.status()==QTextStream::Ok) {
|
||||
mText = in.readAll();
|
||||
if (in.status()==QTextStream::Ok)
|
||||
mResult = true;
|
||||
else
|
||||
mText = "";
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
if (mResult)
|
||||
mErrormsg = tr("Style sheet data read from '%1'").arg(QDir::toNativeSeparators(path));
|
||||
else
|
||||
mErrormsg = tr("Style sheet data unable to be read from '%1'").arg(QDir::toNativeSeparators(path));
|
||||
qDebug() << mErrormsg;
|
||||
return mResult;
|
||||
}
|
||||
|
||||
bool Stylesheet::update()
|
||||
{
|
||||
mResult = false;
|
||||
mErrormsg = "";
|
||||
QDir path(mCustomPath);
|
||||
if (!path.exists()) {
|
||||
QDir dir;
|
||||
if (!dir.mkpath(mCustomPath))
|
||||
mErrormsg = tr("Cannot create folder '%1'").arg(QDir::toNativeSeparators(mCustomPath));
|
||||
}
|
||||
if (path.exists()) {
|
||||
QFile file(mCustomFile);
|
||||
if (!file.open(QFile::WriteOnly | QFile::Text)) {
|
||||
mErrormsg = tr("Cannot open file for writing '%1': Error: %2").arg(QDir::toNativeSeparators(mCustomFile), file.errorString());
|
||||
}
|
||||
else {
|
||||
QTextStream out(&file);
|
||||
if (out.status()==QTextStream::Ok) {
|
||||
out << mText;
|
||||
if (!(out.status()==QTextStream::Ok)) {
|
||||
mErrormsg = tr("Cannot write to file '%1': Error: %2").arg(QDir::toNativeSeparators(mCustomFile), file.errorString());
|
||||
if (!file.flush()) {
|
||||
mErrormsg = tr("Cannot flush buffer for file '%1': Error: %2").arg(QDir::toNativeSeparators(mCustomFile), file.errorString());
|
||||
}
|
||||
}
|
||||
else {
|
||||
mResult = true;
|
||||
mErrormsg = tr("Style sheet written to '%1'").arg(QDir::toNativeSeparators(mCustomFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
qDebug() << mErrormsg;
|
||||
return mResult;
|
||||
}
|
||||
|
||||
bool Stylesheet::deleteCustom()
|
||||
{
|
||||
QFile file(mCustomFile);
|
||||
mResult = file.remove();
|
||||
if (mResult)
|
||||
mErrormsg = tr("Custom style sheet deleted: '%1'").arg(QDir::toNativeSeparators(mCustomFile));
|
||||
else
|
||||
mErrormsg = tr("Unable to delete custom style sheet: '%1'").arg(QDir::toNativeSeparators(mCustomFile));
|
||||
qDebug() << mErrormsg;
|
||||
return mResult;
|
||||
}
|
||||
|
||||
QString Stylesheet::name()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
QString Stylesheet::text()
|
||||
{
|
||||
return mText;
|
||||
}
|
||||
|
||||
void Stylesheet::setText(const QString & text)
|
||||
{
|
||||
mText = text;
|
||||
}
|
||||
|
||||
QString Stylesheet::errormsg()
|
||||
{
|
||||
return mErrormsg;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,11 +21,54 @@
|
||||
#ifndef _HELPERS_HTML_H_
|
||||
#define _HELPERS_HTML_H_
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
QString doTC(const QString &s, const QString &color="", bool bold=false);
|
||||
QString doTR(const QString &s, const QString &color="", bool bold=false);
|
||||
QString doTL(const QString &s, const QString &color="", bool bold=false);
|
||||
QString fv(const QString &name, const QString &value, const QString &color="green");
|
||||
#define THEMES_DEFAULT_PATH ":/themes/default/"
|
||||
#define MODEL_PRINT_CSS "modelprt.css"
|
||||
|
||||
QString tdAlign(const QString & s, const QString & align, const QString & color, bool bold);
|
||||
QString doTC(const QString & s, const QString & color = "", bool bold = false);
|
||||
QString doTR(const QString & s, const QString & color = "", bool bold = false);
|
||||
QString doTL(const QString & s, const QString & color = "", bool bold = false);
|
||||
QString fv(const QString & name, const QString & value, const QString & color = "green");
|
||||
QString doTableCell(const QString & s, const unsigned int width = 0, const QString & align = "", const QString & color = "", bool bold = false);
|
||||
QString doTableRow(const QStringList & strl, const unsigned int width = 0, const QString & align = "", const QString & color = "", bool bold = false);
|
||||
QString doTableBlankRow();
|
||||
|
||||
class Stylesheet: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum StyleType {
|
||||
STYLE_TYPE_NONE,
|
||||
STYLE_TYPE_DEFAULT,
|
||||
STYLE_TYPE_CUSTOM,
|
||||
STYLE_TYPE_EFFECTIVE
|
||||
};
|
||||
|
||||
Stylesheet(const QString & name);
|
||||
Stylesheet(const QString & name, const StyleType styleType);
|
||||
~Stylesheet();
|
||||
bool load(const StyleType styleType);
|
||||
bool update();
|
||||
bool deleteCustom();
|
||||
QString name();
|
||||
QString text();
|
||||
QString errormsg();
|
||||
void setText(const QString & text);
|
||||
|
||||
private:
|
||||
bool mResult;
|
||||
QString mErrormsg;
|
||||
QString mName;
|
||||
QString mText;
|
||||
QString mCustomFile;
|
||||
QString mCustomPath;
|
||||
QString mDefaultFile;
|
||||
void init();
|
||||
bool read(const QString & filepath);
|
||||
};
|
||||
|
||||
#endif // _HELPERS_HTML_H_
|
||||
|
||||
|
Before Width: | Height: | Size: 78 KiB |
@@ -1 +0,0 @@
|
||||
IDI_ICON1 ICON DISCARDABLE "icon.ico"
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 206 B |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |