Compare commits
864 Commits
Author | SHA1 | Date |
---|---|---|
Matt McWilliams | 5f7fa6287f | |
Matt McWilliams | 2af8b4b209 | |
Matt McWilliams | 66096fa2ea | |
Matt McWilliams | 18875a01c6 | |
Matt McWilliams | 7d2c2b9d09 | |
Matt McWilliams | 67a290a02a | |
Matt McWilliams | 63f4278b2b | |
Matt McWilliams | 6778f871db | |
Matt McWilliams | edc72a5486 | |
Matt McWilliams | 2779258111 | |
Matt McWilliams | da735779b4 | |
Matt McWilliams | b7e2e912f4 | |
Matt McWilliams | d34172d8e9 | |
Matt McWilliams | f30ce78f9d | |
Matt McWilliams | ed767aedb5 | |
Matt McWilliams | ab35895cb3 | |
Matt McWilliams | 1e2b65644d | |
Matt McWilliams | 3f58bbc617 | |
Matt McWilliams | c1da7b53a2 | |
Matt McWilliams | 4181c22995 | |
Matt McWilliams | d31ac53bd1 | |
Matt McWilliams | 9b954852aa | |
Matt McWilliams | 3758916fb5 | |
Matt McWilliams | 25c1395655 | |
Matt McWilliams | 440edd7b18 | |
Matt McWilliams | a2f045841f | |
Matt McWilliams | c890107e1e | |
Matt McWilliams | a5df1650b9 | |
Matt McWilliams | 173ce499bc | |
Matt McWilliams | 33412b0588 | |
Matt McWilliams | 3c5e31a961 | |
Matt McWilliams | 39676f9a06 | |
Matt McWilliams | 0f893d94c4 | |
Matt McWilliams | b08f5094d5 | |
Matt McWilliams | 70e046eeb7 | |
Matt McWilliams | 58d0742187 | |
Matt McWilliams | f84e8b741a | |
Matt McWilliams | fcf24b5539 | |
Matt McWilliams | 128a4d2ded | |
Matt McWilliams | b14d24e650 | |
Matt McWilliams | 7995665c6b | |
Matt McWilliams | a22906d3c2 | |
Matt McWilliams | 042533dc85 | |
Matt McWilliams | 5fbefeecbf | |
Matt McWilliams | a9772ff081 | |
Matt McWilliams | cdf983c7c6 | |
Matt McWilliams | 03f886580f | |
Matt McWilliams | a06e2869b9 | |
Matt McWilliams | 6bafb263de | |
Matt McWilliams | 493ff5fbf6 | |
Matt McWilliams | c29e0880ac | |
Matt McWilliams | 986c7a915b | |
Matt McWilliams | 68b1b8b819 | |
Matt McWilliams | 382ba56fa7 | |
Matt McWilliams | 24d6685047 | |
Matt McWilliams | 565d2ecceb | |
Matt McWilliams | c4456e458f | |
Matt McWilliams | f707dedc91 | |
Matt McWilliams | 702fc4680d | |
Matt McWilliams | 99b63150ac | |
Matt McWilliams | 6e7c226c57 | |
Matt McWilliams | c8e5f7b742 | |
Matt McWilliams | 0cf147d185 | |
Matt McWilliams | cf1514f53e | |
Matt McWilliams | af3843a8ef | |
Matt McWilliams | 91ce2dd450 | |
Matt McWilliams | 71c9efae42 | |
Matt McWilliams | 08ce0d792b | |
Matt McWilliams | 754ef17b74 | |
Matt McWilliams | 5d4fec8c81 | |
Matt McWilliams | 1e0338a77f | |
Matt McWilliams | e6b9628746 | |
Matt McWilliams | 6f68081dc5 | |
Matt McWilliams | 66b18dd351 | |
Matt McWilliams | b5f5b6461a | |
Matt McWilliams | 6dd29d9596 | |
Matt McWilliams | 29ba125534 | |
Matt McWilliams | 144af1414c | |
Matt McWilliams | 06906eca42 | |
Matt McWilliams | 0d47748d6a | |
Matt McWilliams | b1c8192625 | |
Matt McWilliams | d2c7781d79 | |
Matt McWilliams | 37d4f50ef4 | |
Matt McWilliams | 082ac85c5c | |
Matt McWilliams | cfca56ba48 | |
Matt McWilliams | c7cb4ddbc5 | |
Matt McWilliams | 7f98d6028b | |
Matt McWilliams | 401822a7bb | |
Matt McWilliams | 173ba06590 | |
Matt McWilliams | 2677118bad | |
Matt McWilliams | 8e90456d87 | |
Matt McWilliams | 0b880a5e79 | |
Matt McWilliams | 082dbc0826 | |
Matt McWilliams | 5eccbbf6df | |
Matt McWilliams | 513deb7a0a | |
Matt McWilliams | 2b24dc647c | |
Matt McWilliams | f8e5968f30 | |
Matt McWilliams | 18b8c84fff | |
Matt McWilliams | 1d6ccb7838 | |
Matt McWilliams | a7a63a3be7 | |
Matt McWilliams | 153ef9eceb | |
Matt McWilliams | eec7765e73 | |
Matt McWilliams | 03f2b55762 | |
Matt McWilliams | 6714374639 | |
Matt McWilliams | b6b1f5d5ba | |
Matt McWilliams | d7a10f9737 | |
Matt McWilliams | d778adc7d0 | |
Matt McWilliams | dcbb57f732 | |
Matt McWilliams | 24452794a9 | |
Matt McWilliams | 24fe1e8773 | |
Matt McWilliams | b30c637c10 | |
Matt McWilliams | f16795b11c | |
Matt McWilliams | 141d27599f | |
Matt McWilliams | 86c88c4ac2 | |
Matt McWilliams | fbab0c043a | |
Matt McWilliams | 1a01a4f05e | |
Matt McWilliams | b0305ae6da | |
Matt McWilliams | dd4834de04 | |
Matt McWilliams | 2d90c127a3 | |
Matt McWilliams | 51d440fccc | |
Matt McWilliams | 2e3ed56bb3 | |
Matt McWilliams | 4be57f3128 | |
Matt McWilliams | de6f0d0495 | |
Matt McWilliams | 98e1e73163 | |
Matt McWilliams | 1ae524ff31 | |
Matt McWilliams | 010927c5ca | |
Matt McWilliams | 3346bf01af | |
Matt McWilliams | 788cac7d50 | |
Matt McWilliams | 4c0fa2ba41 | |
Matt McWilliams | 83209f466f | |
Matt McWilliams | 10c452c1b3 | |
Matt McWilliams | a8a33a823a | |
Matt McWilliams | e7e7f86ab3 | |
Matt McWilliams | 386285d48c | |
Matt McWilliams | c4119ab7cc | |
Matt McWilliams | 176643f148 | |
Matt McWilliams | 8b235bb6b0 | |
Matt McWilliams | 8a170f65ca | |
Matt McWilliams | 2f56dd4b8a | |
Matt McWilliams | 699c2dbec8 | |
Matt McWilliams | dac720863d | |
Matt McWilliams | 3b03eb70fb | |
Matt McWilliams | a173cf0d7c | |
Matt McWilliams | 55b39e7db3 | |
Matt McWilliams | 505a2a71e7 | |
Matt McWilliams | fb51716e3a | |
Matt McWilliams | bdd74fa90a | |
Matt McWilliams | 8631250b9e | |
Matt McWilliams | c9f35ffe90 | |
Matt McWilliams | 18d6e2c7cd | |
Matt McWilliams | f47ea2d382 | |
Matt McWilliams | 0cc167b3a6 | |
Matthew McWilliams | 5133295f38 | |
Matt McWilliams | 621948fbac | |
Matt McWilliams | 4539c6d897 | |
Matt McWilliams | a7db072dc6 | |
Matt McWilliams | 58ce079330 | |
Matt McWilliams | dd03583a27 | |
Matt McWilliams | 3feaea74bf | |
Matt McWilliams | 1d6cbe5c53 | |
Matt McWilliams | 318f931dbf | |
Matt McWilliams | 5400518ea6 | |
Matt McWilliams | f73a1e3931 | |
Matthew McWilliams | 60d7ab4b5e | |
Matthew McWilliams | 95cde2907a | |
Matthew McWilliams | 35b67f1815 | |
Matt McWilliams | f958789b20 | |
Matt McWilliams | 4beef04a3f | |
Matthew McWilliams | 6d379d284b | |
Matt McWilliams | 2c21110b97 | |
Matt McWilliams | 777db577d7 | |
Matt McWilliams | bf320216cf | |
Matt McWilliams | b48c498574 | |
Matt McWilliams | 0b71da8e7b | |
Matt McWilliams | c0d6cbccec | |
Matt McWilliams | 95ede98623 | |
Matt McWilliams | 3881dd4891 | |
Matt McWilliams | 71e4bea384 | |
Matt McWilliams | 83aa3099c4 | |
Matt McWilliams | 672db32917 | |
Matt McWilliams | 80a9c23f4d | |
Matt McWilliams | 49ad3c28a8 | |
Matt McWilliams | a29c85628c | |
Matt McWilliams | 3ec93ab3b1 | |
Matt McWilliams | 10c29d3af1 | |
Matt McWilliams | 41840b90c8 | |
Matt McWilliams | c89e865d3d | |
Matt McWilliams | c6ec54bd06 | |
Matt McWilliams | af3b1b8cbb | |
Matt McWilliams | 86273a9f09 | |
Matt McWilliams | ba0241a811 | |
Matt McWilliams | 1bd73876b4 | |
Matt McWilliams | cc806cbe52 | |
Matt McWilliams | 8f7a40075a | |
Matt McWilliams | 64faaa9427 | |
Matt McWilliams | d44c67ce80 | |
Matt McWilliams | 144b408092 | |
Matt McWilliams | d2390dca30 | |
Matt McWilliams | 503a8ec92f | |
Matt McWilliams | ca22a3ba4b | |
Matt McWilliams | ef54e61494 | |
Matt McWilliams | b1745c786b | |
Matt McWilliams | 83efbc18c7 | |
Matthew McWilliams | f47396e48c | |
Matt McWilliams | 03c27a9226 | |
Matt McWilliams | 08655898d4 | |
Matt McWilliams | 5d347d23e4 | |
Matthew McWilliams | a25d93ec55 | |
Matthew McWilliams | bbf0cbd1c6 | |
Matthew McWilliams | 4aceeac1c2 | |
Matt McWilliams | 1f5bb85304 | |
Matthew McWilliams | 087fd3f763 | |
Matthew McWilliams | daece3b45a | |
Matthew McWilliams | 9705505285 | |
Matthew McWilliams | 9016062f70 | |
Matthew McWilliams | a6de66eb66 | |
Matt McWilliams | 6ada6b08ed | |
Matt McWilliams | 710e178ba2 | |
Matt McWilliams | 9e7990851e | |
Matt McWilliams | ae34558f18 | |
Matt McWilliams | c1a51f1ce8 | |
Matt McWilliams | 13702a3d5b | |
Matt McWilliams | 6b66cfe03f | |
Matt McWilliams | cbc876c57c | |
Matt McWilliams | 7813a8c904 | |
Matt McWilliams | 5f941e91b5 | |
Matt McWilliams | d262ed418d | |
Matt McWilliams | 2e9db4d667 | |
Matt McWilliams | bd9317dd8f | |
Matt McWilliams | 461add1cda | |
Matt McWilliams | 1528dec668 | |
Matt McWilliams | fff9d5d410 | |
Matt McWilliams | 231c354cb1 | |
Matt McWilliams | 4e0149e752 | |
Matt McWilliams | 5c6b9191e5 | |
Matt McWilliams | 77a0f7d8a0 | |
Matt McWilliams | 9faae6fc36 | |
Matt McWilliams | 3689eb7528 | |
Matt McWilliams | 210dc85558 | |
Matt McWilliams | 174b900cd8 | |
Matt McWilliams | fbe954280f | |
Matt McWilliams | 142c990a0e | |
Matt McWilliams | 790ea3d551 | |
Matt McWilliams | c6b8592490 | |
Matt McWilliams | f67e011d5e | |
Matt McWilliams | a4bc54482d | |
Matt McWilliams | be50eb6fcf | |
Matt McWilliams | a7d784583a | |
Matt McWilliams | 7af1f739e4 | |
Matt McWilliams | 3e247703a8 | |
Matt McWilliams | c7e338ebff | |
Matt McWilliams | cc2af435d5 | |
Matt McWilliams | 87695b173d | |
Matt McWilliams | 722ff9c05e | |
Matt McWilliams | 51114df576 | |
Matt McWilliams | 9126bc82c0 | |
Matt McWilliams | e09fe7d42f | |
Matt McWilliams | 234e69c7a2 | |
Matt McWilliams | d7017af245 | |
Matt McWilliams | f49c70ead6 | |
Matt McWilliams | 9a89dbe6a5 | |
Matt McWilliams | 844bb286a5 | |
Matt McWilliams | 4eceecf139 | |
Matt McWilliams | 95e2e997e5 | |
Matt McWilliams | 346c303edb | |
Matt McWilliams | 908fe52ad8 | |
Matt McWilliams | 3fd1e47b7b | |
Matt McWilliams | d41f082839 | |
Matt McWilliams | 2047ce4f76 | |
Matt McWilliams | 3ef56cab21 | |
Matt McWilliams | 6b77b98aad | |
Matt McWilliams | 211101cd6b | |
Matt McWilliams | e27cae353f | |
Matt McWilliams | b12a08e47a | |
Matt McWilliams | 9b298ac676 | |
Matt McWilliams | 52acb97e08 | |
Matt McWilliams | 78450e9e6a | |
Matt McWilliams | dc746fe6f4 | |
Matt McWilliams | 0e3bc563a7 | |
Matt McWilliams | d0ef5d410d | |
Matt McWilliams | d9aa7dc698 | |
Matt McWilliams | 70ab8cb527 | |
Matt McWilliams | 512f6c86ad | |
Matt McWilliams | d23eb290d9 | |
Matt McWilliams | 648bca5b2e | |
Matt McWilliams | 5db5d477e4 | |
Matt McWilliams | 7741134917 | |
Matt McWilliams | 3c19cd35cf | |
Matt McWilliams | 85832d18f6 | |
Matt McWilliams | 5f0da91659 | |
Matt McWilliams | e1bf69e622 | |
Matt McWilliams | d9290f7262 | |
Matt McWilliams | 81b6846261 | |
Matt McWilliams | a57519adce | |
Matt McWilliams | 02639466ee | |
Matt McWilliams | 6e2795d380 | |
Matt McWilliams | 8e35596088 | |
Matt McWilliams | 0162d012c5 | |
Matt McWilliams | 47fb673b78 | |
Matt McWilliams | f296488bc2 | |
Matt McWilliams | f5392aea9f | |
Matt McWilliams | 24b1301f9f | |
Matt McWilliams | 1290a8f324 | |
Matt McWilliams | e64277e438 | |
Matt McWilliams | c9bcb74a9f | |
Matt McWilliams | 42db1f81b8 | |
Matt McWilliams | 7222952eba | |
Matt McWilliams | 744f10c948 | |
Matt McWilliams | b50704a6a8 | |
Matt McWilliams | c152806511 | |
Matt McWilliams | 4d9454daf2 | |
Matt McWilliams | e754c65602 | |
Matt McWilliams | b672921c84 | |
Matt McWilliams | 6116ada2fd | |
Matt McWilliams | d7baa4d17b | |
Matt McWilliams | ebc5504998 | |
Matt McWilliams | c5e66a6f40 | |
Matt McWilliams | cff558ef9a | |
Matt McWilliams | 325837d93e | |
Matt McWilliams | 135540b261 | |
Matt McWilliams | 49464cd25a | |
Matt McWilliams | d0fe54b429 | |
Matt McWilliams | 2dce6f4b08 | |
Matt McWilliams | 99794d04c2 | |
Matt McWilliams | cc06655cd6 | |
Matt McWilliams | ab6f517d27 | |
Matt McWilliams | 682167db48 | |
Matt McWilliams | f127dc1128 | |
Matt McWilliams | 0b816ae8e1 | |
Matt McWilliams | c600fea4e1 | |
Matt McWilliams | 92067bdbef | |
Matt McWilliams | c181e003a3 | |
Matt McWilliams | 597137670d | |
Matt McWilliams | 3036aebbc4 | |
Matt McWilliams | cbe6477af2 | |
Matthew McWilliams | c2546d2bc5 | |
Matt McWilliams | 46be1bfd3b | |
Matt McWilliams | 1029885047 | |
Matt McWilliams | 164bde8cce | |
Matt McWilliams | 41504caac9 | |
Matt McWilliams | 9b34b4e026 | |
Matt McWilliams | 95612c1d18 | |
Matt McWilliams | 0829ec9081 | |
Matt McWilliams | ef0d246901 | |
Matt McWilliams | 622a8a7c42 | |
Matt McWilliams | 925659ba4b | |
Matt McWilliams | 20c9287ac2 | |
Matt McWilliams | 8aaa2b8940 | |
Matt McWilliams | 30bd35e21d | |
Matthew McWilliams | 0c2e39f0b2 | |
Matt McWilliams | cbd7001228 | |
Matt McWilliams | dec96ec9be | |
Matt McWilliams | 3942cd05be | |
Matt McWilliams | ee1e9c9feb | |
Matt McWilliams | fcb77232ec | |
Matt McWilliams | 1fcbec7466 | |
Matt McWilliams | 98f2c7a24a | |
Matt McWilliams | 787e6ed06e | |
Matt McWilliams | bb5b7c7897 | |
Matt McWilliams | 42b3aa767d | |
Matt McWilliams | b20a6084e6 | |
Matthew McWilliams | d9a8576701 | |
Matthew McWilliams | 69273d2a1c | |
Matthew McWilliams | 755ea757f7 | |
Matt McWilliams | 81fc54af8d | |
Matt McWilliams | 4281ca4390 | |
Matt McWilliams | 3419172535 | |
Matt McWilliams | 206c266b08 | |
Matthew McWilliams | 5026cf869f | |
Matthew McWilliams | d5ecd9e057 | |
Matthew McWilliams | 72b5077356 | |
Matthew McWilliams | 6601c030f7 | |
Matthew McWilliams | 3ec1373f08 | |
Matt McWilliams | b29478cb58 | |
Matt McWilliams | fe61e63e76 | |
Matt McWilliams | ee0ab663d7 | |
Matt McWilliams | 1964d6002d | |
Matt McWilliams | f55b72044c | |
Matt McWilliams | 3f759f5678 | |
Matt McWilliams | 6582154ec6 | |
Matt McWilliams | 9d0545aa4f | |
Matt McWilliams | ea055d6e56 | |
Matthew McWilliams | bc48765b35 | |
Matthew McWilliams | 70c2c695f0 | |
Matthew McWilliams | 8ec5816364 | |
Matthew McWilliams | c33c6e24f6 | |
Matt McWilliams | b0ca15bd8d | |
Matt McWilliams | 76799bd66d | |
Matthew McWilliams | 18dbb72a54 | |
Matthew McWilliams | c0ec81c0f9 | |
Matt McWilliams | c3661d6ff1 | |
Matt McWilliams | c0f056cd8d | |
Matt McWilliams | 2924efe39f | |
Matt McWilliams | e275539fb0 | |
Matt McWilliams | 4c13c54815 | |
Matt McWilliams | 62a66f5f6d | |
Matt McWilliams | 3a435933e3 | |
Matt McWilliams | 78f7ac0e68 | |
Matt McWilliams | 28dc19fc32 | |
Matt McWilliams | 585c47d6c7 | |
Matt McWilliams | 04a0330327 | |
Matt McWilliams | dae4e65aee | |
Matt McWilliams | 129647b863 | |
Matt McWilliams | 2f9201716a | |
Matt McWilliams | f9d716552b | |
Matt McWilliams | 818c8453ee | |
Matthew McWilliams | f7a3c52260 | |
Matt McWilliams | 9d3bf24627 | |
Matt McWilliams | c77201ef4e | |
Matt McWilliams | f585aa2a5a | |
Matt McWilliams | 96e0ce6050 | |
Matt McWilliams | 17d4ff459f | |
Matt McWilliams | c15c376a2f | |
Matt McWilliams | 22bed4632b | |
Matt McWilliams | 8b5faaa1a4 | |
Matt McWilliams | 81d94fd727 | |
Matt McWilliams | bbfe6fc657 | |
Matt McWilliams | 467a5c06d6 | |
Matt McWilliams | 9dce9fb1f2 | |
Matt McWilliams | e1c8ba1320 | |
mmcwilliams | 4ef318c55e | |
mmcwilliams | 7f7513809a | |
Matt McWilliams | b3bb07454f | |
Matt McWilliams | faad084b2b | |
Matt McWilliams | 3e528c23a5 | |
Matt McWilliams | 6fed941441 | |
Matt McWilliams | 6fee5a803c | |
Matt McWilliams | 2861bc52fd | |
Matt McWilliams | 8c14a06b96 | |
Matt McWilliams | 3e0ac3f0d0 | |
Matt McWilliams | 394fbe2323 | |
Matt McWilliams | 11267796ba | |
Matt McWilliams | aac5e5d488 | |
Matt McWilliams | 8a6bc0b4f5 | |
Matt McWilliams | a2af605d37 | |
Matt McWilliams | 32f70be614 | |
Matt McWilliams | 31c701734a | |
Matt McWilliams | fb7b1e2fb6 | |
Matt McWilliams | 5061a511ab | |
Matt McWilliams | c0121bcfe7 | |
Matt McWilliams | 66639e951b | |
Matt McWilliams | 53d147b9bc | |
Matt McWilliams | ad1ac51fc8 | |
Matt McWilliams | 88a6e9f563 | |
Matt McWilliams | 7dc4d153be | |
Matt McWilliams | dcc91501ee | |
Matt McWilliams | 6473f388d8 | |
Matt McWilliams | a21fff82f1 | |
Matt McWilliams | 2c8eabeffd | |
Matt McWilliams | 85bfa57127 | |
Matt McWilliams | 112e6b543c | |
Matt McWilliams | 232f39b861 | |
Matt McWilliams | 338a60f947 | |
Matt McWilliams | 9ab1436d49 | |
Matt McWilliams | 8d3c035e7b | |
sixteenmillimeter | 10b823bca8 | |
sixteenmillimeter | 7f9020e698 | |
sixteenmillimeter | 6a563e131b | |
dependabot[bot] | 1fb5c984ac | |
dependabot[bot] | b90a68cb39 | |
dependabot[bot] | 7ebfe16897 | |
sixteenmillimeter | e84f1ce8ff | |
sixteenmillimeter | eb7e62aac7 | |
sixteenmillimeter | dab5c67c04 | |
sixteenmillimeter | 69ca62f884 | |
dependabot[bot] | 53941835cb | |
dependabot[bot] | 7d4e53fe24 | |
sixteenmillimeter | 6f19842da0 | |
sixteenmillimeter | 3692195887 | |
sixteenmillimeter | e672c2dc93 | |
sixteenmillimeter | 65292524b1 | |
sixteenmillimeter | 5e481e77b0 | |
sixteenmillimeter | 7c9543239e | |
sixteenmillimeter | 8672b6584a | |
sixteenmillimeter | c5d7f9c91f | |
sixteenmillimeter | 9502d255c7 | |
sixteenmillimeter | 08c3c23da0 | |
sixteenmillimeter | 6eeeae85c8 | |
sixteenmillimeter | 7c61af7043 | |
sixteenmillimeter | d501623290 | |
sixteenmillimeter | 0ccb29dfb0 | |
sixteenmillimeter | f02782d4da | |
sixteenmillimeter | c2e83ab27b | |
sixteenmillimeter | 32356b0037 | |
sixteenmillimeter | dd1bec8394 | |
sixteenmillimeter | 4f2252d113 | |
sixteenmillimeter | 0145bebb4b | |
mmcwilliams | 5e6fbbb43c | |
mmcwilliams | 7e516a59b6 | |
mmcwilliams | 948b20fead | |
mmcwilliams | c61c128044 | |
mmcwilliams | 296ef93ecb | |
sixteenmillimeter | 74621ef1fb | |
sixteenmillimeter | 0811222d27 | |
sixteenmillimeter | 0c364576c9 | |
dependabot[bot] | 7ff49f0aa6 | |
dependabot[bot] | a9b678f748 | |
dependabot[bot] | f2fd77a858 | |
sixteenmillimeter | 8c97258866 | |
sixteenmillimeter | 5c691a8e12 | |
sixteenmillimeter | e5e4c7ded7 | |
sixteenmillimeter | a748f689bd | |
sixteenmillimeter | 5309f85638 | |
sixteenmillimeter | efc6d0ef03 | |
sixteenmillimeter | a379e4b086 | |
sixteenmillimeter | 4a1bf417a4 | |
mmcwilliams | b702929e1f | |
sixteenmillimeter | d042381293 | |
dependabot[bot] | 9805127387 | |
dependabot[bot] | 270862bd5f | |
sixteenmillimeter | 53e012018f | |
sixteenmillimeter | 420a3fbd50 | |
sixteenmillimeter | 5258fcbf30 | |
sixteenmillimeter | 4db3ce8b88 | |
sixteenmillimeter | e3d36a1f27 | |
sixteenmillimeter | 67d0e750c2 | |
mmcwilliams | f4eb066725 | |
mmcwilliams | fb63bade2f | |
Matt | ed0175b733 | |
mmcwilliams | 8163f7d454 | |
mmcwilliams | 5ec50713ba | |
Matt | 37719b9974 | |
sixteenmillimeter | 3fd2b04e75 | |
mmcwilliams | c15cd512ae | |
mmcwilliams | cc41b75130 | |
mmcwilliams | f929ea2cc2 | |
mmcwilliams | d4987ed3a3 | |
mmcwilliams | da00c62db3 | |
sixteenmillimeter | 55c460fbb4 | |
sixteenmillimeter | 01cac728f5 | |
sixteenmillimeter | 8d5663d3a2 | |
sixteenmillimeter | 1c940d6df7 | |
sixteenmillimeter | 891c34ad88 | |
sixteenmillimeter | aec5b79f90 | |
sixteenmillimeter | e25a8bbc7c | |
sixteenmillimeter | d70de98256 | |
sixteenmillimeter | aec3e29476 | |
sixteenmillimeter | 32fe873707 | |
sixteenmillimeter | 549cd3cc04 | |
sixteenmillimeter | 8dc955a5e7 | |
sixteenmillimeter | ed75924e24 | |
sixteenmillimeter | 49ba9a090b | |
sixteenmillimeter | 691e741d70 | |
sixteenmillimeter | 35b8b0def2 | |
mmcwilliams | 529c275c0f | |
mmcwilliams | d604f2aab5 | |
mmcwilliams | b0c7e4eed4 | |
mmcwilliams | c6d0256929 | |
mmcwilliams | b74fd270e2 | |
mmcwilliams | 4d022883ff | |
sixteenmillimeter | b595225870 | |
sixteenmillimeter | fc2593c6ee | |
sixteenmillimeter | 4c0aa4220c | |
mmcwilliams | 42621bbf71 | |
mmcwilliams | 4c8c2b66f3 | |
mmcwilliams | c6ebab4032 | |
mmcwilliams | 3fb276f401 | |
mmcwilliams | bf4ef96a06 | |
sixteenmillimeter | 6ec81a3429 | |
sixteenmillimeter | 00ccf4cb8f | |
sixteenmillimeter | 09da9500b5 | |
mmcwilliams | de7015022f | |
mmcwilliams | e59d165689 | |
mmcwilliams | 1075c7ff4a | |
mmcwilliams | 4461670e14 | |
mmcwilliams | 8e4c32073a | |
sixteenmillimeter | ac1da17b8d | |
sixteenmillimeter | 9b2ed018bf | |
sixteenmillimeter | 51acbdfd30 | |
mmcwilliams | 5ce0aed2ff | |
sixteenmillimeter | f0c28b8624 | |
mmcwilliams | 5f701ccecb | |
mmcwilliams | cfa22d3a1d | |
mmcwilliams | 1b83fe6937 | |
mmcwilliams | 2ff98a2148 | |
mmcwilliams | 30c36baa9c | |
mmcwilliams | bd79025305 | |
mmcwilliams | 7c4e9d5823 | |
mmcwilliams | 5695bfd645 | |
mmcwilliams | c5f3c72f73 | |
mmcwilliams | 7e05b5f680 | |
mmcwilliams | 741d4619ee | |
mmcwilliams | 7c50b66499 | |
mmcwilliams | 96d0897f65 | |
mmcwilliams | c01f3ceff8 | |
mmcwilliams | 4023704d31 | |
mmcwilliams | 798e9ce1a3 | |
mmcwilliams | 6612ffa6d1 | |
mmcwilliams | 07100a588c | |
mmcwilliams | 0b2d386ca2 | |
mmcwilliams | 4b5dd4868b | |
mmcwilliams | f0804fe23b | |
mmcwilliams | 97591b1c1d | |
mmcwilliams | b5da7ba233 | |
mmcwilliams | 0f52812767 | |
mmcwilliams | 0d6c3e44b0 | |
mmcwilliams | 60147e3b0f | |
mmcwilliams | f8c64b45a7 | |
mmcwilliams | 504912009b | |
mmcwilliams | 084916c317 | |
mmcwilliams | 073e778a3b | |
mmcwilliams | b5465384ce | |
mmcwilliams | 45f96e6537 | |
mmcwilliams | f8fc9fded6 | |
mmcwilliams | f239f862e8 | |
mmcwilliams | 872b46d4a5 | |
mmcwilliams | ddfc46a48f | |
mmcwilliams | ad67e2f010 | |
mmcwilliams | 9331a766df | |
mmcwilliams | 6b10e9c28d | |
mmcwilliams | d15fe37de5 | |
mmcwilliams | 5014a2db38 | |
mmcwilliams | f3e885df35 | |
mmcwilliams | 98a0eff503 | |
mmcwilliams | 6cda9aed1d | |
mmcwilliams | 9a464a2fcf | |
mmcwilliams | a4f8ffc3c6 | |
mmcwilliams | 23a7896db9 | |
mmcwilliams | e25054117f | |
mmcwilliams | 2e4ef09a60 | |
mmcwilliams | 717cf77e55 | |
mmcwilliams | ede6fcdfb8 | |
mmcwilliams | 6fcb85bca2 | |
mmcwilliams | 0cff7c5794 | |
mmcwilliams | 9b17d5cd47 | |
mmcwilliams | 8ebbd0ac47 | |
mmcwilliams | 49f9f7f160 | |
mmcwilliams | 22187777e7 | |
mmcwilliams | 00b26719f6 | |
mmcwilliams | d6da1824cd | |
mmcwilliams | 23d663c3e7 | |
mmcwilliams | 1e2b542e4c | |
mmcwilliams | 5cd6b22ea4 | |
mmcwilliams | 32f02d42ce | |
mmcwilliams | 7740dc39ec | |
mmcwilliams | 07940bc2c6 | |
mmcwilliams | 7c43f2de2c | |
mmcwilliams | 39e6ab5247 | |
mmcwilliams | 76c7b49142 | |
mmcwilliams | 5b418aeccd | |
mmcwilliams | b5fbe0153b | |
mmcwilliams | da7d14e898 | |
mmcwilliams | 3aeb971b4d | |
mmcwilliams | dab5c34bad | |
mmcwilliams | 596832119b | |
mmcwilliams | 6442d99817 | |
mmcwilliams | a7c7715207 | |
mmcwilliams | e3d213e4f1 | |
mmcwilliams | c169b7fbae | |
mmcwilliams | d8e5e4521a | |
mmcwilliams | 418670ce33 | |
mmcwilliams | 8ddc6e5a20 | |
mmcwilliams | f015a6f2c5 | |
mmcwilliams | 7907ba9533 | |
mmcwilliams | 1fd3b83ca1 | |
mmcwilliams | 35a540f5df | |
mmcwilliams | da6fef6080 | |
mmcwilliams | 9a0ebcca06 | |
mmcwilliams | 93144322db | |
Matt | 8e832d0aa3 | |
mmcwilliams | 02ca59ea7e | |
mmcwilliams | ce226a7f86 | |
mmcwilliams | 4ea390897a | |
mmcwilliams | c942d89572 | |
mmcwilliams | d0cc8eca70 | |
mmcwilliams | 2e8d20f40a | |
mmcwilliams | 5c9091d957 | |
mmcwilliams | 1b3f554492 | |
mmcwilliams | 67a009ae8d | |
mmcwilliams | 4dd69319e5 | |
mmcwilliams | 39301f5b59 | |
mmcwilliams | ab8d7f57e9 | |
mmcwilliams | 867d6a4069 | |
mmcwilliams | f33dbb2f1b | |
mmcwilliams | 1111800383 | |
mmcwilliams | abaeb1cbda | |
mmcwilliams | 4f9de487cc | |
mmcwilliams | e15d03a536 | |
mmcwilliams | ad558608ee | |
mmcwilliams | 1a612376cb | |
mmcwilliams | a241ef0a2a | |
mmcwilliams | 687e1887ee | |
mmcwilliams | 5e0947d343 | |
mmcwilliams | 1fe71cefca | |
mmcwilliams | 88e470c5ac | |
mmcwilliams | 2d7599472e | |
mmcw-dev | bb2bfabf9c | |
mmcw-dev | b33ef36ab4 | |
mmcw-dev | ed14564de7 | |
mmcw-dev | 9603f82c49 | |
mmcw-dev | 52aac3f8b0 | |
mmcw-dev | 4f7dd92311 | |
mmcw-dev | 265f383f65 | |
mmcw-dev | 11b389172c | |
mmcw-dev | dac70a122f | |
mmcwilliams | 7a52bc7c6e | |
mmcwilliams | 18c515402e | |
mmcwilliams | cda100b3e6 | |
mmcwilliams | 63e42f2dd3 | |
mmcwilliams | fd09e7c024 | |
mmcw-dev | d995a4800d | |
mmcwilliams | 96754fcf49 | |
mmcwilliams | d1480181b3 | |
mmcwilliams | d6fd83762e | |
mmcwilliams | 7d2033db3d | |
mmcwilliams | 072c67fd0f | |
mmcwilliams | 3e5bda77db | |
mmcwilliams | 1510762fbb | |
mmcwilliams | 429e66717d | |
mmcwilliams | c129739394 | |
mmcwilliams | 43ee0d0672 | |
mmcwilliams | 11e9176cb8 | |
mmcwilliams | 4d62421446 | |
mmcwilliams | e35c41791b | |
mmcwilliams | b02b92c1c7 | |
mmcwilliams | 372ab01d57 | |
mmcwilliams | 79e16fb166 | |
mmcwilliams | 74e6b9c1b2 | |
mmcwilliams | 1413e323f0 | |
mmcwilliams | f09ada2cd2 | |
mmcwilliams | 283085cb8d | |
mmcwilliams | 5717fc8cfe | |
mmcwilliams | 42691c1577 | |
mmcwilliams | cfbeeb3ce9 | |
mmcwilliams | dcca364b78 | |
mmcwilliams | 553d2bbb0d | |
mmcwilliams | 425dd9fd6a | |
mmcwilliams | c436406e9e | |
mmcwilliams | 52e6431d65 | |
mmcwilliams | ddb33e7f35 | |
mmcwilliams | 3dcfa708d2 | |
mmcwilliams | aff3678daf | |
mmcwilliams | 4356abc820 | |
mmcwilliams | 41a5fd087d | |
mmcwilliams | 742adccf34 | |
mmcwilliams | 97f1464106 | |
mmcwilliams | aef8709ab0 | |
mmcwilliams | 0ff1b5ff7d | |
mmcwilliams | d264429726 | |
mmcwilliams | 65ba1f8c18 | |
mmcwilliams | 48e8415ee4 | |
mmcwilliams | e5a1654341 | |
mmcwilliams | 6d1e9ec78f | |
mmcwilliams | fe046027da | |
mmcwilliams | 600a0abc72 | |
M McWilliams | 7a87ac924a | |
mmcwilliams | 7ce3fa854a | |
mmcwilliams | 82e10bb4a4 | |
mmcwilliams | fc3cc96cd8 | |
mmcwilliams | 478799965e | |
mmcwilliams | 099cd3052a | |
mmcwilliams | ea91ea5ff5 | |
mmcwilliams | 6a31eda3c4 | |
mmcwilliams | d74e756b05 | |
mmcwilliams | 91ee19f2ab | |
mmcwilliams | c563bf0dd3 | |
mmcwilliams | 87d43fc15b | |
mmcwilliams | 94942d86f9 | |
mmcwilliams | bfb9bcbbe4 | |
mmcwilliams | f5f23284a3 | |
mmcwilliams | 9472527c70 | |
mmcwilliams | 6faf78b92e | |
mmcwilliams | 1b6c56b2ad | |
mmcwilliams | 42358e98eb | |
mmcwilliams | 746f0e2753 | |
mmcwilliams | cf7664fb2a | |
mmcwilliams | 05d1bc3ae2 | |
mmcwilliams | e9ccdfc191 | |
mmcwilliams | dc080b8566 | |
mmcwilliams | 56aba1eaba | |
mmcwilliams | c276525d3a | |
mmcwilliams | fce259d29b | |
mmcwilliams | 72575ce2a4 | |
mmcwilliams | 2408456d47 | |
mmcwilliams | f2c2d6ce43 | |
mmcwilliams | 7f0ab0fee3 | |
mmcwilliams | 4236651a09 | |
mmcwilliams | fe85cc1b37 | |
mmcwilliams | d308b8a59e | |
mmcwilliams | cc227e9a66 | |
mmcwilliams | a4682ed9d3 | |
mmcwilliams | d19e83d616 | |
mmcwilliams | 9bfc133a67 | |
mmcwilliams | f89ad53235 | |
mmcwilliams | 0fbe45073c | |
mmcwilliams | 415306d7a8 | |
mmcwilliams | b1e4015630 | |
mmcwilliams | ad97086bf0 | |
mmcwilliams | 1d993b85d3 | |
mmcwilliams | 46da2e6541 | |
mmcwilliams | d4c2f5b678 | |
mmcwilliams | 9b4525e5a7 | |
mmcwilliams | 1a31767572 | |
mmcwilliams | 74b326caeb | |
mmcwilliams | 029dd628b6 | |
mmcwilliams | cf6e4f9de9 | |
mmcwilliams | e47abeaaa5 | |
mmcwilliams | 4eee61ab1b | |
mmcwilliams | 4202d01630 | |
mmcwilliams | 00b5efa484 | |
mmcwilliams | 15bb696b59 | |
mmcwilliams | 95b6f77848 | |
mmcwilliams | e186b1b9fc | |
mmcwilliams | ede29216f7 | |
mmcwilliams | faeddb84ab | |
mmcwilliams | 87f3bcef6f | |
mmcwilliams | f0fae8ce1b | |
mmcw-dev | febb39aef7 | |
mmcw-dev | b93266d1eb | |
mmcwilliams | c3f24b125e | |
mmcwilliams | fcdc6ebb1d | |
mmcwilliams | ec0b8e3b4f | |
mmcwilliams | aa5bbfc9fd | |
mmcwilliams | 806342b623 | |
mmcwilliams | 307ef33a10 | |
mmcwilliams | f276d5ce83 | |
mmcwilliams | 200671b1cf | |
mmcwilliams | 46ce99ec18 | |
mmcwilliams | fcc4da3672 | |
mmcwilliams | c93413bae4 | |
mmcwilliams | ac888b1fc4 | |
mmcwilliams | b9bd62bb78 | |
mmcwilliams | 1612d737a1 | |
mmcwilliams | 7a901b31c4 | |
mmcwilliams | aff06619a0 | |
mmcwilliams | da7faf59a5 | |
mmcwilliams | a5a9a4ea86 | |
mmcwilliams | b481906c86 | |
mmcwilliams | b19b20dad9 | |
mmcwilliams | a9dd45a464 | |
mmcwilliams | bc9e882a37 | |
mmcwilliams | fa477aec83 | |
mmcwilliams | 8b2095227c | |
mmcwilliams | 6622a72241 | |
mmcwilliams | c964410f7b | |
mmcwilliams | b98b831ae4 | |
mmcwilliams | 643e88aef3 | |
mmcw-dev | aff070cdc4 | |
mmcw-dev | 955e49fff2 | |
mmcwilliams | 7398f7993d | |
mmcwilliams | 48b86ebc93 | |
mmcwilliams | bee40965b1 | |
mmcwilliams | fb08a28543 | |
mmcwilliams | 4947cbcc9d | |
mmcwilliams | bf3adec727 | |
mmcwilliams | 58ade0518e | |
mmcwilliams | 56a83615a9 | |
mmcwilliams | 73ae599cff | |
mmcw-dev | 723b23fa41 | |
mmcw-dev | bf148c6784 | |
mmcwilliams | 7fd449724b | |
mmcwilliams | 8ebdbf9f6f | |
mmcwilliams | 54ab121e89 | |
mmcwilliams | 16dcd1e3d4 | |
mmcwilliams | 8bd505da36 | |
Matt | b99491909b | |
mmcwilliams | 4de536e2e8 | |
mmcwilliams | 8fd29e89d8 | |
mmcwilliams | e7ac873f41 | |
mmcwilliams | ed8f1add35 | |
mmcwilliams | dbe96491f9 | |
mmcw-dev | 962a7c8213 | |
mmcw-dev | 3493759998 | |
mmcw-dev | b6a6b8a81e |
|
@ -1,3 +1,12 @@
|
|||
*.DS_Store
|
||||
dist/
|
||||
*.Parent
|
||||
.AppleDouble
|
||||
*.Parent
|
||||
|
||||
node_modules
|
||||
dist
|
||||
|
||||
*.svd
|
||||
*debug_custom.json
|
||||
*debug.cfg
|
||||
|
||||
notes/mphd
|
|
@ -0,0 +1,9 @@
|
|||
[submodule "scad/common"]
|
||||
path = scad/common
|
||||
url = https://git.sixteenmillimeter.com/modules/common.git
|
||||
[submodule "scad/sprocketed_roller"]
|
||||
path = scad/sprocketed_roller
|
||||
url = https://git.sixteenmillimeter.com/modules/sprocketed_roller.git
|
||||
[submodule "scad/MCAD"]
|
||||
path = scad/MCAD
|
||||
url = https://github.com/openscad/MCAD.git
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright 2018 M McWilliams
|
||||
Copyright 2018-2021 M McWilliams
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
|
166
Readme.md
166
Readme.md
|
@ -1,73 +1,93 @@
|
|||
# mcopy
|
||||
|
||||
An open platform for controlling small-gauge film optical printers (16mm, Super8, 8mm).
|
||||
|
||||
-------
|
||||
1. <a href="#intro">Introduction</a>
|
||||
2. <a href="#downloads">Downloads</a>
|
||||
1. <a href="#usage">Usage</a>
|
||||
2. <a href="#software">Software</a>
|
||||
3. <a href="#firmware">Firmware</a>
|
||||
3. <a href="#hardware">Hardware</a>
|
||||
4. <a href="#why">Why?</a>
|
||||
|
||||
-------
|
||||
|
||||
## Introduction <a name="intro"></a>
|
||||
|
||||
The `mcopy` project is comprised of software and hardware for optical printers, built with re-purposed broken projectors.
|
||||
|
||||
#### Components
|
||||
|
||||
* Sequencer desktop app
|
||||
* Scripting language, called `mscript`, for orchestrating complex sequences
|
||||
* Arduino firmware for projectors, cameras, lights and existing printers
|
||||
* 3D models of parts used for modifying projectors and printers
|
||||
* Schematics for simple Arduino-based electronics
|
||||
|
||||
## Downloads <a name="downloads"></a>
|
||||
|
||||
* [1.0.3](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.0.3) for macOS and Linux (.deb)
|
||||
|
||||
For Windows, you can [install from source](https://github.com/sixteenmillimeter/mcopy/tree/master/app#mcopy-desktop-app) for now.
|
||||
|
||||
## Usage <a name="usage"></a>
|
||||
|
||||
The software requires your hardware to be in place before the mcopy control app is useful.
|
||||
|
||||
![mcopy app](docs/mcopy.png?raw=true "mcopy app")
|
||||
|
||||
## Software <a name="software"></a>
|
||||
|
||||
The mcopy desktop app is an Electron-based project which can be built for Linux, Windows and macOS.
|
||||
Pre-built packages will be made available for macOS, initially, with the other two target platforms to follow.
|
||||
To build the desktop app from source, see the [installation and running instructions](https://github.com/sixteenmillimeter/mcopy/tree/master/app#mcopy-desktop-app).
|
||||
The desktop software also interoperates with two related projects; the Bluetooth + Wifi capable, Raspberry Pi-based [INTVAL3](https://github.com/sixteenmillimeter/intval3) and the Arduino-based [intval2](https://github.com/sixteenmillimeter/intval2).
|
||||
|
||||
## Firmware <a name="firmware"></a>
|
||||
|
||||
This project contains Arduino formware for controlling:
|
||||
|
||||
* a projector
|
||||
* a camera (see [intval2](https://github.com/sixteenmillimeter/intval2) for more info)
|
||||
* a light
|
||||
* a projector + a camera
|
||||
* a projector + a light
|
||||
* a camera + a light
|
||||
* a camera + a projector + a light
|
||||
|
||||
Using a simple serial interface, this modular platform can be used to control DIY components, modified existing optical printers or a mixture of components.
|
||||
The desktop app can connect to multiple serial devices, so your mcopy optical printer can be built from various designs that suit your hardware tastes/needs/available parts.
|
||||
|
||||
|
||||
## Hardware <a name="hardware"></a>
|
||||
|
||||
All non-electronic hardware for this project is available as plaintext OpenSCAD files and 3D print-able .STL files.
|
||||
The hardware component of this project is aimed at modifying broken Bell & Howell projectors into USB serial-controlled projectors to be used in optical printing.
|
||||
As a secondary capability, this desktop software and firmware package can be used to replace the sequencers for early-model JK optical printers, with some modification.
|
||||
|
||||
|
||||
## Why? <a name="why"></a>
|
||||
|
||||
I'm interested in expanding the viability and access of the 16mm film format and to repurpose thre rising tide of discarded film technology.
|
||||
|
||||
# mcopy
|
||||
|
||||
An open platform for controlling small-gauge film optical printers (16mm, Super8, 8mm).
|
||||
|
||||
## [Project Home - git.sixteenmillimeter.com/16mm/mcopy](https://git.sixteenmillimeter.com/16mm/mcopy)
|
||||
|
||||
* Github Mirror - [github.com/sixteenmillimeter/mcopy](https://github.com/sixteenmillimeter/mcopy)
|
||||
* Gitlab Mirror - [gitlab.com/16mm/mcopy](https://gitlab.com/16mm/mcopy)
|
||||
|
||||
-------
|
||||
1. <a href="#intro">Introduction</a>
|
||||
2. <a href="#downloads">Downloads</a>
|
||||
1. <a href="#usage">Usage</a>
|
||||
2. <a href="#software">Software</a>
|
||||
3. <a href="#firmware">Firmware</a>
|
||||
3. <a href="#hardware">Hardware</a>
|
||||
4. <a href="#why">Why?</a>
|
||||
|
||||
-------
|
||||
|
||||
## Introduction <a name="intro"></a>
|
||||
|
||||
The `mcopy` project is comprised of software and hardware for optical printers, built with re-purposed broken projectors.
|
||||
|
||||
#### Components
|
||||
|
||||
* Sequencer desktop app
|
||||
* Scripting language, called `mscript`, for orchestrating complex sequences
|
||||
* Arduino firmware for projectors, cameras, lights and existing printers
|
||||
* 3D models of parts used for modifying projectors and printers
|
||||
* Schematics for simple Arduino-based electronics
|
||||
* Filmout feature for digitally transferring video and images to analog film
|
||||
* Interoperability with the [intval3](https://github.com/sixteenmillimeter/intval3) intervalometer
|
||||
|
||||
## Downloads <a name="downloads"></a>
|
||||
|
||||
### Latest Installers
|
||||
|
||||
* [1.6.9](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.6.9) for macOS, Linux (.deb) and Windows (.msi)
|
||||
|
||||
### Older Versions
|
||||
* [1.6.7](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.6.7) for macOS and Linux (.deb)
|
||||
* [1.6.4](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.6.4) for macOS, Linux (.deb) and Windows (.msi)
|
||||
* [1.6.2](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.6.2) for macOS
|
||||
* [1.6.1](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.6.1) for macOS
|
||||
* [1.5.2](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.5.2) for macOS
|
||||
* [1.4.9](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.4.9) for macOS and Linux (.deb)
|
||||
* [1.2.0](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.2.0) for macOS and Linux (.deb)
|
||||
* [1.0.3](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.0.3) for macOS and Linux (.deb)
|
||||
|
||||
For Windows, you can [install from source](https://github.com/sixteenmillimeter/mcopy/tree/master/app#mcopy-desktop-app) for now.
|
||||
|
||||
## Usage <a name="usage"></a>
|
||||
|
||||
The software requires your hardware to be in place before the mcopy control app is useful.
|
||||
|
||||
![mcopy app](docs/mcopy.png?raw=true "mcopy app")
|
||||
|
||||
## Software <a name="software"></a>
|
||||
|
||||
The mcopy desktop app is an Electron-based project which can be built for Linux, Windows and macOS.
|
||||
Pre-built packages will be made available for macOS, initially, with the other two target platforms to follow.
|
||||
To build the desktop app from source, see the [installation and running instructions](https://github.com/sixteenmillimeter/mcopy/tree/master/app#mcopy-desktop-app).
|
||||
The desktop software also interoperates with two related projects; the Bluetooth + Wifi capable, Raspberry Pi-based [INTVAL3](https://github.com/sixteenmillimeter/intval3) and the Arduino-based [intval2](https://github.com/sixteenmillimeter/intval2).
|
||||
|
||||
## Firmware <a name="firmware"></a>
|
||||
|
||||
This project contains Arduino formware for controlling:
|
||||
|
||||
* a projector
|
||||
* a camera (see [intval2](https://github.com/sixteenmillimeter/intval2) for more info)
|
||||
* a light
|
||||
* a projector + a camera
|
||||
* a projector + a light
|
||||
* a camera + a light
|
||||
* a camera + a projector + a light
|
||||
|
||||
Using a simple serial interface, this modular platform can be used to control DIY components, modified existing optical printers or a mixture of components.
|
||||
The desktop app can connect to multiple serial devices, so your mcopy optical printer can be built from various designs that suit your hardware tastes/needs/available parts.
|
||||
|
||||
|
||||
## Hardware <a name="hardware"></a>
|
||||
|
||||
All non-electronic hardware for this project is available as plaintext OpenSCAD files and 3D print-able .STL files.
|
||||
The hardware component of this project is aimed at modifying broken Bell & Howell projectors into USB serial-controlled projectors to be used in optical printing.
|
||||
|
||||
As a secondary capability, this desktop software and firmware package can be used to replace the sequencers for early-model JK optical printers, with some modification.
|
||||
|
||||
|
||||
## Why? <a name="why"></a>
|
||||
|
||||
I'm interested in expanding the viability and access of the 16mm film format and to repurpose thre rising tide of discarded film technology.
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
node_modules/*
|
||||
logs/*
|
||||
data/transfer*.json
|
||||
data/transfer*.json
|
||||
.appleId*
|
||||
.applePwd*
|
||||
.appleIdentity*
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
./node_modules/.bin/electron-packager . --overwrite --platform=darwin --arch=x64 --icon=assets/icons/icon.icns --prune=true --out=../dist
|
||||
#build dmg for mac install
|
||||
sleep 5s
|
||||
mkdir ../dist/installers
|
||||
./node_modules/.bin/electron-installer-dmg ../dist/mcopy-app-darwin-x64/mcopy-app.app mcopy-app --out=../dist/installers --icon=assets/icons/icon.icns --overwrite
|
||||
# Path to the icon file that will be the app icon in the DMG window.
|
||||
# --icon-size=<px> How big to make the icon for the app in the DMG. [Default: `80`].
|
||||
# --background=<path> Path to a PNG image to use as the background of the DMG.
|
||||
#--overwrite Overwrite any existing DMG.
|
|
@ -1,18 +0,0 @@
|
|||
const { MSICreator } = require('electron-wix-msi');
|
||||
|
||||
// Step 1: Instantiate the MSICreator
|
||||
const msiCreator = new MSICreator({
|
||||
appDirectory: '../dist/mcopy-win32-x64',
|
||||
description: 'mcopy optical printer GUI',
|
||||
exe: 'mcopy',
|
||||
name: 'mcopy',
|
||||
manufacturer: 'sixteenmillimeter.com',
|
||||
version: '2.0.0',
|
||||
outputDirectory: '../dist/'
|
||||
});
|
||||
|
||||
// Step 2: Create a .wxs template file
|
||||
msiCreator.create();
|
||||
|
||||
// Step 3: Compile the template to a .msi file
|
||||
setTimeout(msiCreator.compile, 30000)
|
|
@ -1,7 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
./node_modules/.bin/electron-packager . mcopy --overwrite --asar=true --platform=win32 --arch=x64 --icon=assets/icons/icon.ico --prune=true --out=../dist --version-string.CompanyName="sixteenmillimeter.com" --version-string.FileDescription="Open Source Optical Printer Platform" --version-string.ProductName="mcopy"
|
||||
|
||||
mkdir ../dist/installers
|
||||
|
||||
node ./build_win.js
|
525
app/css/app.css
525
app/css/app.css
|
@ -194,8 +194,8 @@ button:focus {
|
|||
width: 66px;
|
||||
height: 66px;
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
left: 7px;
|
||||
top: 14px / 2;
|
||||
left: 14px / 2;
|
||||
}
|
||||
.dial-wrapper input {
|
||||
margin-top: 94px;
|
||||
|
@ -210,10 +210,10 @@ button:focus {
|
|||
top: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
width: 40px;
|
||||
width: 80px / 2;
|
||||
}
|
||||
.dial-container.dial-container1 {
|
||||
left: 40px;
|
||||
left: 80px / 2;
|
||||
}
|
||||
.dial-container.dial-container1 .dial-wedge {
|
||||
transform: rotateZ(0deg);
|
||||
|
@ -227,16 +227,16 @@ button:focus {
|
|||
.dial-container.dial-container2 .dial-wedge {
|
||||
transform: rotateZ(0deg);
|
||||
border-radius: 80px 0 0 80px;
|
||||
transform-origin: 40px 40px;
|
||||
transform-origin: 80px/2 80px/2;
|
||||
}
|
||||
.dial-wedge {
|
||||
height: 80px;
|
||||
width: 40px;
|
||||
width: 80px / 2;
|
||||
}
|
||||
.dial-marker {
|
||||
border-radius: 50%;
|
||||
height: 7px;
|
||||
width: 7px;
|
||||
height: 14px / 2;
|
||||
width: 14px / 2;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(50% - (14px * 2));
|
||||
|
@ -367,6 +367,7 @@ button:focus {
|
|||
float: right;
|
||||
width: 90px;
|
||||
margin-right: 60px;
|
||||
height: 32px;
|
||||
}
|
||||
#seq_stats {
|
||||
width: 40%;
|
||||
|
@ -381,16 +382,16 @@ button:focus {
|
|||
font-weight: 600;
|
||||
float: right;
|
||||
}
|
||||
#seq_loop {
|
||||
#seq_loop_wrap {
|
||||
width: 40%;
|
||||
float: left;
|
||||
padding: 0 0 0 56px;
|
||||
}
|
||||
#seq_loop h3 {
|
||||
#seq_loop_wrap h3 {
|
||||
font-size: 20px;
|
||||
margin: 12px 0 3px;
|
||||
}
|
||||
#seq_loop input {
|
||||
#seq_loop_wrap input {
|
||||
font-family: 'Menlo', monospace;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: #fff;
|
||||
|
@ -402,48 +403,91 @@ button:focus {
|
|||
#sequence {
|
||||
width: 970px;
|
||||
padding-bottom: 21px;
|
||||
padding-left: 70px;
|
||||
padding-left: 92px;
|
||||
}
|
||||
#sequence #cam_forward,
|
||||
#sequence #proj_forward,
|
||||
#sequence #camera_forward,
|
||||
#sequence #camera_second_forward,
|
||||
#sequence #projector_forward,
|
||||
#sequence #projector_second_forward,
|
||||
#sequence #black_forward {
|
||||
clear: both;
|
||||
}
|
||||
#sequence #cam_forward input[type=checkbox],
|
||||
#sequence #proj_forward input[type=checkbox],
|
||||
#sequence #camera_forward input[type=checkbox],
|
||||
#sequence #camera_second_forward input[type=checkbox],
|
||||
#sequence #projector_forward input[type=checkbox],
|
||||
#sequence #projector_second_forward input[type=checkbox],
|
||||
#sequence #black_forward input[type=checkbox] {
|
||||
border: 2px solid #00C4A0;
|
||||
}
|
||||
#sequence #cam_forward input[type=checkbox]:checked,
|
||||
#sequence #proj_forward input[type=checkbox]:checked,
|
||||
#sequence #camera_forward input[type=checkbox]:checked,
|
||||
#sequence #camera_second_forward input[type=checkbox]:checked,
|
||||
#sequence #projector_forward input[type=checkbox]:checked,
|
||||
#sequence #projector_second_forward input[type=checkbox]:checked,
|
||||
#sequence #black_forward input[type=checkbox]:checked {
|
||||
background: #00C4A0;
|
||||
}
|
||||
#sequence #cam_forward > div,
|
||||
#sequence #proj_forward > div,
|
||||
#sequence #camera_forward > div,
|
||||
#sequence #camera_second_forward > div,
|
||||
#sequence #projector_forward > div,
|
||||
#sequence #projector_second_forward > div,
|
||||
#sequence #black_forward > div {
|
||||
color: #00C4A0;
|
||||
}
|
||||
#sequence #cam_backward,
|
||||
#sequence #proj_backward,
|
||||
#sequence #camera_backward,
|
||||
#sequence #camera_second_backward,
|
||||
#sequence #projector_backward,
|
||||
#sequence #projector_second_backward,
|
||||
#sequence #black_backward {
|
||||
clear: both;
|
||||
}
|
||||
#sequence #cam_backward input[type=checkbox],
|
||||
#sequence #proj_backward input[type=checkbox],
|
||||
#sequence #camera_backward input[type=checkbox],
|
||||
#sequence #camera_second_backward input[type=checkbox],
|
||||
#sequence #projector_backward input[type=checkbox],
|
||||
#sequence #projector_second_backward input[type=checkbox],
|
||||
#sequence #black_backward input[type=checkbox] {
|
||||
border: 2px solid #AB1A25;
|
||||
}
|
||||
#sequence #cam_backward input[type=checkbox]:checked,
|
||||
#sequence #proj_backward input[type=checkbox]:checked,
|
||||
#sequence #camera_backward input[type=checkbox]:checked,
|
||||
#sequence #camera_second_backward input[type=checkbox]:checked,
|
||||
#sequence #projector_backward input[type=checkbox]:checked,
|
||||
#sequence #projector_second_backward input[type=checkbox]:checked,
|
||||
#sequence #black_backward input[type=checkbox]:checked {
|
||||
background: #AB1A25;
|
||||
}
|
||||
#sequence #cam_backward > div,
|
||||
#sequence #proj_backward > div,
|
||||
#sequence #camera_backward > div,
|
||||
#sequence #camera_second_backward > div,
|
||||
#sequence #projector_backward > div,
|
||||
#sequence #projector_second_backward > div,
|
||||
#sequence #black_backward > div {
|
||||
color: #AB1A25;
|
||||
}
|
||||
#sequence #camera_second_forward input[type=checkbox],
|
||||
#sequence #projector_second_forward input[type=checkbox] {
|
||||
border: 2px solid #14d8b4;
|
||||
}
|
||||
#sequence #camera_second_forward input[type=checkbox]:checked,
|
||||
#sequence #projector_second_forward input[type=checkbox]:checked {
|
||||
background: #14d8b4;
|
||||
}
|
||||
#sequence #camera_second_forward > div,
|
||||
#sequence #projector_second_forward > div {
|
||||
color: #14d8b4;
|
||||
}
|
||||
#sequence #camera_second_backward input[type=checkbox],
|
||||
#sequence #projector_second_backward input[type=checkbox] {
|
||||
border: 2px solid #bf2e39;
|
||||
}
|
||||
#sequence #camera_second_backward input[type=checkbox]:checked,
|
||||
#sequence #projector_second_backward input[type=checkbox]:checked {
|
||||
background: #bf2e39;
|
||||
}
|
||||
#sequence #camera_second_backward > div,
|
||||
#sequence #projector_second_backward > div {
|
||||
color: #bf2e39;
|
||||
}
|
||||
#sequence #black input[type=checkbox]:checked {
|
||||
background: white;
|
||||
}
|
||||
#sequence input[type=checkbox] {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
@ -460,6 +504,10 @@ button:focus {
|
|||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
}
|
||||
#sequence input[type=checkbox].disabled {
|
||||
cursor: not-allowed;
|
||||
border-color: #646464;
|
||||
}
|
||||
#sequence .L {
|
||||
display: inline-block;
|
||||
width: 35px;
|
||||
|
@ -504,10 +552,10 @@ button:focus {
|
|||
font-family: 'Menlo', monospace;
|
||||
background-color: #272b30;
|
||||
position: absolute;
|
||||
top: 115px;
|
||||
top: 113px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 15px;
|
||||
width: 54px;
|
||||
width: 75px;
|
||||
}
|
||||
#seq_labels div {
|
||||
height: 43px;
|
||||
|
@ -518,16 +566,41 @@ button:focus {
|
|||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
#seq_labels i.fa {
|
||||
right: 3px;
|
||||
position: absolute;
|
||||
margin-top: 10px;
|
||||
}
|
||||
#loop_current {
|
||||
margin-top: 54px;
|
||||
width: 121px;
|
||||
font-family: 'Menlo', monospace;
|
||||
font-size: 22px;
|
||||
margin-top: 13px;
|
||||
margin-right: 50px;
|
||||
width: 93px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
float: right;
|
||||
color: #DAE035;
|
||||
}
|
||||
#buttons > div {
|
||||
#seq_pause {
|
||||
display: none;
|
||||
}
|
||||
#seq_progress {
|
||||
width: 100%;
|
||||
height: 15px;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
#buttons > div,
|
||||
#buttons_2 > div {
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
#buttons .proj2,
|
||||
#buttons_2 .proj2 {
|
||||
float: right !important;
|
||||
}
|
||||
.cmd {
|
||||
width: 240px;
|
||||
text-align: center;
|
||||
|
@ -562,6 +635,11 @@ button:focus {
|
|||
background: #AB1A25;
|
||||
border-color: #AB1A25;
|
||||
}
|
||||
.cmd:active.capper,
|
||||
.cmd.active.capper {
|
||||
background: white;
|
||||
color: #272b30;
|
||||
}
|
||||
.cmd:active i,
|
||||
.cmd.active i {
|
||||
color: #272b30;
|
||||
|
@ -585,14 +663,44 @@ button:focus {
|
|||
::-webkit-scrollbar-thumb:window-inactive {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
#settings h4 {
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
#settings > div {
|
||||
width: 300px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#settings > div.left {
|
||||
float: left;
|
||||
padding-left: 30px;
|
||||
}
|
||||
#settings > div.right {
|
||||
float: right;
|
||||
padding-right: 30px;
|
||||
}
|
||||
#settings > div.right input[type=number] {
|
||||
min-width: 200px;
|
||||
width: 200px;
|
||||
}
|
||||
#settings > div.right input[readonly] {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
#settings > div.right .spacer {
|
||||
height: 62px;
|
||||
}
|
||||
#settings > div.right .proj_time {
|
||||
height: 111px;
|
||||
}
|
||||
#settings > div.right .cam_time {
|
||||
height: 111px;
|
||||
}
|
||||
#settings > div.right > div {
|
||||
width: 270px;
|
||||
}
|
||||
#settings > div > div {
|
||||
width: 360px;
|
||||
}
|
||||
#settings input[type=text],
|
||||
#settings input[type=number],
|
||||
#settings select {
|
||||
display: block;
|
||||
border-radius: 5px;
|
||||
|
@ -607,33 +715,43 @@ button:focus {
|
|||
padding: 6px 12px;
|
||||
font-size: 21px;
|
||||
min-width: 300px;
|
||||
max-width: 300px;
|
||||
}
|
||||
#settings input[type=text] span,
|
||||
#settings input[type=number] span,
|
||||
#settings select span {
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
font-weight: 200;
|
||||
}
|
||||
#settings input[type=text]:active,
|
||||
#settings input[type=number]:active,
|
||||
#settings select:active,
|
||||
#settings input[type=text] .active,
|
||||
#settings input[type=number] .active,
|
||||
#settings select .active {
|
||||
background: #fff;
|
||||
color: #272b30;
|
||||
outline: none;
|
||||
}
|
||||
#settings input[type=text]:focus,
|
||||
#settings input[type=number]:focus,
|
||||
#settings select:focus {
|
||||
outline: none;
|
||||
}
|
||||
#settings input[type=text].active,
|
||||
#settings input[type=number].active,
|
||||
#settings select.active {
|
||||
border-color: #DAE035;
|
||||
color: #DAE035;
|
||||
}
|
||||
#settings input[type=text] {
|
||||
width: 200px;
|
||||
}
|
||||
#settings button {
|
||||
margin-top: -1px;
|
||||
margin-top: 0px;
|
||||
float: right;
|
||||
padding: 8px 16px 9px;
|
||||
}
|
||||
#settings input[type=radio] {
|
||||
float: right;
|
||||
|
@ -642,6 +760,17 @@ button:focus {
|
|||
#settings .spacer {
|
||||
margin-top: 10px;
|
||||
}
|
||||
#settings #version {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
bottom: 10px;
|
||||
z-index: 1000;
|
||||
height: 14px;
|
||||
width: auto;
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
color: #999;
|
||||
}
|
||||
.cm-s-monokai.CodeMirror {
|
||||
background: #272b30 !important;
|
||||
}
|
||||
|
@ -674,10 +803,148 @@ button:focus {
|
|||
background: black;
|
||||
color: #fff;
|
||||
}
|
||||
#log {
|
||||
position: fixed;
|
||||
#video input,
|
||||
#video select {
|
||||
display: block;
|
||||
border-radius: 5px;
|
||||
border: 2px solid #fff;
|
||||
text-align: center;
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
padding: 8px 0;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
font-size: 21px;
|
||||
min-width: 300px;
|
||||
}
|
||||
#video input span,
|
||||
#video select span {
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
font-weight: 200;
|
||||
}
|
||||
#video input:active,
|
||||
#video select:active,
|
||||
#video input .active,
|
||||
#video select .active {
|
||||
background: #fff;
|
||||
color: #272b30;
|
||||
outline: none;
|
||||
}
|
||||
#video input:focus,
|
||||
#video select:focus {
|
||||
outline: none;
|
||||
}
|
||||
#video input.active,
|
||||
#video select.active {
|
||||
border-color: #DAE035;
|
||||
color: #DAE035;
|
||||
}
|
||||
#video button,
|
||||
#video select {
|
||||
padding: 9px 16px 8px;
|
||||
}
|
||||
#path_bar {
|
||||
padding: 5px;
|
||||
height: 50px;
|
||||
}
|
||||
#path_bar input {
|
||||
float: left;
|
||||
}
|
||||
#path_bar button {
|
||||
float: left;
|
||||
margin-left: 5px;
|
||||
}
|
||||
#path_bar select {
|
||||
line-height: 41px;
|
||||
height: 37px;
|
||||
margin-right: 5px;
|
||||
float: right;
|
||||
box-sizing: content-box;
|
||||
padding: 0 0 0 8px;
|
||||
}
|
||||
#filmout_monitor {
|
||||
display: none;
|
||||
border: 2px solid white;
|
||||
box-sizing: border-box;
|
||||
height: 360px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
#filmout_monitor.on {
|
||||
display: block;
|
||||
}
|
||||
#filmout_preview_wrap {
|
||||
background: #000;
|
||||
width: 100%;
|
||||
height: 160px;
|
||||
height: 360px;
|
||||
}
|
||||
#filmout {
|
||||
position: absolute;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: block;
|
||||
opacity: 0;
|
||||
}
|
||||
#filmout.on {
|
||||
opacity: 1;
|
||||
}
|
||||
#filmout_position_wrap {
|
||||
padding-top: 5px;
|
||||
height: 50px;
|
||||
}
|
||||
#filmout_position_wrap input {
|
||||
margin-right: 5px;
|
||||
margin-left: 5px;
|
||||
width: 308px !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
#filmout_position_wrap button,
|
||||
#filmout_position_wrap input {
|
||||
float: left;
|
||||
}
|
||||
#filmout_position_wrap > div {
|
||||
width: 425px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#filmout_functions {
|
||||
padding-top: 5px;
|
||||
}
|
||||
#filmout_functions > div {
|
||||
width: 425px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#filmout_stats_video,
|
||||
#filmout_stats_monitor {
|
||||
width: 150px;
|
||||
position: absolute;
|
||||
padding: 10px 5px;
|
||||
text-align: center;
|
||||
}
|
||||
#filmout_stats_video h3,
|
||||
#filmout_stats_monitor h3 {
|
||||
font-size: 20px;
|
||||
margin: 16px 0 3px;
|
||||
text-align: center;
|
||||
}
|
||||
#filmout_stats_video {
|
||||
left: 5px;
|
||||
}
|
||||
#filmout_stats_monitor {
|
||||
right: 5px;
|
||||
}
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
.show {
|
||||
display: block;
|
||||
}
|
||||
#screens {
|
||||
overflow-x: hidden;
|
||||
|
@ -733,29 +1000,71 @@ button:focus {
|
|||
}
|
||||
#counters .cam,
|
||||
#counters_2 .cam,
|
||||
#counters_3 .cam,
|
||||
#move_to .cam,
|
||||
#move_to_2 .cam,
|
||||
#counters .cam2,
|
||||
#counters_2 .cam2,
|
||||
#counters_3 .cam2,
|
||||
#move_to .cam2,
|
||||
#move_to_2 .cam2,
|
||||
#counters .proj,
|
||||
#counters_2 .proj,
|
||||
#move_to .proj {
|
||||
#counters_3 .proj,
|
||||
#move_to .proj,
|
||||
#move_to_2 .proj,
|
||||
#counters .proj2,
|
||||
#counters_2 .proj2,
|
||||
#counters_3 .proj2,
|
||||
#move_to .proj2,
|
||||
#move_to_2 .proj2 {
|
||||
width: 50%;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
#counters .cam label,
|
||||
#counters_2 .cam label,
|
||||
#counters_3 .cam label,
|
||||
#move_to .cam label,
|
||||
#move_to_2 .cam label,
|
||||
#counters .cam2 label,
|
||||
#counters_2 .cam2 label,
|
||||
#counters_3 .cam2 label,
|
||||
#move_to .cam2 label,
|
||||
#move_to_2 .cam2 label,
|
||||
#counters .proj label,
|
||||
#counters_2 .proj label,
|
||||
#move_to .proj label {
|
||||
#counters_3 .proj label,
|
||||
#move_to .proj label,
|
||||
#move_to_2 .proj label,
|
||||
#counters .proj2 label,
|
||||
#counters_2 .proj2 label,
|
||||
#counters_3 .proj2 label,
|
||||
#move_to .proj2 label,
|
||||
#move_to_2 .proj2 label {
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
display: block;
|
||||
}
|
||||
#counters .cam input,
|
||||
#counters_2 .cam input,
|
||||
#counters_3 .cam input,
|
||||
#move_to .cam input,
|
||||
#move_to_2 .cam input,
|
||||
#counters .cam2 input,
|
||||
#counters_2 .cam2 input,
|
||||
#counters_3 .cam2 input,
|
||||
#move_to .cam2 input,
|
||||
#move_to_2 .cam2 input,
|
||||
#counters .proj input,
|
||||
#counters_2 .proj input,
|
||||
#move_to .proj input {
|
||||
#counters_3 .proj input,
|
||||
#move_to .proj input,
|
||||
#move_to_2 .proj input,
|
||||
#counters .proj2 input,
|
||||
#counters_2 .proj2 input,
|
||||
#counters_3 .proj2 input,
|
||||
#move_to .proj2 input,
|
||||
#move_to_2 .proj2 input {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: #fff;
|
||||
padding: 6px 12px;
|
||||
|
@ -767,44 +1076,147 @@ button:focus {
|
|||
}
|
||||
#counters .cam input.changed,
|
||||
#counters_2 .cam input.changed,
|
||||
#counters_3 .cam input.changed,
|
||||
#move_to .cam input.changed,
|
||||
#move_to_2 .cam input.changed,
|
||||
#counters .cam2 input.changed,
|
||||
#counters_2 .cam2 input.changed,
|
||||
#counters_3 .cam2 input.changed,
|
||||
#move_to .cam2 input.changed,
|
||||
#move_to_2 .cam2 input.changed,
|
||||
#counters .proj input.changed,
|
||||
#counters_2 .proj input.changed,
|
||||
#move_to .proj input.changed {
|
||||
#counters_3 .proj input.changed,
|
||||
#move_to .proj input.changed,
|
||||
#move_to_2 .proj input.changed,
|
||||
#counters .proj2 input.changed,
|
||||
#counters_2 .proj2 input.changed,
|
||||
#counters_3 .proj2 input.changed,
|
||||
#move_to .proj2 input.changed,
|
||||
#move_to_2 .proj2 input.changed {
|
||||
color: #DAE035;
|
||||
}
|
||||
#counters .cam,
|
||||
#counters_2 .cam,
|
||||
#move_to .cam {
|
||||
#counters_3 .cam,
|
||||
#move_to .cam,
|
||||
#move_to_2 .cam,
|
||||
#counters .cam2,
|
||||
#counters_2 .cam2,
|
||||
#counters_3 .cam2,
|
||||
#move_to .cam2,
|
||||
#move_to_2 .cam2 {
|
||||
float: left;
|
||||
}
|
||||
#counters .proj,
|
||||
#counters_2 .proj,
|
||||
#move_to .proj {
|
||||
#counters_3 .proj,
|
||||
#move_to .proj,
|
||||
#move_to_2 .proj,
|
||||
#counters .proj2,
|
||||
#counters_2 .proj2,
|
||||
#counters_3 .proj2,
|
||||
#move_to .proj2,
|
||||
#move_to_2 .proj2 {
|
||||
float: right;
|
||||
}
|
||||
#move_to {
|
||||
#counters.projectors .proj,
|
||||
#counters.projectors .proj2 {
|
||||
width: 25%;
|
||||
}
|
||||
#counters.projectors .proj label,
|
||||
#counters.projectors .proj2 label {
|
||||
line-height: 34px;
|
||||
font-size: 18px;
|
||||
}
|
||||
#counters.projectors .proj input,
|
||||
#counters.projectors .proj2 input {
|
||||
width: 90%;
|
||||
}
|
||||
#counters.cameras .cam,
|
||||
#counters.cameras .cam2 {
|
||||
width: 25%;
|
||||
}
|
||||
#counters.cameras .cam label,
|
||||
#counters.cameras .cam2 label {
|
||||
line-height: 34px;
|
||||
font-size: 18px;
|
||||
}
|
||||
#counters.cameras .cam input,
|
||||
#counters.cameras .cam2 input {
|
||||
width: 90%;
|
||||
}
|
||||
#move_to,
|
||||
#move_to_2 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
#move_to .cam > div,
|
||||
#move_to .proj > div {
|
||||
#move_to_2 .cam > div,
|
||||
#move_to .cam2 > div,
|
||||
#move_to_2 .cam2 > div,
|
||||
#move_to .proj > div,
|
||||
#move_to_2 .proj > div,
|
||||
#move_to .proj2 > div,
|
||||
#move_to_2 .proj2 > div {
|
||||
width: 294px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#move_to .cam label,
|
||||
#move_to .proj label {
|
||||
#move_to_2 .cam label,
|
||||
#move_to .cam2 label,
|
||||
#move_to_2 .cam2 label,
|
||||
#move_to .proj label,
|
||||
#move_to_2 .proj label,
|
||||
#move_to .proj2 label,
|
||||
#move_to_2 .proj2 label {
|
||||
font-size: 18px;
|
||||
}
|
||||
#move_to .cam input,
|
||||
#move_to .proj input {
|
||||
#move_to_2 .cam input,
|
||||
#move_to .cam2 input,
|
||||
#move_to_2 .cam2 input,
|
||||
#move_to .proj input,
|
||||
#move_to_2 .proj input,
|
||||
#move_to .proj2 input,
|
||||
#move_to_2 .proj2 input {
|
||||
display: inline-block;
|
||||
width: 206px;
|
||||
}
|
||||
#move_to .cam button,
|
||||
#move_to .proj button {
|
||||
#move_to_2 .cam button,
|
||||
#move_to .cam2 button,
|
||||
#move_to_2 .cam2 button,
|
||||
#move_to .proj button,
|
||||
#move_to_2 .proj button,
|
||||
#move_to .proj2 button,
|
||||
#move_to_2 .proj2 button {
|
||||
padding: 7px 16px;
|
||||
float: right;
|
||||
}
|
||||
#move_to > .proj2,
|
||||
#move_to_2 > .proj2 {
|
||||
float: right;
|
||||
}
|
||||
.cam2,
|
||||
.proj2,
|
||||
.black {
|
||||
display: none;
|
||||
}
|
||||
.cam2 > *,
|
||||
.proj2 > *,
|
||||
.black > * {
|
||||
visibility: hidden;
|
||||
}
|
||||
.cam2.on,
|
||||
.proj2.on,
|
||||
.black.on {
|
||||
display: block;
|
||||
}
|
||||
.cam2.on > *,
|
||||
.proj2.on > *,
|
||||
.black.on > * {
|
||||
visibility: visible;
|
||||
}
|
||||
#overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
@ -829,6 +1241,21 @@ button:focus {
|
|||
color: #fff;
|
||||
text-shadow: 1px 1px 2px #000;
|
||||
}
|
||||
#spinnerCancel {
|
||||
display: none;
|
||||
position: absolute;
|
||||
z-index: 2000000000;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
text-align: center;
|
||||
margin-left: -40%;
|
||||
margin-top: 120px;
|
||||
width: 80%;
|
||||
}
|
||||
#spinnerCancel .btn {
|
||||
margin: 0 auto;
|
||||
background: rgba(80, 80, 80, 0.4);
|
||||
}
|
||||
.cp-app {
|
||||
position: relative !important;
|
||||
border-radius: 0px !important;
|
||||
|
|
|
@ -1,107 +1,197 @@
|
|||
{
|
||||
"version" : "2.0.0",
|
||||
"ext_port" : 1111,
|
||||
"profiles" : {
|
||||
"mcopy" : {
|
||||
"label" : "Default mcopy profile",
|
||||
"cam" : {
|
||||
"time" : 850,
|
||||
"delay" : 50,
|
||||
"momentary" : 0
|
||||
},
|
||||
"proj" : {
|
||||
"time" : 1400,
|
||||
"delay" : 50,
|
||||
"momentary" : 0
|
||||
},
|
||||
"black" : {
|
||||
"before" : 0,
|
||||
"after" : 0
|
||||
}
|
||||
},
|
||||
"jk103" : {
|
||||
"label" : "JK103",
|
||||
"cam" : {
|
||||
"time" : 600,
|
||||
"delay" : 50,
|
||||
"momentary" : 240
|
||||
},
|
||||
"proj" : {
|
||||
"time" : 950,
|
||||
"delay" : 50,
|
||||
"momentary" : 240
|
||||
},
|
||||
"black" : {
|
||||
"before" : 0,
|
||||
"after" : 0
|
||||
}
|
||||
},
|
||||
"jk_original" : {
|
||||
"label" : "JK45 profile",
|
||||
"cam" : {
|
||||
"time" : 750,
|
||||
"delay" : 50,
|
||||
"momentary" : 300
|
||||
},
|
||||
"proj" : {
|
||||
"time" : 1300,
|
||||
"delay" : 50,
|
||||
"momentary" : 300
|
||||
},
|
||||
"black" : {
|
||||
"before" : 250,
|
||||
"after" : 250
|
||||
}
|
||||
},
|
||||
"intval3" : {
|
||||
"label" : "INTVAL3",
|
||||
"cam" : {
|
||||
"time" : 630,
|
||||
"delay" : 50,
|
||||
"momentary" : 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"arduino" : {
|
||||
"baud" : 57600,
|
||||
"board" : "uno",
|
||||
"serialDelay" : 20,
|
||||
"sequenceDelay" : 100,
|
||||
"cam" : {
|
||||
"time" : 850,
|
||||
"delay" : 50,
|
||||
"momentary" : 300
|
||||
},
|
||||
"proj" : {
|
||||
"time" : 1300,
|
||||
"delay" : 50,
|
||||
"momentary" : 300
|
||||
},
|
||||
"black" : {
|
||||
"before" : 250,
|
||||
"after" : 250
|
||||
},
|
||||
"cmd" : {
|
||||
"debug" : "d",
|
||||
"connect": "i",
|
||||
"light" : "l",
|
||||
"camera" : "c",
|
||||
"projector" : "p",
|
||||
"black" : "b",
|
||||
"cam_forward" : "e",
|
||||
"cam_backward" : "f",
|
||||
"proj_forward" : "g",
|
||||
"proj_backward" : "h",
|
||||
"proj_identifier" : "j",
|
||||
"cam_identifier" : "k",
|
||||
"mcopy_identifier" : "m",
|
||||
"cam_timed" : "n",
|
||||
"proj_identifier" : "j",
|
||||
"cam_identifier" : "k",
|
||||
"light_identifier" : "o",
|
||||
"proj_light_identifier" : "q",
|
||||
"proj_cam_light_identifier" : "r",
|
||||
"proj_cam_identifier" : "s"
|
||||
}
|
||||
}
|
||||
}
|
||||
"version": "1.8.104",
|
||||
"ext_port": 1111,
|
||||
"profiles": {
|
||||
"mcopy": {
|
||||
"label": "Default mcopy profile",
|
||||
"cam": {
|
||||
"time": 850,
|
||||
"delay": 50,
|
||||
"momentary": 0
|
||||
},
|
||||
"proj": {
|
||||
"time": 1400,
|
||||
"delay": 50,
|
||||
"momentary": 0
|
||||
},
|
||||
"black": {
|
||||
"before": 100,
|
||||
"after": 100
|
||||
},
|
||||
"light": false
|
||||
},
|
||||
"jk103": {
|
||||
"label": "JK103",
|
||||
"cam": {
|
||||
"time": 600,
|
||||
"delay": 50,
|
||||
"momentary": 240
|
||||
},
|
||||
"proj": {
|
||||
"time": 950,
|
||||
"delay": 50,
|
||||
"momentary": 240
|
||||
},
|
||||
"black": {
|
||||
"before": 0,
|
||||
"after": 0
|
||||
},
|
||||
"light": false
|
||||
},
|
||||
"jk_original": {
|
||||
"label": "JK45 profile",
|
||||
"cam": {
|
||||
"time": 750,
|
||||
"delay": 50,
|
||||
"momentary": 300
|
||||
},
|
||||
"proj": {
|
||||
"time": 1300,
|
||||
"delay": 50,
|
||||
"momentary": 300
|
||||
},
|
||||
"black": {
|
||||
"before": 250,
|
||||
"after": 250
|
||||
},
|
||||
"light": false
|
||||
},
|
||||
"intval3": {
|
||||
"label": "INTVAL3",
|
||||
"cam": {
|
||||
"time": 630,
|
||||
"delay": 50,
|
||||
"momentary": 0
|
||||
},
|
||||
"light": false
|
||||
},
|
||||
"jk_mono": {
|
||||
"label": "MONO's JK",
|
||||
"cam": {
|
||||
"time": 750,
|
||||
"delay": 50,
|
||||
"momentary": 300
|
||||
},
|
||||
"proj": {
|
||||
"time": 1300,
|
||||
"delay": 50,
|
||||
"momentary": 300
|
||||
},
|
||||
"light": false,
|
||||
"projector_second": true
|
||||
},
|
||||
"oxberry": {
|
||||
"label": "Oxberry",
|
||||
"cam": {
|
||||
"time": 550,
|
||||
"delay": 50,
|
||||
"momentary": 130
|
||||
},
|
||||
"proj": {
|
||||
"time": 1340,
|
||||
"delay": 50,
|
||||
"momentary": 300
|
||||
},
|
||||
"light": false
|
||||
},
|
||||
"norris": {
|
||||
"label": "Norris",
|
||||
"cam": {
|
||||
"time": 650,
|
||||
"delay": 50,
|
||||
"momentary": 130
|
||||
},
|
||||
"light": false
|
||||
}
|
||||
},
|
||||
"cmd": {
|
||||
"camera_forward": "CF",
|
||||
"camera_backward": "CB",
|
||||
"projector_forward": "PF",
|
||||
"projector_backward": "PB",
|
||||
"black_forward": "BF",
|
||||
"black_backward": "BB",
|
||||
"camera_second_forward": "C2F",
|
||||
"camera_second_backward": "C2B",
|
||||
"cameras_forward": "CCF",
|
||||
"cameras_backward": "CCB",
|
||||
"camera_forward_camera_second_backward": "CFCB",
|
||||
"camera_backward_camera_second_forward": "CBCF",
|
||||
"projector_second_forward": "P2F",
|
||||
"projector_second_backward": "P2B",
|
||||
"projectors_forward": "PPF",
|
||||
"projectors_backward": "PPB",
|
||||
"projector_forward_projector_second_backward": "PFPB",
|
||||
"projector_backward_projector_second_forward": "PBPF",
|
||||
"pause": "PA",
|
||||
"alert": "AL"
|
||||
},
|
||||
"arduino": {
|
||||
"baud": 57600,
|
||||
"board": "uno",
|
||||
"serialDelay": 20,
|
||||
"sequenceDelay": 100,
|
||||
"cam": {
|
||||
"time": 850,
|
||||
"delay": 50,
|
||||
"momentary": 300
|
||||
},
|
||||
"proj": {
|
||||
"time": 1300,
|
||||
"delay": 50,
|
||||
"momentary": 300
|
||||
},
|
||||
"black": {
|
||||
"before": 250,
|
||||
"after": 250
|
||||
},
|
||||
"cmd": {
|
||||
"debug": "d",
|
||||
"connect": "i",
|
||||
"light": "l",
|
||||
"camera": "c",
|
||||
"projector": "p",
|
||||
"black": "b",
|
||||
"camera_forward": "e",
|
||||
"camera_backward": "f",
|
||||
"projector_forward": "g",
|
||||
"projector_backward": "h",
|
||||
"projector_identifier": "j",
|
||||
"camera_identifier": "k",
|
||||
"mcopy_identifier": "m",
|
||||
"camera_timed": "n",
|
||||
"light_identifier": "o",
|
||||
"projector_light_identifier": "q",
|
||||
"projector_camera_light_identifier": "r",
|
||||
"projector_camera_identifier": "s",
|
||||
"projector_second_identifier": "t",
|
||||
"projectors_identifier": "d",
|
||||
"projector_second_forward": "u",
|
||||
"projector_second_backward": "v",
|
||||
"projector_second": "w",
|
||||
"projectors": "x",
|
||||
"camera_second_identifier": "y",
|
||||
"cameras_identifier": "a",
|
||||
"camera_second_forward": "1",
|
||||
"camera_second_backward": "2",
|
||||
"camera_second": "3",
|
||||
"cameras": "4",
|
||||
"camera_projectors_identifier": "5",
|
||||
"cameras_projector_identifier": "6",
|
||||
"cameras_projectors_identifier": "7",
|
||||
"capper_identifier": "C",
|
||||
"camera_capper_identifier": "8",
|
||||
"camera_capper_projector_identifier": "9",
|
||||
"camera_capper_projectors_identifier": "0",
|
||||
"capper_on": "A",
|
||||
"capper_off": "B",
|
||||
"takeup_forward": "D",
|
||||
"takeup_backward": "F",
|
||||
"error": "E",
|
||||
"camera_exposure": "G",
|
||||
"state": "H",
|
||||
"home": "I",
|
||||
"offset": "O"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
221
app/display.html
221
app/display.html
|
@ -13,6 +13,16 @@
|
|||
body.meter {
|
||||
background: rgb(117, 117, 117);
|
||||
}
|
||||
body.meter #img,
|
||||
body.meter #can {
|
||||
display: none;
|
||||
}
|
||||
body.image #can{
|
||||
display: none;
|
||||
}
|
||||
body.image #img {
|
||||
display: block;
|
||||
}
|
||||
#img {
|
||||
position: absolute;
|
||||
/*background-image: url(".../img/background.jpg");*/
|
||||
|
@ -30,8 +40,9 @@
|
|||
background: #fff;
|
||||
display: none;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
#can.show{
|
||||
display: block;
|
||||
|
@ -45,61 +56,158 @@
|
|||
</canvas>
|
||||
<script>
|
||||
'use strict';
|
||||
const { remote, ipcRenderer } = require('electron')
|
||||
|
||||
async function setImage (src) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
//let img = new Image()
|
||||
let img = document.getElementById('img')
|
||||
let body = document.querySelector('body')
|
||||
if (body.classList.contains('meter')) {
|
||||
body.classList.remove('meter')
|
||||
}
|
||||
|
||||
img.style.backgroundImage = `url('${src}')`;
|
||||
//img.onload = () => {
|
||||
//document.body.appendChild(img)
|
||||
//return resolve(img)
|
||||
//}
|
||||
//img.onerror = reject
|
||||
//img.src = src
|
||||
const { ipcRenderer } = require('electron')
|
||||
const remote = require('@electron/remote')
|
||||
let imgTmp;
|
||||
function delay (ms) {
|
||||
return new Promise((resolve) => {
|
||||
return setTimeout(resolve, ms)
|
||||
})
|
||||
}
|
||||
async function setMeter () {
|
||||
let body = document.querySelector('body')
|
||||
if (!body.classList.contains('meter')) {
|
||||
body.classList.add('meter')
|
||||
}
|
||||
async function setImage (src) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
imgTmp = new Image()
|
||||
let img = document.getElementById('img')
|
||||
let body = document.querySelector('body')
|
||||
body.className = ''
|
||||
body.classList.add('image')
|
||||
imgTmp.onload = function () {
|
||||
img.style.backgroundImage = `url('${src}')`
|
||||
return resolve(src)
|
||||
}
|
||||
imgTmp.src = src
|
||||
})
|
||||
}
|
||||
async function setGrid () {
|
||||
|
||||
function setBlank () {
|
||||
let img = document.getElementById('img')
|
||||
img.style.background = ''
|
||||
img.style.backgroundUrl = ''
|
||||
img.style.backgroundColor = 'black'
|
||||
}
|
||||
async function onMeter () {
|
||||
console.log('meter')
|
||||
const body = document.querySelector('body')
|
||||
body.className = ''
|
||||
body.classList.add('meter')
|
||||
}
|
||||
async function onFocus () {
|
||||
console.log('focus')
|
||||
const can = document.getElementById('can')
|
||||
const ctx = can.getContext('2d')
|
||||
const dpr = window.devicePixelRatio || 1
|
||||
const body = document.querySelector('body')
|
||||
let ctx;
|
||||
body.className = ''
|
||||
if (!can.classList.contains('show')) {
|
||||
can.classList.add('show')
|
||||
}
|
||||
can.width = window.innerWidth
|
||||
can.height = window.innerHeight
|
||||
can.width = window.innerWidth * dpr
|
||||
can.height = window.innerHeight * dpr
|
||||
|
||||
can.style.width = `${window.innerWidth}px`
|
||||
can.style.height = `${window.innerHeight}px`
|
||||
|
||||
ctx = can.getContext('2d')
|
||||
ctx.scale(dpr, dpr)
|
||||
|
||||
try{
|
||||
await drawGrid(can, ctx)
|
||||
await drawFocus(can, ctx)
|
||||
} catch (err) {
|
||||
alert(JSON.stringify(err))
|
||||
}
|
||||
}
|
||||
async function drawGrid (can, ctx) {
|
||||
async function drawFocus (can, ctx) {
|
||||
const count = 20
|
||||
const half = Math.round(count / 2)
|
||||
const w = can.width
|
||||
const h = can.height
|
||||
const dpr = window.devicePixelRatio || 1
|
||||
const w = can.width / dpr
|
||||
const h = can.height / dpr
|
||||
const longest = w >= h ? w * 1.5 : h * 1.5
|
||||
const opp = Math.tan(360 / (count * 32)) * longest / 10
|
||||
|
||||
//console.log(`l: ${longest}`)
|
||||
//console.log(`${360 / (count * 8)}deg`)
|
||||
//console.log(`o: ${opp}`)
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(w / 2, h / 2)
|
||||
ctx.lineTo((w / 2) + opp, longest)
|
||||
ctx.lineTo((w / 2) - opp, longest)
|
||||
ctx.fill()
|
||||
ctx.translate(w / 2, h / 2);
|
||||
ctx.rotate((360 / count) * Math.PI / 180)
|
||||
ctx.translate(- w / 2, -h / 2)
|
||||
}
|
||||
}
|
||||
async function onField (evt, arg) {
|
||||
console.log('field guide')
|
||||
const can = document.getElementById('can')
|
||||
const dpr = window.devicePixelRatio || 1
|
||||
const screen = window.outerWidth / window.outerHeight
|
||||
const body = document.querySelector('body')
|
||||
let ctx
|
||||
body.className = ''
|
||||
if (!can.classList.contains('show')) {
|
||||
can.classList.add('show')
|
||||
}
|
||||
if (arg.ratio) {
|
||||
if (arg.ratio < screen) {
|
||||
can.width = (window.innerHeight * arg.ratio) * dpr
|
||||
can.height = window.innerHeight * dpr
|
||||
} else {
|
||||
can.width = window.innerWidth * dpr
|
||||
can.height = (window.innerWidth / arg.ratio) * dpr
|
||||
}
|
||||
} else {
|
||||
can.width = window.innerWidth * dpr
|
||||
can.height = window.innerHeight * dpr
|
||||
}
|
||||
|
||||
|
||||
if (arg.ratio) {
|
||||
if (arg.ratio < screen) {
|
||||
can.style.width = `${window.innerHeight * arg.ratio}px`
|
||||
can.style.height = `${window.innerHeight}px`
|
||||
} else {
|
||||
can.style.width = `${window.innerWidth}px`
|
||||
can.style.height = `${window.innerWidth / arg.ratio}px`
|
||||
}
|
||||
} else {
|
||||
can.style.width = `${window.innerWidth}px`
|
||||
can.style.height = `${window.innerHeight}px`
|
||||
}
|
||||
|
||||
ctx = can.getContext('2d')
|
||||
ctx.scale(dpr, dpr)
|
||||
|
||||
try{
|
||||
await drawField(can, ctx)
|
||||
} catch (err) {
|
||||
alert(JSON.stringify(err))
|
||||
}
|
||||
}
|
||||
// draw a field guide
|
||||
async function drawField (can, ctx) {
|
||||
const count = 20
|
||||
const half = Math.round(count / 2)
|
||||
const dpr = window.devicePixelRatio || 1
|
||||
const w = can.width / dpr
|
||||
const h = can.height / dpr
|
||||
const wsec = w / count
|
||||
const hsec= h / count
|
||||
const hsec = h / count
|
||||
const spacer = 12
|
||||
const fontSize = 18
|
||||
|
||||
ctx.lineWidth = 2
|
||||
|
||||
ctx.moveTo(w / 2, 0)
|
||||
ctx.lineTo(w / 2, h)
|
||||
ctx.stroke()
|
||||
ctx.moveTo(0, h / 2)
|
||||
ctx.lineTo(w, h / 2)
|
||||
ctx.stroke()
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
ctx.moveTo(wsec * i, hsec * i)
|
||||
ctx.lineTo(wsec * i, h - (hsec * i))
|
||||
|
@ -108,40 +216,45 @@
|
|||
ctx.lineTo(w - (wsec * i), hsec * i)
|
||||
ctx.stroke()
|
||||
}
|
||||
ctx.font = '30px Arial'
|
||||
|
||||
ctx.lineWidth = 1
|
||||
|
||||
ctx.font = `${fontSize}px Arial`
|
||||
for (let i = 0; i < half; i++) {
|
||||
ctx.fillText(`${(half - i)}`, (wsec * i) + 15, (h / 2) - 15)
|
||||
ctx.fillText(`${(half - i)}`, (w - (wsec * i)) - 25, (h / 2) - 15)
|
||||
ctx.fillText(`${(half - i)}`, (w / 2) + 15, (hsec * i) + 25 )
|
||||
ctx.fillText(`${(half - i)}`, (w / 2) + 15, (h - (hsec * i)) - 15)
|
||||
//left count
|
||||
ctx.fillText(`${(half - i)}`, (wsec * i) + spacer, (h / 2) - spacer)
|
||||
//right count
|
||||
ctx.fillText(`${(half - i)}`, (w - (wsec * i)) - (spacer * 2), (h / 2) + (spacer * 2))
|
||||
//up count
|
||||
ctx.fillText(`${(half - i)}`, (w / 2) + spacer, (hsec * i) + spacer + (fontSize / 2) )
|
||||
//down count
|
||||
ctx.fillText(`${(half - i)}`, (w / 2) - (spacer * 2), (h - (hsec * i)) - spacer)
|
||||
}
|
||||
}
|
||||
async function onDigital (event, arg) {
|
||||
console.log('called')
|
||||
if (arg.src) {
|
||||
if (arg.exposure) {
|
||||
setBlank()
|
||||
await delay(10)
|
||||
}
|
||||
try {
|
||||
await setImage(arg.src)
|
||||
await setImage(arg.src)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
} else if (arg.meter) {
|
||||
try {
|
||||
await setMeter()
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
} else if (arg.grid) {
|
||||
try {
|
||||
await setGrid()
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
if (arg.exposure) {
|
||||
await delay(arg.exposure)
|
||||
setBlank()
|
||||
}
|
||||
ipcRenderer.send('display_load', { src : arg.src })
|
||||
}
|
||||
return event.returnValue = true
|
||||
}
|
||||
|
||||
async function onEscape (evt) {
|
||||
let isEscape = false
|
||||
let win
|
||||
|
||||
evt = evt || window.event
|
||||
|
||||
if ('key' in evt) {
|
||||
|
@ -149,12 +262,16 @@
|
|||
} else {
|
||||
isEscape = (evt.keyCode == 27)
|
||||
}
|
||||
|
||||
if (isEscape) {
|
||||
win = remote.getCurrentWindow()
|
||||
win.close()
|
||||
}
|
||||
}
|
||||
ipcRenderer.on('display', onDigital)
|
||||
ipcRenderer.on('field', onField)
|
||||
ipcRenderer.on('meter', onMeter)
|
||||
ipcRenderer.on('focus', onFocus)
|
||||
document.onkeydown = onEscape
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.debugger</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -18,17 +18,17 @@ var scripts = [
|
|||
'./src/index.js'
|
||||
];
|
||||
|
||||
gulp.task('js', function () {
|
||||
gulp.task('js', () => {
|
||||
'use strict';
|
||||
return gulp.src(scripts)
|
||||
.pipe(concat('app.js'))
|
||||
.pipe(gulp.dest('./js/'));
|
||||
});
|
||||
|
||||
gulp.task('less', function () {
|
||||
gulp.task('less', () => {
|
||||
return gulp.src('./less/app.less')
|
||||
.pipe(less())
|
||||
.pipe(gulp.dest('./css'));
|
||||
});
|
||||
|
||||
gulp.task('default', ['js', 'less']);
|
||||
gulp.task('default', gulp.parallel('js', 'less'));
|
||||
|
|
249
app/index.html
249
app/index.html
|
@ -18,37 +18,61 @@
|
|||
<div id="counters">
|
||||
<div class="cam">
|
||||
<label>CAMERA</label>
|
||||
<input type="number" id="seq_cam_count" class="count" value="00000" onchange="gui.counterFormat(this, mcopy.state.camera.pos);" onblur="gui.updateCam(this);" />
|
||||
<input type="number" id="seq_cam_count" class="count" value="00000" onchange="gui.counterFormat(this, cam.pos);" onblur="gui.updateCam(this);" />
|
||||
</div>
|
||||
<div class="cam2">
|
||||
<label>CAMERA</label>
|
||||
<input type="number" id="seq_cam_2_count" class="count" value="00000" onchange="gui.counterFormat(this, cam.second.pos);" onblur="gui.updateCam2(this);" />
|
||||
</div>
|
||||
<div class="proj2">
|
||||
<label>PROJECTOR 2</label>
|
||||
<input type="number" id="seq_proj_2_count" class="count" value="00000" onchange="gui.counterFormat(this, proj.second.pos);" onblur="gui.updateProj2(this);" />
|
||||
</div>
|
||||
<div class="proj">
|
||||
<label>PROJECTOR</label>
|
||||
<input type="number" id="seq_proj_count" class="count" value="00000" onchange="gui.counterFormat(this, mcopy.state.projector.pos);" onblur="gui.updateProj(this);" />
|
||||
<input type="number" id="seq_proj_count" class="count" value="00000" onchange="gui.counterFormat(this, proj.pos);" onblur="gui.updateProj(this);" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="seq_scroll">
|
||||
<div id="sequence">
|
||||
<div id="cam_forward" class="row" y="0"></div>
|
||||
<div id="proj_forward" class="row" y="1"></div>
|
||||
<div id="cam_backward" class="row spacer" y="0"></div>
|
||||
<div id="proj_backward" class="row" y="1"></div>
|
||||
<div id="camera_forward" class="row" y="0"></div>
|
||||
<div id="camera_second_forward" class="row cam2" y="2"></div>
|
||||
<div id="projector_forward" class="row" y="1"></div>
|
||||
<div id="projector_second_forward" class="row proj2" y="3"></div>
|
||||
|
||||
<div id="camera_backward" class="row spacer" y="0"></div>
|
||||
<div id="camera_second_backward" class="row cam2" y="2"></div>
|
||||
<div id="projector_backward" class="row" y="1"></div>
|
||||
<div id="projector_second_backward" class="row proj2" y="3"></div>
|
||||
|
||||
<div id="black" class="row black"></div>
|
||||
|
||||
<div id="light_set" class="row spacer"></div>
|
||||
<div id="numbers" class="row"></div>
|
||||
</div>
|
||||
<div id="seq_labels">
|
||||
<div><span>CAM </span><i class="fa fa-plus"></i></div>
|
||||
<div><span>PRO </span><i class="fa fa-plus"></i></div>
|
||||
<div class="cam2"><span>CAM2 </span><i class="fa fa-plus"></i></div>
|
||||
<div><span>PROJ </span><i class="fa fa-plus"></i></div>
|
||||
<div class="proj2"><span>PROJ2 </span><i class="fa fa-plus"></i></div>
|
||||
|
||||
<div class="spacer"><span>CAM </span><i class="fa fa-minus"></i></div>
|
||||
<div><span>PRO </span><i class="fa fa-minus"></i></div>
|
||||
<div class="cam2"><span>CAM2 </span><i class="fa fa-minus"></i></div>
|
||||
<div><span>PROJ </span><i class="fa fa-minus"></i></div>
|
||||
<div class="proj2"><span>PROJ2 </span><i class="fa fa-minus"></i></div>
|
||||
|
||||
<div class="black"><span>BLANK </span><i class="fa fa-times"></i></div>
|
||||
|
||||
<div class="spacer"><span>LIGHT</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="actions">
|
||||
<button id="seq_run" onclick="seq.init();">RUN</button>
|
||||
<button id="seq_stop" onclick="seq.stop(true);">STOP</button>
|
||||
<button id="seq_clear" onclick="gui.grid.clear();">CLEAR</button>
|
||||
<button id="seq_plus24" onclick="gui.grid.plus_24();">+ 24</button>
|
||||
<button id="seq_run" onclick="seq.start();">START</button>
|
||||
<button id="seq_pause" onclick="seq.pause();">STOP</button>
|
||||
<button id="seq_stop" onclick="seq.stop();">STOP</button>
|
||||
<button id="seq_clear" onclick="grid.clear();">CLEAR</button>
|
||||
<button id="seq_plus24" onclick="grid.plus_24();">+ 24</button>
|
||||
<button id="seq_mscript" onclick="mse.mscript.fromSequence();">TO SCRIPT</button>
|
||||
<input id="seq_scroll_state" type="number" min="0" value="00000" />
|
||||
</div>
|
||||
|
@ -58,11 +82,17 @@
|
|||
<div class="cam_end">Camera end: <span>00000</span></div>
|
||||
<div class="proj_end">Projector end: <span>00000</span></div>
|
||||
</div>
|
||||
<div id="seq_loop">
|
||||
<div id="seq_loop_wrap">
|
||||
<h3>LOOPS</h3>
|
||||
<input type="number" min="1" id="seq_loop" value="00001" onchange="this.value = gui.fmtZero(this.value, 6); gui.grid.loopChange(this);"/>
|
||||
<input type="number" min="1" id="seq_loop" value="00001" onchange="this.value = gui.fmtZero(this.value, 6); seq.setLoops(parseInt(this.value));"/>
|
||||
<div id="loop_current"></div>
|
||||
</div>
|
||||
<div id="seq_progress">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
|
||||
<span class="sr-only">0% Complete</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="script" class="screen">
|
||||
<textarea id="editor"></textarea>
|
||||
|
@ -76,73 +106,87 @@
|
|||
</footer>
|
||||
</div>
|
||||
<div id="controls" class="screen">
|
||||
<div id="counters_2">
|
||||
<div id="counters_2" class="clearfix">
|
||||
<div class="cam">
|
||||
<label>CAMERA</label>
|
||||
<input type="number" id="seq_cam_count_2" class="count" value="00000" onchange="gui.counterFormat(this, mcopy.state.camera.pos);" onblur="gui.updateCam(this);" />
|
||||
<input type="number" id="seq_cam_count_2" class="count" value="00000" onchange="gui.counterFormat(this, cam.pos);" onblur="gui.updateCam(this);" />
|
||||
</div>
|
||||
<div class="proj">
|
||||
<label>PROJECTOR</label>
|
||||
<input type="number" id="seq_proj_count_2" class="count" value="00000" onchange="gui.counterFormat(this, mcopy.state.projector.pos);" onblur="gui.updateProj(this);" />
|
||||
<input type="number" id="seq_proj_count_2" class="count" value="00000" onchange="gui.counterFormat(this, proj.pos);" onblur="gui.updateProj(this);" />
|
||||
</div>
|
||||
</div>
|
||||
<div id="move_to">
|
||||
<div id="move_to" class="clearfix">
|
||||
<div class="cam">
|
||||
<!--<label>MOVE TO</label>-->
|
||||
<div>
|
||||
<input type="number" id="move_cam_to" class="count" value="00000" onchange="gui.counterFormat(this, this.value);" />
|
||||
<button id="move_cam_to_go" onclick="return cmd.cam_to();">GO TO</button>
|
||||
<button id="move_cam_to_go" onclick="return cmd.camera_to();">GO TO</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="proj">
|
||||
<!--<label>MOVE TO</label>-->
|
||||
<div>
|
||||
<input type="number" id="move_proj_to" class="count" value="00000" onchange="gui.counterFormat(this, this.value);"/>
|
||||
<button id="move_proj_to_go" onclick="return cmd.proj_to();">GO TO</button>
|
||||
<button id="move_proj_to_go" onclick="return cmd.projector_to();">GO TO</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="buttons" class="clearfix">
|
||||
<div>
|
||||
<div>
|
||||
<button id="cmd_cam_forward" onclick="cmd.cam_forward(light.color);" class="cmd fwd">
|
||||
<button id="cmd_cam_forward" onclick="cmd.camera_forward(light.color);" class="cmd fwd">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
CAMERA +1
|
||||
<i class="fa fa-step-forward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="cmd_cam_backward" onclick="cmd.cam_backward(light.color);" class="cmd bwd">
|
||||
<button id="cmd_cam_backward" onclick="cmd.camera_backward(light.color);" class="cmd bwd">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
CAMERA -1
|
||||
<i class="fa fa-step-backward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<div class="hide">
|
||||
<button id="cmd_black_forward" onclick="cmd.black_forward();" class="cmd fwd">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
BLANK +1
|
||||
<i class="fa fa-step-forward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<div class="hide">
|
||||
<button id="cmd_black_backward" onclick="cmd.black_backward();" class="cmd bwd">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
BLANK -1
|
||||
<i class="fa fa-step-backward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="hide">
|
||||
<button id="cmd_capper_on" onclick="cmd.capper_on();" class="cmd capper">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
CAPPER ON
|
||||
<i class="fa fa-eye"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="hide">
|
||||
<button id="cmd_capper_off" onclick="cmd.capper_off();" class="cmd capper active">
|
||||
<i class="fa fa-eye"></i>
|
||||
CAPPER OFF
|
||||
<i class="fa fa-eye"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<button id="cmd_proj_forward" onclick="cmd.proj_forward();" class="cmd fwd">
|
||||
<button id="cmd_proj_forward" onclick="cmd.projector_forward();" class="cmd fwd">
|
||||
<i class="fa fa-film"></i>
|
||||
PROJECTOR +1
|
||||
<i class="fa fa-step-forward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="cmd_proj_backward" onclick="cmd.proj_backward();" class="cmd bwd">
|
||||
<button id="cmd_proj_backward" onclick="cmd.projector_backward();" class="cmd bwd">
|
||||
<i class="fa fa-film"></i>
|
||||
PROJECTOR -1
|
||||
<i class="fa fa-step-backward"></i>
|
||||
|
@ -150,9 +194,80 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div id="log"></div>
|
||||
</footer>
|
||||
<div id="counters_3" class="clearfix">
|
||||
<div class="cam2">
|
||||
<label>CAMERA 2</label>
|
||||
<input type="number" id="seq_cam_2_count_2" class="count" value="00000" onchange="gui.counterFormat(this, cam.second.pos);" onblur="gui.updateCam2(this);" />
|
||||
</div>
|
||||
<div class="proj2">
|
||||
<label>PROJECTOR 2</label>
|
||||
<input type="number" id="seq_proj_2_count_2" class="count" value="00000" onchange="gui.counterFormat(this, proj.second.pos);" onblur="gui.updateProj2(this);" />
|
||||
</div>
|
||||
</div>
|
||||
<div id="move_to_2" class="clearfix">
|
||||
<div class="cam2">
|
||||
<!--<label>MOVE TO</label>-->
|
||||
<div>
|
||||
<input type="number" id="move_cam_to_2" class="count" value="00000" onchange="gui.counterFormat(this, this.value);" />
|
||||
<button id="move_cam_to_go_2" onclick="return cmd.camera_second_to();">GO TO</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="proj2">
|
||||
<!--<label>MOVE TO</label>-->
|
||||
<div>
|
||||
<input type="number" id="move_proj_to_2" class="count" value="00000" onchange="gui.counterFormat(this, this.value);"/>
|
||||
<button id="move_proj_to_go_2" onclick="return cmd.projector_second_to();">GO TO</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="buttons_2" class="clearfix">
|
||||
<div class="cam2">
|
||||
<div>
|
||||
<button id="cmd_cam2_forward" onclick="cmd.camera_second_forward(light.color);" class="cmd fwd">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
CAMERA 2 +1
|
||||
<i class="fa fa-step-forward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="cmd_cam2_backward" onclick="cmd.camera_second_backward(light.color);" class="cmd bwd">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
CAMERA 2 -1
|
||||
<i class="fa fa-step-backward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="cmd_black2_forward" onclick="cmd.black2_forward();" class="cmd fwd">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
BLANK +1
|
||||
<i class="fa fa-step-forward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="cmd_black2_backward" onclick="cmd.black2_backward();" class="cmd bwd">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
BLANK -1
|
||||
<i class="fa fa-step-backward"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="proj2">
|
||||
<div>
|
||||
<button id="cmd_proj2_forward" onclick="cmd.projector_second_forward();" class="cmd fwd">
|
||||
<i class="fa fa-film"></i>
|
||||
PROJECTOR 2 +1
|
||||
<i class="fa fa-step-forward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="cmd_proj2_backward" onclick="cmd.projector_second_backward();" class="cmd bwd">
|
||||
<i class="fa fa-film"></i>
|
||||
PROJECTOR 2 -1
|
||||
<i class="fa fa-step-backward"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="light" class="screen">
|
||||
<div id="colors-tabs"></div>
|
||||
|
@ -245,8 +360,54 @@
|
|||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<div id="settings" class="screen">
|
||||
<div id="video" class="screen">
|
||||
<div>
|
||||
<div>
|
||||
<div id="path_bar">
|
||||
<input id="filmout_file" type="text" onclick="filmout.selectFile();" readonly />
|
||||
<button onclick="$('#projector_type_digital').click();">USE FILE</button>
|
||||
<select id="filmout_displays"></select>
|
||||
</div>
|
||||
|
||||
<div id="filmout_preview_wrap">
|
||||
<div id="filmout_monitor">
|
||||
<div id="filmout"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="filmout_stats">
|
||||
<div id="filmout_stats_video">
|
||||
<h3>File</h3>
|
||||
<div id="filmout_stats_video_name"></div>
|
||||
<div id="filmout_stats_video_size"></div>
|
||||
<div id="filmout_stats_video_frames"></div>
|
||||
</div>
|
||||
<div id="filmout_stats_monitor">
|
||||
<h3>Monitor</h3>
|
||||
<div id="filmout_stats_monitor_size"></div>
|
||||
<div id="filmout_stats_monitor_aspect"></div>
|
||||
<div id="filmout_stats_monitor_scale"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="filmout_position_wrap">
|
||||
<div>
|
||||
<button id="filmout_rewind" title="Rewind 1 Frame" onclick="filmout.rewind();"><</button>
|
||||
<input id="filmout_position" class="count" type="number" value="00000" onchange="gui.counterFormat(this, this.value);" />
|
||||
<button id="filmout_advance" title="Advance 1 Frame" onclick="filmout.advance();">></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="filmout_functions">
|
||||
<div>
|
||||
<button id="filmout_preview" onclick="filmout.preview();">PREVIEW</button>
|
||||
<button id="filmout_meter" onclick="filmout.meter();">METER</button>
|
||||
<button id="filmout_focus" onclick="filmout.focus();">FOCUS</button>
|
||||
<button id="filmout_field" onclick="filmout.field();">FIELD GUIDE</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="settings" class="screen">
|
||||
<div class="left">
|
||||
<div>
|
||||
<h4>Devices</h4>
|
||||
<select id="devices">
|
||||
|
@ -262,8 +423,8 @@
|
|||
<input type="radio" id="projector_type_arduino" name="projector_type" value="arduino" checked="checked" />
|
||||
</div>
|
||||
<div class="spacer">
|
||||
<input type="text" id="digital" name="digital" placeholder="Digital file" onclick="devices.digitalSelect();" data-file="" readonly />
|
||||
<input type="radio" id="projector_type" name="projector_type" value="video" onclick="devices.digital();" />
|
||||
<input type="text" id="digital" name="digital" placeholder="Digital file" onclick="filmout.selectFile();" data-file="" readonly />
|
||||
<input type="radio" id="projector_type_digital" name="projector_type" value="video" onclick="filmout.useFile();" />
|
||||
</div>
|
||||
<div>
|
||||
<h4>Camera</h4>
|
||||
|
@ -276,6 +437,13 @@
|
|||
<input type="text" id="intval" name="intval" placeholder="INTVAL3 URL"/>
|
||||
<input type="radio" id="camera_type_intval" name="camera_type" value="intval" onclick="devices.intval();" />
|
||||
</div>
|
||||
<div class="spacer">
|
||||
<input type="text" id="processing" name="processing" placeholder="PROCESSING URL" />
|
||||
<input type="radio" id="camera_type_processing" name="camera_type" value="processing" onclick="devices.processing();" />
|
||||
</div>
|
||||
<div>
|
||||
<div id="version"></div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Light</h4>
|
||||
<select id="light_device">
|
||||
|
@ -289,15 +457,32 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="spacer"></div>
|
||||
<div class="proj_time">
|
||||
<h4>Projector Time (ms)</h4>
|
||||
<input type="number" readonly id="proj_time" value="0" />
|
||||
<button id="submit_proj_time" class="hide">✓</button>
|
||||
</div>
|
||||
<div class="cam_time">
|
||||
<h4>Camera Time (ms)</h4>
|
||||
<input type="number" readonly id="cam_time" value="0" />
|
||||
<button id="submit_cam_time" class="hide" onclick="cam.exposure($('#cam_time').val());">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="overlay" onclick="gui.overlay(false);gui.spinner(false);"></div>
|
||||
<div id="spinner">
|
||||
<div id="spinnerMsg"></div>
|
||||
<div id="spinnerCancel">
|
||||
<div class="btn" style="margin:auto;" onclick="seq.cancel();">Cancel</div>
|
||||
</div>
|
||||
<div id="spinnerProgress" class="progress">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
|
||||
<span class="sr-only">0% Complete</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script src="./js/app.js"></script>
|
||||
|
|
|
@ -2472,77 +2472,64 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
},k.push(["lab",J])}).call(this);
|
||||
//fgnass.github.com/spin.js#v2.0.1
|
||||
!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define(b):a.Spinner=b()}(this,function(){"use strict";function a(a,b){var c,d=document.createElement(a||"div");for(c in b)d[c]=b[c];return d}function b(a){for(var b=1,c=arguments.length;c>b;b++)a.appendChild(arguments[b]);return a}function c(a,b,c,d){var e=["opacity",b,~~(100*a),c,d].join("-"),f=.01+c/d*100,g=Math.max(1-(1-a)/b*(100-f),a),h=j.substring(0,j.indexOf("Animation")).toLowerCase(),i=h&&"-"+h+"-"||"";return l[e]||(m.insertRule("@"+i+"keyframes "+e+"{0%{opacity:"+g+"}"+f+"%{opacity:"+a+"}"+(f+.01)+"%{opacity:1}"+(f+b)%100+"%{opacity:"+a+"}100%{opacity:"+g+"}}",m.cssRules.length),l[e]=1),e}function d(a,b){var c,d,e=a.style;for(b=b.charAt(0).toUpperCase()+b.slice(1),d=0;d<k.length;d++)if(c=k[d]+b,void 0!==e[c])return c;return void 0!==e[b]?b:void 0}function e(a,b){for(var c in b)a.style[d(a,c)||c]=b[c];return a}function f(a){for(var b=1;b<arguments.length;b++){var c=arguments[b];for(var d in c)void 0===a[d]&&(a[d]=c[d])}return a}function g(a,b){return"string"==typeof a?a:a[b%a.length]}function h(a){this.opts=f(a||{},h.defaults,n)}function i(){function c(b,c){return a("<"+b+' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">',c)}m.addRule(".spin-vml","behavior:url(#default#VML)"),h.prototype.lines=function(a,d){function f(){return e(c("group",{coordsize:k+" "+k,coordorigin:-j+" "+-j}),{width:k,height:k})}function h(a,h,i){b(m,b(e(f(),{rotation:360/d.lines*a+"deg",left:~~h}),b(e(c("roundrect",{arcsize:d.corners}),{width:j,height:d.width,left:d.radius,top:-d.width>>1,filter:i}),c("fill",{color:g(d.color,a),opacity:d.opacity}),c("stroke",{opacity:0}))))}var i,j=d.length+d.width,k=2*j,l=2*-(d.width+d.length)+"px",m=e(f(),{position:"absolute",top:l,left:l});if(d.shadow)for(i=1;i<=d.lines;i++)h(i,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(i=1;i<=d.lines;i++)h(i);return b(a,m)},h.prototype.opacity=function(a,b,c,d){var e=a.firstChild;d=d.shadow&&d.lines||0,e&&b+d<e.childNodes.length&&(e=e.childNodes[b+d],e=e&&e.firstChild,e=e&&e.firstChild,e&&(e.opacity=c))}}var j,k=["webkit","Moz","ms","O"],l={},m=function(){var c=a("style",{type:"text/css"});return b(document.getElementsByTagName("head")[0],c),c.sheet||c.styleSheet}(),n={lines:12,length:7,width:5,radius:10,rotate:0,corners:1,color:"#000",direction:1,speed:1,trail:100,opacity:.25,fps:20,zIndex:2e9,className:"spinner",top:"50%",left:"50%",position:"absolute"};h.defaults={},f(h.prototype,{spin:function(b){this.stop();{var c=this,d=c.opts,f=c.el=e(a(0,{className:d.className}),{position:d.position,width:0,zIndex:d.zIndex});d.radius+d.length+d.width}if(e(f,{left:d.left,top:d.top}),b&&b.insertBefore(f,b.firstChild||null),f.setAttribute("role","progressbar"),c.lines(f,c.opts),!j){var g,h=0,i=(d.lines-1)*(1-d.direction)/2,k=d.fps,l=k/d.speed,m=(1-d.opacity)/(l*d.trail/100),n=l/d.lines;!function o(){h++;for(var a=0;a<d.lines;a++)g=Math.max(1-(h+(d.lines-a)*n)%l*m,d.opacity),c.opacity(f,a*d.direction+i,g,d);c.timeout=c.el&&setTimeout(o,~~(1e3/k))}()}return c},stop:function(){var a=this.el;return a&&(clearTimeout(this.timeout),a.parentNode&&a.parentNode.removeChild(a),this.el=void 0),this},lines:function(d,f){function h(b,c){return e(a(),{position:"absolute",width:f.length+f.width+"px",height:f.width+"px",background:b,boxShadow:c,transformOrigin:"left",transform:"rotate("+~~(360/f.lines*k+f.rotate)+"deg) translate("+f.radius+"px,0)",borderRadius:(f.corners*f.width>>1)+"px"})}for(var i,k=0,l=(f.lines-1)*(1-f.direction)/2;k<f.lines;k++)i=e(a(),{position:"absolute",top:1+~(f.width/2)+"px",transform:f.hwaccel?"translate3d(0,0,0)":"",opacity:f.opacity,animation:j&&c(f.opacity,f.trail,l+k*f.direction,f.lines)+" "+1/f.speed+"s linear infinite"}),f.shadow&&b(i,e(h("#000","0 0 4px #000"),{top:"2px"})),b(d,b(i,h(g(f.color,k),"0 0 1px rgba(0,0,0,.1)")));return d},opacity:function(a,b,c){b<a.childNodes.length&&(a.childNodes[b].style.opacity=c)}});var o=e(a("group"),{behavior:"url(#default#VML)"});return!d(o,"transform")&&o.adj?i():j=d(o,"animation"),h});
|
||||
|
||||
const mcopy = {};
|
||||
mcopy.cfg = require('./data/cfg.json');
|
||||
|
||||
|
||||
const { remote, ipcRenderer } = require('electron');
|
||||
const dialog = require('electron').remote.dialog;
|
||||
const remote = require('@electron/remote');
|
||||
const { ipcRenderer } = require('electron');
|
||||
const { dialog } = remote;
|
||||
const notifier = require('node-notifier');
|
||||
const fs = require('fs');
|
||||
const uuid = require('uuid');
|
||||
const uuid = require('uuid').v4;
|
||||
const moment = require('moment');
|
||||
const path = require('path');
|
||||
const humanizeDuration = require('humanize-duration');
|
||||
const PACKAGE = require('./package.json');
|
||||
const cfg = require('./data/cfg.json');
|
||||
const gui = require('./lib/ui');
|
||||
const grid = require('./lib/ui/grid.js');
|
||||
const light = require('./lib/ui/light.js');
|
||||
const proj = require('./lib/ui/proj.js');
|
||||
const cam = require('./lib/ui/cam.js');
|
||||
const nav = require('./lib/ui/nav.js');
|
||||
const seq = require('./lib/ui/seq.js');
|
||||
const cmd = require('./lib/ui/cmd.js');
|
||||
const log = require('./lib/ui/log.js');
|
||||
const devices = require('./lib/ui/devices.js');
|
||||
const filmout = require('./lib/ui/filmout.js');
|
||||
const mse = require('./lib/ui/mscript.js');
|
||||
const capper = require('./lib/ui/capper.js');
|
||||
const timing = require('./lib/ui/timing.js');
|
||||
const Mscript = require('./lib/mscript');
|
||||
const { delay } = require('./lib/delay');
|
||||
const alertObj = require('./lib/ui/alert.js');
|
||||
|
||||
let log;
|
||||
|
||||
/******
|
||||
State shared by ALL interfaces
|
||||
*******/
|
||||
mcopy.state = {
|
||||
version : '2.0.0', //use for file compatibility check
|
||||
camera : {
|
||||
pos : 0,
|
||||
direction: true
|
||||
},
|
||||
projector : {
|
||||
pos : 0,
|
||||
direction: true
|
||||
},
|
||||
sequence : {
|
||||
size : 24,
|
||||
arr : ['CF', 'PF'],
|
||||
light : ['255,255,255', ''],
|
||||
cmd : {
|
||||
camera: mcopy.cfg.arduino.cmd.camera,
|
||||
projector: mcopy.cfg.arduino.cmd.projector,
|
||||
cam_direction: mcopy.cfg.arduino.cmd.cam_direction,
|
||||
cam_direction: mcopy.cfg.arduino.cmd.proj_direction
|
||||
},
|
||||
pads: {
|
||||
cam_forward: 'CF',
|
||||
proj_forward : 'PF',
|
||||
black_forward : 'BF',
|
||||
|
||||
cam_backward: 'CB',
|
||||
proj_backward : 'PB',
|
||||
black_backward : 'BB',
|
||||
|
||||
light_set : 'L'
|
||||
}
|
||||
}
|
||||
version : PACKAGE.version //use for file compatibility check
|
||||
};
|
||||
//
|
||||
|
||||
function init () {
|
||||
async function init () {
|
||||
'use strict';
|
||||
|
||||
log = await require('log')({})
|
||||
|
||||
nav.init();
|
||||
gui.grid.init();
|
||||
gui.init();
|
||||
grid.init();
|
||||
mse.mscript.init();
|
||||
mse.console.init();
|
||||
log.init();
|
||||
|
||||
devices.init();
|
||||
filmout.init();
|
||||
light.init();
|
||||
proj.init();
|
||||
cam.init();
|
||||
seq.init();
|
||||
capper.init();
|
||||
alertObj.init();
|
||||
timing.init();
|
||||
};
|
|
@ -8,11 +8,13 @@
|
|||
@import "./scroll.less";
|
||||
@import "./settings.less";
|
||||
@import "./mscript.less";
|
||||
@import "./filmout.less";
|
||||
|
||||
#log{
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: @FOOTER_H;
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#screens{
|
||||
|
@ -77,9 +79,13 @@
|
|||
|
||||
#counters,
|
||||
#counters_2,
|
||||
#move_to{
|
||||
#counters_3,
|
||||
#move_to,
|
||||
#move_to_2{
|
||||
.cam,
|
||||
.proj{
|
||||
.cam2,
|
||||
.proj,
|
||||
.proj2{
|
||||
width: 50%;
|
||||
padding-bottom: 10px;
|
||||
label{
|
||||
|
@ -101,18 +107,52 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.cam{
|
||||
.cam,
|
||||
.cam2{
|
||||
float: left;
|
||||
}
|
||||
.proj{
|
||||
.proj,
|
||||
.proj2{
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
#move_to{
|
||||
#counters{
|
||||
&.projectors{
|
||||
.proj,
|
||||
.proj2{
|
||||
width: 25%;
|
||||
label{
|
||||
line-height: 34px;
|
||||
font-size: 18px;
|
||||
}
|
||||
input{
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.cameras{
|
||||
.cam,
|
||||
.cam2{
|
||||
width: 25%;
|
||||
label{
|
||||
line-height: 34px;
|
||||
font-size: 18px;
|
||||
}
|
||||
input{
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#move_to,
|
||||
#move_to_2{
|
||||
margin-top: 20px;
|
||||
.cam,
|
||||
.proj{
|
||||
.cam2,
|
||||
.proj,
|
||||
.proj2{
|
||||
> div {
|
||||
width: 294px;
|
||||
margin: 0 auto;
|
||||
|
@ -129,6 +169,25 @@
|
|||
float: right;
|
||||
}
|
||||
}
|
||||
> .proj2{
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.cam2,
|
||||
.proj2,
|
||||
.black{
|
||||
display : none;
|
||||
> * {
|
||||
visibility: hidden;
|
||||
}
|
||||
&.on {
|
||||
display: block;
|
||||
> * {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#overlay{
|
||||
|
@ -158,6 +217,22 @@
|
|||
text-shadow: 1px 1px 2px #000;
|
||||
}
|
||||
|
||||
#spinnerCancel{
|
||||
display:none;
|
||||
position: absolute;
|
||||
z-index: 2000000000;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
text-align: center;
|
||||
margin-left: -40%;
|
||||
margin-top: 120px;
|
||||
width: 80%;
|
||||
.btn{
|
||||
margin: 0 auto;
|
||||
background: rgba(80,80,80, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.cp-app{
|
||||
position: relative !important;
|
||||
border-radius: 0px !important;
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
#buttons{
|
||||
#buttons,
|
||||
#buttons_2{
|
||||
> div{
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
.proj2 {
|
||||
float: right !important;
|
||||
}
|
||||
}
|
||||
|
||||
.cmd{
|
||||
|
@ -38,6 +42,10 @@
|
|||
background: @BACKWARD;
|
||||
border-color: @BACKWARD;
|
||||
}
|
||||
&.capper{
|
||||
background: white;
|
||||
color: @BG;
|
||||
}
|
||||
i{
|
||||
color: @BG;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
#video{
|
||||
input,select{
|
||||
.button();
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
font-size: 21px;
|
||||
min-width: 300px;
|
||||
&.active{
|
||||
border-color: @SELECTED;
|
||||
color: @SELECTED;
|
||||
}
|
||||
}
|
||||
button, select {
|
||||
padding: 9px 16px 8px;
|
||||
}
|
||||
}
|
||||
|
||||
#path_bar{
|
||||
padding: 5px;
|
||||
height: 50px;
|
||||
input{
|
||||
float: left;
|
||||
}
|
||||
button{
|
||||
float: left;
|
||||
margin-left: 5px;
|
||||
}
|
||||
select{
|
||||
line-height: 41px;
|
||||
height: 37px;
|
||||
margin-right: 5px;
|
||||
float: right;
|
||||
box-sizing: content-box;
|
||||
padding: 0 0 0 8px;
|
||||
}
|
||||
}
|
||||
#filmout_file {
|
||||
|
||||
}
|
||||
#filmout_monitor{
|
||||
display: none;
|
||||
border: 2px solid white;
|
||||
box-sizing: border-box;
|
||||
height: 360px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
&.on{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
#filmout_preview_wrap {
|
||||
background: #000;
|
||||
width: 100%;
|
||||
height: 360px;
|
||||
}
|
||||
#filmout {
|
||||
position: absolute;
|
||||
background-repeat:no-repeat;
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: block;
|
||||
opacity: 0;
|
||||
&.on {
|
||||
opacity: 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
#filmout_position_wrap{
|
||||
padding-top: 5px;
|
||||
height: 50px;
|
||||
input{
|
||||
margin-right: 5px;
|
||||
margin-left: 5px;
|
||||
width: 308px !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
button, input{
|
||||
float: left;
|
||||
}
|
||||
> div{
|
||||
width: 425px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
#filmout_functions{
|
||||
padding-top: 5px;
|
||||
> div{
|
||||
width: 425px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
#filmout_stats_video,
|
||||
#filmout_stats_monitor{
|
||||
width: 150px;
|
||||
position: absolute;
|
||||
//background: grey;
|
||||
padding: 10px 5px;
|
||||
text-align: center;
|
||||
h3{
|
||||
font-size: 20px;
|
||||
margin: 16px 0 3px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
#filmout_stats_video{
|
||||
left: 5px;
|
||||
}
|
||||
#filmout_stats_monitor{
|
||||
right: 5px;
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
float: right;
|
||||
width: 90px;
|
||||
margin-right: 60px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
#seq_stats{
|
||||
|
@ -45,7 +46,7 @@
|
|||
.timing{
|
||||
}
|
||||
}
|
||||
#seq_loop{
|
||||
#seq_loop_wrap{
|
||||
width: 40%;
|
||||
float: left;
|
||||
padding: 0 0 0 56px;
|
||||
|
@ -64,43 +65,75 @@
|
|||
}
|
||||
}
|
||||
|
||||
#sequencer{
|
||||
|
||||
}
|
||||
#sequence{
|
||||
width: 970px;
|
||||
padding-bottom: 21px;
|
||||
padding-left: 70px;
|
||||
#cam_forward,
|
||||
#proj_forward,
|
||||
padding-left: 92px;
|
||||
#camera_forward,
|
||||
#camera_second_forward,
|
||||
#projector_forward,
|
||||
#projector_second_forward,
|
||||
#black_forward{
|
||||
clear: both;
|
||||
input[type=checkbox]{
|
||||
border: 2px solid @FORWARD;
|
||||
&:checked{
|
||||
background: @FORWARD;
|
||||
//background: radial-gradient(circle at 25px 25px, #00C4A0, #343434);
|
||||
}
|
||||
}
|
||||
>div{
|
||||
color: @FORWARD;
|
||||
}
|
||||
}
|
||||
#cam_backward,
|
||||
#proj_backward,
|
||||
#camera_backward,
|
||||
#camera_second_backward,
|
||||
#projector_backward,
|
||||
#projector_second_backward,
|
||||
#black_backward{
|
||||
clear: both;
|
||||
input[type=checkbox]{
|
||||
border: 2px solid @BACKWARD;
|
||||
&:checked{
|
||||
background: @BACKWARD;
|
||||
//background: radial-gradient(circle at 25px 25px, #AB1A25, #343434);
|
||||
}
|
||||
}
|
||||
>div{
|
||||
color: @BACKWARD;
|
||||
}
|
||||
}
|
||||
|
||||
#camera_second_forward,
|
||||
#projector_second_forward {
|
||||
input[type=checkbox]{
|
||||
border: 2px solid @FORWARD + @SECOND;
|
||||
&:checked{
|
||||
background: @FORWARD + @SECOND;
|
||||
}
|
||||
}
|
||||
>div{
|
||||
color: @FORWARD + @SECOND;
|
||||
}
|
||||
|
||||
}
|
||||
#camera_second_backward,
|
||||
#projector_second_backward{
|
||||
input[type=checkbox]{
|
||||
border: 2px solid @BACKWARD + @SECOND;
|
||||
&:checked{
|
||||
background: @BACKWARD + @SECOND;
|
||||
}
|
||||
}
|
||||
>div{
|
||||
color: @BACKWARD + @SECOND;
|
||||
}
|
||||
}
|
||||
#black{
|
||||
input[type=checkbox]{
|
||||
&:checked{
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
input[type=checkbox]{
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
@ -116,6 +149,10 @@
|
|||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
&.disabled{
|
||||
cursor: not-allowed;
|
||||
border-color: rgb(100, 100, 100);
|
||||
}
|
||||
}
|
||||
.L{
|
||||
display: inline-block;
|
||||
|
@ -164,10 +201,10 @@
|
|||
.monospace();
|
||||
background-color: #272b30;
|
||||
position: absolute;
|
||||
top: 115px;
|
||||
top: 113px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 15px;
|
||||
width: 54px;
|
||||
width: 75px;
|
||||
div{
|
||||
height: 43px;
|
||||
line-height: 35px;
|
||||
|
@ -177,11 +214,33 @@
|
|||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
i.fa{
|
||||
right: 3px;
|
||||
position: absolute;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
#loop_current{
|
||||
margin-top: 54px;
|
||||
width: 121px;
|
||||
font-family: 'Menlo', monospace;
|
||||
font-size: 22px;
|
||||
margin-top: 13px;
|
||||
margin-right: 50px;
|
||||
width: 93px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
float: right;
|
||||
color: @SELECTED;
|
||||
}
|
||||
}
|
||||
|
||||
#seq_pause{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#seq_progress{
|
||||
width: 100%;
|
||||
height: 15px;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
|
|
@ -1,25 +1,61 @@
|
|||
#settings{
|
||||
h4{
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
> div{
|
||||
width: 300px;
|
||||
margin: 0 auto;
|
||||
&.left{
|
||||
float: left;
|
||||
padding-left: 30px;
|
||||
}
|
||||
&.right{
|
||||
float: right;
|
||||
padding-right: 30px;
|
||||
input[type=number] {
|
||||
min-width: 200px;
|
||||
width: 200px;
|
||||
}
|
||||
input[readonly]{
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.spacer{
|
||||
height: 62px;
|
||||
}
|
||||
.proj_time{
|
||||
height: 111px;
|
||||
}
|
||||
.cam_time{
|
||||
height: 111px;
|
||||
}
|
||||
& > div {
|
||||
width: 270px;
|
||||
}
|
||||
}
|
||||
}
|
||||
> div > div{
|
||||
width: 360px;
|
||||
}
|
||||
input[type=text], select{
|
||||
input[type=text],
|
||||
input[type=number],
|
||||
select{
|
||||
.button();
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
font-size: 21px;
|
||||
min-width: 300px;
|
||||
max-width: 300px;
|
||||
&.active{
|
||||
border-color: @SELECTED;
|
||||
color: @SELECTED;
|
||||
}
|
||||
}
|
||||
input[type=text]{
|
||||
width: 200px;
|
||||
}
|
||||
button{
|
||||
margin-top: -1px;
|
||||
float: right;
|
||||
margin-top: 0px;
|
||||
float: right;
|
||||
padding: 8px 16px 9px;
|
||||
}
|
||||
input[type=radio]{
|
||||
float: right;
|
||||
|
@ -28,4 +64,15 @@
|
|||
.spacer{
|
||||
margin-top: 10px;
|
||||
}
|
||||
#version{
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
bottom: 10px;
|
||||
z-index: 1000;
|
||||
height: 14px;
|
||||
width: auto;
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
@FORWARD: #00C4A0;
|
||||
@BACKWARD: #AB1A25;
|
||||
@SELECTED: #DAE035;
|
||||
@SECOND : rgb(20, 20, 20);
|
||||
|
||||
@SEQ: #3C3636;
|
||||
@SCRIPT: rgb(39, 40, 34);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export {};
|
|
@ -0,0 +1,58 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/* class representing alert functionality */
|
||||
class Alert {
|
||||
constructor(ui) {
|
||||
this.id = 'alert';
|
||||
this.cb = null;
|
||||
this.ui = ui;
|
||||
this.init();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async init() {
|
||||
const Log = require('log');
|
||||
this.log = await Log({ label: this.id });
|
||||
this.ipc = require('electron').ipcMain;
|
||||
this.listen();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
listen() {
|
||||
this.ipc.on(this.id, this.listener.bind(this));
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async listener(event, arg) {
|
||||
if (this.cb !== null) {
|
||||
try {
|
||||
await this.cb(arg.state, arg.id);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
event.returnValue = true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async start(cmd) {
|
||||
const start = +new Date();
|
||||
const msg = (cmd + '').replace('ALERT', '').replace('Alert', '').replace('alert', '').trim();
|
||||
this.ui.send(this.id, { msg });
|
||||
return new Promise(function (resolve, reject) {
|
||||
this.cb = function () {
|
||||
const ms = (+new Date()) - start;
|
||||
return resolve(ms);
|
||||
};
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
module.exports = function (ui) {
|
||||
return new Alert(ui);
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/alert/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAIb,4CAA4C;AAE5C,MAAM,KAAK;IAOV,YAAc,EAAQ;QAJd,OAAE,GAAY,OAAO,CAAA;QACrB,OAAE,GAAc,IAAI,CAAA;QAI3B,IAAI,CAAC,EAAE,GAAG,EAAE,CAAA;QACZ,IAAI,CAAC,IAAI,EAAE,CAAA;IACZ,CAAC;IAED;;QAEI;IACI,KAAK,CAAC,IAAI;QACjB,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;QAC1B,IAAI,CAAC,GAAG,GAAG,MAAM,GAAG,CAAC,EAAE,KAAK,EAAG,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;QACzC,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAA;QACtC,IAAI,CAAC,MAAM,EAAE,CAAA;IACd,CAAC;IAED;;QAEI;IACI,MAAM;QACb,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAC/C,CAAC;IAED;;QAEI;IACI,KAAK,CAAC,QAAQ,CAAE,KAAW,EAAE,GAAS;QAC7C,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE;YACrB,IAAI;gBACH,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;aAChC;YAAC,OAAO,GAAG,EAAE;gBACb,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;aACnB;SACD;QACD,KAAK,CAAC,WAAW,GAAG,IAAI,CAAA;IACzB,CAAC;IAED;;QAEI;IACG,KAAK,CAAC,KAAK,CAAE,GAAY;QAC/B,MAAM,KAAK,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAY,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;QACrG,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAA;QAC9B,OAAO,IAAI,OAAO,CAAC,UAAU,OAAkB,EAAE,MAAiB;YACjE,IAAI,CAAC,EAAE,GAAG;gBACT,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC;gBACjC,OAAO,OAAO,CAAC,EAAE,CAAC,CAAC;YACpB,CAAC,CAAA;QACF,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACf,CAAC;CACD;AAED,MAAM,CAAC,OAAO,GAAG,UAAU,EAAQ;IAClC,OAAO,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC;AACtB,CAAC,CAAA"}
|
|
@ -0,0 +1,71 @@
|
|||
<a name="Arduino"></a>
|
||||
|
||||
## Arduino
|
||||
Class representing the arduino communication features
|
||||
|
||||
**Kind**: global class
|
||||
|
||||
* [Arduino](#Arduino)
|
||||
* [.enumerate()](#Arduino+enumerate) ⇒ <code>Promise</code>
|
||||
* [.sendAsync(device, cmd)](#Arduino+sendAsync) ⇒ <code>Promise</code>
|
||||
* [.writeAsync(device, str)](#Arduino+writeAsync) ⇒ <code>Promise</code>
|
||||
* [.openArduino(device)](#Arduino+openArduino) ⇒ <code>Promise</code>
|
||||
* [.closeArduino(device)](#Arduino+closeArduino) ⇒ <code>Promise</code>
|
||||
|
||||
<a name="Arduino+enumerate"></a>
|
||||
|
||||
### arduino.enumerate() ⇒ <code>Promise</code>
|
||||
Enumerate all connected devices that might be Arduinos
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#Arduino)
|
||||
**Returns**: <code>Promise</code> - Resolves after enumerating
|
||||
<a name="Arduino+sendAsync"></a>
|
||||
|
||||
### arduino.sendAsync(device, cmd) ⇒ <code>Promise</code>
|
||||
Send a command to an Arduino using async/await
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#Arduino)
|
||||
**Returns**: <code>Promise</code> - Resolves after sending
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| device | <code>string</code> | Arduino identifier |
|
||||
| cmd | <code>string</code> | Single character command to send |
|
||||
|
||||
<a name="Arduino+writeAsync"></a>
|
||||
|
||||
### arduino.writeAsync(device, str) ⇒ <code>Promise</code>
|
||||
Send a string to an Arduino using async/await
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#Arduino)
|
||||
**Returns**: <code>Promise</code> - Resolves after sending
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| device | <code>string</code> | Arduino identifier |
|
||||
| str | <code>string</code> | String to send |
|
||||
|
||||
<a name="Arduino+openArduino"></a>
|
||||
|
||||
### arduino.openArduino(device) ⇒ <code>Promise</code>
|
||||
Connect to an Arduino using async/await
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#Arduino)
|
||||
**Returns**: <code>Promise</code> - Resolves after opening
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| device | <code>string</code> | Arduino identifier |
|
||||
|
||||
<a name="Arduino+closeArduino"></a>
|
||||
|
||||
### arduino.closeArduino(device) ⇒ <code>Promise</code>
|
||||
Close a connection to an Arduino using async/await
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#Arduino)
|
||||
**Returns**: <code>Promise</code> - Resolves after closing
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| device | <code>string</code> | Arduino identifier |
|
||||
|
|
@ -0,0 +1 @@
|
|||
export {};
|
|
@ -1,327 +1,601 @@
|
|||
'use strict'
|
||||
|
||||
const SerialPort = require('serialport')
|
||||
const Readline = SerialPort.parsers.Readline
|
||||
const exec = require('child_process').exec
|
||||
const parser = new Readline('')
|
||||
const newlineRe = new RegExp('\n', 'g')
|
||||
const returnRe = new RegExp('\r', 'g')
|
||||
let eventEmitter
|
||||
|
||||
const mcopy = {}
|
||||
|
||||
async function delay (ms) {
|
||||
return new Promise(resolve => {
|
||||
return setTimeout(resolve, ms)
|
||||
})
|
||||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/**
|
||||
* 2023-07-16 Clarification
|
||||
*
|
||||
* Previous versions of this script intermingled and even
|
||||
* swapped the usage of the terms 'serial' and 'device'.
|
||||
* From here on out, the terms will be used as such:
|
||||
*
|
||||
* serial - a hardware address of a serial port
|
||||
* device - common name of a type of mcopy device (eg. camera,
|
||||
* projector, light) that is aliased to a serial port
|
||||
*
|
||||
**/
|
||||
//import Log = require('log');
|
||||
const delay_1 = require("delay");
|
||||
const { SerialPort } = require('serialport');
|
||||
const { ReadlineParser } = require('@serialport/parser-readline');
|
||||
const exec = require('child_process').exec;
|
||||
const parser = new ReadlineParser({ delimiter: '\r\n' });
|
||||
const newlineRe = new RegExp('\n', 'g');
|
||||
const returnRe = new RegExp('\r', 'g');
|
||||
let eventEmitter;
|
||||
let cfg;
|
||||
let arduino;
|
||||
const KNOWN = [
|
||||
'/dev/tty.usbmodem1a161',
|
||||
'/dev/tty.usbserial-A800f8dk',
|
||||
'/dev/tty.usbserial-A900cebm',
|
||||
'/dev/tty.usbmodem1a131',
|
||||
'/dev/tty.usbserial-a900f6de',
|
||||
'/dev/tty.usbmodem1a141',
|
||||
'/dev/ttyACM0',
|
||||
'COM3'
|
||||
];
|
||||
/**
|
||||
* Class representing the arduino communication features
|
||||
**/
|
||||
class Arduino {
|
||||
constructor(errorState) {
|
||||
this.path = {};
|
||||
this.known = KNOWN;
|
||||
this.alias = {};
|
||||
this.serial = {};
|
||||
this.hasState = {};
|
||||
this.baud = 57600;
|
||||
this.queue = {};
|
||||
this.timer = 0;
|
||||
this.locks = {};
|
||||
this.stateStr = {};
|
||||
this.errorState = errorState;
|
||||
this.init();
|
||||
}
|
||||
async init() {
|
||||
const Log = require('log');
|
||||
this.log = await Log({ label: 'arduino' });
|
||||
this.keys = Object.keys(cfg.arduino.cmd);
|
||||
this.values = this.keys.map(key => cfg.arduino.cmd[key]);
|
||||
}
|
||||
/**
|
||||
* Enumerate all connected devices that might be Arduinos
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise} Resolves after enumerating
|
||||
**/
|
||||
async enumerate() {
|
||||
let ports;
|
||||
let matches = [];
|
||||
try {
|
||||
ports = await SerialPort.list();
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
this.log.info('Available ports:');
|
||||
this.log.info(ports.map((port) => { return port.path; }).join(','));
|
||||
ports.forEach((port) => {
|
||||
if (this.known.indexOf(port.path) !== -1) {
|
||||
matches.push(port.path);
|
||||
}
|
||||
else if ((port.manufacturer + '').toLowerCase().indexOf('arduino') !== -1) {
|
||||
matches.push(port.path);
|
||||
}
|
||||
else if ((port.path + '').toLowerCase().indexOf('usbserial') !== -1) {
|
||||
matches.push(port.path);
|
||||
}
|
||||
else if ((port.path + '').toLowerCase().indexOf('usbmodem') !== -1) {
|
||||
matches.push(port.path);
|
||||
}
|
||||
else if ((port.path + '').toLowerCase().indexOf('ttyusb') !== -1) {
|
||||
matches.push(port.path);
|
||||
}
|
||||
});
|
||||
if (matches.length === 0) {
|
||||
throw new Error('No USB devices found');
|
||||
}
|
||||
else if (matches.length > 0) {
|
||||
return matches;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Send a command to an Arduino using async/await
|
||||
*
|
||||
* @param {string} device The Arduino device identifier
|
||||
* @param {string} cmd Single character command to send
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise} Resolves after sending
|
||||
**/
|
||||
async sendAsync(device, cmd) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.log.info(`sendAsync ${cmd} -> ${device}`);
|
||||
this.queue[cmd] = (ms) => {
|
||||
return resolve(ms);
|
||||
};
|
||||
this.log.info(`Device: ${device}`);
|
||||
return this.serial[this.alias[device]].write(cmd, (err, results) => {
|
||||
if (err) {
|
||||
//this.log.error(err)
|
||||
return reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Sends a command to the specified Arduino and waits for a response.
|
||||
* Handles the communication lock to prevent sending multiple commands simultaneously.
|
||||
* Emits an 'arduino_send' event after successfully sending the command.
|
||||
*
|
||||
* @async
|
||||
* @param {string} device - The Arduino device identifier.
|
||||
* @param {string} cmd - The command to be sent to the Arduino.
|
||||
* @returns {Promise<boolean|string>} Returns 'false' if the communication is locked, otherwise returns the response from the device.
|
||||
* @throws {Error} Throws an error if the sendAsync method encounters an error.
|
||||
**/
|
||||
async send(device, cmd) {
|
||||
const serial = this.alias[device];
|
||||
let ms;
|
||||
this.log.info(`send ${cmd} -> ${device}`);
|
||||
if (this.isLocked(serial)) {
|
||||
this.log.warn(`send Serial ${serial} is locked`);
|
||||
return null;
|
||||
}
|
||||
this.timer = new Date().getTime();
|
||||
this.lock(serial);
|
||||
await (0, delay_1.delay)(cfg.arduino.serialDelay);
|
||||
try {
|
||||
ms = await this.sendAsync(device, cmd);
|
||||
}
|
||||
catch (e) {
|
||||
return this.log.error(e);
|
||||
}
|
||||
this.unlock(serial);
|
||||
await eventEmitter.emit('arduino_send', cmd);
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Sends a string to the specified Arduino.
|
||||
* Handles different types of devices, including fake devices for testing purposes.
|
||||
* Waits for a specified delay before sending the string.
|
||||
*
|
||||
* @async
|
||||
* @param {string} device - The Arduino device identifier.
|
||||
* @param {string} str - The string to be sent to the Arduino.
|
||||
* @returns {Promise<boolean|string>} Returns 'true' if the string is sent successfully, otherwise returns an error message.
|
||||
* @throws {Error} Throws an error if the writeAsync method encounters an error.
|
||||
**/
|
||||
async sendString(device, str) {
|
||||
let writeSuccess;
|
||||
await (0, delay_1.delay)(cfg.arduino.serialDelay);
|
||||
if (typeof this.serial[this.alias[device]].fake !== 'undefined'
|
||||
&& this.serial[this.alias[device]].fake) {
|
||||
return this.serial[this.alias[device]].string(str);
|
||||
}
|
||||
else {
|
||||
this.log.info(`sendString ${str} -> ${device}`);
|
||||
try {
|
||||
writeSuccess = await this.writeAsync(device, str);
|
||||
}
|
||||
catch (e) {
|
||||
return this.log.error(e);
|
||||
}
|
||||
this.unlock(this.alias[device]);
|
||||
return writeSuccess;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async stateAsync(device, confirm = false) {
|
||||
const cmd = cfg.arduino.cmd.state;
|
||||
const serial = confirm ? this.alias['connect'] : this.alias[device];
|
||||
return new Promise((resolve, reject) => {
|
||||
this.queue[cmd] = (state) => {
|
||||
this.stateStr[device] = state;
|
||||
if (confirm) {
|
||||
this.hasState[device] = true;
|
||||
this.log.info(`Device ${device} supports state [${state}]`);
|
||||
}
|
||||
return resolve(state);
|
||||
};
|
||||
if (confirm) {
|
||||
setTimeout(function () {
|
||||
if (typeof this.queue[cmd] !== 'undefined') {
|
||||
delete this.queue[cmd];
|
||||
this.hasState[device] = false;
|
||||
this.log.info(`Device ${device} does not support state`);
|
||||
return resolve(null);
|
||||
}
|
||||
}.bind(this), 1000);
|
||||
}
|
||||
this.log.info(`stateAsync ${cmd} -> ${device}`);
|
||||
return this.serial[serial].write(cmd, (err, results) => {
|
||||
if (err) {
|
||||
//this.log.error(err)
|
||||
return reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async state(device, confirm = false) {
|
||||
const serial = confirm ? this.alias['connect'] : this.alias[device];
|
||||
let results;
|
||||
if (this.isLocked(serial)) {
|
||||
this.log.warn(`state Serial ${serial} is locked`);
|
||||
return null;
|
||||
}
|
||||
this.timer = new Date().getTime();
|
||||
this.lock(serial);
|
||||
await (0, delay_1.delay)(cfg.arduino.serialDelay);
|
||||
try {
|
||||
results = await this.stateAsync(device, confirm);
|
||||
}
|
||||
catch (e) {
|
||||
return this.log.error(e);
|
||||
}
|
||||
this.unlock(serial);
|
||||
await eventEmitter.emit('arduino_state', cfg.arduino.cmd.state);
|
||||
return results;
|
||||
}
|
||||
/**
|
||||
* Send a string to an Arduino using async/await
|
||||
*
|
||||
* @param {string} device Arduino identifier
|
||||
* @param {string} str String to send
|
||||
*
|
||||
* @returns {Promise} Resolves after sending
|
||||
**/
|
||||
async writeAsync(device, str) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.serial[this.alias[device]].write(str, function (err, results) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
return resolve(results);
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Handles the end of communication with the Arduino.
|
||||
* Calculates the time taken for the communication, executes the callback,
|
||||
* and emits an 'arduino_end' event. Handles errors and stray data received.
|
||||
*
|
||||
* @param {string} serial - The serial address of the Arduino device.
|
||||
* @param {string} data - The data received from the Arduino.
|
||||
* @returns {any} The time taken for the communication in milliseconds.
|
||||
**/
|
||||
end(serial, data) {
|
||||
const end = new Date().getTime();
|
||||
const ms = end - this.timer;
|
||||
let complete;
|
||||
//this.log.info(`end ${serial} -> ${data}`)
|
||||
if (this.queue[data] !== undefined) {
|
||||
this.unlock(serial);
|
||||
complete = this.queue[data](ms); //execute callback
|
||||
eventEmitter.emit('arduino_end', data);
|
||||
delete this.queue[data];
|
||||
}
|
||||
else if (data[0] === cfg.arduino.cmd.state) {
|
||||
//this.log.info(`end serial -> ${serial}`)
|
||||
this.unlock(serial);
|
||||
complete = this.queue[cfg.arduino.cmd.state](data);
|
||||
eventEmitter.emit('arduino_end', data);
|
||||
delete this.queue[cfg.arduino.cmd.state];
|
||||
return data;
|
||||
}
|
||||
else if (data[0] === cfg.arduino.cmd.error) {
|
||||
this.log.error(`Received error from device ${serial}`);
|
||||
this.unlock(serial);
|
||||
this.error(serial, data);
|
||||
//error state
|
||||
//stop sequence
|
||||
//throw error in ui
|
||||
}
|
||||
else {
|
||||
this.log.info('Received stray "' + data + '"'); //silent to user
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
error(serial, data) {
|
||||
this.log.error("ERROR", data);
|
||||
}
|
||||
/**
|
||||
* Associates an alias with an Arduinos serial address.
|
||||
* Used to map multi-purpose devices onto the same serial connection.
|
||||
*
|
||||
* @param {string} device - The serial number of the target Arduino.
|
||||
* @param {string} serial - The alias to be associated with the target device.
|
||||
**/
|
||||
aliasSerial(device, serial) {
|
||||
//this.log.info(`Making "${serial}" an alias of ${device}`)
|
||||
this.alias[device] = serial;
|
||||
}
|
||||
/**
|
||||
* Connects to an Arduino using its serial number.
|
||||
* Sets up the SerialPort instance and path for the device, and handles data communication.
|
||||
* Handles opening the connection and emitting 'arduino_end' or 'confirmEnd' events upon receiving data.
|
||||
*
|
||||
* @async
|
||||
* @param {string} device - The device identifier (common name).
|
||||
* @param {string} serial - The serial address of the target Arduino (e.g., COM port on Windows).
|
||||
* @param {function} confirm - A callback function to be executed upon receiving confirmation data.
|
||||
* @returns {Promise<string>} Resolves with the device path if the connection is successful.
|
||||
* @throws {Error} Rejects with an error message if the connection fails.
|
||||
**/
|
||||
async connect(device, serial, confirm) {
|
||||
//this.log.info(`connect device ${device}`)
|
||||
//this.log.info(`connect serial ${serial}`)
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let connectSuccess;
|
||||
this.path[device] = serial;
|
||||
this.aliasSerial(device, serial);
|
||||
this.serial[serial] = new SerialPort({
|
||||
path: serial,
|
||||
autoOpen: false,
|
||||
baudRate: cfg.arduino.baud,
|
||||
parser
|
||||
});
|
||||
this.unlock(serial);
|
||||
try {
|
||||
connectSuccess = await this.openArduino(device);
|
||||
}
|
||||
catch (e) {
|
||||
this.log.error(`Failed to open ${device} @ ${serial}: ` + e);
|
||||
return reject(e);
|
||||
}
|
||||
this.log.info(`Opened connection with ${this.path[device]} as ${device}`);
|
||||
if (!confirm) {
|
||||
this.serial[this.alias[device]].on('data', async (data) => {
|
||||
let d = data.toString('utf8');
|
||||
d = d.replace(newlineRe, '').replace(returnRe, '');
|
||||
return this.end(serial, d);
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.serial[this.alias[device]].on('data', async (data) => {
|
||||
let d = data.toString('utf8');
|
||||
d = d.replace(newlineRe, '').replace(returnRe, '');
|
||||
return await this.confirmEnd(d);
|
||||
});
|
||||
}
|
||||
return resolve(this.path[serial]);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Handles the confirmation data received from an Arduino.
|
||||
* Executes the confirmation callback function if the received data is present in the list of expected values.
|
||||
*
|
||||
* @param {string} data - The data received from the Arduino.
|
||||
**/
|
||||
confirmEnd(data) {
|
||||
if (this.values.indexOf(data) !== -1 && typeof this.confirmExec === 'function') {
|
||||
this.confirmExec(null, data);
|
||||
this.confirmExec = {};
|
||||
this.unlock(this.alias['connect']);
|
||||
}
|
||||
else if (data[0] === cfg.arduino.cmd.state) {
|
||||
this.queue[cfg.arduino.cmd.state](data);
|
||||
delete this.queue[cfg.arduino.cmd.state];
|
||||
this.unlock(this.alias['connect']);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Verifies the connection to an Arduino by sending a connect command.
|
||||
* The confirmation callback checks if the received data matches the expected connect command.
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise<boolean>} Resolves with 'true' if the connection is verified successfully.
|
||||
* @throws {Error} Rejects with an error message if the connection verification fails.
|
||||
**/
|
||||
async verify() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const device = 'connect';
|
||||
let writeSuccess;
|
||||
this.confirmExec = function (err, data) {
|
||||
if (data === cfg.arduino.cmd.connect) {
|
||||
return resolve(true);
|
||||
}
|
||||
else {
|
||||
return reject('Wrong data returned');
|
||||
}
|
||||
};
|
||||
await (0, delay_1.delay)(cfg.arduino.serialDelay);
|
||||
try {
|
||||
writeSuccess = await this.sendAsync(device, cfg.arduino.cmd.connect);
|
||||
}
|
||||
catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
return resolve(writeSuccess);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Distinguishes the type of Arduino connected.
|
||||
* Sends a command to the device to identify its type and resolves the promise with the received type.
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise<string>} Resolves with the type of the connected Arduino-based device.
|
||||
* @throws {Error} Rejects with an error message if the distinguish operation fails.
|
||||
**/
|
||||
async distinguish() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const device = 'connect';
|
||||
let writeSuccess;
|
||||
let type;
|
||||
this.confirmExec = function (err, data) {
|
||||
if (data === cfg.arduino.cmd.projector_identifier) {
|
||||
type = 'projector';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.camera_identifier) {
|
||||
type = 'camera';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.light_identifier) {
|
||||
type = 'light';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.projector_light_identifier) {
|
||||
type = 'projector,light';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.projector_camera_light_identifier) {
|
||||
type = 'projector,camera,light';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.projector_camera_identifier) {
|
||||
type = 'projector,camera';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.projector_second_identifier) {
|
||||
type = 'projector_second';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.projectors_identifier) {
|
||||
type = 'projector,projector_second';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.camera_second_identifier) {
|
||||
type = 'camera_second';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.cameras_identifier) {
|
||||
type = 'camera,camera_second';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.camera_projectors_identifier) {
|
||||
type = 'camera,projector,projector_second';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.cameras_projector_identifier) {
|
||||
type = 'camera,camera_second,projector';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.cameras_projectors_identifier) {
|
||||
type = 'camera,camera_second,projector,projector_second';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.capper_identifier) {
|
||||
type = 'capper';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.camera_capper_identifier) {
|
||||
type = 'camera,capper';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.camera_capper_projector_identifier) {
|
||||
type = 'camera,capper,projector';
|
||||
}
|
||||
else if (data === cfg.arduino.cmd.camera_capper_projectors_identifier) {
|
||||
type = 'camera,capper,projector,projector_second';
|
||||
}
|
||||
return resolve(type);
|
||||
};
|
||||
await (0, delay_1.delay)(cfg.arduino.serialDelay);
|
||||
try {
|
||||
writeSuccess = await this.sendAsync(device, cfg.arduino.cmd.mcopy_identifier);
|
||||
this.log.info(writeSuccess);
|
||||
}
|
||||
catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Closes the connection to an Arduino.
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise<boolean>} Resolves with 'true' if the connection is closed successfully.
|
||||
* @throws {Error} Throws an error if the closeArduino method encounters an error.
|
||||
**/
|
||||
async close() {
|
||||
const device = 'connect';
|
||||
let closeSuccess;
|
||||
try {
|
||||
closeSuccess = await this.closeArduino(device);
|
||||
}
|
||||
catch (e) {
|
||||
throw e;
|
||||
}
|
||||
return closeSuccess;
|
||||
}
|
||||
/**
|
||||
* Establishes a fake connection to an Arduino for testing purposes.
|
||||
* Creates a fake SerialPort instance with custom write and string methods.
|
||||
*
|
||||
* @async
|
||||
* @param {string} serial - The device identifier of the fake Arduino.
|
||||
* @returns {Promise<boolean>} Resolves with 'true' if the fake connection is established successfully.
|
||||
**/
|
||||
async fakeConnect(device) {
|
||||
const serial = '/dev/fake';
|
||||
this.aliasSerial(device, serial);
|
||||
this.serial[serial] = {
|
||||
write: async function (cmd, cb) {
|
||||
const t = {
|
||||
c: cfg.arduino.cam.time + cfg.arduino.cam.delay,
|
||||
p: cfg.arduino.proj.time + cfg.arduino.proj.delay,
|
||||
A: 180,
|
||||
B: 180
|
||||
};
|
||||
let timeout = t[cmd];
|
||||
if (typeof timeout === 'undefined')
|
||||
timeout = 10;
|
||||
arduino.timer = +new Date();
|
||||
await (0, delay_1.delay)(timeout);
|
||||
arduino.end(serial, cmd);
|
||||
return cb();
|
||||
},
|
||||
string: async function (str) {
|
||||
//do nothing
|
||||
return true;
|
||||
},
|
||||
fake: true
|
||||
};
|
||||
//this.log.info('Connected to fake arduino! Not real! Does not exist!')
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Connect to an Arduino using async/await
|
||||
*
|
||||
* @param {string} device Arduino identifier
|
||||
*
|
||||
* @returns {Promise} Resolves after opening
|
||||
**/
|
||||
async openArduino(device) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return this.serial[this.alias[device]].open((err) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
return resolve(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Close a connection to an Arduino using async/await
|
||||
*
|
||||
* @param {string} device Arduino identifier
|
||||
*
|
||||
* @returns {Promise} Resolves after closing
|
||||
**/
|
||||
async closeArduino(device) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return this.serial[this.alias[device]].close((err) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
return resolve(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
lock(serial) {
|
||||
//this.log.info(`Locked serial ${serial}`)
|
||||
this.locks[serial] = true;
|
||||
}
|
||||
unlock(serial) {
|
||||
//this.log.info(`Unlocked serial ${serial}`)
|
||||
this.locks[serial] = false;
|
||||
}
|
||||
isLocked(serial) {
|
||||
return typeof this.locks[serial] !== 'undefined' && this.locks[serial] === true;
|
||||
}
|
||||
}
|
||||
|
||||
async function send (device, cmd) {
|
||||
return new Promise ((resolve, reject) => {
|
||||
mcopy.arduino.queue[cmd] = (ms) => {
|
||||
return resolve(ms)
|
||||
}
|
||||
return mcopy.arduino.serial[device].write(cmd, (err, results) => {
|
||||
if (err) {
|
||||
//console.error(err)
|
||||
return reject(err)
|
||||
}
|
||||
//
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function write (device, str) {
|
||||
return new Promise ((resolve, reject) => {
|
||||
mcopy.arduino.serial[device].write(str, function (err, results) {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
//console.log('sent: ' + str)
|
||||
return resolve(results)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function open (device) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return mcopy.arduino.serial[device].open(error => {
|
||||
if (error) {
|
||||
return reject(error)
|
||||
}
|
||||
return resolve(true)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function close (device) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return mcopy.arduino.serial[device].close((err) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
return resolve(true)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/******
|
||||
Arduino handlers
|
||||
*******/
|
||||
mcopy.arduino = {
|
||||
path : {},
|
||||
known: [
|
||||
'/dev/tty.usbmodem1a161',
|
||||
'/dev/tty.usbserial-A800f8dk',
|
||||
'/dev/tty.usbserial-A900cebm',
|
||||
'/dev/tty.usbmodem1a131',
|
||||
'/dev/tty.usbserial-a900f6de',
|
||||
'/dev/tty.usbmodem1a141',
|
||||
'/dev/ttyACM0',
|
||||
'COM3'
|
||||
],
|
||||
alias : {
|
||||
|
||||
},
|
||||
serial : {
|
||||
connect : {},
|
||||
projector : {},
|
||||
camera : {},
|
||||
light : {}
|
||||
},
|
||||
baud : 57600,
|
||||
queue : {},
|
||||
timer : 0,
|
||||
lock : false
|
||||
}
|
||||
|
||||
mcopy.arduino.enumerate = async function () {
|
||||
return new Promise( (resolve, reject) => {
|
||||
return SerialPort.list((err, ports) => {
|
||||
let matches = []
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
ports.forEach(port => {
|
||||
if (mcopy.arduino.known.indexOf(port.comName) !== -1) {
|
||||
matches.push(port.comName)
|
||||
} else if ((port.manufacturer + '').toLowerCase().indexOf('arduino') !== -1) {
|
||||
matches.push(port.comName)
|
||||
}
|
||||
})
|
||||
if (matches.length === 0) {
|
||||
return reject('No USB devices found');
|
||||
} else if (matches.length > 0) {
|
||||
return resolve(matches)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
//commands which respond to a sent char
|
||||
mcopy.arduino.send = async function (serial, cmd, res) {
|
||||
const device = mcopy.arduino.alias[serial]
|
||||
let results
|
||||
if (mcopy.arduino.lock) {
|
||||
return false
|
||||
}
|
||||
mcopy.arduino.lock = true
|
||||
await delay(mcopy.cfg.arduino.serialDelay)
|
||||
try {
|
||||
results = await send(device, cmd)
|
||||
} catch (e) {
|
||||
return console.error(e)
|
||||
}
|
||||
mcopy.arduino.lock = false
|
||||
mcopy.arduino.timer = new Date().getTime()
|
||||
return await eventEmitter.emit('arduino_send', cmd)
|
||||
}
|
||||
|
||||
//send strings, after char triggers firmware to accept
|
||||
mcopy.arduino.string = async function (serial, str) {
|
||||
const device = mcopy.arduino.alias[serial]
|
||||
let writeSuccess
|
||||
await delay(mcopy.cfg.arduino.serialDelay)
|
||||
if (typeof mcopy.arduino.serial[device].fake !== 'undefined'
|
||||
&& mcopy.arduino.serial[device].fake) {
|
||||
return mcopy.arduino.serial[device].string(str)
|
||||
} else {
|
||||
try {
|
||||
writeSuccess = await write(device, str)
|
||||
} catch (e) {
|
||||
return console.error(e)
|
||||
}
|
||||
return writeSuccess
|
||||
}
|
||||
}
|
||||
|
||||
//respond with same char over serial when done
|
||||
mcopy.arduino.end = async function (data) {
|
||||
const end = new Date().getTime()
|
||||
const ms = end - mcopy.arduino.timer
|
||||
let complete
|
||||
if (mcopy.arduino.queue[data] !== undefined) {
|
||||
mcopy.arduino.lock = false;
|
||||
//console.log('Command ' + data + ' took ' + ms + 'ms');
|
||||
complete = mcopy.arduino.queue[data](ms) //execute callback
|
||||
eventEmitter.emit('arduino_end', data)
|
||||
delete mcopy.arduino.queue[data]
|
||||
} else {
|
||||
//console.log('Received stray "' + data + '"'); //silent to user
|
||||
}
|
||||
return complete
|
||||
};
|
||||
mcopy.arduino.alias = function (serial, device) {
|
||||
console.log(`Making "${serial}" an alias of ${device}`)
|
||||
mcopy.arduino.alias[serial] = device
|
||||
}
|
||||
mcopy.arduino.connect = async function (serial, device, confirm) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let connectSuccess
|
||||
mcopy.arduino.path[serial] = device;
|
||||
mcopy.arduino.alias[serial] = device;
|
||||
mcopy.arduino.serial[device] = new SerialPort(mcopy.arduino.path[serial], {
|
||||
autoOpen : false,
|
||||
baudRate: mcopy.cfg.arduino.baud,
|
||||
parser: parser
|
||||
})
|
||||
try {
|
||||
connectSuccess = await open(device)
|
||||
} catch (e) {
|
||||
console.error('failed to open: ' + e)
|
||||
return reject(e)
|
||||
}
|
||||
console.log(`Opened connection with ${mcopy.arduino.path[serial]} as ${serial}`);
|
||||
if (!confirm) {
|
||||
mcopy.arduino.serial[device].on('data', async (data) => {
|
||||
let d = data.toString('utf8')
|
||||
d = d.replace(newlineRe, '').replace(returnRe, '')
|
||||
return await mcopy.arduino.end(d)
|
||||
})
|
||||
} else {
|
||||
mcopy.arduino.serial[device].on('data', async (data) => {
|
||||
let d = data.toString('utf8')
|
||||
d = d.replace(newlineRe, '').replace(returnRe, '')
|
||||
return await mcopy.arduino.confirmEnd(d)
|
||||
})
|
||||
}
|
||||
return resolve(mcopy.arduino.path[serial])
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
mcopy.arduino.confirmExec = {};
|
||||
mcopy.arduino.confirmEnd = function (data) {
|
||||
//console.dir(data)
|
||||
if (data === mcopy.cfg.arduino.cmd.connect
|
||||
|| data === mcopy.cfg.arduino.cmd.proj_identifier
|
||||
|| data === mcopy.cfg.arduino.cmd.cam_identifier
|
||||
|| data === mcopy.cfg.arduino.cmd.light_identifier
|
||||
|| data === mcopy.cfg.arduino.cmd.proj_light_identifier
|
||||
|| data === mcopy.cfg.arduino.cmd.proj_cam_light_identifier
|
||||
|| data === mcopy.cfg.arduino.cmd.proj_cam_identifier ) {
|
||||
mcopy.arduino.confirmExec(null, data);
|
||||
mcopy.arduino.confirmExec = {};
|
||||
}
|
||||
}
|
||||
|
||||
mcopy.arduino.verify = async function () {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const device = mcopy.arduino.alias['connect']
|
||||
let writeSuccess
|
||||
mcopy.arduino.confirmExec = function (err, data) {
|
||||
if (data === mcopy.cfg.arduino.cmd.connect) {
|
||||
return resolve(true)
|
||||
} else {
|
||||
return reject('Wrong data returned')
|
||||
}
|
||||
}
|
||||
await delay(mcopy.cfg.arduino.serialDelay)
|
||||
try {
|
||||
writeSuccess = await send(device, mcopy.cfg.arduino.cmd.connect)
|
||||
} catch (e) {
|
||||
return reject(e)
|
||||
}
|
||||
return resolve(writeSuccess)
|
||||
})
|
||||
}
|
||||
|
||||
mcopy.arduino.distinguish = async function () {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const device = mcopy.arduino.alias['connect']
|
||||
let writeSuccess
|
||||
let type
|
||||
mcopy.arduino.confirmExec = function (err, data) {
|
||||
if (data === mcopy.cfg.arduino.cmd.proj_identifier) {
|
||||
type = 'projector'
|
||||
} else if (data === mcopy.cfg.arduino.cmd.cam_identifier) {
|
||||
type = 'camera'
|
||||
} else if (data === mcopy.cfg.arduino.cmd.light_identifier) {
|
||||
type = 'light'
|
||||
} else if (data === mcopy.cfg.arduino.cmd.proj_light_identifier) {
|
||||
type = 'projector,light'
|
||||
} else if (data === mcopy.cfg.arduino.cmd.proj_cam_light_identifier) {
|
||||
type = 'projector,camera,light'
|
||||
} else if (data === mcopy.cfg.arduino.cmd.proj_cam_identifier) {
|
||||
type = 'projector,camera'
|
||||
}
|
||||
return resolve(type)
|
||||
}
|
||||
await delay(mcopy.cfg.arduino.serialDelay)
|
||||
try {
|
||||
writeSuccess = await send(device, mcopy.cfg.arduino.cmd.mcopy_identifier)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return reject(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
mcopy.arduino.close = async function (callback) {
|
||||
const device = mcopy.arduino.alias['connect']
|
||||
let closeSuccess
|
||||
try {
|
||||
closeSuccess = await close(device)
|
||||
} catch (e) {
|
||||
return console.error(e)
|
||||
}
|
||||
return closeSuccess
|
||||
};
|
||||
|
||||
mcopy.arduino.fakeConnect = async function (serial) {
|
||||
//console.log('Connecting to fake arduino...');
|
||||
const device = '/dev/fake'
|
||||
mcopy.arduino.alias[serial] = device
|
||||
mcopy.arduino.serial[device] = {
|
||||
write : function (cmd, cb) {
|
||||
const t = {
|
||||
c : mcopy.cfg.arduino.cam.time + mcopy.cfg.arduino.cam.delay,
|
||||
p : mcopy.cfg.arduino.proj.time + mcopy.cfg.arduino.proj.delay
|
||||
}
|
||||
let timeout = t[cmd]
|
||||
let end
|
||||
if (typeof timeout === 'undefined') timeout = 10
|
||||
mcopy.arduino.timer = +new Date()
|
||||
setTimeout(() => {
|
||||
mcopy.arduino.end(cmd)
|
||||
return cb()
|
||||
}, timeout)
|
||||
|
||||
},
|
||||
string : async function (str) {
|
||||
//do nothing
|
||||
return true
|
||||
},
|
||||
fake : true
|
||||
};
|
||||
//console.log('Connected to fake arduino! Not real! Doesn\'t exist!');
|
||||
return true
|
||||
}
|
||||
|
||||
if (typeof module !== 'undefined' && module.parent) {
|
||||
module.exports = function (cfg, ee) {
|
||||
eventEmitter = ee
|
||||
mcopy.cfg = cfg
|
||||
return mcopy.arduino
|
||||
}
|
||||
}
|
||||
module.exports = function (c, ee, errorState) {
|
||||
eventEmitter = ee;
|
||||
cfg = c;
|
||||
arduino = new Arduino(errorState);
|
||||
return arduino;
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,49 @@
|
|||
<a name="Camera"></a>
|
||||
|
||||
## Camera
|
||||
class representing camera functions
|
||||
|
||||
**Kind**: global class
|
||||
|
||||
* [Camera](#Camera)
|
||||
* [.init()](#Camera+init)
|
||||
* [.listen()](#Camera+listen)
|
||||
* [.set()](#Camera+set)
|
||||
* [.move()](#Camera+move)
|
||||
* [.exposure()](#Camera+exposure)
|
||||
* [.connectIntval()](#Camera+connectIntval)
|
||||
* [.listener()](#Camera+listener)
|
||||
* [.end()](#Camera+end)
|
||||
|
||||
<a name="Camera+init"></a>
|
||||
|
||||
### camera.init()
|
||||
**Kind**: instance method of [<code>Camera</code>](#Camera)
|
||||
<a name="Camera+listen"></a>
|
||||
|
||||
### camera.listen()
|
||||
**Kind**: instance method of [<code>Camera</code>](#Camera)
|
||||
<a name="Camera+set"></a>
|
||||
|
||||
### camera.set()
|
||||
**Kind**: instance method of [<code>Camera</code>](#Camera)
|
||||
<a name="Camera+move"></a>
|
||||
|
||||
### camera.move()
|
||||
**Kind**: instance method of [<code>Camera</code>](#Camera)
|
||||
<a name="Camera+exposure"></a>
|
||||
|
||||
### camera.exposure()
|
||||
**Kind**: instance method of [<code>Camera</code>](#Camera)
|
||||
<a name="Camera+connectIntval"></a>
|
||||
|
||||
### camera.connectIntval()
|
||||
**Kind**: instance method of [<code>Camera</code>](#Camera)
|
||||
<a name="Camera+listener"></a>
|
||||
|
||||
### camera.listener()
|
||||
**Kind**: instance method of [<code>Camera</code>](#Camera)
|
||||
<a name="Camera+end"></a>
|
||||
|
||||
### camera.end()
|
||||
**Kind**: instance method of [<code>Camera</code>](#Camera)
|
|
@ -0,0 +1 @@
|
|||
export {};
|
|
@ -0,0 +1,342 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const intval_1 = require("intval");
|
||||
const processing_1 = require("processing");
|
||||
const delay_1 = require("delay");
|
||||
/** class representing camera functions **/
|
||||
class Camera {
|
||||
/**
|
||||
*
|
||||
**/
|
||||
constructor(arduino, cfg, ui, filmout, second = false) {
|
||||
this.state = {
|
||||
pos: 0,
|
||||
dir: true,
|
||||
capepr: false
|
||||
};
|
||||
this.arduino = null;
|
||||
this.intval = null;
|
||||
this.processing = null;
|
||||
this.id = 'camera';
|
||||
this.arduino = arduino;
|
||||
this.cfg = cfg;
|
||||
this.ui = ui;
|
||||
this.filmout = filmout;
|
||||
if (second)
|
||||
this.id += '_second';
|
||||
this.init();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async init() {
|
||||
const Log = require('log');
|
||||
this.log = await Log({ label: this.id });
|
||||
this.ipc = require('electron').ipcMain;
|
||||
this.listen();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
listen() {
|
||||
this.ipc.on(this.id, this.listener.bind(this));
|
||||
this.ipc.on('intval', this.connectIntval.bind(this));
|
||||
this.ipc.on('processing', this.connectProcessing.bind(this));
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async set(dir, id) {
|
||||
let cmd;
|
||||
let ms;
|
||||
if (dir) {
|
||||
cmd = this.cfg.arduino.cmd[`${this.id}_forward`];
|
||||
}
|
||||
else {
|
||||
cmd = this.cfg.arduino.cmd[`${this.id}_backward`];
|
||||
}
|
||||
this.state.dir = dir;
|
||||
if (this.processing) {
|
||||
try {
|
||||
ms = await this.processing.setDir(dir);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
else if (this.intval) {
|
||||
try {
|
||||
ms = await this.intval.setDir(dir);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
ms = await this.arduino.send(this.id, cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
return await this.end(cmd, id, ms);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async cap(state, id) {
|
||||
let cmd;
|
||||
let ms;
|
||||
if (state) {
|
||||
cmd = this.cfg.arduino.cmd[`${this.id}_forward`];
|
||||
}
|
||||
else {
|
||||
cmd = this.cfg.arduino.cmd[`${this.id}_backward`];
|
||||
}
|
||||
this.state.capper = state;
|
||||
try {
|
||||
ms = await this.arduino.send(this.id, cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
return await this.end(cmd, id, ms);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async move(frame, id) {
|
||||
const cmd = this.cfg.arduino.cmd[this.id];
|
||||
let ms;
|
||||
if (this.filmout.state.enabled) {
|
||||
await this.filmout.start();
|
||||
}
|
||||
if (this.processing) {
|
||||
try {
|
||||
ms = await this.processing.move();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
else if (this.intval) {
|
||||
try {
|
||||
ms = await this.intval.move();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
ms = await this.arduino.send(this.id, cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
if (this.filmout.state.enabled) {
|
||||
//await delay(100 * 1000);
|
||||
await this.filmout.end();
|
||||
}
|
||||
//this.log.info('Camera move time', { ms });
|
||||
return this.end(cmd, id, ms);
|
||||
}
|
||||
async both(frame, id) {
|
||||
const cmd = this.cfg.arduino.cmd[id];
|
||||
let ms;
|
||||
try {
|
||||
ms = await this.arduino.send(this.id, cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(`Error moving ${this.id}`, err);
|
||||
}
|
||||
//this.log.info('Cameras move time', { ms });
|
||||
return await this.end(cmd, id, ms);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async exposure(exposure, id) {
|
||||
const cmd = this.cfg.arduino.cmd.camera_exposure;
|
||||
const str = `${exposure}`;
|
||||
const started = +new Date();
|
||||
let ms;
|
||||
let confirmState;
|
||||
let parts;
|
||||
let confirmExposure;
|
||||
if (this.intval) {
|
||||
return this.intval.setExposure(this.id, exposure, (ms) => {
|
||||
this.ui.send('timing', { c: 'c', ms: exposure });
|
||||
return this.end(cmd, id, ms);
|
||||
});
|
||||
}
|
||||
else if (this.arduino.hasState[this.id]) {
|
||||
try {
|
||||
ms = this.arduino.send(this.id, cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error sending camera exposure command', err);
|
||||
}
|
||||
await (0, delay_1.delay)(1);
|
||||
try {
|
||||
ms = await this.arduino.sendString(this.id, str);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error sending camera exposure string', err);
|
||||
}
|
||||
await ms;
|
||||
await (0, delay_1.delay)(1);
|
||||
try {
|
||||
confirmState = await this.arduino.state(this.id, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(`Error confirming set state`, err);
|
||||
}
|
||||
parts = this.arduino.stateStr[this.id].split('G');
|
||||
if (parts.length > 1) {
|
||||
parts = parts[1].split('H');
|
||||
confirmExposure = parseInt(parts[0]);
|
||||
if (!isNaN(confirmExposure)) {
|
||||
this.log.info(`Exposure successfully set to ${confirmExposure}ms`);
|
||||
this.ui.send('timing', { c: 'c', ms: exposure });
|
||||
}
|
||||
}
|
||||
ms = (+new Date()) - started;
|
||||
return await this.end(cmd, id, ms);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async connectIntval(event, arg) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (arg.connect) {
|
||||
this.intval = new intval_1.Intval(arg.url);
|
||||
this.processing = null;
|
||||
this.intval.connect((err, ms, state) => {
|
||||
if (err) {
|
||||
this.ui.send('intval', { connected: false });
|
||||
this.log.info(`Cannot connect to ${arg.url}`, 'INTVAL');
|
||||
this.intval = null;
|
||||
}
|
||||
else {
|
||||
this.ui.send('intval', { connected: true, url: arg.url, state: state });
|
||||
this.log.info(`Connected to INTVAL3 @ ${arg.url}`, 'INTVAL');
|
||||
}
|
||||
return resolve(true);
|
||||
});
|
||||
}
|
||||
else if (arg.disconnect) {
|
||||
this.intval = null;
|
||||
return resolve(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async connectProcessing(event, arg) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.processing = new processing_1.Processing(arg.url);
|
||||
this.intval = null;
|
||||
this.ui.send('processing', { connected: true, url: arg.url });
|
||||
return resolve(true);
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async listener(event, arg) {
|
||||
if (typeof arg.dir !== 'undefined') {
|
||||
try {
|
||||
await this.set(arg.dir, arg.id);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
else if (typeof arg.frame !== 'undefined') {
|
||||
try {
|
||||
await this.move(arg.frame, arg.id);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
else if (typeof arg.val !== 'undefined') {
|
||||
this.state.pos = arg.val;
|
||||
}
|
||||
else if (typeof arg.capper !== 'undefined') {
|
||||
try {
|
||||
await this.cap(arg.capper, arg.id);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
else if (typeof arg.exposure !== 'undefined') {
|
||||
try {
|
||||
await this.exposure(arg.exposure, arg.id);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
event.returnValue = true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async end(cmd, id, ms) {
|
||||
let message = '';
|
||||
if (cmd === this.cfg.arduino.cmd.camera_forward) {
|
||||
message = 'Camera set to FORWARD';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.cmd.camera_backward) {
|
||||
message = 'Camera set to BACKWARD';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.cmd.camera_second_forward) {
|
||||
message = 'Camera second set to FORWARD';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.cmd.camera_second_backward) {
|
||||
message = 'Camera second set to BACKWARD';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.cmd.camera) {
|
||||
message = 'Camera ';
|
||||
if (this.state.dir) {
|
||||
message += 'ADVANCED';
|
||||
}
|
||||
else {
|
||||
message += 'REWOUND';
|
||||
}
|
||||
message += ' 1 frame';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.cmd.camera_second) {
|
||||
message = 'Camera second ';
|
||||
if (this.state.dir) {
|
||||
message += 'ADVANCED';
|
||||
}
|
||||
else {
|
||||
message += 'REWOUND';
|
||||
}
|
||||
message += ' 1 frame';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.cmd.camerass) {
|
||||
message += 'Cameras both MOVED 1 frame each';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.camera_exposure) {
|
||||
message += 'Camera set exposure';
|
||||
}
|
||||
message += ` ${ms}ms`;
|
||||
this.log.info(message);
|
||||
this.ui.send(this.id, { cmd: cmd, id: id, ms: ms });
|
||||
return ms;
|
||||
}
|
||||
}
|
||||
module.exports = function (arduino, cfg, ui, filmout, second) {
|
||||
return new Camera(arduino, cfg, ui, filmout, second);
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "cam",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export {};
|
|
@ -0,0 +1,89 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/** class representing capper functions **/
|
||||
class Capper {
|
||||
/**
|
||||
*
|
||||
**/
|
||||
constructor(arduino, cfg, ui, filmout) {
|
||||
this.state = {
|
||||
capper: false
|
||||
};
|
||||
this.arduino = null;
|
||||
this.id = 'capper';
|
||||
this.arduino = arduino;
|
||||
this.cfg = cfg;
|
||||
this.ui = ui;
|
||||
this.filmout = filmout;
|
||||
this.init();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async init() {
|
||||
const Log = require('log');
|
||||
this.log = await Log({ label: this.id });
|
||||
this.ipc = require('electron').ipcMain;
|
||||
this.listen();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
listen() {
|
||||
this.ipc.on(this.id, this.listener.bind(this));
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async capper(state, id) {
|
||||
let cmd;
|
||||
let ms;
|
||||
if (state) {
|
||||
cmd = this.cfg.arduino.cmd[`${this.id}_on`];
|
||||
}
|
||||
else {
|
||||
cmd = this.cfg.arduino.cmd[`${this.id}_off`];
|
||||
}
|
||||
this.state.capper = state;
|
||||
try {
|
||||
ms = await this.arduino.send(this.id, cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
return await this.end(cmd, id, ms);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async listener(event, arg) {
|
||||
if (typeof arg.state !== 'undefined') {
|
||||
try {
|
||||
await this.capper(arg.state, arg.id);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
event.returnValue = true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async end(cmd, id, ms) {
|
||||
let message = '';
|
||||
if (cmd === this.cfg.arduino.cmd.capper_on) {
|
||||
message = 'Capper set to ON';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.cmd.capper_off) {
|
||||
message = 'Capper set to OFF';
|
||||
}
|
||||
message += ` ${ms}ms`;
|
||||
this.log.info(message);
|
||||
this.ui.send(this.id, { cmd: cmd, id: id, ms: ms });
|
||||
}
|
||||
}
|
||||
module.exports = function (arduino, cfg, ui, filmout) {
|
||||
return new Capper(arduino, cfg, ui, filmout);
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/capper/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAMb,2CAA2C;AAE3C,MAAM,MAAM;IAWX;;QAEI;IACJ,YAAa,OAAiB,EAAE,GAAS,EAAE,EAAQ,EAAE,OAAa;QAb1D,UAAK,GAAS;YACrB,MAAM,EAAG,KAAK;SACd,CAAC;QACM,YAAO,GAAa,IAAI,CAAC;QAMzB,OAAE,GAAY,QAAQ,CAAC;QAK9B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,EAAE,CAAC;IACb,CAAC;IAED;;QAEI;IACI,KAAK,CAAC,IAAI;QACjB,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,CAAC,GAAG,GAAG,MAAM,GAAG,CAAC,EAAE,KAAK,EAAG,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC;QACvC,IAAI,CAAC,MAAM,EAAE,CAAC;IACf,CAAC;IAED;;QAEI;IACI,MAAM;QACb,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChD,CAAC;IAED;;QAEI;IACI,KAAK,CAAC,MAAM,CAAE,KAAe,EAAE,EAAW;QACjD,IAAI,GAAY,CAAC;QACjB,IAAI,EAAW,CAAC;QAEhB,IAAI,KAAK,EAAE;YACV,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;SAC5C;aAAM;YACN,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;SAC7C;QAED,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;QAE1B,IAAI;YACH,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;SAC3C;QAAC,OAAO,GAAG,EAAE;YACb,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;SACpB;QAED,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACpC,CAAC;IAED;;QAEI;IACI,KAAK,CAAC,QAAQ,CAAE,KAAW,EAAE,GAAS;QAC7C,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,WAAW,EAAE;YACrC,IAAI;gBACH,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;aACpC;YAAC,OAAO,GAAG,EAAE;gBACb,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;aACnB;SACD;QACD,KAAK,CAAC,WAAW,GAAG,IAAI,CAAA;IACzB,CAAC;IAED;;QAEI;IACI,KAAK,CAAC,GAAG,CAAE,GAAY,EAAE,EAAW,EAAE,EAAW;QACxD,IAAI,OAAO,GAAG,EAAE,CAAC;QAEjB,IAAI,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE;YAC3C,OAAO,GAAG,kBAAkB,CAAC;SAC7B;aAAM,IAAI,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE;YACnD,OAAO,GAAG,mBAAmB,CAAC;SAC9B;QAED,OAAO,IAAI,IAAI,EAAE,IAAI,CAAA;QAErB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAC,CAAC,CAAC;IACpD,CAAC;CACD;AAED,MAAM,CAAC,OAAO,GAAG,UAAU,OAAiB,EAAE,GAAS,EAAE,EAAQ,EAAE,OAAY;IAC9E,OAAO,IAAI,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC,CAAA"}
|
|
@ -8,8 +8,8 @@ const parser = new Readline('');
|
|||
const newlineRe = new RegExp('\n', 'g');
|
||||
const returnRe = new RegExp('\r', 'g');
|
||||
|
||||
const exec = require('exec');
|
||||
const delay = require('delay');
|
||||
const { exec } = require('exec');
|
||||
const { delay } = require('delay');
|
||||
|
||||
let system = {};
|
||||
let INTVAL;
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
export {};
|
|
@ -0,0 +1,644 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const uuid_1 = require("uuid");
|
||||
const delay_1 = require("delay");
|
||||
class Commands {
|
||||
/**
|
||||
* @constructor
|
||||
* Assign all connected devices and mock devices as private classes.
|
||||
*
|
||||
* @param {object} cfg Configuration object
|
||||
* @param {object} proj Projector 1
|
||||
* @param {object} cam Camera 1
|
||||
* @param {object} light Light source
|
||||
* @param {object} alert Alert object
|
||||
* @param {object} cam2 (optional) Camera 2
|
||||
* @param {object} proj2 (optional) Projector 2
|
||||
* @param {object} capper Capper object
|
||||
*
|
||||
**/
|
||||
constructor(cfg, proj, cam, light, alert, cam2 = null, proj2 = null, capper = null) {
|
||||
this.cfg = cfg;
|
||||
this.proj = proj;
|
||||
this.cam = cam;
|
||||
this.light = light;
|
||||
this.alertObj = alert;
|
||||
if (cam2 !== null)
|
||||
this.cam2 = cam2;
|
||||
if (proj2 !== null)
|
||||
this.proj2 = proj2;
|
||||
if (capper !== null)
|
||||
this.capper = capper;
|
||||
this.ipc = require('electron').ipcMain;
|
||||
}
|
||||
/**
|
||||
* Move the projector one frame forward
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projector_forward() {
|
||||
let ms;
|
||||
try {
|
||||
if (!this.proj.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj.set(true);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.proj.move();
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the projector one frame backward
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projector_backward() {
|
||||
let ms;
|
||||
try {
|
||||
if (this.proj.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj.set(false);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.proj.move();
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the camera one frame forward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async camera_forward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let ms;
|
||||
try {
|
||||
if (!this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(true);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.cam.move();
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the camera one frame forward with light off
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async black_forward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let ms = 0;
|
||||
try {
|
||||
if (!this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(true);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.capper) {
|
||||
ms += await this.capper.capper(true, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id); //make sure set to off
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms += await this.cam.move();
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
if (this.capper) {
|
||||
ms += await this.capper.capper(false, id);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the camera one frame backward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async camera_backward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let ms;
|
||||
try {
|
||||
if (this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(false);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.cam.move();
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the camera one frame forward, light set to black or off
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async black_backward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let ms = 0;
|
||||
try {
|
||||
if (this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(false);
|
||||
}
|
||||
if (this.capper) {
|
||||
ms += await this.capper.capper(true, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id); //make sure set to off
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms += await this.cam.move();
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
if (this.capper) {
|
||||
ms += await this.capper.capper(false, id);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the second camera one frame forward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async camera_second_forward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let ms;
|
||||
try {
|
||||
if (!this.cam2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam2.set(true);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.cam2.move();
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the second camera one frame backward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async camera_second_backward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let ms;
|
||||
try {
|
||||
if (this.cam2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam2.set(false);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.cam2.move();
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the both cameras one frame forward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async cameras_forward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (!this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(true);
|
||||
}
|
||||
if (!this.cam2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam2.set(true);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.cam && this.cam2 && this.cam.arduino.alias.camera === this.cam.arduino.alias.camera_second) {
|
||||
ms = await this.cam.both();
|
||||
}
|
||||
else {
|
||||
this.cam.move();
|
||||
this.cam2.move();
|
||||
both = [await this.cam.move, await this.cam2.move];
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the both cameras one frame backward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async cameras_backward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(false);
|
||||
}
|
||||
if (this.cam2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam2.set(false);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.cam && this.cam2 && this.cam.arduino.alias.camera === this.cam.arduino.alias.camera_second) {
|
||||
ms = await this.cam.both();
|
||||
}
|
||||
else {
|
||||
this.cam.move();
|
||||
this.cam2.move();
|
||||
both = [await this.cam.move, await this.cam2.move];
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move first camera one frame forward and rewind secondary camera one frame backward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async camera_forward_camera_second_backward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (!this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(true);
|
||||
}
|
||||
if (this.cam2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam2.set(false);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.cam && this.cam2 && this.cam.arduino.alias.camera === this.cam.arduino.alias.camera_second) {
|
||||
ms = await this.cam.both();
|
||||
}
|
||||
else {
|
||||
this.cam.move();
|
||||
this.cam2.move();
|
||||
both = [await this.cam.move, await this.cam2.move];
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Rewind first camera one frame backward and move secondary camera one frame forward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async camera_backward_camera_second_forward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(false);
|
||||
}
|
||||
if (!this.cam2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam2.set(true);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.cam && this.cam2 && this.cam.arduino.alias.camera === this.cam.arduino.alias.camera_second) {
|
||||
ms = await this.cam.both();
|
||||
}
|
||||
else {
|
||||
this.cam.move();
|
||||
this.cam.move();
|
||||
both = [await this.cam.move, await this.proj2.move];
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the secondary projector forward one frame
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projector_second_forward() {
|
||||
let ms;
|
||||
try {
|
||||
if (!this.proj2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj2.set(true);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.proj2.move();
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Rewind the secondary projector backward one frame
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projector_second_backward() {
|
||||
let ms;
|
||||
try {
|
||||
if (this.proj2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj2.set(false);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.proj2.move();
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the both projectors forward one frame
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projectors_forward() {
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (!this.proj.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj.set(true);
|
||||
}
|
||||
if (!this.proj2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj2.set(true);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.proj && this.proj2 && this.proj.arduino.alias.projector === this.proj.arduino.alias.projector_second) {
|
||||
ms = await this.proj.both();
|
||||
}
|
||||
else {
|
||||
this.proj.move();
|
||||
this.proj2.move();
|
||||
both = [await this.proj.move, await this.proj2.move];
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Rewind both projectors backwards one frame
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projectors_backward() {
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (this.proj.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj.set(false);
|
||||
}
|
||||
if (this.proj2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj2.set(false);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
//run one projector without await?
|
||||
if (this.proj && this.proj2 && this.proj.arduino.alias.projector === this.proj.arduino.alias.projector_second) {
|
||||
ms = await this.proj.both();
|
||||
}
|
||||
else {
|
||||
this.proj.move();
|
||||
this.proj2.move();
|
||||
both = [await this.proj.move, await this.proj2.move];
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the primary projector forward one frame and rewind the secondary projector
|
||||
* one frame backwards.
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projector_forward_projector_second_backward() {
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (!this.proj.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj.set(true);
|
||||
}
|
||||
if (this.proj2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj2.set(false);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
//run one projector without await?
|
||||
if (this.proj && this.proj2 && this.proj.arduino.alias.projector === this.proj.arduino.alias.projector_second) {
|
||||
ms = await this.proj.both();
|
||||
}
|
||||
else {
|
||||
this.proj.move();
|
||||
this.proj2.move();
|
||||
both = [await this.proj.move, await this.proj2.move];
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Rewind the primary projector backwards one frame and move the secondary
|
||||
* projector forward one frame.
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projector_backward_projector_second_forward() {
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (this.proj.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj.set(false);
|
||||
}
|
||||
if (!this.proj2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj2.set(true);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
//run one projector without await?
|
||||
if (this.proj && this.proj2 && this.proj.arduino.alias.projector === this.proj.arduino.alias.projector_second) {
|
||||
ms = await this.proj.both();
|
||||
}
|
||||
else {
|
||||
this.proj.move();
|
||||
this.proj2.move();
|
||||
both = [await this.proj.move, await this.proj2.move];
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Throws an alert to pause a sequence
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async alert(cmd) {
|
||||
let ms;
|
||||
try {
|
||||
ms = await this.alertObj.start(cmd.light); //change this meta
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Pauses a sequence for a length of time
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async pause(cmd) {
|
||||
let ms;
|
||||
try {
|
||||
ms = await (0, delay_1.delay)(cmd.light * 1000); //delay is in seconds
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
async camera_exposure(cmd) {
|
||||
let ms;
|
||||
try {
|
||||
ms = await this.cam.exposure(cmd.light);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
}
|
||||
module.exports = function (cfg, proj, cam, light, alert, cam2, proj2, capper) {
|
||||
return new Commands(cfg, proj, cam, light, alert, cam2, proj2, capper);
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "cmd",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<a name="delay"></a>
|
||||
|
||||
## delay(ms) ⇒ <code>Promise</code>
|
||||
Delay in an async/await function
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>Promise</code> - Promise to resolve after timeout
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| ms | <code>integer</code> | Milliseconds to delay for |
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* Delay in an async/await function
|
||||
*
|
||||
* @param {integer} ms Milliseconds to delay for
|
||||
*
|
||||
* @returns {Promise} Promise to resolve after timeout
|
||||
**/
|
||||
export declare function delay(ms: number): Promise<unknown>;
|
|
@ -1,9 +1,18 @@
|
|||
'use strict';
|
||||
|
||||
function delay (ms) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.delay = void 0;
|
||||
/**
|
||||
* Delay in an async/await function
|
||||
*
|
||||
* @param {integer} ms Milliseconds to delay for
|
||||
*
|
||||
* @returns {Promise} Promise to resolve after timeout
|
||||
**/
|
||||
function delay(ms) {
|
||||
return new Promise((resolve) => {
|
||||
return setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = delay;
|
||||
exports.delay = delay;
|
||||
module.exports = { delay };
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/delay/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAEb;;;;;;IAMI;AAEJ,SAAgB,KAAK,CAAE,EAAW;IACjC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAa,EAAE,EAAE;QACpC,OAAO,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACJ,CAAC;AAJD,sBAIC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,KAAK,EAAE,CAAC"}
|
|
@ -0,0 +1,74 @@
|
|||
<a name="Devices"></a>
|
||||
|
||||
## Devices
|
||||
class representing the device discovery features
|
||||
|
||||
**Kind**: global class
|
||||
|
||||
* [Devices](#Devices)
|
||||
* [.init()](#Devices+init)
|
||||
* [.listen()](#Devices+listen)
|
||||
* [.listener()](#Devices+listener)
|
||||
* [.enumerate()](#Devices+enumerate)
|
||||
* [.favor()](#Devices+favor)
|
||||
* [.distinguish()](#Devices+distinguish)
|
||||
* [.fakeProjector()](#Devices+fakeProjector)
|
||||
* [.fakeCamera()](#Devices+fakeCamera)
|
||||
* [.fakeLight()](#Devices+fakeLight)
|
||||
* [.connectDevice()](#Devices+connectDevice)
|
||||
* [.all()](#Devices+all)
|
||||
* [.remember()](#Devices+remember)
|
||||
* [.ready()](#Devices+ready)
|
||||
|
||||
<a name="Devices+init"></a>
|
||||
|
||||
### devices.init()
|
||||
**Kind**: instance method of [<code>Devices</code>](#Devices)
|
||||
<a name="Devices+listen"></a>
|
||||
|
||||
### devices.listen()
|
||||
**Kind**: instance method of [<code>Devices</code>](#Devices)
|
||||
<a name="Devices+listener"></a>
|
||||
|
||||
### devices.listener()
|
||||
**Kind**: instance method of [<code>Devices</code>](#Devices)
|
||||
<a name="Devices+enumerate"></a>
|
||||
|
||||
### devices.enumerate()
|
||||
**Kind**: instance method of [<code>Devices</code>](#Devices)
|
||||
<a name="Devices+favor"></a>
|
||||
|
||||
### devices.favor()
|
||||
**Kind**: instance method of [<code>Devices</code>](#Devices)
|
||||
<a name="Devices+distinguish"></a>
|
||||
|
||||
### devices.distinguish()
|
||||
**Kind**: instance method of [<code>Devices</code>](#Devices)
|
||||
<a name="Devices+fakeProjector"></a>
|
||||
|
||||
### devices.fakeProjector()
|
||||
**Kind**: instance method of [<code>Devices</code>](#Devices)
|
||||
<a name="Devices+fakeCamera"></a>
|
||||
|
||||
### devices.fakeCamera()
|
||||
**Kind**: instance method of [<code>Devices</code>](#Devices)
|
||||
<a name="Devices+fakeLight"></a>
|
||||
|
||||
### devices.fakeLight()
|
||||
**Kind**: instance method of [<code>Devices</code>](#Devices)
|
||||
<a name="Devices+connectDevice"></a>
|
||||
|
||||
### devices.connectDevice()
|
||||
**Kind**: instance method of [<code>Devices</code>](#Devices)
|
||||
<a name="Devices+all"></a>
|
||||
|
||||
### devices.all()
|
||||
**Kind**: instance method of [<code>Devices</code>](#Devices)
|
||||
<a name="Devices+remember"></a>
|
||||
|
||||
### devices.remember()
|
||||
**Kind**: instance method of [<code>Devices</code>](#Devices)
|
||||
<a name="Devices+ready"></a>
|
||||
|
||||
### devices.ready()
|
||||
**Kind**: instance method of [<code>Devices</code>](#Devices)
|
|
@ -0,0 +1 @@
|
|||
export {};
|
|
@ -0,0 +1,585 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const delay_1 = require("delay");
|
||||
const Log = require("log");
|
||||
/**
|
||||
* class representing the device discovery features
|
||||
*
|
||||
*
|
||||
**/
|
||||
class Devices {
|
||||
/**
|
||||
* Constructor assigns arduino, settings, UI browser window and cam objects
|
||||
* locally to this class for reference.
|
||||
**/
|
||||
constructor(arduino, settings, mainWindow, cam) {
|
||||
this.connected = {};
|
||||
this.arduino = arduino;
|
||||
this.settings = settings;
|
||||
this.mainWindow = mainWindow;
|
||||
this.ui = this.mainWindow.webContents;
|
||||
this.cam = cam;
|
||||
this.init();
|
||||
}
|
||||
/**
|
||||
* Initialize the log for "devices". Establish an ipc connection to the UI.
|
||||
* Start listening on that ipc connection.
|
||||
**/
|
||||
async init() {
|
||||
this.log = await Log({ label: 'devices' });
|
||||
this.ipc = require('electron').ipcMain;
|
||||
this.listen();
|
||||
}
|
||||
/**
|
||||
* Listen to the "profile" channel for messages from the UI.
|
||||
**/
|
||||
listen() {
|
||||
this.ipc.handle('profile', this.listener.bind(this));
|
||||
}
|
||||
/**
|
||||
* The "profile" channel callback. If a profile is changed, set it in the
|
||||
* local settings object.
|
||||
**/
|
||||
async listener(event, arg) {
|
||||
if (typeof arg.profile !== 'undefined') {
|
||||
this.log.info(`Saving profile ${arg.profile}`, 'SETTINGS', false, false);
|
||||
this.settings.update('profile', arg.profile);
|
||||
await this.settings.save();
|
||||
}
|
||||
if (typeof arg.timing !== 'undefined') {
|
||||
this.log.info(`Saving timing info`, 'SETTINGS', false, false);
|
||||
this.settings.update('timing', arg.timing);
|
||||
await this.settings.save();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async enumerate() {
|
||||
let serials;
|
||||
try {
|
||||
serials = await this.arduino.enumerate();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.warn(err, 'SERIAL', false, true);
|
||||
await (0, delay_1.delay)(1000);
|
||||
return this.all([]);
|
||||
}
|
||||
this.log.info(`Found ${serials.length} USB devices`, 'SERIAL', true, true);
|
||||
serials = this.favor(serials);
|
||||
return await this.all(serials);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
favor(serials) {
|
||||
const past = this.settings.state.devices.filter((device) => {
|
||||
if (device.serial) {
|
||||
return device;
|
||||
}
|
||||
}).map((device) => {
|
||||
return device.serial;
|
||||
});
|
||||
if (past.length === 0) {
|
||||
return serials;
|
||||
}
|
||||
serials.sort((a, b) => {
|
||||
if (past.indexOf(a) !== -1 && past.indexOf(b) === -1) {
|
||||
return 1;
|
||||
}
|
||||
else if (past.indexOf(a) === -1 && past.indexOf(b) !== -1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
return serials;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async distinguish(serial) {
|
||||
let connectSuccess;
|
||||
let verifySuccess;
|
||||
let device;
|
||||
//this.log.info(`distinguish() ${serial}`)
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('connect', serial, true);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting', err);
|
||||
return null;
|
||||
}
|
||||
await (0, delay_1.delay)(2000);
|
||||
try {
|
||||
verifySuccess = await this.arduino.verify();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error verifying device', err);
|
||||
return null;
|
||||
}
|
||||
this.log.info(`Verified ${serial} as mcopy device`, 'SERIAL', true, true);
|
||||
await (0, delay_1.delay)(1000);
|
||||
try {
|
||||
device = await this.arduino.distinguish();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error distinguishing device', err);
|
||||
return null;
|
||||
}
|
||||
this.remember(device, serial, 'arduino');
|
||||
this.log.info(`Determined ${device} to be ${device}`, 'SERIAL', true, true);
|
||||
await (0, delay_1.delay)(100);
|
||||
try {
|
||||
await this.arduino.state(device, true);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error checking state capability', err);
|
||||
}
|
||||
return device;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async fakeProjector() {
|
||||
this.connected.projector = '/dev/fake';
|
||||
try {
|
||||
await this.arduino.fakeConnect('projector');
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(`Error connecting to fake PROjECTOR device`, 'SERIAL', true, true);
|
||||
this.log.error(err);
|
||||
return false;
|
||||
}
|
||||
this.log.info('Connected to fake PROJECTOR device', 'SERIAL', true, true);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async fakeCamera() {
|
||||
this.connected.camera = '/dev/fake';
|
||||
try {
|
||||
await this.arduino.fakeConnect('camera');
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(`Error connecting to fake CAMERA device`, 'SERIAL', true, true);
|
||||
this.log.error(err);
|
||||
return false;
|
||||
}
|
||||
this.log.info('Connected to fake CAMERA device', 'SERIAL', true, true);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async fakeLight() {
|
||||
this.connected.light = '/dev/fake';
|
||||
try {
|
||||
await this.arduino.fakeConnect('light');
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(`Error connecting to fake LIGHT device`, 'SERIAL', true, true);
|
||||
this.log.error(err);
|
||||
return false;
|
||||
}
|
||||
this.log.info('Connected to fake LIGHT device', 'SERIAL', true, true);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async fakeCapper() {
|
||||
this.connected.capper = '/dev/fake';
|
||||
try {
|
||||
await this.arduino.fakeConnect('capper');
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(`Error connecting to fake CAPPER device`, 'SERIAL', true, true);
|
||||
this.log.error(err);
|
||||
return false;
|
||||
}
|
||||
this.log.info('Connected to fake CAPPER device', 'SERIAL', true, true);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async connectDevice(device, serial) {
|
||||
let closeSuccess;
|
||||
let connectSuccess;
|
||||
try {
|
||||
closeSuccess = await this.arduino.close();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error closing arduino connection', err);
|
||||
return false;
|
||||
}
|
||||
if (device === 'projector') {
|
||||
this.connected.projector = serial;
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('projector', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to projector', err);
|
||||
return false;
|
||||
}
|
||||
this.log.info(`Connected to ${device} as PROJECTOR`, 'SERIAL', true, true);
|
||||
}
|
||||
else if (device === 'camera') {
|
||||
this.connected.camera = serial;
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera', err);
|
||||
return false;
|
||||
}
|
||||
this.log.info(`Connected to ${device} as CAMERA`, 'SERIAL', true, true);
|
||||
}
|
||||
else if (device === 'light') {
|
||||
this.connected.light = serial;
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('light', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to light', err);
|
||||
return false;
|
||||
}
|
||||
this.log.info(`Connected to ${device} as LIGHT`, 'SERIAL', true, true);
|
||||
}
|
||||
else if (device === 'projector,light') {
|
||||
this.connected.projector = serial;
|
||||
this.connected.light = serial;
|
||||
this.arduino.aliasSerial('light', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('projector', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to projector and light', err);
|
||||
return false;
|
||||
}
|
||||
this.log.info(`Connected to ${device} as PROJECTOR + LIGHT`, 'SERIAL', true, true);
|
||||
}
|
||||
else if (device === 'projector,camera,light') {
|
||||
this.connected.projector = serial;
|
||||
this.connected.camera = serial;
|
||||
this.connected.light = serial;
|
||||
this.arduino.aliasSerial('camera', serial);
|
||||
this.arduino.aliasSerial('light', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('projector', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to projector, camera and light', err);
|
||||
return false;
|
||||
}
|
||||
this.log.info(`Connected to ${device} as PROJECTOR + CAMERA + LIGHT`, 'SERIAL', true, true);
|
||||
}
|
||||
else if (device === 'projector,camera') {
|
||||
this.connected.projector = serial;
|
||||
this.connected.camera = serial;
|
||||
this.arduino.aliasSerial('camera', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('projector', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to projector and camera', err);
|
||||
return false;
|
||||
}
|
||||
this.log.info(`Connected to ${device} as PROJECTOR + CAMERA`, 'SERIAL', true, true);
|
||||
}
|
||||
else if (device === 'projector_second') {
|
||||
this.connected.projector_second = serial;
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('projector_second', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to secondary projector', err);
|
||||
return false;
|
||||
}
|
||||
this.log.info(`Connected to ${device} as PROJECTOR_SECOND`, 'SERIAL', true, true);
|
||||
}
|
||||
else if (device === 'projector,projector_second') {
|
||||
this.connected.projector = serial;
|
||||
this.connected.projector_second = serial;
|
||||
this.arduino.aliasSerial('projector_second', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('projector', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to projector and secondary projector', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera_second') {
|
||||
this.connected.camera_second = serial;
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera_second', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera,camera_second') {
|
||||
this.connected.camera = serial;
|
||||
this.connected.camera_second = serial;
|
||||
this.arduino.aliasSerial('camera_second', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera, camera_secondary and projector', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera,projector,projector_second') {
|
||||
this.connected.camera = serial;
|
||||
this.connected.projector = serial;
|
||||
this.connected.projector_second = serial;
|
||||
this.arduino.aliasSerial('projector', serial);
|
||||
this.arduino.aliasSerial('projector_second', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera, projector and projector_second', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera,camera_second,projector') {
|
||||
this.connected.camera = serial;
|
||||
this.connected.camera_second = serial;
|
||||
this.connected.projector = serial;
|
||||
this.arduino.aliasSerial('camera_second', serial);
|
||||
this.arduino.aliasSerial('projector', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera, camera_second and projector', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera,camera_second,projector,projector_second') {
|
||||
this.connected.camera = serial;
|
||||
this.connected.camera_second = serial;
|
||||
this.connected.projector = serial;
|
||||
this.connected.projector_second = serial;
|
||||
this.arduino.aliasSerial('camera_second', serial);
|
||||
this.arduino.aliasSerial('projector', serial);
|
||||
this.arduino.aliasSerial('projector_second', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera, camera_second, projector and projector_second', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'capper') {
|
||||
this.connected.capper = serial;
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('capper', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting capper', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera,capper') {
|
||||
this.connected.camera = serial;
|
||||
this.connected.capper = serial;
|
||||
this.arduino.aliasSerial('capper', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera and capper', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera,capper,projector') {
|
||||
this.connected.camera = serial;
|
||||
this.connected.capper = serial;
|
||||
this.connected.projector = serial;
|
||||
this.arduino.aliasSerial('capper', serial);
|
||||
this.arduino.aliasSerial('projector', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera, capper and projector', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera,capper,projector,projector_second') {
|
||||
this.connected.camera = serial;
|
||||
this.connected.capper = serial;
|
||||
this.connected.projector = serial;
|
||||
this.connected.projector_second = serial;
|
||||
this.arduino.aliasSerial('capper', serial);
|
||||
this.arduino.aliasSerial('projector', serial);
|
||||
this.arduino.aliasSerial('projector_second', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera, capper, projector and projector_second', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return connectSuccess;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
//Cases for 1 or 2 arduinos connected
|
||||
async all(serials) {
|
||||
let c = {};
|
||||
let p = {};
|
||||
let l = {};
|
||||
let device;
|
||||
let d;
|
||||
let cs = {};
|
||||
let ps = {};
|
||||
let capper = {};
|
||||
let checklist = [];
|
||||
let exposure;
|
||||
let parts;
|
||||
this.connected = {
|
||||
projector: false,
|
||||
camera: false,
|
||||
light: false,
|
||||
projector_second: false,
|
||||
capper: false
|
||||
};
|
||||
for (let serial of serials) {
|
||||
try {
|
||||
device = await this.distinguish(serial);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error distinguishing device', err);
|
||||
throw err;
|
||||
}
|
||||
try {
|
||||
await this.connectDevice(device, serial);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to device', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
//done checking devices
|
||||
if (!this.connected.projector) {
|
||||
await this.fakeProjector();
|
||||
}
|
||||
else if (this.arduino.hasState['projector']) {
|
||||
p.state = true;
|
||||
}
|
||||
p.arduino = this.connected.projector;
|
||||
if (!this.connected.camera) {
|
||||
await this.fakeCamera();
|
||||
}
|
||||
else if (this.arduino.hasState['camera']) {
|
||||
if (device.indexOf('camera') !== -1) {
|
||||
parts = this.arduino.stateStr[device].split('G');
|
||||
if (parts.length > 1) {
|
||||
parts = parts[1].split('H');
|
||||
exposure = parseInt(parts[0]);
|
||||
if (!isNaN(exposure)) {
|
||||
this.log.info(`Timing for [${device}] = ${exposure}`);
|
||||
this.ui.send('timing', { c: 'c', ms: exposure });
|
||||
}
|
||||
}
|
||||
}
|
||||
c.state = true;
|
||||
c.exposure = true;
|
||||
}
|
||||
c.arduino = this.connected.camera;
|
||||
if (!this.connected.light) {
|
||||
await this.fakeLight();
|
||||
}
|
||||
l.arduino = this.connected.light;
|
||||
if (this.connected.camera_second) {
|
||||
cs.arduino = this.connected.camera_second;
|
||||
}
|
||||
if (this.connected.projector_second) {
|
||||
ps.arduino = this.connected.projector_second;
|
||||
}
|
||||
if (this.connected.capper) {
|
||||
capper.arduino = this.connected.capper;
|
||||
}
|
||||
if (this.settings.state.camera && this.settings.state.camera.intval) {
|
||||
c.intval = this.settings.state.camera.intval;
|
||||
}
|
||||
return this.ready(p, c, l, cs, ps, capper);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
remember(device, serial, type) {
|
||||
let deviceEntry;
|
||||
const match = this.settings.state.devices.filter((dev) => {
|
||||
if (typeof dev.device !== 'undefined' && dev.device === device &&
|
||||
typeof dev.serial !== 'undefined' && dev.serial === serial) {
|
||||
return dev;
|
||||
}
|
||||
});
|
||||
if (match.length === 0) {
|
||||
deviceEntry = {
|
||||
device,
|
||||
type,
|
||||
serial
|
||||
};
|
||||
this.settings.state.devices.push(deviceEntry);
|
||||
this.settings.update('devices', this.settings.state.devices);
|
||||
this.settings.save();
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
ready(projector, camera, light, camera_second, projector_second, capper) {
|
||||
let args = {
|
||||
camera,
|
||||
projector,
|
||||
light,
|
||||
profile: this.settings.state.profile
|
||||
};
|
||||
if (this.settings.state.timing) {
|
||||
args.timing = this.settings.state.timing;
|
||||
}
|
||||
if (projector_second && projector_second.arduino) {
|
||||
args.projector_second = projector_second;
|
||||
this.settings.update('projector_second', projector_second);
|
||||
this.mainWindow.setSize(800, 800);
|
||||
}
|
||||
if (camera_second && camera_second.arduino) {
|
||||
args.camera_second = camera_second;
|
||||
this.settings.update('camera_second', camera_second);
|
||||
if (projector_second && projector_second.arduino) {
|
||||
this.mainWindow.setSize(900, 800);
|
||||
}
|
||||
else {
|
||||
this.mainWindow.setSize(800, 800);
|
||||
}
|
||||
}
|
||||
if (capper && capper.arduino) {
|
||||
args.capper = capper;
|
||||
this.mainWindow.setSize(800, 800);
|
||||
this.settings.update('capper', capper);
|
||||
}
|
||||
this.settings.update('camera', camera);
|
||||
this.settings.update('projector', projector);
|
||||
this.settings.update('light', light);
|
||||
this.settings.save();
|
||||
this.ui.send('ready', args);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
module.exports = function (arduino, settings, mainWindow, cam) {
|
||||
return new Devices(arduino, settings, mainWindow, cam);
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "devices",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export {};
|
|
@ -1,127 +1,198 @@
|
|||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/**
|
||||
* @module display
|
||||
* Provides features for displaying a full screen display of images for the digital module.
|
||||
**/
|
||||
const path_1 = require("path");
|
||||
const url_1 = require("url");
|
||||
const delay_1 = require("delay");
|
||||
const Log = require("log");
|
||||
const { BrowserWindow } = require('electron');
|
||||
|
||||
const exec = require('exec');
|
||||
const spawn = require('spawn');
|
||||
const delay = require('delay');
|
||||
|
||||
let wv;
|
||||
let cp;
|
||||
let system = {};
|
||||
let digitalWindow;
|
||||
|
||||
let TMPDIR;
|
||||
|
||||
class WebView {
|
||||
constructor() {
|
||||
|
||||
}
|
||||
async open () {
|
||||
digitalWindow = new BrowserWindow({
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
allowRunningInsecureContent: false,
|
||||
'unsafe-eval' : false
|
||||
},
|
||||
width: 800,
|
||||
height: 600,
|
||||
minWidth : 800,
|
||||
minHeight : 600//,
|
||||
//icon: path.join(__dirname, '../../assets/icons/icon.png')
|
||||
});
|
||||
digitalWindow.loadURL('file://' + __dirname + '../../../display.html');
|
||||
if (process.argv.indexOf('-d') !== -1 || process.argv.indexOf('--dev') !== -1) {
|
||||
digitalWindow.webContents.openDevTools();
|
||||
}
|
||||
digitalWindow.on('closed', () => {
|
||||
digitalWindow = null
|
||||
});
|
||||
}
|
||||
async fullScreen () {
|
||||
return digitalWindow.setFullScreen(true);
|
||||
}
|
||||
async setImage (src) {
|
||||
return digitalWindow.webContents.send('display', { src });
|
||||
}
|
||||
async setMeter () {
|
||||
return digitalWindow.webContents.send('display', { meter : true });
|
||||
}
|
||||
async setGrid () {
|
||||
return digitalWindow.webContents.send('display', { grid : true });
|
||||
}
|
||||
async close () {
|
||||
if (digitalWindow) {
|
||||
digitalWindow.close();
|
||||
}
|
||||
return true
|
||||
}
|
||||
async move () {
|
||||
|
||||
}
|
||||
constructor(platform, display) {
|
||||
this.opened = false;
|
||||
this.showing = false;
|
||||
this.loadWait = {};
|
||||
const prefs = {
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
allowRunningInsecureContent: false,
|
||||
enableRemoteModule: true,
|
||||
contextIsolation: false
|
||||
},
|
||||
width: 800,
|
||||
height: 600,
|
||||
minWidth: 800,
|
||||
minHeight: 600 //,
|
||||
//icon: path.join(__dirname, '../../assets/icons/icon.png')
|
||||
};
|
||||
const pagePath = (0, path_1.normalize)((0, path_1.join)(__dirname, '../../display.html'));
|
||||
const pageUrl = (0, url_1.format)({
|
||||
pathname: pagePath,
|
||||
protocol: 'file:'
|
||||
});
|
||||
this.init();
|
||||
if (!display.primary) {
|
||||
prefs.x = display.x + 50;
|
||||
prefs.y = display.y + 50;
|
||||
}
|
||||
this.digitalWindow = new BrowserWindow(prefs);
|
||||
require('@electron/remote/main').enable(this.digitalWindow.webContents);
|
||||
this.digitalWindow.loadURL(pageUrl);
|
||||
if (process.argv.indexOf('-d') !== -1 || process.argv.indexOf('--dev') !== -1) {
|
||||
this.digitalWindow.webContents.openDevTools();
|
||||
}
|
||||
this.digitalWindow.on('closed', () => {
|
||||
this.digitalWindow = null;
|
||||
this.close();
|
||||
});
|
||||
//this.digitalWindow.hide();
|
||||
this.platform = platform;
|
||||
this.display = display;
|
||||
this.ipc = require('electron').ipcMain;
|
||||
this.ipc.on('display_load', this.onLoad.bind(this));
|
||||
}
|
||||
async init() {
|
||||
this.log = await Log({ label: 'devices' });
|
||||
}
|
||||
async open() {
|
||||
this.digitalWindow.show();
|
||||
this.showing = true;
|
||||
this.opened = true;
|
||||
await this.digitalWindow.setFullScreen(true);
|
||||
await (0, delay_1.delay)(300);
|
||||
if (this.platform === 'osx') {
|
||||
await (0, delay_1.delay)(300); //give macs an extra 300ms to open fullscreen
|
||||
}
|
||||
}
|
||||
async show(src) {
|
||||
const normalSrc = (0, path_1.normalize)((0, path_1.join)(src));
|
||||
if (!this.digitalWindow) {
|
||||
this.log.warn(`Cannot show "${src}" because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
this.digitalWindow.webContents.send('display', { src: normalSrc });
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
this.showing = true;
|
||||
return new Promise(function (resolve) {
|
||||
this.loadWait[src] = resolve;
|
||||
}.bind(this));
|
||||
}
|
||||
onLoad(evt, arg) {
|
||||
if (this.loadWait[arg.src]) {
|
||||
this.loadWait[arg.src]();
|
||||
delete this.loadWait[arg.src];
|
||||
}
|
||||
}
|
||||
async focus() {
|
||||
if (!this.digitalWindow) {
|
||||
this.log.warn(`Cannot show focus screen because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
await (0, delay_1.delay)(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('focus', { focus: true });
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
async field(ratio) {
|
||||
if (!this.digitalWindow) {
|
||||
this.log.warn(`Cannot show field guide because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
await (0, delay_1.delay)(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('field', { field: true, ratio });
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
async meter() {
|
||||
if (!this.digitalWindow) {
|
||||
this.log.warn(`Cannot show meter screen because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
await (0, delay_1.delay)(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('meter', { meter: true });
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
hide() {
|
||||
if (this.digitalWindow) {
|
||||
this.digitalWindow.hide();
|
||||
}
|
||||
this.showing = false;
|
||||
return true;
|
||||
}
|
||||
close() {
|
||||
this.hide();
|
||||
if (this.digitalWindow) {
|
||||
this.digitalWindow.close();
|
||||
this.digitalWindow = null;
|
||||
}
|
||||
this.opened = false;
|
||||
this.showing = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function padded_frame (i) {
|
||||
let len = (i + '').length;
|
||||
let str = i + '';
|
||||
for (let x = 0; x < 5 - len; x++) {
|
||||
str = '0' + str;
|
||||
}
|
||||
return str;
|
||||
class Display {
|
||||
constructor(sys) {
|
||||
this.platform = sys.platform;
|
||||
this.displays = sys.displays;
|
||||
this.tmpdir = (0, path_1.join)(sys.tmp, 'mcopy_digital');
|
||||
this.display = this.displays.find((display) => {
|
||||
if (display.primary)
|
||||
return true;
|
||||
});
|
||||
}
|
||||
async open() {
|
||||
if (this.wv && this.wv.display && this.wv.display.id !== this.display.id) {
|
||||
this.wv.close();
|
||||
}
|
||||
if (!this.wv || !this.wv.opened) {
|
||||
this.wv = new WebView(this.platform, this.display);
|
||||
await this.wv.open();
|
||||
}
|
||||
}
|
||||
async show(src) {
|
||||
await this.wv.show(src);
|
||||
}
|
||||
async showPath(pathStr) {
|
||||
return await this.wv.show(pathStr);
|
||||
}
|
||||
hide() {
|
||||
}
|
||||
async close() {
|
||||
return await this.wv.close();
|
||||
}
|
||||
async focus() {
|
||||
return await this.wv.focus();
|
||||
}
|
||||
async field(ratio) {
|
||||
return await this.wv.field(ratio);
|
||||
}
|
||||
async meter() {
|
||||
return await this.wv.meter();
|
||||
}
|
||||
change(id) {
|
||||
this.display = this.displays.find((display) => {
|
||||
if (display.id == id)
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function display_eog (src) {
|
||||
//timeout 3 eog --fullscreen ${src}
|
||||
cp = spawn('eog', ['--fullscreen', src]);
|
||||
}
|
||||
|
||||
|
||||
async function display_wv (src) {
|
||||
await wv.open();
|
||||
await wv.fullScreen();
|
||||
await delay(200);
|
||||
await wv.setImage(src);
|
||||
}
|
||||
|
||||
async function end () {
|
||||
if (system.platform !== 'nix') {
|
||||
await wv.close();
|
||||
} else {
|
||||
if (cp) cp.kill()
|
||||
}
|
||||
}
|
||||
|
||||
async function start (frame) {
|
||||
let padded = padded_frame(frame);
|
||||
let ext = 'tif';
|
||||
let tmppath;
|
||||
|
||||
if (system.platform !== 'nix') {
|
||||
ext = 'png';
|
||||
}
|
||||
|
||||
tmppath = path.join(TMPDIR, `export-${padded}.${ext}`);
|
||||
|
||||
if (system.platform !== 'nix') {
|
||||
display_wv(tmppath);
|
||||
} else {
|
||||
display_eog(tmppath);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function (sys) {
|
||||
system = sys;
|
||||
TMPDIR = path.join(system.tmp, 'mcopy_digital');
|
||||
|
||||
if (system.platform !== 'nix') {
|
||||
wv = new WebView();
|
||||
} else {
|
||||
//child process
|
||||
}
|
||||
|
||||
return {
|
||||
start,
|
||||
end
|
||||
}
|
||||
}
|
||||
return new Display(sys);
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
export declare const execRaw: any;
|
|
@ -1,7 +1,7 @@
|
|||
'use strict'
|
||||
|
||||
const execRaw = require('child_process').exec
|
||||
|
||||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.execRaw = void 0;
|
||||
exports.execRaw = require('child_process').exec;
|
||||
/**
|
||||
* Promisified child_process.exec
|
||||
*
|
||||
|
@ -14,26 +14,26 @@ const execRaw = require('child_process').exec
|
|||
* @returns {Promise<{ stdout: string, stderr: stderr }>}
|
||||
*/
|
||||
async function exec(...args) {
|
||||
let cmd = args[0]
|
||||
let argz = null
|
||||
let opts = null
|
||||
if (typeof args[1] === 'object' && Array.isArray(args[1])) {
|
||||
argz = args[1]
|
||||
}
|
||||
if (argz === null && typeof args[1] === 'object') {
|
||||
opts = args[1]
|
||||
} else if (typeof args[2] === 'object') {
|
||||
opts = args[2]
|
||||
}
|
||||
if (opts === null) {
|
||||
opts = { maxBuffer : 1024 * 1024 }
|
||||
}
|
||||
let cmd = args[0];
|
||||
let argz = null;
|
||||
let opts = null;
|
||||
if (typeof args[1] === 'object' && Array.isArray(args[1])) {
|
||||
argz = args[1];
|
||||
}
|
||||
if (argz === null && typeof args[1] === 'object') {
|
||||
opts = args[1];
|
||||
}
|
||||
else if (typeof args[2] === 'object') {
|
||||
opts = args[2];
|
||||
}
|
||||
if (opts === null) {
|
||||
opts = { maxBuffer: 1024 * 1024 };
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = execRaw(cmd, opts,
|
||||
(err, stdout, stderr) => err ? reject(err) : resolve({
|
||||
stdout: stdout,
|
||||
stderr: stderr
|
||||
}));
|
||||
const child = (0, exports.execRaw)(cmd, opts, (err, stdout, stderr) => err ? reject(err) : resolve({
|
||||
stdout,
|
||||
stderr
|
||||
}));
|
||||
if (opts.stdout) {
|
||||
child.stdout.pipe(opts.stdout);
|
||||
}
|
||||
|
@ -42,5 +42,5 @@ async function exec(...args) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = exec
|
||||
module.exports.exec = exec;
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exec/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;;;AAEC,QAAA,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,IAAI,CAAA;AAEpD;;;;;;;;;;GAUG;AACH,KAAK,UAAU,IAAI,CAAC,GAAG,IAAe;IACrC,IAAI,GAAG,GAAY,IAAI,CAAC,CAAC,CAAC,CAAA;IAC1B,IAAI,IAAI,GAAY,IAAI,CAAA;IACxB,IAAI,IAAI,GAAS,IAAI,CAAA;IAErB,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAC1D,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;KACd;IACD,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE;QACjD,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;KACd;SAAM,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE;QACvC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;KACd;IACD,IAAI,IAAI,KAAK,IAAI,EAAE;QAClB,IAAI,GAAG,EAAE,SAAS,EAAG,IAAI,GAAG,IAAI,EAAE,CAAA;KAClC;IACE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtC,MAAM,KAAK,GAAG,IAAA,eAAO,EAAC,GAAG,EAAE,IAAI,EACjC,CAAC,GAAW,EAAE,MAAe,EAAE,MAAc,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC7E,MAAM;YACN,MAAM;SACN,CAAC,CAAC,CAAC;QACC,IAAI,IAAI,CAAC,MAAM,EAAE;YACb,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SAClC;QACD,IAAI,IAAI,CAAC,MAAM,EAAE;YACb,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SAClC;IACL,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAA"}
|
|
@ -0,0 +1,13 @@
|
|||
<a name="exit"></a>
|
||||
|
||||
## exit(msg, code)
|
||||
Exit process with either a 0 code or other
|
||||
specified failure code. Print message to console first.
|
||||
|
||||
**Kind**: global function
|
||||
|
||||
| Param | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| msg | <code>string</code> | | Reason for exit |
|
||||
| code | <code>integer</code> | <code>0</code> | process exit code, default 0 |
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* Exit process with either a 0 code or other
|
||||
* specified failure code. Print message to console first.
|
||||
*
|
||||
* @param {string} msg Reason for exit
|
||||
* @param {integer} code process exit code, default 0
|
||||
**/
|
||||
declare function exit(msg: string, code?: number): void;
|
|
@ -1,13 +1,20 @@
|
|||
'use strict';
|
||||
|
||||
function exit (msg, code = 0) {
|
||||
if (code === 0) {
|
||||
console.log(msg);
|
||||
process.exit();
|
||||
} else {
|
||||
console.error(msg);
|
||||
process.exit(code);
|
||||
}
|
||||
/**
|
||||
* Exit process with either a 0 code or other
|
||||
* specified failure code. Print message to console first.
|
||||
*
|
||||
* @param {string} msg Reason for exit
|
||||
* @param {integer} code process exit code, default 0
|
||||
**/
|
||||
function exit(msg, code = 0) {
|
||||
if (code === 0) {
|
||||
console.log(msg);
|
||||
process.exit();
|
||||
}
|
||||
else {
|
||||
console.error(msg);
|
||||
process.exit(code);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exit;
|
||||
module.exports.exit = exit;
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exit/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;;;IAMI;AAEJ,SAAS,IAAI,CAAE,GAAY,EAAE,OAAgB,CAAC;IAC7C,IAAI,IAAI,KAAK,CAAC,EAAE;QACf,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjB,OAAO,CAAC,IAAI,EAAE,CAAC;KACf;SAAM;QACN,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;KACnB;AACF,CAAC;AAED,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC"}
|
|
@ -0,0 +1 @@
|
|||
export {};
|
|
@ -1,158 +1,356 @@
|
|||
'use strict';
|
||||
|
||||
const uuid = require('uuid').v4;
|
||||
const path = require('path');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
const exec = require('exec');
|
||||
//const spawn = require('spawn');
|
||||
const exit = require('exit');
|
||||
|
||||
let system = {};
|
||||
let TMPDIR;
|
||||
|
||||
function padded_frame (i) {
|
||||
let len = (i + '').length;
|
||||
let str = i + '';
|
||||
for (let x = 0; x < 5 - len; x++) {
|
||||
str = '0' + str;
|
||||
}
|
||||
return str;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/** @module ffmpeg **/
|
||||
const path_1 = require("path");
|
||||
const fs_extra_1 = require("fs-extra");
|
||||
const exec_1 = require("exec");
|
||||
const child_process_1 = require("child_process");
|
||||
async function spawnAsync(bin, args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = (0, child_process_1.spawn)(bin, args);
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
child.on('exit', (code) => {
|
||||
if (code === 0) {
|
||||
return resolve({ stdout, stderr });
|
||||
}
|
||||
else {
|
||||
console.error(`Process exited with code: ${code}`);
|
||||
console.error(stderr);
|
||||
return reject(stderr);
|
||||
}
|
||||
});
|
||||
child.stdout.on('data', (data) => {
|
||||
stdout += data;
|
||||
});
|
||||
child.stderr.on('data', (data) => {
|
||||
stderr += data;
|
||||
});
|
||||
return child;
|
||||
});
|
||||
}
|
||||
|
||||
async function frame (video, frame, obj) {
|
||||
let padded = padded_frame(frame);
|
||||
let ext = 'tif';
|
||||
let tmpoutput;
|
||||
let cmd;
|
||||
let output;
|
||||
|
||||
if (system.platform !== 'nix') {
|
||||
ext = 'png';
|
||||
}
|
||||
|
||||
tmpoutput = path.join(TMPDIR, `export-${padded}.${ext}`)
|
||||
|
||||
cmd = `ffmpeg -i "${video}" -vf select='gte(n\\,${frame})' -vframes 1 -compression_algo raw -pix_fmt rgb24 "${tmpoutput}"`
|
||||
|
||||
//ffmpeg -i "${video}" -ss 00:00:07.000 -vframes 1 "export-${time}.jpg"
|
||||
//ffmpeg -i "${video}" -compression_algo raw -pix_fmt rgb24 "export-%05d.tiff"
|
||||
//-vf "select=gte(n\,${frame})" -compression_algo raw -pix_fmt rgb24 "export-${padded}.png"
|
||||
|
||||
try {
|
||||
console.log(cmd);
|
||||
output = await exec(cmd);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
if (output) console.log(`"${output}"`);
|
||||
|
||||
/** @class FFMPEG **/
|
||||
class FFMPEG {
|
||||
/**
|
||||
* @constructor
|
||||
* Creates an ffmpeg class
|
||||
*
|
||||
* @param {object} sys System object to be used to get temp directory
|
||||
**/
|
||||
constructor(sys) {
|
||||
this.id = 'ffmpeg';
|
||||
this.onProgress = () => { };
|
||||
this.bin = sys.deps.ffmpeg;
|
||||
this.TMPDIR = (0, path_1.join)(sys.tmp, 'mcopy_digital');
|
||||
this.init();
|
||||
}
|
||||
/**
|
||||
* Async method to call async functions from constructor
|
||||
**/
|
||||
async init() {
|
||||
const Log = require('log');
|
||||
this.log = await Log({ label: this.id });
|
||||
await this.checkDir();
|
||||
}
|
||||
/**
|
||||
* Add padding to a number to 5 places. Return a string.
|
||||
*
|
||||
* @param {integer} i Integer to pad
|
||||
*
|
||||
* @returns {string} Padded string
|
||||
**/
|
||||
padded_frame(i) {
|
||||
let len = (i + '').length;
|
||||
let str = i + '';
|
||||
for (let x = 0; x < 8 - len; x++) {
|
||||
str = '0' + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
/**
|
||||
* Parse the stderr output of ffmpeg
|
||||
*
|
||||
* @param {string} line Stderr line
|
||||
**/
|
||||
parseStderr(line) {
|
||||
//frame= 6416 fps= 30 q=31.0 size= 10251kB time=00:03:34.32 bitrate= 391.8kbits/s speed= 1x
|
||||
let obj = {};
|
||||
if (line.substring(0, 'frame='.length) === 'frame=') {
|
||||
try {
|
||||
obj.frame = line.split('frame=')[1].split('fps=')[0];
|
||||
obj.frame = parseInt(obj.frame);
|
||||
obj.fps = line.split('fps=')[1].split('q=')[0];
|
||||
obj.fps = parseFloat(obj.fps);
|
||||
obj.time = line.split('time=')[1].split('bitrate=')[0];
|
||||
obj.speed = line.split('speed=')[1].trim().replace('x', '');
|
||||
obj.speed = parseFloat(obj.speed);
|
||||
obj.size = line.split('size=')[1].split('time=')[0].trim();
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
console.log(line);
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
else {
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
/**
|
||||
* Render a single frame from a video or image to a png.
|
||||
*
|
||||
* @param {object} state State object containing file data
|
||||
* @param {object} light Object containing color information for frame
|
||||
*
|
||||
* @returns {string} Path of frame
|
||||
**/
|
||||
async frame(state, light) {
|
||||
const frameNum = state.frame;
|
||||
const video = state.directory ? state.files[frameNum] : state.path;
|
||||
const w = state.info.width;
|
||||
const h = state.info.height;
|
||||
const padded = this.padded_frame(frameNum);
|
||||
let ext = 'png';
|
||||
let rgb = light.color;
|
||||
let rgba = {};
|
||||
let tmpoutput;
|
||||
let cmd;
|
||||
let output;
|
||||
let fileExists = false;
|
||||
let scale = '';
|
||||
if (state.directory) {
|
||||
return video;
|
||||
}
|
||||
if (w && h) {
|
||||
scale = `,scale=trunc(ih*dar):${h}`; //:force_original_aspect_ratio=decrease,pad=${w}:${h}:(ow-iw)/2:(oh-ih)/2
|
||||
}
|
||||
tmpoutput = (0, path_1.join)(this.TMPDIR, `${state.hash}-export-${padded}.${ext}`);
|
||||
try {
|
||||
fileExists = await (0, fs_extra_1.exists)(tmpoutput);
|
||||
}
|
||||
catch (err) {
|
||||
//
|
||||
}
|
||||
if (fileExists) {
|
||||
this.log.info(`File ${tmpoutput} exists`);
|
||||
return tmpoutput;
|
||||
}
|
||||
//
|
||||
cmd = `${this.bin} -y -i "${video}" -vf "select='gte(n\\,${frameNum})'${scale}" -vframes 1 -compression_algo raw -pix_fmt rgb24 -crf 0 "${tmpoutput}"`;
|
||||
//cmd2 = `${this.convert} "${tmpoutput}" -resize ${w}x${h} -size ${w}x${h} xc:"rgb(${rgb[0]},${rgb[1]},${rgb[2]})" +swap -compose Darken -composite "${tmpoutput}"`;
|
||||
//ffmpeg -i "${video}" -ss 00:00:07.000 -vframes 1 "export-${time}.jpg"
|
||||
//ffmpeg -i "${video}" -compression_algo raw -pix_fmt rgb24 "export-%05d.tiff"
|
||||
//-vf "select=gte(n\,${frame})" -compression_algo raw -pix_fmt rgb24 "export-${padded}.png"
|
||||
try {
|
||||
this.log.info(cmd);
|
||||
output = await (0, exec_1.exec)(cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
if (output && output.stdout)
|
||||
this.log.info(`"${output.stdout.trim()}"`);
|
||||
if (rgb[0] !== 255 || rgb[1] !== 255 || rgb[2] !== 255) {
|
||||
rgb = rgb.map((e) => {
|
||||
return parseInt(e);
|
||||
});
|
||||
rgba = { r: rgb[0], g: rgb[1], b: rgb[2], a: 255 };
|
||||
try {
|
||||
//await Frame.blend(tmpoutput, rgba, tmpoutput);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
return tmpoutput;
|
||||
}
|
||||
/**
|
||||
* Render all frames in a video to the temp directory.
|
||||
* Not in use.
|
||||
*
|
||||
* @param {string} video Path to video
|
||||
* @param {object} obj Not sure
|
||||
*
|
||||
* @returns {?}
|
||||
**/
|
||||
async frames(state) {
|
||||
const video = state.path;
|
||||
const w = state.info.width;
|
||||
const h = state.info.height;
|
||||
const tmppath = this.TMPDIR;
|
||||
let ext = 'png';
|
||||
let tmpoutput = (0, path_1.join)(tmppath, `${state.hash}-export-%08d.${ext}`);
|
||||
let args;
|
||||
let output;
|
||||
let estimated = -1;
|
||||
//cmd = `${this.bin} -y -i "${video}" -vf "${scale}" -compression_algo raw -pix_fmt rgb24 -crf 0 "${tmpoutput}"`;
|
||||
args = [
|
||||
'-y',
|
||||
'-i', video
|
||||
];
|
||||
if (w && h) {
|
||||
args.push('-vf');
|
||||
args.push(`scale=${w}:${h}`);
|
||||
}
|
||||
args = args.concat([
|
||||
'-compression_algo', 'raw',
|
||||
'-pix_fmt', 'rgb24',
|
||||
'-crf', '0',
|
||||
tmpoutput
|
||||
]);
|
||||
//console.dir(args)
|
||||
//console.dir(state)
|
||||
try {
|
||||
await (0, fs_extra_1.mkdir)(tmppath);
|
||||
}
|
||||
catch (err) {
|
||||
if (err.code && err.code === 'EEXIST') {
|
||||
//directory exists
|
||||
}
|
||||
else {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
//ffmpeg -i "${video}" -compression_algo raw -pix_fmt rgb24 "${tmpoutput}"
|
||||
return new Promise((resolve, reject) => {
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
this.log.info(`${this.bin} ${args.join(' ')}`);
|
||||
this.child = (0, child_process_1.spawn)(this.bin, args);
|
||||
this.child.on('exit', (code) => {
|
||||
//console.log('GOT TO EXIT');
|
||||
if (code === 0) {
|
||||
console.log(stderr);
|
||||
console.log(stdout);
|
||||
return resolve(true);
|
||||
}
|
||||
else {
|
||||
console.error(`Process exited with code: ${code}`);
|
||||
console.error(stderr);
|
||||
return reject(stderr + stdout);
|
||||
}
|
||||
});
|
||||
this.child.stdout.on('data', (data) => {
|
||||
const line = data.toString();
|
||||
stdout += line;
|
||||
});
|
||||
this.child.stderr.on('data', (data) => {
|
||||
const line = data.toString();
|
||||
const obj = this.parseStderr(line);
|
||||
if (obj.frame && state.frames) {
|
||||
obj.progress = obj.frame / state.frames;
|
||||
}
|
||||
if (obj.frame && obj.speed && state.frames && state.info.fps) {
|
||||
//scale by speed
|
||||
obj.remaining = ((state.frames - obj.frame) / state.info.fps) / obj.speed;
|
||||
obj.estimated = state.info.seconds / obj.speed;
|
||||
if (obj.estimated > estimated) {
|
||||
estimated = obj.estimated;
|
||||
}
|
||||
}
|
||||
if (obj.frame) {
|
||||
//log.info(`${input.name} ${obj.frame}/${input.frames} ${Math.round(obj.progress * 1000) / 10}% ${Math.round(obj.remaining)} seconds remaining of ${Math.round(obj.estimated)}`);
|
||||
this.onProgress(obj);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
cancel() {
|
||||
if (this.child) {
|
||||
this.child.kill();
|
||||
this.log.info(`Stopped exporting sequence with ffmpeg`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Clears a specific frame from the tmp directory
|
||||
*
|
||||
* @param {integer} frame Integer of frame to clear
|
||||
*
|
||||
* @returns {boolean} True if successful, false if not
|
||||
**/
|
||||
async clear(state) {
|
||||
const padded = this.padded_frame(state.frame);
|
||||
let ext = 'png';
|
||||
let tmppath;
|
||||
let fileExists;
|
||||
tmppath = (0, path_1.join)(this.TMPDIR, `${state.hash}-export-${padded}.${ext}`);
|
||||
try {
|
||||
fileExists = await (0, fs_extra_1.exists)(tmppath);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
if (!fileExists)
|
||||
return false;
|
||||
try {
|
||||
await (0, fs_extra_1.unlink)(tmppath);
|
||||
this.log.info(`Cleared frame ${tmppath}`);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Deletes all frames in temp directory.
|
||||
*
|
||||
**/
|
||||
async clearAll() {
|
||||
const tmppath = this.TMPDIR;
|
||||
let files;
|
||||
try {
|
||||
files = await (0, fs_extra_1.readdir)(tmppath);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
files = files.filter((file) => {
|
||||
if (file.indexOf('-export-') !== -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (files) {
|
||||
files.forEach(async (file, index) => {
|
||||
try {
|
||||
await (0, fs_extra_1.unlink)((0, path_1.join)(tmppath, file));
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Checks if mcopy temp directory exists. If it doesn't,
|
||||
* creates it.
|
||||
**/
|
||||
async checkDir() {
|
||||
let fileExists;
|
||||
try {
|
||||
fileExists = await (0, fs_extra_1.exists)(this.TMPDIR);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error checking for tmp dir', err);
|
||||
}
|
||||
if (!fileExists) {
|
||||
try {
|
||||
await (0, fs_extra_1.mkdir)(this.TMPDIR);
|
||||
this.log.info(`Created tmpdir ${this.TMPDIR}`);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error creating tmp dir', err);
|
||||
}
|
||||
}
|
||||
try {
|
||||
await this.clearAll();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function frames (video, obj) {
|
||||
let tmppath = TMPDIR;
|
||||
let ext = 'tif';
|
||||
let tmpoutput;
|
||||
|
||||
if (system.platform !== 'nix') {
|
||||
ext = 'png';
|
||||
}
|
||||
|
||||
tmpoutput = path.join(tmppath, `export-%05d.${ext}`);
|
||||
try {
|
||||
await fs.mkdir(tmppath)
|
||||
} catch (Err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
//ffmpeg -i "${video}" -compression_algo raw -pix_fmt rgb24 "${tmpoutput}"
|
||||
}
|
||||
|
||||
async function clear (frame) {
|
||||
let padded = padded_frame(frame);
|
||||
let ext = 'tif';
|
||||
let tmppath;
|
||||
let tmpoutput;
|
||||
let cmd;
|
||||
let exists;
|
||||
|
||||
if (system.platform !== 'nix') {
|
||||
ext = 'png';
|
||||
}
|
||||
|
||||
tmppath = path.join(TMPDIR, `export-${padded}.${ext}`);
|
||||
|
||||
try {
|
||||
exists = await fs.exists(tmppath);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
if (!exists) return false;
|
||||
|
||||
try {
|
||||
await fs.unlink(tmppath);
|
||||
console.log(`Cleared frame ${tmppath}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async function clearAll () {
|
||||
let tmppath = TMPDIR;
|
||||
let files;
|
||||
try {
|
||||
files = await fs.readdir(tmppath);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
if (files) {
|
||||
files.forEach(async (file, index) => {
|
||||
try {
|
||||
await fs.unlink(path.join(tmppath, file));
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function checkDir () {
|
||||
let exists;
|
||||
try {
|
||||
exists = await fs.exists(TMPDIR);
|
||||
} catch (err) {
|
||||
console.error('Error checking for tmp dir', err);
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
try {
|
||||
await fs.mkdir(TMPDIR);
|
||||
console.log(`Created tmpdir ${TMPDIR}`);
|
||||
} catch (err) {
|
||||
console.error('Error creating tmp dir', err);
|
||||
}
|
||||
}
|
||||
try {
|
||||
await clearAll();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = (sys) => {
|
||||
system = sys;
|
||||
TMPDIR = path.join(system.tmp, 'mcopy_digital');
|
||||
|
||||
checkDir();
|
||||
|
||||
return {
|
||||
frames,
|
||||
frame,
|
||||
clear,
|
||||
clearAll
|
||||
}
|
||||
}
|
||||
return new FFMPEG(sys);
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
export {};
|
|
@ -1,104 +1,144 @@
|
|||
'use strict';
|
||||
|
||||
const fs = require('fs-extra');
|
||||
|
||||
const exec = require('exec');
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/** @module FFPROBE **/
|
||||
const fs_extra_1 = require("fs-extra");
|
||||
const path_1 = require("path");
|
||||
const exec_1 = require("exec");
|
||||
//const spawn = require('spawn');
|
||||
//const exit = require('exit');
|
||||
|
||||
let system = {};
|
||||
|
||||
async function info (video) {
|
||||
let cmd = `ffprobe -v quiet -print_format json -show_format -show_streams "${video}"`
|
||||
let exists;
|
||||
let raw;
|
||||
let json;
|
||||
let vid;
|
||||
|
||||
try {
|
||||
exists = await fs.exists(video);
|
||||
} catch (err) {
|
||||
return exit(err, 5);
|
||||
}
|
||||
if (!exists) {
|
||||
//return exit(`File ${video} does not exist`, 6);
|
||||
console.error(err);
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(cmd);
|
||||
raw = await exec(cmd);
|
||||
} catch (err) {
|
||||
//return exit(err, 7);
|
||||
console.error(err);
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
json = JSON.parse(raw.stdout);
|
||||
} catch (err) {
|
||||
return raw.stdout;
|
||||
}
|
||||
|
||||
if (json && json.streams) {
|
||||
vid = json.streams.find(stream => {
|
||||
if (stream.width && stream.height) return stream;
|
||||
});
|
||||
}
|
||||
|
||||
if (vid) {
|
||||
json.width = vid.width;
|
||||
json.height = vid.height;
|
||||
}
|
||||
|
||||
return json;
|
||||
class FFPROBE {
|
||||
constructor(sys) {
|
||||
this.bin = sys.deps.ffprobe;
|
||||
}
|
||||
/**
|
||||
* Parse the fps entry into a float representing the fps of a video
|
||||
**/
|
||||
parseFps(fpsStr) {
|
||||
let fps = 30.0;
|
||||
let parts;
|
||||
if (fpsStr.indexOf('/') !== -1) {
|
||||
parts = fpsStr.split('/');
|
||||
fps = parseFloat(parts[0]) / parseFloat(parts[1]);
|
||||
}
|
||||
else {
|
||||
fps = parseFloat(fpsStr);
|
||||
}
|
||||
return fps;
|
||||
}
|
||||
/**
|
||||
* Get info on a video in json format. Use for filmout.
|
||||
*
|
||||
* @param {string} video Path to video
|
||||
*
|
||||
* @returns {object} Video info in an object
|
||||
**/
|
||||
async info(video) {
|
||||
const cmd = `${this.bin} -v quiet -print_format json -show_format -show_streams "${video}"`;
|
||||
let fileExists;
|
||||
let raw;
|
||||
let json;
|
||||
let vid; //whether video has stream with video data
|
||||
try {
|
||||
fileExists = await (0, fs_extra_1.exists)(video);
|
||||
}
|
||||
catch (err) {
|
||||
return exit(err, 5);
|
||||
}
|
||||
if (!fileExists) {
|
||||
//return exit(`File ${video} does not exist`, 6);
|
||||
console.error(new Error(`File ${video} does not exist`));
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
console.log(cmd);
|
||||
raw = await (0, exec_1.exec)(cmd);
|
||||
}
|
||||
catch (err) {
|
||||
//return exit(err, 7);
|
||||
console.error(err);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
json = JSON.parse(raw.stdout);
|
||||
}
|
||||
catch (err) {
|
||||
return raw.stdout;
|
||||
}
|
||||
if (json.format && json.format.duration) {
|
||||
json.seconds = parseFloat(json.format.duration);
|
||||
}
|
||||
if (json && json.streams) {
|
||||
vid = json.streams.find((stream) => {
|
||||
if (stream.width && stream.height)
|
||||
return stream;
|
||||
});
|
||||
}
|
||||
if (vid) {
|
||||
json.width = vid.width;
|
||||
json.height = vid.height;
|
||||
json.fps = this.parseFps(vid.r_frame_rate);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
/**
|
||||
* Count the number of frames in the video using one of two methods.
|
||||
* The first uses -select_streams and is very fast. The second uses
|
||||
* -count_frames and is VERY slow.
|
||||
*
|
||||
* @param {string} video Path to video
|
||||
*
|
||||
* @returns {integer} Number of frames in video
|
||||
**/
|
||||
async frames(video) {
|
||||
const ext = (0, path_1.extname)(video.toLowerCase());
|
||||
let cmd = `${this.bin} -v error -select_streams v:0 -show_entries stream=nb_frames -of default=nokey=1:noprint_wrappers=1 "${video}"`;
|
||||
let backup_cmd = `${this.bin} -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 "${video}"`;
|
||||
let gif_cmd = `identify -format "%n\n" "${video}" | head -1`;
|
||||
let fileExists;
|
||||
let raw;
|
||||
let frames;
|
||||
try {
|
||||
fileExists = await (0, fs_extra_1.exists)(video);
|
||||
}
|
||||
catch (err) {
|
||||
//return exit(err, 5);
|
||||
console.error(err);
|
||||
return false;
|
||||
}
|
||||
if (!fileExists) {
|
||||
//return exit(`File ${video} does not exist`, 6);
|
||||
console.error(new Error(`File ${video} does not exist`));
|
||||
return false;
|
||||
}
|
||||
if (ext === '.mkv') {
|
||||
cmd = backup_cmd;
|
||||
}
|
||||
else if (ext === '.gif') {
|
||||
cmd = gif_cmd;
|
||||
}
|
||||
try {
|
||||
console.log(cmd);
|
||||
raw = await (0, exec_1.exec)(cmd);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
frames = parseInt(raw.stdout);
|
||||
}
|
||||
catch (err) {
|
||||
return raw.stdout;
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
}
|
||||
|
||||
async function frames (video) {
|
||||
let cmd = `ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 "${video}"`;
|
||||
let exists;
|
||||
let raw;
|
||||
let frames;
|
||||
|
||||
try {
|
||||
exists = await fs.exists(video);
|
||||
} catch (err) {
|
||||
//return exit(err, 5);
|
||||
console.error(err);
|
||||
return false
|
||||
}
|
||||
if (!exists) {
|
||||
//return exit(`File ${video} does not exist`, 6);
|
||||
console.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(cmd);
|
||||
raw = await exec(cmd);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
frames = parseInt(raw.stdout)
|
||||
} catch (err) {
|
||||
return raw.stdout;
|
||||
}
|
||||
|
||||
return frames;
|
||||
/*
|
||||
function map (obj : any) {
|
||||
console.dir(obj);
|
||||
}
|
||||
|
||||
function map (obj) {
|
||||
console.dir(obj);
|
||||
}
|
||||
|
||||
*/
|
||||
module.exports = (sys) => {
|
||||
system = sys;
|
||||
return {
|
||||
info,
|
||||
frames
|
||||
}
|
||||
}
|
||||
return new FFPROBE(sys);
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ffprobe/index.ts"],"names":[],"mappings":"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"}
|
|
@ -0,0 +1,44 @@
|
|||
<a name="Digital"></a>
|
||||
|
||||
## Digital
|
||||
**Kind**: global class
|
||||
|
||||
* [Digital](#Digital)
|
||||
* [.init()](#Digital+init)
|
||||
* [.listen()](#Digital+listen)
|
||||
* [.set()](#Digital+set)
|
||||
* [.move()](#Digital+move)
|
||||
* [.start()](#Digital+start)
|
||||
* [.end()](#Digital+end)
|
||||
* [.connectDigital()](#Digital+connectDigital)
|
||||
|
||||
<a name="Digital+init"></a>
|
||||
|
||||
### digital.init()
|
||||
**Kind**: instance method of [<code>Digital</code>](#Digital)
|
||||
<a name="Digital+listen"></a>
|
||||
|
||||
### digital.listen()
|
||||
**Kind**: instance method of [<code>Digital</code>](#Digital)
|
||||
<a name="Digital+set"></a>
|
||||
|
||||
### digital.set()
|
||||
**Kind**: instance method of [<code>Digital</code>](#Digital)
|
||||
<a name="Digital+move"></a>
|
||||
|
||||
### digital.move()
|
||||
**Kind**: instance method of [<code>Digital</code>](#Digital)
|
||||
<a name="Digital+start"></a>
|
||||
|
||||
### digital.start()
|
||||
**Kind**: instance method of [<code>Digital</code>](#Digital)
|
||||
<a name="Digital+end"></a>
|
||||
|
||||
### digital.end()
|
||||
**Kind**: instance method of [<code>Digital</code>](#Digital)
|
||||
<a name="Digital+connectDigital"></a>
|
||||
|
||||
### digital.connectDigital()
|
||||
Use a file as the "digital" source on "projector"
|
||||
|
||||
**Kind**: instance method of [<code>Digital</code>](#Digital)
|
|
@ -0,0 +1 @@
|
|||
export {};
|
|
@ -0,0 +1,504 @@
|
|||
'use strict';
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const animated_gif_detector_1 = __importDefault(require("animated-gif-detector"));
|
||||
const path_1 = require("path");
|
||||
const fs_extra_1 = require("fs-extra");
|
||||
const delay_1 = require("delay");
|
||||
const crypto_1 = require("crypto");
|
||||
const frame_1 = __importDefault(require("frame"));
|
||||
/**
|
||||
* @module FilmOut
|
||||
**/
|
||||
class FilmOut {
|
||||
/**
|
||||
* @constructor
|
||||
* Builds FilmOut class with display, ffmpeg, ffprobe, ui and light as internal properties.
|
||||
*
|
||||
* @param {object} display Display object for showing frames
|
||||
* @param {object} ffmpeg FFMPEG wrapper
|
||||
* @param {object} ffprobe FFPROBE wrapper for file info
|
||||
* @param {object} ui Electron ui object
|
||||
* @param {object} light Light device object
|
||||
**/
|
||||
constructor(display, server, ffmpeg, ffprobe, ui, light) {
|
||||
this.id = 'filmout';
|
||||
this.videoExtensions = ['.mpg', '.mpeg', '.mov', '.mkv', '.avi', '.mp4'];
|
||||
this.stillExtensions = ['.tif', '.tiff', '.png', '.jpg', '.jpeg', '.bmp'];
|
||||
this.sequenceExtensions = ['.png', '.jpg', '.jpeg'];
|
||||
this.gifExtension = '.gif';
|
||||
this.state = {
|
||||
frame: 0,
|
||||
frames: 0,
|
||||
still: false,
|
||||
path: null,
|
||||
fileName: null,
|
||||
directory: false,
|
||||
info: {},
|
||||
dir: true,
|
||||
enabled: false,
|
||||
files: []
|
||||
};
|
||||
this.display = display;
|
||||
this.server = server;
|
||||
this.ffmpeg = ffmpeg;
|
||||
this.ffprobe = ffprobe;
|
||||
this.ui = ui;
|
||||
this.light = light;
|
||||
this.init();
|
||||
}
|
||||
/**
|
||||
* Async function for requiring log, ipcMain and bind events.
|
||||
**/
|
||||
async init() {
|
||||
const Log = require('log');
|
||||
this.log = await Log({ label: this.id });
|
||||
this.ipc = require('electron').ipcMain;
|
||||
this.listen();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
listen() {
|
||||
this.ipc.on(this.id, this.onConnect.bind(this));
|
||||
this.ipc.on('focus', this.focus.bind(this));
|
||||
this.ipc.on('field', this.field.bind(this));
|
||||
this.ipc.on('meter', this.meter.bind(this));
|
||||
this.ipc.on('filmout_close', this.close.bind(this));
|
||||
this.ipc.on('preview', this.preview.bind(this));
|
||||
this.ipc.on('preview_frame', this.previewFrame.bind(this));
|
||||
this.ipc.on('display', this.onDisplay.bind(this));
|
||||
this.ipc.on('pre_export', this.onPreExport.bind(this));
|
||||
this.ffmpeg.onProgress = (obj) => {
|
||||
this.ui.send('pre_export_progress', { progress: obj });
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Create a hash of a string.
|
||||
*
|
||||
* @param {string} data Data to produce hash of
|
||||
*/
|
||||
hash(data) {
|
||||
return (0, crypto_1.createHash)('sha1').update(data).digest('hex');
|
||||
}
|
||||
/**
|
||||
* Sets filmout direction.
|
||||
*
|
||||
* @param {boolean} dir Direction of filmout
|
||||
**/
|
||||
set(dir) {
|
||||
this.state.dir = dir;
|
||||
}
|
||||
/**
|
||||
* Moves filmout a frame at a time.
|
||||
*
|
||||
* @returns {number} Time since start
|
||||
**/
|
||||
async move() {
|
||||
let start = +new Date();
|
||||
if (this.state.still) {
|
||||
return -1;
|
||||
}
|
||||
if (this.state.dir) {
|
||||
this.state.frame++;
|
||||
}
|
||||
else {
|
||||
this.state.frame--;
|
||||
}
|
||||
if (this.state.frame < 1) {
|
||||
this.state.frame = 1;
|
||||
}
|
||||
return (+new Date()) - start;
|
||||
}
|
||||
/**
|
||||
* Begin the process of exporting single frames from the video for display.
|
||||
**/
|
||||
async start() {
|
||||
let path;
|
||||
try {
|
||||
path = await this.ffmpeg.frame(this.state, this.light.state);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
throw err;
|
||||
}
|
||||
if (this.server.displayImage(path)) {
|
||||
await (0, delay_1.delay)(20);
|
||||
return;
|
||||
}
|
||||
await this.display.show(path);
|
||||
await (0, delay_1.delay)(20);
|
||||
}
|
||||
/**
|
||||
* Ends the filmout process and closes the display.
|
||||
**/
|
||||
async end() {
|
||||
await (0, delay_1.delay)(20);
|
||||
this.display.hide();
|
||||
}
|
||||
/**
|
||||
* Use a video file as a film out source on "projector"
|
||||
*
|
||||
* @param {object} evt Original connect event
|
||||
* @param {object} arg Arguments from ipc message
|
||||
*
|
||||
* @returns {boolean} Success state
|
||||
**/
|
||||
async onConnect(evt, arg) {
|
||||
let frames = 0;
|
||||
let isAnimated = false;
|
||||
let info;
|
||||
let ext;
|
||||
let stats;
|
||||
let frameList;
|
||||
try {
|
||||
stats = await (0, fs_extra_1.lstat)(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
return false;
|
||||
}
|
||||
ext = (0, path_1.extname)(arg.fileName.toLowerCase());
|
||||
if (stats.isDirectory()) {
|
||||
this.state.directory = true;
|
||||
this.state.still = false;
|
||||
}
|
||||
else if (ext === this.gifExtension) {
|
||||
try {
|
||||
isAnimated = await this.isGifAnimated(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
this.state.still = !isAnimated;
|
||||
}
|
||||
else if (this.stillExtensions.indexOf(ext) !== -1) {
|
||||
this.state.still = true;
|
||||
this.state.directory = false;
|
||||
}
|
||||
else if (this.videoExtensions.indexOf(ext) !== -1) {
|
||||
this.state.still = false;
|
||||
this.state.directory = false;
|
||||
}
|
||||
else {
|
||||
this.log.error(`File is not of a valid file type`, 'FILMOUT', true, true);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
await this.ffmpeg.clearAll();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
throw err;
|
||||
}
|
||||
if (this.state.directory) {
|
||||
try {
|
||||
frameList = await this.dirList(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
info = await this.dirInfo(frameList);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
frames = frameList.length;
|
||||
this.state.files = frameList;
|
||||
}
|
||||
else if (this.state.still) {
|
||||
try {
|
||||
info = await this.stillInfo(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
frames = 1;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
info = await this.ffprobe.info(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
frames = await this.ffprobe.frames(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this.state.frame = 0;
|
||||
this.state.path = arg.path;
|
||||
this.state.fileName = arg.fileName;
|
||||
this.state.frames = frames;
|
||||
this.state.info = info;
|
||||
this.state.hash = this.hash(arg.path);
|
||||
if (info.fps) {
|
||||
this.state.fps = info.fps;
|
||||
}
|
||||
else {
|
||||
this.state.fps = 24; //default
|
||||
}
|
||||
if (info.seconds) {
|
||||
this.state.seconds = info.seconds;
|
||||
}
|
||||
else if (info.fps && frames) {
|
||||
this.state.seconds = frames / info.fps;
|
||||
}
|
||||
else if (this.state.directory) {
|
||||
this.state.seconds = frames / 24;
|
||||
}
|
||||
this.log.info(`Opened ${this.state.fileName}`, 'FILMOUT', true, true);
|
||||
this.log.info(`Frames : ${frames}`, 'FILMOUT', true, true);
|
||||
this.state.enabled = true;
|
||||
await this.ui.send(this.id, { valid: true, state: JSON.stringify(this.state) });
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Pre-export all frames from video for display.
|
||||
*
|
||||
* @param {object} evt IPC event
|
||||
* @param {object} arg IPC args
|
||||
*
|
||||
* @returns {any} UI send call
|
||||
*/
|
||||
async onPreExport(evt, arg) {
|
||||
if (!this.state.path) {
|
||||
return await this.ui.send('pre_export', { complete: false, err: 'No file to pre export.' });
|
||||
}
|
||||
try {
|
||||
await this.ffmpeg.frames(this.state);
|
||||
}
|
||||
catch (err) {
|
||||
return await this.ui.send('pre_export', { complete: false, err });
|
||||
}
|
||||
return await this.ui.send('pre_export', { complete: true });
|
||||
}
|
||||
/**
|
||||
* Return true if gif is animated, false if it is a still
|
||||
*
|
||||
* @param {string} pathStr Path to gif to check
|
||||
*
|
||||
* @returns {boolean} Whether or not gif is animated
|
||||
**/
|
||||
async isGifAnimated(pathStr) {
|
||||
let gifBuffer;
|
||||
try {
|
||||
gifBuffer = await (0, fs_extra_1.readFile)(pathStr);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
return false;
|
||||
}
|
||||
return (0, animated_gif_detector_1.default)(gifBuffer);
|
||||
}
|
||||
/**
|
||||
* Return information on a still image using the Jimp module
|
||||
*
|
||||
* @param {string} pathStr Path to gif to check
|
||||
*
|
||||
* @returns {object} Info about still from sharp
|
||||
**/
|
||||
async stillInfo(pathStr) {
|
||||
let info;
|
||||
try {
|
||||
info = await frame_1.default.info(pathStr);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
/**
|
||||
* Return information on the first still image found in a
|
||||
* directory using the Jimp module.
|
||||
*
|
||||
* @param {array} images List of image paths
|
||||
*
|
||||
* @returns {object} Info about first image
|
||||
**/
|
||||
async dirInfo(images) {
|
||||
let info;
|
||||
try {
|
||||
info = await this.stillInfo(images[0]);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
/**
|
||||
* Returns a list of images within a directory, filtered
|
||||
* for supported types and sorted.
|
||||
*
|
||||
* @param {string} pathStr Path to directory
|
||||
*
|
||||
* @returns {array} Array of image paths
|
||||
**/
|
||||
async dirList(pathStr) {
|
||||
let frameList = [];
|
||||
try {
|
||||
frameList = await (0, fs_extra_1.readdir)(pathStr);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
frameList = frameList.filter((fileName) => {
|
||||
let ext = (0, path_1.extname)(fileName);
|
||||
if (this.sequenceExtensions.indexOf(ext) !== -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
frameList.sort();
|
||||
frameList = frameList.map((fileName) => {
|
||||
return (0, path_1.join)(pathStr, fileName);
|
||||
});
|
||||
return frameList;
|
||||
}
|
||||
/**
|
||||
* Preview a frame from the selected video.
|
||||
*
|
||||
* @param {object} evt Original event
|
||||
* @param {object} arg Arguments from message
|
||||
**/
|
||||
async previewFrame(evt, arg) {
|
||||
const state = JSON.parse(JSON.stringify(this.state));
|
||||
let path;
|
||||
state.frame = arg.frame;
|
||||
try {
|
||||
path = await this.ffmpeg.frame(state, { color: [255, 255, 255] });
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
throw err;
|
||||
}
|
||||
this.ui.send('preview_frame', { path, frame: arg.frame });
|
||||
}
|
||||
/**
|
||||
* Open a single frame in a display window to preview filmout.
|
||||
*
|
||||
* @param {object} evt Original event
|
||||
* @param {object} arg Arguments from message
|
||||
**/
|
||||
async preview(evt, arg) {
|
||||
const state = JSON.parse(JSON.stringify(this.state));
|
||||
let path;
|
||||
state.frame = arg.frame;
|
||||
this.log.info(`Previewing frame ${state.frame} of ${state.fileName}`);
|
||||
try {
|
||||
path = await this.ffmpeg.frame(state, { color: [255, 255, 255] });
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
throw err;
|
||||
}
|
||||
try {
|
||||
if (await this.server.displayImage(path)) {
|
||||
return;
|
||||
}
|
||||
await this.display.open();
|
||||
await this.display.show(path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async focus(evt, arg) {
|
||||
this.log.info(`Showing focus screen`);
|
||||
try {
|
||||
if (await this.server.cmdAll('focus')) {
|
||||
return;
|
||||
}
|
||||
await this.display.open();
|
||||
await this.display.focus();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async field(evt, arg) {
|
||||
const ratio = arg.ratio;
|
||||
this.log.info(`Showing field guide screen`);
|
||||
try {
|
||||
if (await this.server.cmdAll('field', { ratio })) {
|
||||
return;
|
||||
}
|
||||
await this.display.open();
|
||||
await this.display.field(ratio);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async meter(evt, arg) {
|
||||
this.log.info(`Showing meter screen`);
|
||||
try {
|
||||
if (await this.server.cmdAll('meter')) {
|
||||
return;
|
||||
}
|
||||
await this.display.open();
|
||||
await this.display.meter();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async close(evt, arg) {
|
||||
try {
|
||||
if (await this.server.cmdAll('blank')) {
|
||||
return;
|
||||
}
|
||||
await this.display.hide();
|
||||
await this.display.close();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
onDisplay(evt, arg) {
|
||||
this.display.change(arg.display);
|
||||
this.log.info(`Changing the display to ${arg.display}`);
|
||||
}
|
||||
}
|
||||
module.exports = (display, server, ffmpeg, ffprobe, ui, light) => {
|
||||
return new FilmOut(display, server, ffmpeg, ffprobe, ui, light);
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "digital",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
interface RGBA {
|
||||
r: number;
|
||||
g: number;
|
||||
b: number;
|
||||
a: number;
|
||||
}
|
||||
export default class Frame {
|
||||
static info(imagePath: string): Promise<{
|
||||
width: any;
|
||||
height: any;
|
||||
}>;
|
||||
static solidColor(width: number, height: number, color: RGBA): Promise<unknown>;
|
||||
static blend(inPath: any, color: RGBA, imagePath: string): Promise<string>;
|
||||
}
|
||||
export {};
|
|
@ -0,0 +1,70 @@
|
|||
'use strict';
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const jimp_1 = __importDefault(require("jimp"));
|
||||
class Frame {
|
||||
static async info(imagePath) {
|
||||
let image;
|
||||
try {
|
||||
image = await jimp_1.default.read(imagePath);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return {
|
||||
width: image.bitmap.width,
|
||||
height: image.bitmap.height
|
||||
};
|
||||
}
|
||||
static async solidColor(width, height, color) {
|
||||
//@ts-ignore
|
||||
const colorInt = jimp_1.default.rgbaToInt(color.r, color.g, color.b, color.a);
|
||||
return new Promise((resolve, reject) => {
|
||||
return new jimp_1.default(width, height, colorInt, (err, image) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
return resolve(image);
|
||||
});
|
||||
});
|
||||
}
|
||||
static async blend(inPath, color, imagePath) {
|
||||
//cmd2 = `${this.convert} "${tmpoutput}" -resize ${w}x${h} -size ${w}x${h} xc:"rgb(${rgb[0]},${rgb[1]},${rgb[2]})" +swap -compose Darken -composite "${tmpoutput}"`;
|
||||
const options = {
|
||||
mode: jimp_1.default.BLEND_DARKEN,
|
||||
opacitySource: 1.0,
|
||||
opacityDest: 1.0
|
||||
};
|
||||
let width;
|
||||
let height;
|
||||
let bottom;
|
||||
let top;
|
||||
try {
|
||||
top = await jimp_1.default.read(inPath);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
width = top.bitmap.width;
|
||||
height = top.bitmap.height;
|
||||
try {
|
||||
bottom = await Frame.solidColor(width, height, color);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
bottom.composite(top, 0, 0, options);
|
||||
try {
|
||||
await bottom.writeAsync(imagePath);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return imagePath;
|
||||
}
|
||||
}
|
||||
exports.default = Frame;
|
||||
module.exports = Frame;
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/frame/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;AAEb,gDAAwB;AASxB,MAAqB,KAAK;IACzB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAE,SAAkB;QACpC,IAAI,KAAW,CAAC;QAChB,IAAI;YACH,KAAK,GAAG,MAAM,cAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;SACnC;QAAC,OAAO,GAAG,EAAE;YACb,MAAM,GAAG,CAAC;SACV;QACD,OAAO;YACN,KAAK,EAAG,KAAK,CAAC,MAAM,CAAC,KAAK;YAC1B,MAAM,EAAG,KAAK,CAAC,MAAM,CAAC,MAAM;SAC5B,CAAC;IACH,CAAC;IACD,MAAM,CAAC,KAAK,CAAC,UAAU,CAAE,KAAc,EAAE,MAAe,EAAE,KAAY;QACrE,YAAY;QACZ,MAAM,QAAQ,GAAY,cAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QAC7E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAkB,EAAE,MAAiB,EAAE,EAAE;YAC5D,OAAO,IAAI,cAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;gBACrD,IAAI,GAAG,EAAE;oBACR,OAAO,MAAM,CAAC,GAAG,CAAC,CAAA;iBAClB;gBACD,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,KAAK,CAAE,MAAY,EAAE,KAAY,EAAE,SAAkB;QACjE,oKAAoK;QACpK,MAAM,OAAO,GAAS;YACrB,IAAI,EAAE,cAAI,CAAC,YAAY;YACvB,aAAa,EAAE,GAAG;YAClB,WAAW,EAAE,GAAG;SAChB,CAAC;QACF,IAAI,KAAc,CAAC;QACnB,IAAI,MAAe,CAAC;QACpB,IAAI,MAAY,CAAC;QACjB,IAAI,GAAS,CAAC;QAEd,IAAI;YACH,GAAG,GAAG,MAAM,cAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SAC9B;QAAC,OAAO,GAAG,EAAE;YACb,MAAM,GAAG,CAAC;SACV;QAED,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;QACzB,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;QAE3B,IAAI;YACH,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;SACtD;QAAC,OAAO,GAAG,EAAE;YACb,MAAM,GAAG,CAAC;SACV;QAED,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;QAErC,IAAI;YACH,MAAM,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;SACnC;QAAC,OAAO,GAAG,EAAE;YACb,MAAM,GAAG,CAAC;SACV;QAED,OAAO,SAAS,CAAC;IAClB,CAAC;CACD;AA/DD,wBA+DC;AAED,MAAM,CAAC,OAAO,GAAG,KAAK,CAAA"}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "frame",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
export declare class Intval {
|
||||
private _baseUrl;
|
||||
private req;
|
||||
constructor(url: string);
|
||||
move(): Promise<unknown>;
|
||||
setDir(dir: boolean): Promise<unknown>;
|
||||
setExposure(exposure: number, cb: Function): Promise<unknown>;
|
||||
connect(cb: Function): void;
|
||||
}
|
|
@ -1,71 +1,71 @@
|
|||
'use strict'
|
||||
|
||||
const req = require('request')
|
||||
|
||||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Intval = void 0;
|
||||
class Intval {
|
||||
constructor (url) {
|
||||
this._baseUrl = `http://${url}`
|
||||
}
|
||||
async move () {
|
||||
return new Promise ((resolve, reject) => {
|
||||
const timeStart = +new Date()
|
||||
const url = `${this._baseUrl}/frame`
|
||||
//console.log(url)
|
||||
return req(url, (err, res, body) => {
|
||||
let ms = (+new Date()) - timeStart
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
return resolve(ms)
|
||||
})
|
||||
})
|
||||
}
|
||||
async setDir (dir) {
|
||||
return new Promise ((resolve, reject) => {
|
||||
const timeStart = +new Date()
|
||||
const url = `${this._baseUrl}/dir?dir=${dir}`
|
||||
//console.log(url)
|
||||
return req(url, (err, res, body) => {
|
||||
let ms = (+new Date()) - timeStart
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
return resolve(ms)
|
||||
})
|
||||
})
|
||||
}
|
||||
async setExposure (exposure, cb) {
|
||||
return new Promise ((resolve, reject) => {
|
||||
const timeStart = +new Date()
|
||||
const url = `${this._baseUrl}/exposure?exposure=${exposure}`
|
||||
//console.log(url)
|
||||
return req(url, (err, res, body) => {
|
||||
let ms = (+new Date()) - timeStart
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
return resolve(ms)
|
||||
})
|
||||
})
|
||||
}
|
||||
connect (cb) {
|
||||
const timeStart = +new Date()
|
||||
const url = `${this._baseUrl}/status`
|
||||
const opts = {
|
||||
method : 'GET',
|
||||
uri : url,
|
||||
timeout: 5000
|
||||
}
|
||||
|
||||
req(opts, (err, res, body) => {
|
||||
let ms = (+new Date()) - timeStart
|
||||
if (err) {
|
||||
//console.error(err)
|
||||
return cb(err, ms)
|
||||
}
|
||||
cb(null, ms, body)
|
||||
})
|
||||
}
|
||||
constructor(url) {
|
||||
this._baseUrl = `http://${url}`;
|
||||
this.req = require('request');
|
||||
}
|
||||
async move() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeStart = +new Date();
|
||||
const url = `${this._baseUrl}/frame`;
|
||||
//console.log(url)
|
||||
return this.req(url, (err, res, body) => {
|
||||
let ms = (+new Date()) - timeStart;
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
return resolve(ms);
|
||||
});
|
||||
});
|
||||
}
|
||||
async setDir(dir) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeStart = +new Date();
|
||||
const url = `${this._baseUrl}/dir?dir=${dir}`;
|
||||
//console.log(url)
|
||||
return this.req(url, (err, res, body) => {
|
||||
let ms = (+new Date()) - timeStart;
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
return resolve(ms);
|
||||
});
|
||||
});
|
||||
}
|
||||
async setExposure(exposure, cb) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeStart = +new Date();
|
||||
const url = `${this._baseUrl}/exposure?exposure=${exposure}`;
|
||||
//console.log(url)
|
||||
return this.req(url, (err, res, body) => {
|
||||
let ms = (+new Date()) - timeStart;
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
return resolve(ms);
|
||||
});
|
||||
});
|
||||
}
|
||||
connect(cb) {
|
||||
const timeStart = +new Date();
|
||||
const url = `${this._baseUrl}/status`;
|
||||
const opts = {
|
||||
method: 'GET',
|
||||
uri: url,
|
||||
timeout: 5000
|
||||
};
|
||||
this.req(opts, (err, res, body) => {
|
||||
let ms = (+new Date()) - timeStart;
|
||||
if (err) {
|
||||
//console.error(err)
|
||||
return cb(err, ms);
|
||||
}
|
||||
cb(null, ms, body);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Intval
|
||||
exports.Intval = Intval;
|
||||
module.exports.Intval = Intval;
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/intval/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;;;AAEZ,MAAa,MAAM;IAGlB,YAAa,GAAY;QACxB,IAAI,CAAC,QAAQ,GAAG,UAAU,GAAG,EAAE,CAAA;QAC/B,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;IAC9B,CAAC;IACM,KAAK,CAAC,IAAI;QAChB,OAAO,IAAI,OAAO,CAAE,CAAC,OAAa,EAAE,MAAY,EAAE,EAAE;YACnD,MAAM,SAAS,GAAY,CAAC,IAAI,IAAI,EAAE,CAAA;YACtC,MAAM,GAAG,GAAY,GAAG,IAAI,CAAC,QAAQ,QAAQ,CAAA;YAC7C,kBAAkB;YAClB,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAW,EAAE,GAAS,EAAE,IAAa,EAAE,EAAE;gBAC9D,IAAI,EAAE,GAAY,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,SAAS,CAAA;gBAC3C,IAAI,GAAG,EAAE;oBACR,OAAO,MAAM,CAAC,GAAG,CAAC,CAAA;iBAClB;gBACD,OAAO,OAAO,CAAC,EAAE,CAAC,CAAA;YACnB,CAAC,CAAC,CAAA;QACH,CAAC,CAAC,CAAA;IACH,CAAC;IACM,KAAK,CAAC,MAAM,CAAE,GAAa;QACjC,OAAO,IAAI,OAAO,CAAE,CAAC,OAAa,EAAE,MAAY,EAAE,EAAE;YACnD,MAAM,SAAS,GAAY,CAAC,IAAI,IAAI,EAAE,CAAA;YACtC,MAAM,GAAG,GAAY,GAAG,IAAI,CAAC,QAAQ,YAAY,GAAG,EAAE,CAAA;YACtD,kBAAkB;YAClB,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAW,EAAE,GAAS,EAAE,IAAa,EAAE,EAAE;gBAC9D,IAAI,EAAE,GAAY,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,SAAS,CAAA;gBAC3C,IAAI,GAAG,EAAE;oBACR,OAAO,MAAM,CAAC,GAAG,CAAC,CAAA;iBAClB;gBACD,OAAO,OAAO,CAAC,EAAE,CAAC,CAAA;YACnB,CAAC,CAAC,CAAA;QACH,CAAC,CAAC,CAAA;IACH,CAAC;IACM,KAAK,CAAC,WAAW,CAAE,QAAiB,EAAE,EAAa;QACzD,OAAO,IAAI,OAAO,CAAE,CAAC,OAAa,EAAE,MAAY,EAAE,EAAE;YACnD,MAAM,SAAS,GAAY,CAAC,IAAI,IAAI,EAAE,CAAA;YACtC,MAAM,GAAG,GAAY,GAAG,IAAI,CAAC,QAAQ,sBAAsB,QAAQ,EAAE,CAAA;YACrE,kBAAkB;YAClB,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAW,EAAE,GAAS,EAAE,IAAa,EAAE,EAAE;gBAC9D,IAAI,EAAE,GAAY,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,SAAS,CAAA;gBAC3C,IAAI,GAAG,EAAE;oBACR,OAAO,MAAM,CAAC,GAAG,CAAC,CAAA;iBAClB;gBACD,OAAO,OAAO,CAAC,EAAE,CAAC,CAAA;YACnB,CAAC,CAAC,CAAA;QACH,CAAC,CAAC,CAAA;IACH,CAAC;IACM,OAAO,CAAE,EAAa;QAC5B,MAAM,SAAS,GAAY,CAAC,IAAI,IAAI,EAAE,CAAA;QACtC,MAAM,GAAG,GAAY,GAAG,IAAI,CAAC,QAAQ,SAAS,CAAA;QAC9C,MAAM,IAAI,GAAS;YAClB,MAAM,EAAG,KAAK;YACd,GAAG,EAAG,GAAG;YACT,OAAO,EAAE,IAAI;SACb,CAAA;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAW,EAAE,GAAS,EAAE,IAAa,EAAE,EAAE;YACxD,IAAI,EAAE,GAAY,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,SAAS,CAAA;YAC3C,IAAI,GAAG,EAAE;gBACR,oBAAoB;gBACpB,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;aAClB;YACD,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,CAAA;QACnB,CAAC,CAAC,CAAA;IACH,CAAC;CACD;AAnED,wBAmEC;AAED,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAA"}
|
|
@ -0,0 +1,32 @@
|
|||
<a name="Light"></a>
|
||||
|
||||
## Light
|
||||
**Kind**: global class
|
||||
|
||||
* [Light](#Light)
|
||||
* [.init()](#Light+init)
|
||||
* [.listen()](#Light+listen)
|
||||
* [.listener()](#Light+listener)
|
||||
* [.set()](#Light+set)
|
||||
* [.end()](#Light+end)
|
||||
|
||||
<a name="Light+init"></a>
|
||||
|
||||
### light.init()
|
||||
**Kind**: instance method of [<code>Light</code>](#Light)
|
||||
<a name="Light+listen"></a>
|
||||
|
||||
### light.listen()
|
||||
**Kind**: instance method of [<code>Light</code>](#Light)
|
||||
<a name="Light+listener"></a>
|
||||
|
||||
### light.listener()
|
||||
**Kind**: instance method of [<code>Light</code>](#Light)
|
||||
<a name="Light+set"></a>
|
||||
|
||||
### light.set()
|
||||
**Kind**: instance method of [<code>Light</code>](#Light)
|
||||
<a name="Light+end"></a>
|
||||
|
||||
### light.end()
|
||||
**Kind**: instance method of [<code>Light</code>](#Light)
|
|
@ -0,0 +1 @@
|
|||
export {};
|
|
@ -0,0 +1,97 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const delay_1 = require("delay");
|
||||
const Log = require("log");
|
||||
class Light {
|
||||
/**
|
||||
*
|
||||
**/
|
||||
constructor(arduino, cfg, ui) {
|
||||
this.state = { color: [0, 0, 0] };
|
||||
this.enabled = true;
|
||||
this.id = 'light';
|
||||
this.arduino = arduino;
|
||||
this.cfg = cfg;
|
||||
this.ui = ui;
|
||||
this.init();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async init() {
|
||||
this.log = await Log({ label: this.id });
|
||||
this.ipc = require('electron').ipcMain;
|
||||
this.listen();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
listen() {
|
||||
this.ipc.handle(this.id, this.listener.bind(this));
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async listener(event, arg) {
|
||||
if (typeof arg.rgb !== 'undefined') {
|
||||
try {
|
||||
await this.set(arg.rgb, arg.id, true);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error setting light', err);
|
||||
}
|
||||
}
|
||||
else if (typeof arg.enable !== 'undefined') {
|
||||
this.enabled = true;
|
||||
}
|
||||
else if (typeof arg.disable !== 'undefined') {
|
||||
this.enabled = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async set(rgb, id, on = true) {
|
||||
const str = rgb.join(',');
|
||||
let ms;
|
||||
this.state.color = rgb;
|
||||
try {
|
||||
ms = await this.arduino.send(this.id, this.cfg.arduino.cmd.light);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error sending light command', err);
|
||||
}
|
||||
await (0, delay_1.delay)(1);
|
||||
try {
|
||||
this.arduino.sendString(this.id, str);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error sending light string', err);
|
||||
}
|
||||
await (0, delay_1.delay)(1);
|
||||
await ms;
|
||||
return await this.end(rgb, id, ms);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async end(rgb, id, ms) {
|
||||
let res;
|
||||
//console.trace()
|
||||
this.log.info(`Light set to ${rgb.join(',')}`, 'LIGHT', true, true);
|
||||
try {
|
||||
//console.dir({ rgb, id, ms })
|
||||
res = await this.ui.send(this.id, { rgb, id, ms });
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
throw err;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
module.exports = function (arduino, cfg, ui) {
|
||||
return new Light(arduino, cfg, ui);
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/light/index.ts"],"names":[],"mappings":"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"}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "light",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<a name="logFile"></a>
|
||||
|
||||
## logFile() ⇒ <code>string</code>
|
||||
Determine the location of the log file based on the operating system
|
||||
and return as an absolute string from os.homedir()
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>string</code> - Path to log file
|
|
@ -0,0 +1 @@
|
|||
export {};
|
|
@ -0,0 +1,85 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const winston_1 = require("winston");
|
||||
const path_1 = require("path");
|
||||
const fs_extra_1 = require("fs-extra");
|
||||
const os_1 = require("os");
|
||||
const logTime = 'MM/DD/YY-HH:mm:ss';
|
||||
let transport;
|
||||
/**
|
||||
* Determine the location of the log file based on the operating system
|
||||
* and return as an absolute string from os.homedir()
|
||||
*
|
||||
* @returns {string} Path to log file
|
||||
**/
|
||||
async function logFile() {
|
||||
const homeDir = (0, os_1.homedir)();
|
||||
const linuxDir = `/.mcopy/`;
|
||||
const macDir = `/Library/Logs/mcopy/`;
|
||||
const winDir = `/AppData/Roaming/mcopy/`;
|
||||
let logPath = (0, path_1.normalize)((0, path_1.join)(homeDir, linuxDir));
|
||||
let dirExists;
|
||||
if (process.platform === 'darwin') {
|
||||
logPath = (0, path_1.normalize)((0, path_1.join)(homeDir, macDir));
|
||||
}
|
||||
else if (process.platform === 'win32') {
|
||||
logPath = (0, path_1.normalize)((0, path_1.join)(homeDir, winDir));
|
||||
}
|
||||
try {
|
||||
dirExists = await (0, fs_extra_1.exists)(logPath);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
if (!dirExists) {
|
||||
try {
|
||||
await (0, fs_extra_1.mkdir)(logPath);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(`Error creating directory for mcopy log file, ${logPath}`);
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
return (0, path_1.join)(logPath, 'mcopy.log');
|
||||
}
|
||||
/**
|
||||
* Create and return the logger transport based on settings determined in
|
||||
* arguments object
|
||||
*
|
||||
* @param {object} arg Arguments from process
|
||||
*
|
||||
* @returns {object} Logger transport
|
||||
**/
|
||||
module.exports = async function Log(arg) {
|
||||
let consoleFormat = {
|
||||
colorize: true
|
||||
};
|
||||
let fileFormat = {
|
||||
filename: await logFile(),
|
||||
json: true
|
||||
};
|
||||
if (arg && arg.quiet) {
|
||||
transport = {
|
||||
info: function () { return false; },
|
||||
warn: function () { return false; },
|
||||
error: function () { return false; }
|
||||
};
|
||||
}
|
||||
else {
|
||||
if (arg && arg.label) {
|
||||
consoleFormat.label = arg.label;
|
||||
fileFormat.label = arg.label;
|
||||
}
|
||||
transport = (0, winston_1.createLogger)({
|
||||
format: winston_1.format.combine(winston_1.format.label({ label: arg.label || 'mcopy' }), winston_1.format.timestamp({
|
||||
format: 'YYYY-MM-DD HH:mm:ss'
|
||||
}), winston_1.format.printf((info) => `${info.timestamp} [${info.label}] ${info.level}: ${info.message}` + (info.splat !== undefined ? `${info.splat}` : " "))),
|
||||
transports: [
|
||||
new (winston_1.transports.Console)(consoleFormat),
|
||||
new (winston_1.transports.File)(fileFormat)
|
||||
]
|
||||
});
|
||||
}
|
||||
return transport;
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/log/index.ts"],"names":[],"mappings":"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"}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "log",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
* [.light_to_arr()](#module_lib/mscript..Mscript+light_to_arr)
|
||||
* [.light_state()](#module_lib/mscript..Mscript+light_state)
|
||||
* [.fail()](#module_lib/mscript..Mscript+fail)
|
||||
* [~startsWith()](#module_lib/mscript..startsWith)
|
||||
|
||||
<a name="module_lib/mscript..Mscript"></a>
|
||||
|
||||
|
@ -70,55 +71,55 @@ of steps to be fed into the mcopy.
|
|||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+basic_cmd"></a>
|
||||
|
||||
#### mscript.basic_cmd()
|
||||
#### mscript.basic\_cmd()
|
||||
Apply a basic two character command
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+new_loop"></a>
|
||||
|
||||
#### mscript.new_loop()
|
||||
#### mscript.new\_loop()
|
||||
Start a new loop
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+end_loop"></a>
|
||||
|
||||
#### mscript.end_loop()
|
||||
#### mscript.end\_loop()
|
||||
Close the most recent loop
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+move_cam"></a>
|
||||
|
||||
#### mscript.move_cam()
|
||||
#### mscript.move\_cam()
|
||||
Move camera to explicitly-defined frame
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+move_proj"></a>
|
||||
|
||||
#### mscript.move_proj()
|
||||
#### mscript.move\_proj()
|
||||
Move projector to explicitly-defined frame
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+set_state"></a>
|
||||
|
||||
#### mscript.set_state()
|
||||
#### mscript.set\_state()
|
||||
Set the state of either the cam or projector
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+last_loop"></a>
|
||||
|
||||
#### mscript.last_loop()
|
||||
#### mscript.last\_loop()
|
||||
Return the last loop
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+parent_loop"></a>
|
||||
|
||||
#### mscript.parent_loop()
|
||||
#### mscript.parent\_loop()
|
||||
Return the second-last loop
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+loop_count"></a>
|
||||
|
||||
#### mscript.loop_count()
|
||||
#### mscript.loop\_count()
|
||||
Extract the loop count integer from a LOOP cmd
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
|
@ -130,19 +131,19 @@ Execute a fade of frame length, from color to another color
|
|||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+fade_count"></a>
|
||||
|
||||
#### mscript.fade_count()
|
||||
#### mscript.fade\_count()
|
||||
Extract the fade length integer from a FADE cmd
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+fade_start"></a>
|
||||
|
||||
#### mscript.fade_start()
|
||||
#### mscript.fade\_start()
|
||||
Extract the start color from a string
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+fade_end"></a>
|
||||
|
||||
#### mscript.fade_end()
|
||||
#### mscript.fade\_end()
|
||||
Extract the end color from a string
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
|
@ -155,19 +156,19 @@ by the value defined in val
|
|||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+str_to_arr"></a>
|
||||
|
||||
#### mscript.str_to_arr()
|
||||
#### mscript.str\_to\_arr()
|
||||
Split string on command, extract any integers from string
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+light_to_arr"></a>
|
||||
|
||||
#### mscript.light_to_arr()
|
||||
#### mscript.light\_to\_arr()
|
||||
Split a string on a command to extract data for light array
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..Mscript+light_state"></a>
|
||||
|
||||
#### mscript.light_state()
|
||||
#### mscript.light\_state()
|
||||
Split a string to extract an rgb color value
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
|
@ -177,3 +178,9 @@ Split a string to extract an rgb color value
|
|||
Throw an error with specific message
|
||||
|
||||
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||
<a name="module_lib/mscript..startsWith"></a>
|
||||
|
||||
### lib/mscript~startsWith()
|
||||
startswith function from lodash, do not want the entire lib for this
|
||||
|
||||
**Kind**: inner method of [<code>lib/mscript</code>](#module_lib/mscript)
|
||||
|
|
|
@ -7,4 +7,7 @@ Bash-like variables?
|
|||
Similar to LESS/SASS?
|
||||
Makes a tokenization easier
|
||||
|
||||
@ is better than $
|
||||
@ is better than $
|
||||
|
||||
RangeError: Invalid array length
|
||||
at Mscript.str_to_arr (./mcopy/app/lib/mscript/index.js:474:9)
|
||||
|
|
|
@ -0,0 +1,249 @@
|
|||
/** @module lib/mscript */
|
||||
interface RGB extends Array<number> {
|
||||
[index: number]: number;
|
||||
}
|
||||
/** class Mscript */
|
||||
export default class Mscript {
|
||||
output: any;
|
||||
lines: string[];
|
||||
cam: number;
|
||||
cam2: number;
|
||||
proj: number;
|
||||
proj2: number;
|
||||
color: string;
|
||||
loops: any[];
|
||||
rec: number;
|
||||
two: string;
|
||||
three: string;
|
||||
four: string;
|
||||
arr: any[];
|
||||
meta: string[];
|
||||
target: number;
|
||||
dist: number;
|
||||
variables: any;
|
||||
/**
|
||||
* @constructor
|
||||
* Create new Mscript interpreter
|
||||
**/
|
||||
constructor();
|
||||
/**
|
||||
* Clear the state of the script
|
||||
*/
|
||||
clear(): void;
|
||||
/**
|
||||
* Main function, accepts multi-line string, parses into lines
|
||||
* and interprets the instructions from the text. Returns an array
|
||||
* of steps to be fed into the mcopy sequence.
|
||||
*
|
||||
* @param {string} text Mscript text to interpret
|
||||
* @param {function} callback Function to call when string is interpreted
|
||||
*
|
||||
* @returns {object} if callback is not provided
|
||||
*/
|
||||
interpret(text: string, callback?: Function): any;
|
||||
/**
|
||||
* Interprets variables for complex sequence behavior.
|
||||
* TODO: Fully implement, add test coverage
|
||||
*
|
||||
* @param {string} line Line containing a variable assignment
|
||||
*
|
||||
**/
|
||||
variable(line: string): void;
|
||||
/**
|
||||
* Replace variable with value at time of interpretation
|
||||
* TODO: Implement this please
|
||||
*
|
||||
* @param {string} line Line containing variable to be replaced with value
|
||||
*
|
||||
* @returns {string} New string to be interpreted
|
||||
**/
|
||||
variable_replace(line: string): string;
|
||||
/**
|
||||
* Interpret a basic two character command
|
||||
*
|
||||
* @param {string} line Line of script to interpret
|
||||
* @param {string} short The short command to use
|
||||
*/
|
||||
basic_cmd(line: string, short: string): void;
|
||||
/**
|
||||
* Start a new loop
|
||||
*
|
||||
* @param {string} line Line to evaluate as either loop or fade
|
||||
* @param {boolean} fade Flag as true if fade
|
||||
*/
|
||||
new_loop(line: string, fade?: boolean): void;
|
||||
/**
|
||||
* Close the most recent loop
|
||||
*
|
||||
* @param {string} line Line to interpret
|
||||
*/
|
||||
end_loop(line: string): void;
|
||||
/**
|
||||
* Move camera to explicitly-defined frame
|
||||
*
|
||||
* @param {string} line Line to interpret with camera move statement
|
||||
*/
|
||||
move_cam(line: string): void;
|
||||
/**
|
||||
* Move secondary camera to explicitly-defined frame
|
||||
*
|
||||
* @param {string} line Line to interpret with camera move statement
|
||||
*/
|
||||
move_cam2(line: string): void;
|
||||
/**
|
||||
* Move projector to explicitly-defined frame
|
||||
*
|
||||
* @param {string} line Line containing `move` statement to interpret
|
||||
*/
|
||||
move_proj(line: string): void;
|
||||
/**
|
||||
* Move projector to explicitly-defined frame
|
||||
*
|
||||
* @param {string} line Line containing `move` statement to interpret
|
||||
*/
|
||||
move_proj2(line: string): void;
|
||||
/**
|
||||
* Set the state of either the cam or projector
|
||||
*
|
||||
* @param line {string} String containing set statement
|
||||
*/
|
||||
set_state(line: string): void;
|
||||
/**
|
||||
* Return the last loop
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
last_loop(): any;
|
||||
/**
|
||||
* Return the second-last loop
|
||||
*
|
||||
* @returns {object} Loop array
|
||||
*/
|
||||
parent_loop(): any;
|
||||
/**
|
||||
* Extract the loop count integer from a LOOP cmd
|
||||
*
|
||||
* @returns {integer} Loop count in string parsed into integer
|
||||
*/
|
||||
loop_count(str: string): number;
|
||||
/**
|
||||
* Execute a fade of frame length, from color to another color
|
||||
*
|
||||
* @param {string} line Line containing a fade initiator
|
||||
*/
|
||||
fade(line: string): void;
|
||||
/**
|
||||
* Extract the fade length integer from a FADE cmd
|
||||
*
|
||||
* @param {string} str Line containing the length of fade in frames
|
||||
*/
|
||||
fade_count(str: string): number;
|
||||
/**
|
||||
* Extract the start color from a string
|
||||
*
|
||||
* @param {string} str Line containing the start color value in a fade initiator
|
||||
*
|
||||
* @returns {array} Array containing RGB color values
|
||||
*/
|
||||
fade_start(str: string): RGB;
|
||||
/**
|
||||
* Extract the end color from a string
|
||||
*
|
||||
* @param {string} str Line containing the end color value in a fade initiator
|
||||
*
|
||||
* @returns {array} Array containing RGB color values
|
||||
*/
|
||||
fade_end(str: string): RGB;
|
||||
/**
|
||||
* Determine the state of a fade at a particular frame in the sequence, x
|
||||
*
|
||||
* @param {array} start Color the fade starts at
|
||||
* @param {array} end Color the fade finishes at
|
||||
* @param {integer} len Total length of the fade in frames
|
||||
* @param {integer} x Position of the fade to get color value of
|
||||
*
|
||||
* @returns {array} Array containing RGB color values
|
||||
*/
|
||||
fade_rgb(start: RGB, end: RGB, len: number, x: number): string;
|
||||
/**
|
||||
* Parse string into array of RGB color values. 0-255 octet.
|
||||
*
|
||||
* @param {string} str String containing only color values as `#,#,#`
|
||||
**/
|
||||
rgb(str: string): RGB;
|
||||
/**
|
||||
* Cast RGB color values as string
|
||||
*
|
||||
* @param {array} arr Array to join into string
|
||||
*
|
||||
* @returns {string} String of RGB values
|
||||
**/
|
||||
rgb_str(arr: RGB): string;
|
||||
/**
|
||||
* Increase the state of a specific object, such as the camera/projector,
|
||||
* by the value defined in val.
|
||||
*
|
||||
* @param {string} cmd String representing command to interpret and update state
|
||||
*/
|
||||
update(cmd: string, val?: number): void;
|
||||
/**
|
||||
* Split string on command, turn into array of commands
|
||||
* as long as count variable. Default 1.
|
||||
*
|
||||
* @param {string} str String to split
|
||||
* @param {string} cmd String representing command to split at
|
||||
*
|
||||
* @returns {array} Array containing commands
|
||||
*/
|
||||
str_to_arr(str: string, cmd: string): string[];
|
||||
/**
|
||||
* Split a string on a command to extract data for light array
|
||||
*
|
||||
* @param {string} str String containing light command
|
||||
* @param {string} cmd String representing command
|
||||
*
|
||||
* @returns {array} An RGB array containing the color values
|
||||
*/
|
||||
light_to_arr(str: string, cmd: string): RGB;
|
||||
/**
|
||||
* Split a string to extract an rgb color value
|
||||
*
|
||||
* @param {string} Color string assign to color property
|
||||
*/
|
||||
light_state(str: string): void;
|
||||
/**
|
||||
* Interpret a delay command
|
||||
*
|
||||
* @param {string} line String containing delay command
|
||||
**/
|
||||
delay(line: string): void;
|
||||
/**
|
||||
* Interpret an alert command
|
||||
*
|
||||
* @param {string} line String containing alert message
|
||||
**/
|
||||
alert(line: string): void;
|
||||
/**
|
||||
* Interpret an pause command
|
||||
*
|
||||
* @param {string} line String containing alert message
|
||||
**/
|
||||
pause(line: string): void;
|
||||
/**
|
||||
* Throw an error with specific message
|
||||
*
|
||||
* @param {string} msg Error message to print
|
||||
*/
|
||||
fail(msg: string): void;
|
||||
/**
|
||||
* Determine if array contains matching elements of
|
||||
* another array
|
||||
*
|
||||
* @param {Array} arr Original array to compare
|
||||
* @param {Array} arr2 Array to compare elements from
|
||||
*
|
||||
* @returns {boolean} Whether arr contains elements in arr2
|
||||
**/
|
||||
contains(arr: string[], arr2: string[]): boolean;
|
||||
}
|
||||
export {};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue