mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-07 03:56:57 +03:00
Compare commits
801 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
524d800a0a | ||
|
|
7b0e6200d6 | ||
|
|
65d011c9aa | ||
|
|
dc3604f144 | ||
|
|
1eb2dd4efa | ||
|
|
f4d345b902 | ||
|
|
a38837c61b | ||
|
|
b50be7e825 | ||
|
|
74f45bee28 | ||
|
|
47b3b0c708 | ||
|
|
9c390f3026 | ||
|
|
069aac5723 | ||
|
|
9335cd73d5 | ||
|
|
e90beffb44 | ||
|
|
55a06dbe1d | ||
|
|
ae07159afe | ||
|
|
1fff655ef1 | ||
|
|
3815f9cf0a | ||
|
|
e36490c89e | ||
|
|
d4f02f971f | ||
|
|
ec326d9a11 | ||
|
|
6e4df0ef87 | ||
|
|
3aa0411676 | ||
|
|
9f20c126be | ||
|
|
2707e8c9f4 | ||
|
|
0d467d8ad1 | ||
|
|
66be09c98e | ||
|
|
60e9a427a5 | ||
|
|
f72bdb7c45 | ||
|
|
a53188e697 | ||
|
|
0dd63b9b7a | ||
|
|
513e300676 | ||
|
|
dd28859a9f | ||
|
|
ecc43edbba | ||
|
|
bf8ab423e3 | ||
|
|
8116a546b5 | ||
|
|
5c512367e2 | ||
|
|
e15ea561bc | ||
|
|
9e4332314a | ||
|
|
880d9eae20 | ||
|
|
72fcd791db | ||
|
|
39960b15ed | ||
|
|
395b9a4c5b | ||
|
|
5a2753a50b | ||
|
|
57c5c19cca | ||
|
|
c64ed36fa4 | ||
|
|
754981c67f | ||
|
|
5c22986e2e | ||
|
|
1746920f61 | ||
|
|
d33380d2a0 | ||
|
|
889ed9e6be | ||
|
|
2b0e0f7d4e | ||
|
|
2314d7ef18 | ||
|
|
bec3a5ee3b | ||
|
|
c738a9a4da | ||
|
|
e7c8706b1b | ||
|
|
f725adf5ba | ||
|
|
7bb1b08bdb | ||
|
|
d1e7ef1fce | ||
|
|
08f7e1275e | ||
|
|
529690ec60 | ||
|
|
59431a7eaf | ||
|
|
23b5ffbb92 | ||
|
|
9b8594c040 | ||
|
|
3e082ed06e | ||
|
|
22fe50f80a | ||
|
|
885cd71b80 | ||
|
|
8c6805ec7c | ||
|
|
1fc0b41fca | ||
|
|
7e26744e2e | ||
|
|
1d9ef7e634 | ||
|
|
1be49a75b1 | ||
|
|
b6b7587f0a | ||
|
|
e3017c25a9 | ||
|
|
d914e69e7a | ||
|
|
edf9f11048 | ||
|
|
44afd138c5 | ||
|
|
d2b93a7110 | ||
|
|
ff726485ba | ||
|
|
de46cd899e | ||
|
|
37263bb239 | ||
|
|
d21a38f42f | ||
|
|
9b9a7537f1 | ||
|
|
56d8c65008 | ||
|
|
fc24db7d59 | ||
|
|
0867dcc6da | ||
|
|
b9f57edb92 | ||
|
|
7ebbba3cf2 | ||
|
|
5188734c8b | ||
|
|
4e476a75ca | ||
|
|
7a037a3254 | ||
|
|
f6b44ac905 | ||
|
|
deecc128be | ||
|
|
18f2b5824e | ||
|
|
45084bab70 | ||
|
|
6cdbe38717 | ||
|
|
fe0d0c2590 | ||
|
|
44f61c7c91 | ||
|
|
af8b7d6824 | ||
|
|
170583f8fe | ||
|
|
648a35e4d7 | ||
|
|
99849063d9 | ||
|
|
5b22007a1e | ||
|
|
80cf89c9d5 | ||
|
|
45d37ea957 | ||
|
|
f935c38571 | ||
|
|
bfc7c2b8b7 | ||
|
|
08f90de683 | ||
|
|
32748e3182 | ||
|
|
7a280bc7c6 | ||
|
|
f4ae688527 | ||
|
|
ca45d0a278 | ||
|
|
8f66fcf2a6 | ||
|
|
30549ac5af | ||
|
|
06ab14a6c9 | ||
|
|
72e3570dc4 | ||
|
|
724169b059 | ||
|
|
6e58f5eebb | ||
|
|
96b3d7cc2f | ||
|
|
74c9eada47 | ||
|
|
9d65889824 | ||
|
|
98451c8fc7 | ||
|
|
6b47eef4cd | ||
|
|
158ec65e57 | ||
|
|
c4bbd7c545 | ||
|
|
cb323eb715 | ||
|
|
1aa23aa14a | ||
|
|
41abc19a97 | ||
|
|
99e03dde06 | ||
|
|
9d73c5475e | ||
|
|
25ae9a045f | ||
|
|
dabe66819d | ||
|
|
4ad7b97764 | ||
|
|
083aeb42ec | ||
|
|
a13d1d0692 | ||
|
|
c12645ab4d | ||
|
|
116c99e55c | ||
|
|
43b65d6b2e | ||
|
|
bc7a0e46b7 | ||
|
|
455962bd94 | ||
|
|
86c515bcb8 | ||
|
|
f09067a142 | ||
|
|
8ce24df304 | ||
|
|
279a59d019 | ||
|
|
d88e286696 | ||
|
|
d07aa2a72d | ||
|
|
bf30872439 | ||
|
|
12dc4eb460 | ||
|
|
ab67d1ff35 | ||
|
|
86809d8bf8 | ||
|
|
85adf70394 | ||
|
|
290e7f3835 | ||
|
|
e9e0eed871 | ||
|
|
4ab0f632b7 | ||
|
|
1a33834b3f | ||
|
|
1d367a58d5 | ||
|
|
ec4ce66bcc | ||
|
|
4a0f5eadc2 | ||
|
|
f955f8786b | ||
|
|
38f6e49d00 | ||
|
|
4394d832b8 | ||
|
|
9e68380814 | ||
|
|
c8bb95a852 | ||
|
|
9c2de84ee4 | ||
|
|
d4b1c2c883 | ||
|
|
550d9e1c87 | ||
|
|
3f687a7233 | ||
|
|
c1369ca0ff | ||
|
|
76c8bce7b4 | ||
|
|
e0ae9b8e4f | ||
|
|
9de573c15e | ||
|
|
716c23fed3 | ||
|
|
8e22bd06e9 | ||
|
|
b78929745b | ||
|
|
6986f2186c | ||
|
|
3743ac18f5 | ||
|
|
13f1d40ca3 | ||
|
|
63f28097bd | ||
|
|
ff7fec1de4 | ||
|
|
f65b2850a2 | ||
|
|
3a999358b9 | ||
|
|
d3e195df9f | ||
|
|
dbf8e634d9 | ||
|
|
2b810ca32d | ||
|
|
0adfc45d36 | ||
|
|
2a54d9b889 | ||
|
|
4150c31b98 | ||
|
|
803e8f2bff | ||
|
|
b215345f11 | ||
|
|
98d35e0412 | ||
|
|
437e8e4d25 | ||
|
|
e05085ddf0 | ||
|
|
495b5de38c | ||
|
|
c2b89dd199 | ||
|
|
f15b1e5dfc | ||
|
|
e308a1b5d9 | ||
|
|
1e698440f9 | ||
|
|
98bf7e5387 | ||
|
|
e1f8ac59cb | ||
|
|
0a2b6b71ca | ||
|
|
5daae7b47c | ||
|
|
4951fc9b80 | ||
|
|
0bf8182728 | ||
|
|
a512d82793 | ||
|
|
4f305a8705 | ||
|
|
46daa4cb79 | ||
|
|
485363d7a2 | ||
|
|
c8d2d9d4fd | ||
|
|
0880213342 | ||
|
|
8d4fb74173 | ||
|
|
f10adb3383 | ||
|
|
3be33820d9 | ||
|
|
83f638c64f | ||
|
|
35d77a3925 | ||
|
|
a33da0c750 | ||
|
|
cd2350140d | ||
|
|
bd125b249b | ||
|
|
33b9a15f73 | ||
|
|
0e55fc7f7e | ||
|
|
fc0bbc57cb | ||
|
|
bc46149573 | ||
|
|
be8598bcaa | ||
|
|
ace1936a78 | ||
|
|
e5649d03b2 | ||
|
|
426d6bae3f | ||
|
|
5d35df65f3 | ||
|
|
f91f5e3cba | ||
|
|
1c66f8c6ca | ||
|
|
a42902af0d | ||
|
|
a871055d96 | ||
|
|
64fcb9595c | ||
|
|
9d9cff977d | ||
|
|
5724f37ea6 | ||
|
|
3ca93b49ca | ||
|
|
b2248818dd | ||
|
|
a702fbbe86 | ||
|
|
1002e502d5 | ||
|
|
17a8adae05 | ||
|
|
4fca050623 | ||
|
|
f371c176b6 | ||
|
|
1c6772f383 | ||
|
|
7d2f28084b | ||
|
|
923b8d7444 | ||
|
|
49e4eb3ef3 | ||
|
|
2c481c0d15 | ||
|
|
f2e854c935 | ||
|
|
8045e0bfaf | ||
|
|
40e176ec28 | ||
|
|
1ab135e989 | ||
|
|
99c14ae9e0 | ||
|
|
00d859734d | ||
|
|
de4efff558 | ||
|
|
2ed3f4aa40 | ||
|
|
ba59c8ee66 | ||
|
|
fb97e22dee | ||
|
|
b0e7283d2b | ||
|
|
e341564eee | ||
|
|
730006977c | ||
|
|
ea26a5722a | ||
|
|
62742d92d2 | ||
|
|
50b9983534 | ||
|
|
34ea8302ef | ||
|
|
a8fd0bbdef | ||
|
|
99e6243e25 | ||
|
|
0f6c767143 | ||
|
|
eb0b932c44 | ||
|
|
1e4be0f3fe | ||
|
|
47caa1b118 | ||
|
|
641609e187 | ||
|
|
006fb6a611 | ||
|
|
a0e4ee1d00 | ||
|
|
27d770c759 | ||
|
|
fe39b5120b | ||
|
|
74df27befd | ||
|
|
c92a1e430d | ||
|
|
642d22578f | ||
|
|
140ec1b380 | ||
|
|
17090c177e | ||
|
|
d2721cbd4b | ||
|
|
f80509c886 | ||
|
|
6c85796abe | ||
|
|
e82cbbf117 | ||
|
|
bacdc97d90 | ||
|
|
1e43c70adf | ||
|
|
16bb6e90a9 | ||
|
|
cf6882c579 | ||
|
|
858d0b3361 | ||
|
|
208a5433b7 | ||
|
|
9a7c9604fe | ||
|
|
f44fa4df31 | ||
|
|
68a985a09f | ||
|
|
6b329aaa58 | ||
|
|
80798ae0e6 | ||
|
|
cd61e2c92d | ||
|
|
c943510828 | ||
|
|
9291d330dd | ||
|
|
a856d9e2f2 | ||
|
|
41f9436465 | ||
|
|
5233c14725 | ||
|
|
3d42d949af | ||
|
|
aec1dc770b | ||
|
|
f335c17f0d | ||
|
|
dfe2c466bc | ||
|
|
bb924531ef | ||
|
|
6e24b6fa88 | ||
|
|
d9a7c197fc | ||
|
|
14d30bae9d | ||
|
|
97ef1904bb | ||
|
|
0856aea069 | ||
|
|
73e9253cb7 | ||
|
|
663e97db97 | ||
|
|
8b64266602 | ||
|
|
e697cc5ec8 | ||
|
|
2c4d5a42d8 | ||
|
|
2f2ec23a53 | ||
|
|
3ad72f39a6 | ||
|
|
88a074dfa9 | ||
|
|
8c5f956dfe | ||
|
|
505eed8767 | ||
|
|
cc9a3d3551 | ||
|
|
70b743e364 | ||
|
|
6307b7f278 | ||
|
|
ed2ee7ad90 | ||
|
|
26789f4187 | ||
|
|
923fc20ca5 | ||
|
|
6808a37b69 | ||
|
|
f996e65a4d | ||
|
|
0168f6b9b7 | ||
|
|
e6b8643124 | ||
|
|
69a92712ef | ||
|
|
93804cec3f | ||
|
|
8cd430efc7 | ||
|
|
8175c946f2 | ||
|
|
0eb70b6208 | ||
|
|
5ac3378479 | ||
|
|
356b208f33 | ||
|
|
924f03595b | ||
|
|
90595968b2 | ||
|
|
96a59ca429 | ||
|
|
b76d6cd987 | ||
|
|
98b7224c65 | ||
|
|
ece73f63c8 | ||
|
|
b281ae9583 | ||
|
|
6af7e1edd2 | ||
|
|
f04ca2bdde | ||
|
|
9007d8c484 | ||
|
|
d8a7e7a39d | ||
|
|
ee13581475 | ||
|
|
8c86a3013a | ||
|
|
8aab81acc7 | ||
|
|
8707190d16 | ||
|
|
aa72cab84f | ||
|
|
29607a8617 | ||
|
|
2239ab9019 | ||
|
|
86ea8a8e26 | ||
|
|
bfa8d8e691 | ||
|
|
dc788b14eb | ||
|
|
228a87038e | ||
|
|
d11ee2a4cf | ||
|
|
b38c940dd3 | ||
|
|
6a22d355eb | ||
|
|
a3a46fb0bb | ||
|
|
452339a1f0 | ||
|
|
5e93f1e8bd | ||
|
|
2e4023cfd6 | ||
|
|
12c748534e | ||
|
|
8275bdbc25 | ||
|
|
0ffaf99e10 | ||
|
|
b1b76feeb0 | ||
|
|
265616ff80 | ||
|
|
89c65f6226 | ||
|
|
6634b36f4a | ||
|
|
6c433d83fc | ||
|
|
a9d77a0005 | ||
|
|
efb35b1aa7 | ||
|
|
6f9d21fc21 | ||
|
|
f7df03f0c0 | ||
|
|
e92ff43e09 | ||
|
|
592a52ef0b | ||
|
|
4e19066e26 | ||
|
|
8e39e83c38 | ||
|
|
78900defad | ||
|
|
d0b78e7c73 | ||
|
|
d3675f269d | ||
|
|
64d25f416a | ||
|
|
3f8b38a1ce | ||
|
|
5979acc31e | ||
|
|
7397927b77 | ||
|
|
0d67282c00 | ||
|
|
f9939023c6 | ||
|
|
922d76dace | ||
|
|
02bf674539 | ||
|
|
4ad315b3f7 | ||
|
|
342fa0465c | ||
|
|
2866badc04 | ||
|
|
60194d8db8 | ||
|
|
165745bb7d | ||
|
|
fc4f3eebb6 | ||
|
|
8a6bd97ec2 | ||
|
|
c4ee48ad1e | ||
|
|
3e5aa77ff5 | ||
|
|
b45b0f6a2a | ||
|
|
fc77c0fdf1 | ||
|
|
bf1e96a303 | ||
|
|
86ba3e9bf4 | ||
|
|
d0fb1fc0f1 | ||
|
|
8bf4939ac1 | ||
|
|
75a653a5c7 | ||
|
|
e713ffa52d | ||
|
|
abc3efc16e | ||
|
|
25e20f9299 | ||
|
|
f2effc4253 | ||
|
|
fb03dba60c | ||
|
|
68e57d5ec4 | ||
|
|
a1691a77cf | ||
|
|
aa5651a464 | ||
|
|
0a79fb6196 | ||
|
|
7e108d707a | ||
|
|
fb850fb040 | ||
|
|
95292b8213 | ||
|
|
e59dca4bec | ||
|
|
86e47c722d | ||
|
|
5a1127d2b9 | ||
|
|
b1d4df4309 | ||
|
|
f6f70776d9 | ||
|
|
570777db7e | ||
|
|
b06b42f0e9 | ||
|
|
8a170a7e16 | ||
|
|
5e95634173 | ||
|
|
84cc3490a1 | ||
|
|
ee724d372d | ||
|
|
711578d0a2 | ||
|
|
1956416fb6 | ||
|
|
1ec1f4f75f | ||
|
|
0fb192d79e | ||
|
|
19847652a9 | ||
|
|
d807334141 | ||
|
|
a08a233484 | ||
|
|
7fc9676385 | ||
|
|
7d8cdc79f2 | ||
|
|
6938299b72 | ||
|
|
6794091919 | ||
|
|
6631ebc12a | ||
|
|
efc800c223 | ||
|
|
6756b6d741 | ||
|
|
3138e36137 | ||
|
|
b3b1c18ff5 | ||
|
|
1c9cd46d88 | ||
|
|
f4074fb939 | ||
|
|
7d286337ce | ||
|
|
81f92b8b0f | ||
|
|
01337ddcbf | ||
|
|
3fb545f869 | ||
|
|
04e59482b5 | ||
|
|
50acd26804 | ||
|
|
1bc8e698b4 | ||
|
|
46b8b67fed | ||
|
|
84a653b5d5 | ||
|
|
dee7212531 | ||
|
|
50b0593648 | ||
|
|
4c786406c3 | ||
|
|
6fed12e9ad | ||
|
|
11216350c4 | ||
|
|
577dbdeb7c | ||
|
|
b75f77b31c | ||
|
|
2776e1b127 | ||
|
|
562cc4352b | ||
|
|
013d5a99a8 | ||
|
|
fbe7bb90c2 | ||
|
|
660326af42 | ||
|
|
80aa2dfc73 | ||
|
|
316d8f252a | ||
|
|
28a39d8dfc | ||
|
|
3fc6c194e5 | ||
|
|
0e85b40eba | ||
|
|
d479c8d44e | ||
|
|
6b6e677f8b | ||
|
|
45c9914efa | ||
|
|
a4299cab89 | ||
|
|
67e4ee4aca | ||
|
|
85750c9453 | ||
|
|
d8b4b3f2cf | ||
|
|
fedaef07eb | ||
|
|
9ae9a82cca | ||
|
|
37fec1821f | ||
|
|
c4e69bc036 | ||
|
|
7dd14282c6 | ||
|
|
7e72cc3d1b | ||
|
|
8e2da52d82 | ||
|
|
e38c861cb5 | ||
|
|
b6a571a90c | ||
|
|
26949d8083 | ||
|
|
1c80c2108d | ||
|
|
e1fc44d44a | ||
|
|
32e5c484ab | ||
|
|
bf8589f9ec | ||
|
|
b65d9e5a46 | ||
|
|
5aa4714d05 | ||
|
|
dd8500052e | ||
|
|
2d68f44a40 | ||
|
|
39ec90895e | ||
|
|
3d1d41e36b | ||
|
|
46dfc75724 | ||
|
|
906915e058 | ||
|
|
85418c678d | ||
|
|
81e06c45d3 | ||
|
|
645fbf0231 | ||
|
|
5d10dba3c7 | ||
|
|
78806c081b | ||
|
|
3f659ccf7d | ||
|
|
6cd52a3cdc | ||
|
|
a1f675419a | ||
|
|
9087c1b4e1 | ||
|
|
9418d55a2f | ||
|
|
87076df23f | ||
|
|
aba9603021 | ||
|
|
086aa3134b | ||
|
|
010691f3e5 | ||
|
|
12d9099543 | ||
|
|
c9b7f8d901 | ||
|
|
0372f82f2e | ||
|
|
18be9afbe1 | ||
|
|
36f5618376 | ||
|
|
03542368d7 | ||
|
|
36a02d1658 | ||
|
|
c65182b568 | ||
|
|
e5bd824506 | ||
|
|
10fbb610c3 | ||
|
|
b8ab58a196 | ||
|
|
fa59b5ba6c | ||
|
|
67d47abde2 | ||
|
|
042ff18e65 | ||
|
|
3008952240 | ||
|
|
aef28c7128 | ||
|
|
9c5dfe65c9 | ||
|
|
b12cdd673b | ||
|
|
8247580372 | ||
|
|
d7c7537aa9 | ||
|
|
ad05a1d4fa | ||
|
|
7bd819ad96 | ||
|
|
64b472d6bc | ||
|
|
3d7a906cce | ||
|
|
8c4a5a957a | ||
|
|
21874473cc | ||
|
|
8aa99b34d6 | ||
|
|
6759164c82 | ||
|
|
2445377d0a | ||
|
|
99b6393fbc | ||
|
|
7e049f3270 | ||
|
|
79d1e6b932 | ||
|
|
3403e3ea5c | ||
|
|
c3a3aa9c0d | ||
|
|
89c9ff144c | ||
|
|
82e6334832 | ||
|
|
dd70aa8969 | ||
|
|
4cf190239e | ||
|
|
cb4ba51eee | ||
|
|
4d03867550 | ||
|
|
02294e3afc | ||
|
|
f68aa1d931 | ||
|
|
fb390359e1 | ||
|
|
764c64b615 | ||
|
|
a167770848 | ||
|
|
551743abec | ||
|
|
68a596707b | ||
|
|
47da2d657e | ||
|
|
43372c94a8 | ||
|
|
0643274c68 | ||
|
|
395b471700 | ||
|
|
a040d56fdc | ||
|
|
3c8a65c540 | ||
|
|
2f38643473 | ||
|
|
906a2e05eb | ||
|
|
3390e24534 | ||
|
|
dc28b892bc | ||
|
|
3023cd139d | ||
|
|
127135e1cb | ||
|
|
aa4e115f80 | ||
|
|
90f204b833 | ||
|
|
77427a8ec4 | ||
|
|
eafcdb01c2 | ||
|
|
3f58086aa1 | ||
|
|
d36a4dbdbe | ||
|
|
6879aa96e2 | ||
|
|
fc219cc7f3 | ||
|
|
787f9362eb | ||
|
|
231ac5305f | ||
|
|
4bd79e370f | ||
|
|
5c0cd63da0 | ||
|
|
5a31543538 | ||
|
|
1b88bf8690 | ||
|
|
6db01e67c9 | ||
|
|
f7cb6576b3 | ||
|
|
4a71749d1c | ||
|
|
d13f457344 | ||
|
|
ab41401643 | ||
|
|
592b93ce2b | ||
|
|
5dc7b90a1c | ||
|
|
b1e0203527 | ||
|
|
774dde5767 | ||
|
|
c322cd8b48 | ||
|
|
3dcdd52eb7 | ||
|
|
fe17d97a05 | ||
|
|
b71a34b476 | ||
|
|
ea71c86f69 | ||
|
|
550fe605bd | ||
|
|
109dd97016 | ||
|
|
715f0a10f3 | ||
|
|
d01caea53e | ||
|
|
a9cab31a1f | ||
|
|
d0968e87d7 | ||
|
|
6417f780e6 | ||
|
|
fd4d76de93 | ||
|
|
cdf8663bd3 | ||
|
|
bf9050757b | ||
|
|
bce99da6e5 | ||
|
|
234925c850 | ||
|
|
c9b7a5f84c | ||
|
|
cfaeaa370a | ||
|
|
8cd5a89d6a | ||
|
|
090f8d5cc9 | ||
|
|
29ae8cfa7f | ||
|
|
338184712d | ||
|
|
b2c510d73e | ||
|
|
e8b649d315 | ||
|
|
6a5d5511f1 | ||
|
|
ec99ac3a3b | ||
|
|
58cfd8bc42 | ||
|
|
f676f12e02 | ||
|
|
393fe43090 | ||
|
|
296a50a6d2 | ||
|
|
b1ee3d8793 | ||
|
|
d930fdae78 | ||
|
|
993fbfe5a8 | ||
|
|
af546ef0f1 | ||
|
|
2b60e81a52 | ||
|
|
11418459b8 | ||
|
|
3b8b8e47da | ||
|
|
ae302d49ef | ||
|
|
0153229d3c | ||
|
|
eeb74dd6fd | ||
|
|
ecc62a3ba9 | ||
|
|
aca60465f0 | ||
|
|
57bdca37fc | ||
|
|
6409397770 | ||
|
|
974044adf0 | ||
|
|
59aeeda786 | ||
|
|
b6bf8d992f | ||
|
|
82cb966863 | ||
|
|
9d31edc67a | ||
|
|
1b4f4bdd6d | ||
|
|
c9a879d329 | ||
|
|
ea69b1be00 | ||
|
|
2a8b3a87ea | ||
|
|
52783734ce | ||
|
|
0e1b390ec6 | ||
|
|
ab49bdf82f | ||
|
|
25e7051271 | ||
|
|
85c0a72ae8 | ||
|
|
7315f9adfc | ||
|
|
af1aee4ac3 | ||
|
|
d6ff7eef88 | ||
|
|
7706b4dbc3 | ||
|
|
3561ecd2b7 | ||
|
|
74c7ff7fdf | ||
|
|
a68ce353ad | ||
|
|
0d168f3445 | ||
|
|
073e04a3cc | ||
|
|
591dc048d4 | ||
|
|
bfe8d3b37a | ||
|
|
9695dba415 | ||
|
|
6a48f0502e | ||
|
|
4a8d6592ab | ||
|
|
434aebd641 | ||
|
|
c124c38e70 | ||
|
|
e6d60bb124 | ||
|
|
99afb88957 | ||
|
|
085ea2028c | ||
|
|
0e7c600cf7 | ||
|
|
3f3532defe | ||
|
|
a0ffc88e47 | ||
|
|
11bfaf0e91 | ||
|
|
189093d548 | ||
|
|
34eb89b1b6 | ||
|
|
b725d242d3 | ||
|
|
568e88314b | ||
|
|
70e94205d1 | ||
|
|
aaad952782 | ||
|
|
dc27911174 | ||
|
|
42678ae8e1 | ||
|
|
b6341992f6 | ||
|
|
17fd0f96df | ||
|
|
0b039e8d8c | ||
|
|
eab8a6d96b | ||
|
|
9f72bf117e | ||
|
|
058e9436f0 | ||
|
|
ebd8fe0e4f | ||
|
|
7970f5f691 | ||
|
|
0689ca86c5 | ||
|
|
5783e0f182 | ||
|
|
e190aa8d03 | ||
|
|
15bac02cbf | ||
|
|
7fdacce9a2 | ||
|
|
78ea179e9a | ||
|
|
2cfc3fadb2 | ||
|
|
60cdee2ea6 | ||
|
|
a17ac6860d | ||
|
|
ef24466702 | ||
|
|
de78027b0e | ||
|
|
28c40a0ad2 | ||
|
|
230bbb2239 | ||
|
|
bda2913a32 | ||
|
|
78daaf6e5b | ||
|
|
8939167a39 | ||
|
|
b48c6111d9 | ||
|
|
de1e919b96 | ||
|
|
35a96027f1 | ||
|
|
8e12d71580 | ||
|
|
7a36bfa2ff | ||
|
|
dfeac0cb7f | ||
|
|
dfec780157 | ||
|
|
4cc93324f8 | ||
|
|
bf8833eae6 | ||
|
|
00028010ee | ||
|
|
a681a76c4b | ||
|
|
cce812ff11 | ||
|
|
ccb4bd595c | ||
|
|
dc7eedcd8f | ||
|
|
40faa78929 | ||
|
|
eb53db00d0 | ||
|
|
658ef39736 | ||
|
|
0e90bcb2ef | ||
|
|
a020fce2d7 | ||
|
|
525ccf7aba | ||
|
|
ebcfc16f63 | ||
|
|
4b825efffb | ||
|
|
71871016d2 | ||
|
|
c07ef23d5b | ||
|
|
cbe884ad63 | ||
|
|
1dd703b337 | ||
|
|
bcb1d98191 | ||
|
|
1f5486e8cc | ||
|
|
1371be6f2c | ||
|
|
b0d8ed6248 | ||
|
|
379f4585e3 | ||
|
|
45a71981c8 | ||
|
|
ac3409f644 | ||
|
|
11c33f81dd | ||
|
|
641cc860d8 | ||
|
|
2029bd6e8a | ||
|
|
1ca5e1218d | ||
|
|
887c704f63 | ||
|
|
567dc74cd7 | ||
|
|
53606d5055 | ||
|
|
19a6c21c44 | ||
|
|
3a4b11e4b3 | ||
|
|
d981574ab2 | ||
|
|
eb817739b9 | ||
|
|
8972f17638 | ||
|
|
4d997d9473 | ||
|
|
e79c86c7b6 | ||
|
|
96bb86536f | ||
|
|
2daf6c8b3f | ||
|
|
24b46158de | ||
|
|
63d336ba28 | ||
|
|
8dd3a92671 | ||
|
|
8e8897c70d | ||
|
|
eac513411e | ||
|
|
98f9274085 | ||
|
|
884dd9fc3b | ||
|
|
04c564936a | ||
|
|
957138960a | ||
|
|
58a0297915 | ||
|
|
61bf536207 | ||
|
|
4136a7b372 | ||
|
|
b3afc9961d | ||
|
|
27e2e042da | ||
|
|
cc659bad30 | ||
|
|
776931c0ad | ||
|
|
e22b4b6fe1 | ||
|
|
cad534bffe | ||
|
|
3b44adb6fa | ||
|
|
cc0bd1473f | ||
|
|
58124d27bf | ||
|
|
9ad118814a | ||
|
|
270f8dd093 | ||
|
|
fde0ae4781 | ||
|
|
b87ce8c75d | ||
|
|
e372c87836 | ||
|
|
f8478d7742 | ||
|
|
a3d6923fec | ||
|
|
7bfa22187d | ||
|
|
7a8affae32 | ||
|
|
e48dd7c4c4 | ||
|
|
6d298c1746 | ||
|
|
4fe9ab92e0 | ||
|
|
f2ac4cdc64 | ||
|
|
be902401d1 | ||
|
|
020e93bca2 | ||
|
|
61dfdc2258 | ||
|
|
a98e3c8eab |
67
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
67
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
name: 🐞 Bug Report
|
||||
description: Use this form if you think you found a bug / Verwende dieses Formular, wenn Du denkst, dass Du einen Fehler gefunden hast.
|
||||
labels: bug
|
||||
body:
|
||||
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for taking your time to report a bug.
|
||||
|
||||
Before you proceed, please check:
|
||||
- [ ] Do you use the [latest version](https://github.com/jomjol/AI-on-the-edge-device/releases)?
|
||||
- [ ] Is there already another similar issue? Check for open and closed [Issue](https://github.com/jomjol/AI-on-the-edge-device/issues) and [Discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions).
|
||||
- [ ] Are instructions in the [README](https://github.com/jomjol/AI-on-the-edge-device/tree/master#readme) solving your issue?
|
||||
- [ ] Are instructions in the [Wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki) solving your issue?
|
||||
|
||||
Du darfst gerne auch in Deutsch schreiben!
|
||||
|
||||
|
||||
|
||||
- type: textarea
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: The Problem
|
||||
description: A clear and concise description of what the bug is.
|
||||
|
||||
|
||||
|
||||
- type: input
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Version
|
||||
description: Which version are you using? (See menu `System > Info`).
|
||||
|
||||
|
||||
|
||||
- type: textarea
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Logfile
|
||||
description: Add the logfile (See menu `System > Log Viewer`) to help explain your problem. This will be automatically formatted into code, so no need to format it on your side.
|
||||
render: shell
|
||||
|
||||
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
|
||||
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If applicable, add screenshots to help explain your problem.
|
||||
|
||||
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Add any other context about the problem here.
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 💬 Open a new Discussion
|
||||
url: https://github.com/jomjol/AI-on-the-edge-device/discussions/categories/q-a
|
||||
about: Use this form if you have a question or need help setting your AI-on-the-edge-device it up
|
||||
23
.github/ISSUE_TEMPLATE/feature.yaml
vendored
Normal file
23
.github/ISSUE_TEMPLATE/feature.yaml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: 💡 Feature Request
|
||||
description: Use this form if you have an idea or wish for a new feature
|
||||
labels: feature
|
||||
body:
|
||||
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for taking your time to document your idea.
|
||||
|
||||
Before you proceed, please check:
|
||||
- [ ] Is there already another similar issue open or closed? Check for open and closed [Issue](https://github.com/jomjol/AI-on-the-edge-device/issues) and [Discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions).
|
||||
- [ ] Is there already another similar [discussion](https://github.com/jomjol/AI-on-the-edge-device/discussions) ongoing?
|
||||
|
||||
Please be aware that we might decline your request if we have a reason for it!
|
||||
|
||||
- type: textarea
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: The Feature
|
||||
description: A clear and concise description of what the new feature should do. If possible, refer to other projects or add a mockup.
|
||||
19
.github/ISSUE_TEMPLATE/training.yaml
vendored
Normal file
19
.github/ISSUE_TEMPLATE/training.yaml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: 📖 New Training Data
|
||||
description: Use this form if you collected images and want to provide them for training the model
|
||||
title: New Training Data
|
||||
labels: new training data
|
||||
assignees: jomjol
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before you proceed, please check:
|
||||
- [ ] Did you make sure we don't have similar data yet in the training data? (see [Digital Counters](https://jomjol.github.io/neural-network-digital-counter-readout/) resp. [Analog Needles](https://jomjol.github.io/neural-network-analog-needle-readout))
|
||||
- [ ] Did you follow the guideline as documented in the [Wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/ROI-Configuration)? We will only be able to accept the files if they fulfill the rules!
|
||||
|
||||
- type: textarea
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Files
|
||||
description: You can drag & drop your **zipped** images here
|
||||
8
.github/ISSUE_TEMPLATE/x_plain.yaml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/x_plain.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
name: 🗒️ Blank Form
|
||||
description: Use this form if none of the others fit. Please only use none of the others fit!
|
||||
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Issue
|
||||
|
||||
333
.github/workflows/build.yaml
vendored
Normal file
333
.github/workflows/build.yaml
vendored
Normal file
@@ -0,0 +1,333 @@
|
||||
name: Build and Pack
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
#########################################################################################
|
||||
## Build Firmware
|
||||
#########################################################################################
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- id: skip_check
|
||||
uses: fkirc/skip-duplicate-actions@v5
|
||||
with:
|
||||
concurrent_skipping: same_content_newer
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set Variables
|
||||
id: vars
|
||||
run: |
|
||||
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
|
||||
- name: Build Firmware
|
||||
# run: echo "Testing... ${{ github.ref_name }}, ${{ steps.vars.outputs.sha_short }}" > ./sd-card/html/version.txt; mkdir -p ./code/.pio/build/esp32cam/; cd ./code/.pio/build/esp32cam/; echo "${{ steps.vars.outputs.sha_short }}" > firmware.bin; cp firmware.bin partitions.bin; cp firmware.bin bootloader.bin # Testing
|
||||
run: cd code; platformio run --environment esp32cam
|
||||
|
||||
- name: Store generated files in cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
./code/.pio/build/esp32cam/firmware.bin
|
||||
./code/.pio/build/esp32cam/partitions.bin
|
||||
./code/.pio/build/esp32cam/bootloader.bin
|
||||
./sd-card/html/version.txt
|
||||
key: ${{ github.run_number }}
|
||||
|
||||
|
||||
|
||||
#########################################################################################
|
||||
## Pack for old OTA (v1)
|
||||
#########################################################################################
|
||||
pack-for-OTA-v1:
|
||||
# Old OTA concept
|
||||
# firmware__*.zip needs to be unpacked before attaching to the release!
|
||||
# The bin filename can contain versioning.
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Get generated files from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
./code/.pio/build/esp32cam/firmware.bin
|
||||
./code/.pio/build/esp32cam/partitions.bin
|
||||
./code/.pio/build/esp32cam/bootloader.bin
|
||||
./sd-card/html/version.txt
|
||||
key: ${{ github.run_number }}
|
||||
|
||||
- name: Set Variables
|
||||
id: vars
|
||||
run: |
|
||||
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
echo "branch=$(echo ${{ github.ref_name }} | tr / __)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Rename firmware file to contain versioning (old ota)
|
||||
run: |
|
||||
mkdir -p ./dist_old_ota
|
||||
cp "./code/.pio/build/esp32cam/firmware.bin" "./dist_old_ota/firmware__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }}).bin"
|
||||
|
||||
- name: Upload Firmware artifact (old OTA concept)
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
# name: "firmware__${{ github.ref_name }}__(${{ steps.vars.outputs.sha_short }})__(extract_before_upload__only_needed_for_migration_from_11.3.1)"
|
||||
name: "firmware__(extract_before_upload)__${{ steps.vars.outputs.branch }}__(${{ steps.vars.outputs.sha_short }})"
|
||||
path: ./dist_old_ota/*
|
||||
|
||||
- name: Upload Web interface artifact (old OTA concept)
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "html__${{ steps.vars.outputs.branch }}__(${{ steps.vars.outputs.sha_short }})"
|
||||
path: ./sd-card/html/*
|
||||
|
||||
|
||||
|
||||
#########################################################################################
|
||||
## Pack for new OTA (v2)
|
||||
#########################################################################################
|
||||
pack-for-OTA-v2:
|
||||
# New OTA concept
|
||||
# update__version.zip file with following content:
|
||||
# - /firmware.bin
|
||||
# - (optional) /html/*
|
||||
# - (optional) /config/*.tfl
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Get generated files from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
./code/.pio/build/esp32cam/firmware.bin
|
||||
./code/.pio/build/esp32cam/partitions.bin
|
||||
./code/.pio/build/esp32cam/bootloader.bin
|
||||
./sd-card/html/version.txt
|
||||
key: ${{ github.run_number }}
|
||||
|
||||
- name: Set Variables
|
||||
id: vars
|
||||
run: |
|
||||
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
echo "branch=$(echo ${{ github.ref_name }} | tr / __)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Prepare update.zip artifact
|
||||
run: |
|
||||
mkdir -p ./dist
|
||||
cp "./code/.pio/build/esp32cam/firmware.bin" "dist/firmware.bin"
|
||||
|
||||
# - name: Upload update.zip Artifact (Firmware only)
|
||||
# uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: "update_firmware_only__${{ github.ref_name }}_(${{ steps.vars.outputs.sha_short }})"
|
||||
# path: ./dist/*
|
||||
|
||||
- name: Add Web UI to dist
|
||||
run: cp -r ./sd-card/html ./dist/
|
||||
|
||||
# - name: Upload update.zip artifact (Firmware + Web UI)
|
||||
# uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: "update_firmware+webinterface__${{ github.ref_name }}_(${{ steps.vars.outputs.sha_short }})"
|
||||
# path: ./dist/*
|
||||
|
||||
- name: Add CNN to dist
|
||||
run: |
|
||||
mkdir ./dist/config/
|
||||
cp ./sd-card/config/*.tfl ./dist/config/ 2>/dev/null || true
|
||||
cp ./sd-card/config/*.tflite ./dist/config/ 2>/dev/null || true
|
||||
|
||||
- name: Upload dist as update.zip artifact (Firmware + Web UI + CNN)
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "update__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
|
||||
path: ./dist/*
|
||||
|
||||
- name: Store generated files in cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: dist
|
||||
key: ${{ github.run_number }}-pack-for-OTA-v2
|
||||
|
||||
|
||||
|
||||
|
||||
#########################################################################################
|
||||
## Pack for a fresh install (USB flashing) (initial_esp32_setup)
|
||||
#########################################################################################
|
||||
pack-for-fresh-install:
|
||||
# creates old style binaries for fresh installation (backward compatible to wiki)
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Get generated files from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
./code/.pio/build/esp32cam/firmware.bin
|
||||
./code/.pio/build/esp32cam/partitions.bin
|
||||
./code/.pio/build/esp32cam/bootloader.bin
|
||||
./sd-card/html/version.txt
|
||||
key: ${{ github.run_number }}
|
||||
|
||||
- name: Set Variables
|
||||
id: vars
|
||||
run: |
|
||||
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
echo "branch=$(echo ${{ github.ref_name }} | tr / __)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Prepare artifacts for release
|
||||
run: |
|
||||
mkdir -p firmware
|
||||
rm -rf firmware/*.zip
|
||||
mkdir -p release
|
||||
# copy builds to firmware folder
|
||||
cp -f "./code/.pio/build/esp32cam/firmware.bin" "firmware/firmware.bin"
|
||||
cp -f "./code/.pio/build/esp32cam/bootloader.bin" "firmware/bootloader.bin"
|
||||
cp -f "./code/.pio/build/esp32cam/partitions.bin" "firmware/partitions.bin"
|
||||
zip -r ./firmware/sd-card.zip sd-card
|
||||
cd ./firmware
|
||||
|
||||
- name: Upload initial_esp32_setup.zip artifact (Firmware + Bootloader + Partitions + Web UI)
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "initial_esp32_setup__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
|
||||
path: ./firmware
|
||||
|
||||
- name: Store generated files in cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: firmware
|
||||
key: ${{ github.run_number }}-pack-for-fresh-install
|
||||
|
||||
|
||||
|
||||
|
||||
#########################################################################################
|
||||
## Prepare and create release
|
||||
#########################################################################################
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [pack-for-OTA-v2, pack-for-fresh-install]
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set Variables
|
||||
id: vars
|
||||
run: |
|
||||
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get generated files from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
./code/.pio/build/esp32cam/firmware.bin
|
||||
./code/.pio/build/esp32cam/partitions.bin
|
||||
./code/.pio/build/esp32cam/bootloader.bin
|
||||
./sd-card/html/version.txt
|
||||
key: ${{ steps.vars.outputs.branch }}
|
||||
|
||||
# import the changes from
|
||||
- name: Get generated files from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: dist
|
||||
key: ${{ github.run_number }}-pack-for-OTA-v2
|
||||
|
||||
# import cached artifacts from pack-for-fresh-install
|
||||
- name: Get generated files from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: firmware
|
||||
key: ${{ github.run_number }}-pack-for-fresh-install
|
||||
|
||||
|
||||
|
||||
- name: Prepare artifacts for release
|
||||
run: |
|
||||
mkdir -p release
|
||||
mkdir -p dist
|
||||
# create a update.zip like "update__rolling"
|
||||
pwd
|
||||
ls ./dist
|
||||
cd ./dist
|
||||
zip -r ../release/update.zip .
|
||||
cd ../firmware
|
||||
zip -r ../release/initial_esp32_setup.zip .
|
||||
cd ../sd-card/html
|
||||
zip -r ../../firmware/html-from-11.3.1.zip .
|
||||
|
||||
|
||||
# extract the version used in next step
|
||||
- id: get_version
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
uses: battila7/get-version-action@v2
|
||||
|
||||
# the changelog [unreleased] will now be changed to the release version
|
||||
- name: Update changelog
|
||||
uses: thomaseizinger/keep-a-changelog-new-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
changelogPath: Changelog.md
|
||||
version: ${{ steps.get_version.outputs.version-without-v }}
|
||||
|
||||
# the release notes will be extracted from changelog
|
||||
- name: Extract release notes
|
||||
id: extract-release-notes
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
uses: ffurrer2/extract-release-notes@v1
|
||||
with:
|
||||
changelog_file: Changelog.md
|
||||
|
||||
|
||||
# Releases should only be created on master by tagging the last commit.
|
||||
# all artifacts in firmware folder pushed to the release
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
name: ${{ steps.get_version.outputs.version-without-v }}
|
||||
body: ${{ steps.extract-release-notes.outputs.release_notes }}
|
||||
files: |
|
||||
release/*
|
||||
firmware/firmware.bin
|
||||
firmware/html-from-11.3.1.zip
|
||||
|
||||
|
||||
# Commit&Push Changelog to master branch. Must be manually merged back to rolling
|
||||
- name: Commit changes and push changes
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
run: |
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
git add Changelog.md
|
||||
git commit Changelog.md -m "Update Changelog.md for ${{github.event.inputs.versionIncrement}} release"
|
||||
git push origin HEAD:master
|
||||
10
.gitignore
vendored
10
.gitignore
vendored
@@ -4,7 +4,13 @@
|
||||
.code-workspace
|
||||
/sd-card/htm./.vscode/
|
||||
/code/build
|
||||
|
||||
/code/.helper
|
||||
/sd-card/html/debug/
|
||||
/firmware/
|
||||
version.txt
|
||||
/dist/
|
||||
/dist_release/
|
||||
/dist_old_ota
|
||||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
@@ -15,3 +21,5 @@ install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
code/edgeAI.code-workspace
|
||||
.DS_Store
|
||||
|
||||
9
.gitmodules
vendored
Normal file
9
.gitmodules
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
[submodule "code/components/esp32-camera"]
|
||||
path = code/components/esp32-camera
|
||||
url = https://github.com/espressif/esp32-camera.git
|
||||
[submodule "code/components/esp-nn"]
|
||||
path = code/components/esp-nn
|
||||
url = https://github.com/espressif/esp-nn.git
|
||||
[submodule "code/components/tflite-micro-esp-examples"]
|
||||
path = code/components/tflite-micro-esp-examples
|
||||
url = https://github.com/espressif/tflite-micro-esp-examples.git
|
||||
772
Changelog.md
772
Changelog.md
@@ -1,238 +1,752 @@
|
||||
# Versions
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
**Home Assistant MQTT Discovery Support**
|
||||
|
||||
### Update Procedure
|
||||
:bangbang: **Make sure to read the instructions below carfully!**.
|
||||
|
||||
1. Backup your configuration (use the `System -> Backup/Restore` page)!
|
||||
1. You should update to `12.0.1` before you update to this release. All other migrations are untested.
|
||||
1. Upload and update the `update-*.zip` file from this release.
|
||||
1. Let it restart and check on the `System -> Info` page that the Firmware as well as the Web UI got updated. If only one got updated, redo the update. If it fails several times, you also can update the Firmware and the Web UI separately.
|
||||
1. Safe way:
|
||||
1. Update first the `firmware.bin` (extract from zip file) and do the Reboot
|
||||
1. Update with the full zip file (`update-*.zip`, ignore the version warning after the reboot)
|
||||
|
||||
##### 7.1.2 MQTT-Update - (2021-06-17)
|
||||
1. Please go to `Settings -> Configuration` and address the changed parameters:
|
||||
* DataLogging (storing the values for data graph)
|
||||
* Debug (extended by different debug reporting levels)
|
||||
|
||||
* NEW: 7.1.2: bug fix setting hostname, Flash-LED not off during reboot
|
||||
If anything breaks you can try to enforce manual update as following:
|
||||
|
||||
* NEW: 7.1.1: bug fix wlan password with "=" (again)
|
||||
**OTA:**
|
||||
1. Make sure the last run of the update completed the **Uploading** step.
|
||||
1. Call `http://<IP>/ota?task=update&file=<UPLOAD_FILENAME>` to enforce the extraction/flashing.
|
||||
|
||||
* MQTT error message: changes "no error", send retain flag
|
||||
**Initial Setup:**
|
||||
1. Use the initial_esp32_setup.zip ( <https://github.com/jomjol/AI-on-the-edge-device/wiki/Installation> ) as alternative to have a clean install.
|
||||
|
||||
* Update wlan handling to esp-idf 4.1
|
||||
|
||||
* Upgrade digital CNN to v8.7.0 (added new images)
|
||||
### Added
|
||||
|
||||
* Bug fix: MQTT, WLAN, LED-Controll, GPIO usage, fixed IP, calculation flow rate
|
||||
- Implementation of [Home Assistant MQTT Discovery](https://www.home-assistant.io/integrations/mqtt/#mqtt-discovery)
|
||||
- Improved ROIs configuration: locked ROI geometry, equidistant delta x
|
||||
- Improved OTA Update mechanism (only working after installation for next update)
|
||||
- Added data logging in `/log/data` - One day per file and each measurement is on one line
|
||||
- Format: csv - comma separated
|
||||
- Content: `time`, `name-of-number`, `raw-value`, `return-value`, `pre-value`, `change-rate`, `change-absolute`, `error-text`, `cnn-digital`, `cnn-analog`
|
||||
- Show graph of values direct in the user interface (thanks to [@rdmueller](https://github.com/rdmueller))
|
||||
- Using new data logging (see above)
|
||||
- Possibility to choose different values and switch between different numbers (if present)
|
||||
|
||||
Note: You need to activate data logging for this feature to work, see above!
|
||||
- PreValue is now contained in `/json` ([#1154](https://github.com/jomjol/AI-on-the-edge-device/issues/1154))
|
||||
- SD card info into the `System>Info` menu (thanks to [@Slider007]( https://github.com/Slider0007))
|
||||
- Version check (Firmware vs. Web UI)
|
||||
- Various minor new features
|
||||
|
||||
|
||||
|
||||
##### 7.0.1 MQTT-Update - (2021-05-13)
|
||||
### Changed
|
||||
|
||||
* NEW: 7.0.1: bug fix wlan password with "="
|
||||
- Updated tflite (`dig-cont_0600_s3.tflite`)
|
||||
- Updated OTA functionality (more robust, but not fully bullet prove yet)
|
||||
- Updated Espressif library to `espressif32@v5.2.0`
|
||||
- [#1176](https://github.com/jomjol/AI-on-the-edge-device/discussions/1176) accept minor negative values (-0.2) if extended resolution is enabled
|
||||
- [#1143](https://github.com/jomjol/AI-on-the-edge-device/issues/1143) added config parameter `AnalogDigitalTransitionStart`. It can setup very early and very late digit transition starts.
|
||||
- New version of `dig-class100` (v1.4.0): added images of heliowatt powermeter
|
||||
### Fixed
|
||||
|
||||
* Upgrade digital CNN to v8.5.0 (added new images)
|
||||
- [#1116](https://github.com/jomjol/AI-on-the-edge-device/issues/1116) precision problem at setting prevalue
|
||||
- [#1119](https://github.com/jomjol/AI-on-the-edge-device/issues/1119) renamed `firmware.bin` not working in OTA
|
||||
- [#1143](https://github.com/jomjol/AI-on-the-edge-device/issues/1143) changed postprocess for `analog->digit` (lowest digit processing)
|
||||
- [#1280](https://github.com/jomjol/AI-on-the-edge-device/issues/1280) check ROIs name for unsupported characters
|
||||
- [#983](https://github.com/jomjol/AI-on-the-edge-device/issues/983) old log files did not get deleted
|
||||
- Failed NTP time sync during startup gets now retried every round if needed
|
||||
- Whitespaces and `=` in MQTT and InfluxDB passwords
|
||||
- Various minor fixes and improvements
|
||||
|
||||
* New MQTT topics: flow rate (units/minute), time stamp (last correct read readout)
|
||||
### Removed
|
||||
|
||||
* Update MQTT/Error topic to " " in case no error (instead of empty string)
|
||||
- n.a.
|
||||
|
||||
* Portrait or landscape image orientation in rotated image (avoid cropping)
|
||||
|
||||
##### 6.7.2 Image Processing in Memory - (2021-05-01)
|
||||
## [12.0.1](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v12.0.1), 2022-09-29
|
||||
|
||||
* NEW 6.7.2: Updated html for setup modus - remove reboot on edit configuration)
|
||||
Improve **u**ser e**x**perience
|
||||
|
||||
* NEW 6.7.1: Improved stability of camera (back to v6.6.1) - remove black strips and areas
|
||||
:bangbang: The release breaks a few things in ota update :bangbang:
|
||||
|
||||
* Upgrade digital CNN to v8.3.0 (added new type of digits)
|
||||
**Make sure to read the instructions below carfully!**.
|
||||
|
||||
* Internal update: TFlite (v2.5), esp32cam, startup sequence
|
||||
1. Backup your configuration (use the `System > Backup/Restore` page)!
|
||||
2. You should update to `11.3.1` before you update to this release. All other migrations are not tested.
|
||||
Rolling newer than `11.3.1` can also be used, but no guaranty.
|
||||
3. Upload and update the `firmware.bin` file from this release. **but do not reboot**
|
||||
4. Upload the `html-from-11.3.1.zip` in html upload and update the web interface.
|
||||
5. Now you can reboot.
|
||||
|
||||
* Rollback to espressif v2.1.0, as v3.2.0 shows unstable reboot
|
||||
If anything breaks you can try to
|
||||
1. Call `http://<IP>/ota?task=update&file=firmware.bin` resp. `http://<IP>/ota?task=update&file=html.zip` if the upload successed but the extraction failed.
|
||||
1. Use the initial_esp32_setup.zip ( <https://github.com/jomjol/AI-on-the-edge-device/wiki/Installation> ) as alternative.
|
||||
|
||||
* Bugfix: WLan-passwords, reset of hostname
|
||||
### Added
|
||||
|
||||
- Automatic release creation
|
||||
- Newest firmware of rolling branch now automatically build and provided in [Github Actions Output](https://github.com/jomjol/AI-on-the-edge-device/actions) (developers only)
|
||||
- [#1068](https://github.com/jomjol/AI-on-the-edge-device/issues/1068) New update mechanism:
|
||||
- Handling of all files (`zip`, `tfl`, `tflite`, `bin`) within in one common update interface
|
||||
- Using the `update.zip` from the [Release page](https://github.com/jomjol/AI-on-the-edge-device/releases)
|
||||
- Status (`upload`, `processing`, ...) displayed on Web Interface
|
||||
- Automatical detection and suggestion for reboot where needed (Web Interface uupdates only need a page refresh)
|
||||
- :bangbang: Best for OTA use Firefox. Chrome works with warnings. Safari stuck in upload.
|
||||
|
||||
##### 6.6.1 Image Processing in Memory - (2021-04-05)
|
||||
### Changed
|
||||
|
||||
* NEW 6.6.1: failed SD card initialization indicated by fast blinking LED at startup
|
||||
* Improved SD-card handling (increase compatibility with more type of cards)
|
||||
- Integrated version info better shown on the Info page and in the log
|
||||
- Updated menu
|
||||
- Update used libraries (`tflite`, `esp32-cam`, `esp-nn`, as of 20220924)
|
||||
|
||||
##### 6.5.0 Image Processing in Memory - (2021-03-25)
|
||||
### Fixed
|
||||
|
||||
* Upgrade digital CNN to v8.2.0 (added new type of digits)
|
||||
* Supporting alignment structures in ROI definition
|
||||
* Bug fixing: definition of hostname in `config.ini`
|
||||
- [#1092](https://github.com/jomjol/AI-on-the-edge-device/issues/1092) censor passwords in log outputs
|
||||
- [#1029](https://github.com/jomjol/AI-on-the-edge-device/issues/1029) wrong change of `checkDigitConsistency` now working like releases before `11.3.1`
|
||||
- Spelling corrections (**[cristianmitran](https://github.com/cristianmitran)**)
|
||||
|
||||
##### 6.4.0 Image Processing in Memory - (2021-03-20)
|
||||
### Removed
|
||||
|
||||
* Additional alignment marks for settings the ROIs (analog and digit)
|
||||
* Upgrade analog CNN to v7.0.0 (added new type of pointer)
|
||||
- Remove the folder `/firmware` from GitHub repository.
|
||||
If you want to get the latest `firmware.bin` and `html.zip` files, please download from the automated [build action](https://github.com/jomjol/AI-on-the-edge-device/actions) or [release page](https://github.com/jomjol/AI-on-the-edge-device/releases)
|
||||
|
||||
##### 6.3.1 Image Processing in Memory - (2021-03-16)
|
||||
## [11.3.1](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v11.3.1), 2022-09-17
|
||||
|
||||
* NEW: 6.3.1: bug fixing in initial edit reference image and `config.ini` (Spelling error in `InitialRotate`)
|
||||
* Initial setup mode: bug fixing, error correction
|
||||
* Bug-fixing
|
||||
Intermediate Digits
|
||||
|
||||
##### 6.2.2 Image Processing in Memory - (2021-03-10)
|
||||
- **ATTENTION**:
|
||||
|
||||
* NEW 6.2.2: bug fixing
|
||||
* NEW 6.2.1: Changed brightness and contrast to default if not enabled (resolves to bright images)
|
||||
* Determination of fixed illumination settings during startup - speed up of 5s in each run
|
||||
* Update digital CNN to v8.1.1 (additional digital images trained)
|
||||
* Extended error message in MQTT error message
|
||||
- first update the `firmware.bin` and ensure that the new version is running
|
||||
|
||||
- Only afterwards update the `html.zip`
|
||||
|
||||
* Image brightness is now adjustable
|
||||
- Otherwise the downwards compatibility of the new counter clockwise feature is not given and you end in a reboot loop, that needs manual flashing!
|
||||
|
||||
|
||||
* Bug fixing: minor topics
|
||||
- **NEW v11.3.1**: corrected corrupted asset `firmware.bin`
|
||||
- Increased precision (more than 6-7 digits)
|
||||
- Implements Counter Clockwise Analog Pointers
|
||||
- Improved post processing algorithm
|
||||
- Debugging: intensive use of testcases
|
||||
- MQTT: improved handling, extended logging, automated reconnect
|
||||
- HTML: Backup Option for Configuration
|
||||
- HTML: Improved Reboot
|
||||
- HTML: Update WebUI (Reboot, Infos, CPU Temp, RSSI)
|
||||
- This version is largely also based on the work of **[caco3](https://github.com/caco3)**, **[adellafave](https://github.com/adellafave)**, **[haverland](https://github.com/haverland)**, **[stefanbode](https://github.com/stefanbode)**, **[PLCHome](https://github.com/PLCHome)**
|
||||
|
||||
## [11.2.0](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v11.2.0), 2022-08-28
|
||||
|
||||
##### 6.1.0 Image Processing in Memory - (2021-01-20)
|
||||
Intermediate Digits
|
||||
|
||||
* Disabling of analog / digital counters in configuration
|
||||
* Improved Alignment Algorithm (`AlignmentAlgo` = `Default`, `Accurate` , `Fast`)
|
||||
* Analog counters: `ExtendedResolution` (last digit is extended by sub comma value of CNN)
|
||||
* `config.ini`: additional parameter `hostname` (additional to wlan.ini)
|
||||
* Switching of GPIO12/13 via http-interface: `/GPIO?GPIO=12&Status=high/low`
|
||||
* Bug fixing: html configuration page, wlan password ("=" now possible)
|
||||
- Updated Tensorflow / TFlite to newest tflite (version as of 2022-07-27)
|
||||
|
||||
##### 6.0.0 Image Processing in Memory - (2021-01-02)
|
||||
- Updated analog neural network file (`ana-cont_11.3.0_s2.tflite` - default, `ana-class100_0120_s1_q.tflite`)
|
||||
|
||||
* **Major change**: image processing fully in memory - no need of SD card buffer anymore
|
||||
- Updated digital neural network file (`dig-cont_0570_s3.tflite` - default, `dig-class100_0120_s2_q.tflite`)
|
||||
|
||||
* Need to limit camera resolution to VGA (due to memory limits)
|
||||
* MQTT: Last Will Testament (LWT) implemented: "connection lost" in case of connection lost to `TopicError`
|
||||
* Disabled `CheckDigitIncreaseConsistency` in default configuration - must now be explicit enabled if needed
|
||||
* Update digital CNN to v7.2.1 (additional digital images trained)
|
||||
* Setting of arbitrary time server in `config.ini`
|
||||
* Option for fixed IP-, DNS-Settings in `wlan.ini`
|
||||
* Increased stability (internal image and camera handling)
|
||||
* Bug fixing: edit digits, handling PreValue, html-bugs
|
||||
- Added automated filtering of tflite-file in the graphical configuration (thanks to @**[caco3](https://github.com/caco3)**)
|
||||
|
||||
- Updated consistency algorithm & test cases
|
||||
|
||||
- HTML: added favicon and system name, Improved reboot dialog (thanks to @**[caco3](https://github.com/caco3)**)
|
||||
|
||||
##### 5.0.0 Setup Modus - (2020-12-06)
|
||||
## [11.1.1](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v11.1.1), 2022-08-22
|
||||
|
||||
* Implementation of initial setup modus for fresh installation
|
||||
Intermediate Digits
|
||||
|
||||
* Code restructuring (full compatibility between pure ESP-IDF and Platformio w/ espressif)
|
||||
- New and improved consistency check (especially with analog and digital counters mixed)
|
||||
- Bug Fix: digital counter algorithm
|
||||
|
||||
|
||||
## [11.0.1](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v11.0.1), 2022-08-18
|
||||
|
||||
##### 4.1.1 Configuration editor - (2020-12-02)
|
||||
Intermediate Digits
|
||||
|
||||
* Bug fixing: internal improvement of file handling (reduce not responding)
|
||||
- **NEW v11.0.1**: Bug Fix InfluxDB configuration (only update of html.zip necessary)
|
||||
|
||||
- Implementation of new CNN types to detect intermediate values of digits with rolling numbers
|
||||
|
||||
##### 4.1.0 Configuration editor - (2020-11-30)
|
||||
- By default the old algo (0, 1, ..., 9, "N") is active (due to the limited types of digits trained so far)
|
||||
- Activation can be done by selection a tflite file with the new trained model in the 'config.ini'
|
||||
- **Details can be found in the [wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/Neural-Network-Types)** (different types, trained image types, naming convention)
|
||||
|
||||
* Implementation of configuration editor (including basic and expert mode)
|
||||
- Updated neural network files (and adaption to new naming convention)
|
||||
|
||||
* Adjustable time zone to adjust to local time setting (incl. daylight saving time)
|
||||
- Published a tool to download and combine log files - **Thanks to **
|
||||
|
||||
* MQTT: additional topic for error reporting
|
||||
- Files see ['/tools/logfile-tool'](tbd), How-to see [wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/Gasmeter-Log-Downloader)
|
||||
|
||||
* standardized access to current logfile via `http://IP-ADRESS/logfileact`
|
||||
- Bug Fix: InfluxDB enabling in grahic configuration
|
||||
|
||||
* Update digital CNN to v7.2.0, analog CNN to 6.3.0
|
||||
## [10.6.2](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v10.6.2), 2022-07-24
|
||||
|
||||
* Bug fixing: truncation error, CheckDigitConsistency & PreValue implementation
|
||||
Stability Increase
|
||||
|
||||
### Added
|
||||
|
||||
- **NEW 10.6.2**: ignore hidden files in model selection (configuration page)
|
||||
|
||||
##### 4.0.0 Tflite Core - (2020-11-15)
|
||||
- **NEW 10.6.1**: Revoke esp32cam & tflite update
|
||||
|
||||
* Implementation of rolling log-files
|
||||
- **NEW 10.6.1**: Bug Fix: tflite-filename with ".", HTML spelling error
|
||||
|
||||
* Update Tflite-Core to master@20201108 (v2.4)
|
||||
- IndluxDB: direct injection into InfluxDB - thanks to **[wetneb](https://github.com/wetneb)**
|
||||
|
||||
* Bug-fixing for reducing reboots
|
||||
- MQTT: implemented "Retain Flag" and extend with absolute Change (in addition to rate)
|
||||
|
||||
|
||||
- `config.ini`: removal of modelsize (readout from tflite)
|
||||
|
||||
##### 3.1.0 MQTT-Client - (2020-10-26)
|
||||
- Updated analog neural network file (`ana1000s2.tflite`) & digital neural network file (`dig1400s2q.tflite`)
|
||||
|
||||
* Update digital CNN to v6.5.0 and HTML (Info to hostname, IP, ssid)
|
||||
- TFMicro/Lite: Update (espressif Version 20220716)
|
||||
|
||||
* New implementation of "checkDigitConsistency" also for digits
|
||||
* MQTT-Adapter: user and password for sign in MQTT-Broker
|
||||
- Updated esp32cam (v20220716)
|
||||
|
||||
##### 3.0.0 MQTT-Client (2020-10-14)
|
||||
- ESP-IDF: Update to 4.4
|
||||
|
||||
* Implementation of MQTT Client
|
||||
* Improved Version Control
|
||||
* bug-fixing
|
||||
- Internal update (CNN algorithm optimizations, reparation for new neural network type)
|
||||
|
||||
- Bug Fix: no time with fixed IP, Postprocessing, MQTT
|
||||
|
||||
## [10.5.2](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v10.5.2), 2022-02-22
|
||||
|
||||
##### 2.2.1 Version Control (2020-09-27)
|
||||
Stability Increase
|
||||
|
||||
* Bug-Fixing (hostname in wlan.ini and error handling inside flow)
|
||||
### Changed
|
||||
|
||||
- NEW 10.5.2: Bug Fix: wrong `firmware.bin` (no rate update)
|
||||
- NEW 10.5.1: Bug Fix: wrong return value, rate value & PreValue status, HTML: SSID & IP were not displayed
|
||||
- MQTT: changed wifi naming to "wifiRSSI"
|
||||
- HTML: check selectable values for consistency
|
||||
- Refactoring of check postprocessing consistency (e.g. max rate, negative rate, ...)
|
||||
- Bug Fix: corrected error in "Check Consistency Increase"
|
||||
|
||||
##### 2.2.0 Version Control (2020-09-27)
|
||||
## [10.4.0](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v10.4.0), 2022-02-12
|
||||
|
||||
* Integrated automated versioning system (menu: SYSTEM --> INFO)
|
||||
* Update Build-System to PlatformIO - Espressif 32 v2.0.0 (ESP-IDF 4.1)
|
||||
Stability Increase
|
||||
|
||||
### Changed
|
||||
|
||||
##### 2.1.0 Decimal Shift, Chrome & Edge (2020-09-25)
|
||||
- Graphical configuration: select available neural network files (_.tfl,_.tflite) from drop down menu
|
||||
- OTA-update: add option to upload tfl / tflite files to the correct location (`/config/`)
|
||||
- In the future the new files will also be copied to the `firmware` directory of the repository
|
||||
- Added Wifi RSSI to MQTT information
|
||||
- Updated analog neural network file (`ana-s3-q-20220105.tflite`)
|
||||
- Updated digital neural network file (`dig-s1-q-20220102.tflite`)
|
||||
- Updated build environment to `Espressif 3.5.0`
|
||||
|
||||
* Implementation of Decimal Shift
|
||||
## [10.3.0] - (2022-01-29)
|
||||
|
||||
* Update default CNN for digits to v6.4.0
|
||||
Stability Increase
|
||||
|
||||
* Improvement HTML
|
||||
### Changed
|
||||
|
||||
* Support for Chrome and Edge
|
||||
- Implemented LED flash dimming (`LEDIntensity`).
|
||||
Remark: as auto illumination in the camera is used, this is rather for energy saving. It will not help reducing reflections
|
||||
- Additional camera parameters: saturation, contrast (although not too much impact yet)
|
||||
- Some readings will have removable "N"s that can not be removed automatically and are handled with an "error" --> no return value in the field "value" anymore (still reported back via field "raw value")
|
||||
- Updated esp32 camera hardware driver
|
||||
- Bug fix: MQTT, HTML improvements
|
||||
|
||||
* Reduce logging to minimum - extended logging on demand
|
||||
**ATTENTION: The new ESP32 camera hardware driver is much more stable on newer OV2640 versions (no or much less reboots) but seems to be not fully compatible with older versions.**
|
||||
|
||||
* Implementation of hostname in wlan.ini (`hostname = "HOSTNAME")`
|
||||
If you have problem with stalled systems you can try the following
|
||||
|
||||
* Bug fixing, code corrections
|
||||
- Update the parameter `ImageQuality` to `12` instead of current value `5` (manually in the `config.ini`)
|
||||
|
||||
- If this is not helping, you might need to update your hardware or stay with version 9.2
|
||||
|
||||
##### 2.0.0 Layout update (2020-09-12)
|
||||
## [10.2.0] - (2022-01-14)
|
||||
|
||||
* Update to **new and modern layout**
|
||||
* Support for Chrome improved
|
||||
* Improved robustness: improved error handling in auto flow reduces spontaneous reboots
|
||||
* File server: Option for "DELETE ALL"
|
||||
* WLan: support of spaces in SSID and password
|
||||
* Reference Image: Option for mirror image, option for image update on the fly
|
||||
* additional parameter in `wasserzaehler.html?noerror=true` to suppress an potential error message
|
||||
* bug fixing
|
||||
Stability Increase
|
||||
|
||||
### Changed
|
||||
|
||||
- Due to the updated camera driver, the image looks different and a new setup might be needed
|
||||
|
||||
##### 1.1.3 (2020-09-09)
|
||||
- Update reference image
|
||||
- Update Alignment marks
|
||||
|
||||
* **Bug in configuration of analog ROIs corrected** - correction in v.1.0.2 did not work properly
|
||||
* Improved update page for the web server (`/html` can be updated via a zip-file, which is provided in `/firmware/html.zip`)
|
||||
* Improved Chrome support
|
||||
- Reduce reboot due to camera problems
|
||||
|
||||
##### 1.1.0 (2020-09-06)
|
||||
- Update esp32-camera to new version (master as of 2022-01-09)
|
||||
|
||||
* Implementation of "delete complete directory"
|
||||
**Attention: beside the `firmware.bin`, also the content of `/html` needs to be updated!**
|
||||
## [10.1.1] - (2022-01-12)
|
||||
|
||||
Stability Increase
|
||||
|
||||
### Changed
|
||||
|
||||
##### 1.0.2 (2020-09-06)
|
||||
- Bug Fix MQTT problem
|
||||
- Issue:
|
||||
- Changing from v9.x to 10.x the MQTT-parameter "Topic" was renamed into "MainTopic" to address multiple number meters. This renaming should have been done automatically in the background within the graphical configuration, but was not working. Instead the parameter "Topic" was deleted and "MainTopic" was set to disabled and "undefined".
|
||||
- ToDo
|
||||
- Update the `html.zip`
|
||||
- If old `config.ini` available: copy it to `/config`, open the graphical configuration and save it again.
|
||||
- If old `config.ini` not available: reset the parameter "MainTopic" within the `config.ini` manually
|
||||
- Reboot
|
||||
|
||||
* Bug in configuration of analog ROIs corrected
|
||||
* minor bug correction
|
||||
## [10.1.0] - (2022-01-09)
|
||||
|
||||
##### 1.0.1 (2020-09-05)
|
||||
Stability Increase
|
||||
|
||||
* preValue.ini Bug corrected
|
||||
* minor bug correction
|
||||
### Changed
|
||||
|
||||
##### 1.0.0 (2020-09-04)
|
||||
- Reduce ESP32 frequency to 160MHz
|
||||
|
||||
* **First usable version** - compatible to previous project (https://github.com/jomjol/water-meter-system-complete)
|
||||
* NEW:
|
||||
* no docker container for CNN calculation necessary
|
||||
* web based configuration editor on board
|
||||
- Update tflite (new source: <https://github.com/espressif/tflite-micro-esp-examples>)
|
||||
|
||||
##### 0.1.0 (2020-08-07)
|
||||
- Update analog neural network (ana-s3-q-20220105.tflite)
|
||||
|
||||
* Initial Version
|
||||
- Update digital neural network (dig-s1-q-20220102.tflite)
|
||||
|
||||
- Increased web-server buffers
|
||||
|
||||
- bug fix: compiler compatibility
|
||||
|
||||
## [10.0.2] - (2022-01-01)
|
||||
|
||||
Stability Increase
|
||||
|
||||
### Changed
|
||||
|
||||
- NEW v10.0.2: Corrected JSON error
|
||||
|
||||
- Updated compiler toolchain to ESP-IDF 4.3
|
||||
|
||||
- Removal of memory leak
|
||||
|
||||
- Improved error handling during startup (check PSRAM and camera with remark in logfile)
|
||||
|
||||
- MQTT: implemented raw value additionally, removal of regex contrain
|
||||
|
||||
- Normalized Parameter `MaxRateValue` to "change per minute"
|
||||
|
||||
- HTML: improved input handling
|
||||
|
||||
- Corrected error handling: in case of error the old value, rate, timestamp are not transmitted any more
|
||||
|
||||
## [9.2.0] - (2021-12-02)
|
||||
|
||||
External Illumination
|
||||
|
||||
### Changed
|
||||
|
||||
- Direct JSON access: `http://IP-ADRESS/json`
|
||||
- Error message in log file in case camera error during startup
|
||||
- Upgrade analog CNN to v9.1.0
|
||||
- Upgrade digital CNN to v13.3.0 (added new images)
|
||||
- html: support of different ports
|
||||
|
||||
## [9.1.1] - External Illumination (2021-11-16)
|
||||
|
||||
### Changed
|
||||
|
||||
- NEW 9.1.1 bug fix: LED implemenetation
|
||||
- External LEDs: change control mode (resolve bug with more than 2 LEDs)
|
||||
- Additional info into log file
|
||||
- Bug fix: decimal shift, html, log file
|
||||
|
||||
## [9.0.0] - External Illumination (2021-10-23)
|
||||
|
||||
### Changed
|
||||
|
||||
- Implementation of external illumination to adjust positioning, brightness and color of the illumination now set individually
|
||||
- Technical details can be found in the wiki: <https://github.com/jomjol/AI-on-the-edge-device/wiki/External-LED>
|
||||
<img src="https://raw.githubusercontent.com/jomjol/ai-on-the-edge-device/master/images/intern_vs_external.jpg" width="500">
|
||||
- New housing published for external LEDs and small clearing: <https://www.thingiverse.com/thing:5028229>
|
||||
|
||||
## [8.5.0] - Multi Meter Support (2021-10-07)
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade digital CNN to v13.1.0 (added new images)
|
||||
- bug fix: wlan password with space, double digit output
|
||||
|
||||
## [8.4.0] - Multi Meter Support (2021-09-25)
|
||||
|
||||
### Changed
|
||||
|
||||
- License change (remove MIT license, remark see below)
|
||||
|
||||
- html: show hostname in title and main page
|
||||
|
||||
- configuration:
|
||||
|
||||
- moved setting `ExtendedResolution` to individual number settings
|
||||
- New parameter `IgnoreLeadingNaN` (delete leading NaN's specifically)
|
||||
- **ATTENTION**: update of the `config.ini` needed (open, adjust `ExtendedResolution`, save)
|
||||
|
||||
- Bug fixing (html, images of recognized numbers)
|
||||
|
||||
**ATTENTION: LICENSE CHANGE - removal of MIT License.**
|
||||
|
||||
- Currently no licence published - copyright belongs to author
|
||||
|
||||
- If you are interested in a commercial usage or dedicated versions please contact the developer
|
||||
- no limits to private usage
|
||||
|
||||
## [8.3.0] - Multi Meter Support (2021-09-12)
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade digital CNN to v12.1.0 (added new images)
|
||||
- Dedicated NaN handling, internal refactoring (CNN-Handling)
|
||||
- HTML: confirmation after config.ini update
|
||||
- Bug fixing
|
||||
|
||||
## [8.2.0] - Multi Meter Support (2021-08-24)
|
||||
|
||||
### Changed
|
||||
|
||||
- Improve server responsiveness
|
||||
|
||||
|
||||
- Flow status and prevalue status in overview
|
||||
- Improved prevalue handling
|
||||
|
||||
## [8.1.0] - Multi Meter Support (2021-08-12)
|
||||
|
||||
### Changed
|
||||
|
||||
- GPIO: using the general mqtt main topic for GPIO
|
||||
|
||||
|
||||
- Upgrade digital CNN to v12.0.0 (added new images)
|
||||
- Update tfmicro to new master (2021-08-07)
|
||||
- Bug fix: remove text in mqtt value, remove connect limit in wlan reconnet
|
||||
|
||||
## [8.0.5] - Multi Meter Support (2021-08-01)
|
||||
|
||||
### Changed
|
||||
|
||||
- NEW 8.0.5: bug fix: saving prevalue
|
||||
|
||||
|
||||
- NEW 8.0.4: bug fix: load config.ini after upgrade
|
||||
- NEW 8.0.3: bug fix: reboot during `config.ini` handling, html error
|
||||
- NEW 8.0.2: saving roundes prevalue, bug fix html server
|
||||
- NEW 8.0.1: bug fix: html handling of parameter `FixedExposure` and `ImageSize`
|
||||
- Dual / multi meter support (more than 1 number to be recognized)
|
||||
This is implemented with the feature "number" on the ROI definition as well as selected options
|
||||
- MQTT: standardization of the naming - including new topics (`json`, `freeMem`, `uptime`)c
|
||||
- Preparation for extended GPIO support (thanks to Zwerk2k) - not tested and fully functional yet
|
||||
- Bug fixing: html server, memory leak, MQTT connect, hostname, turn of flash LED
|
||||
|
||||
<span style="color: red;">**ATTENTION: the configuration and prevalue files are modified automatically and will not be backward compatible!**</span>
|
||||
|
||||
## [7.1.2] MQTT-Update - (2021-06-17)
|
||||
|
||||
### Changed
|
||||
|
||||
- NEW: 7.1.2: bug fix setting hostname, Flash-LED not off during reboot
|
||||
|
||||
|
||||
- NEW: 7.1.1: bug fix wlan password with "=" (again)
|
||||
|
||||
- MQTT error message: changes "no error", send retain flag
|
||||
|
||||
- Update wlan handling to esp-idf 4.1
|
||||
|
||||
- Upgrade digital CNN to v8.7.0 (added new images)
|
||||
|
||||
- Bug fix: MQTT, WLAN, LED-Controll, GPIO usage, fixed IP, calculation flow rate
|
||||
|
||||
## [7.0.1] MQTT-Update - (2021-05-13)
|
||||
|
||||
### Changed
|
||||
|
||||
- NEW: 7.0.1: bug fix wlan password with "="
|
||||
|
||||
|
||||
- Upgrade digital CNN to v8.5.0 (added new images)
|
||||
|
||||
- New MQTT topics: flow rate (units/minute), time stamp (last correct read readout)
|
||||
|
||||
- Update MQTT/Error topic to " " in case no error (instead of empty string)
|
||||
|
||||
- Portrait or landscape image orientation in rotated image (avoid cropping)
|
||||
|
||||
## [6.7.2] Image Processing in Memory - (2021-05-01)
|
||||
|
||||
### Changed
|
||||
|
||||
- NEW 6.7.2: Updated html for setup modus - remove reboot on edit configuration)
|
||||
|
||||
|
||||
- NEW 6.7.1: Improved stability of camera (back to v6.6.1) - remove black strips and areas
|
||||
|
||||
- Upgrade digital CNN to v8.3.0 (added new type of digits)
|
||||
|
||||
- Internal update: TFlite (v2.5), esp32cam, startup sequence
|
||||
|
||||
- Rollback to espressif v2.1.0, as v3.2.0 shows unstable reboot
|
||||
|
||||
- Bugfix: WLan-passwords, reset of hostname
|
||||
|
||||
## [6.6.1] Image Processing in Memory - (2021-04-05)
|
||||
|
||||
### Changed
|
||||
|
||||
- NEW 6.6.1: failed SD card initialization indicated by fast blinking LED at startup
|
||||
|
||||
|
||||
- Improved SD-card handling (increase compatibility with more type of cards)
|
||||
|
||||
## [6.5.0] Image Processing in Memory - (2021-03-25)
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade digital CNN to v8.2.0 (added new type of digits)
|
||||
|
||||
|
||||
- Supporting alignment structures in ROI definition
|
||||
- Bug fixing: definition of hostname in `config.ini`
|
||||
|
||||
## [6.4.0] Image Processing in Memory - (2021-03-20)
|
||||
|
||||
### Changed
|
||||
|
||||
- Additional alignment marks for settings the ROIs (analog and digit)
|
||||
|
||||
|
||||
- Upgrade analog CNN to v7.0.0 (added new type of pointer)
|
||||
|
||||
## [6.3.1] Image Processing in Memory - (2021-03-16)
|
||||
|
||||
### Changed
|
||||
|
||||
- NEW: 6.3.1: bug fixing in initial edit reference image and `config.ini` (Spelling error in `InitialRotate`)
|
||||
|
||||
|
||||
- Initial setup mode: bug fixing, error correction
|
||||
- Bug-fixing
|
||||
|
||||
## [6.2.2] Image Processing in Memory - (2021-03-10)
|
||||
|
||||
### Changed
|
||||
|
||||
- NEW 6.2.2: bug fixing
|
||||
|
||||
|
||||
- NEW 6.2.1: Changed brightness and contrast to default if not enabled (resolves to bright images)
|
||||
|
||||
- Determination of fixed illumination settings during startup - speed up of 5s in each run
|
||||
|
||||
- Update digital CNN to v8.1.1 (additional digital images trained)
|
||||
|
||||
- Extended error message in MQTT error message
|
||||
|
||||
- Image brightness is now adjustable
|
||||
|
||||
- Bug fixing: minor topics
|
||||
|
||||
## [6.1.0] Image Processing in Memory - (2021-01-20)
|
||||
|
||||
### Changed
|
||||
|
||||
- Disabling of analog / digital counters in configuration
|
||||
|
||||
|
||||
- Improved Alignment Algorithm (`AlignmentAlgo` = `Default`, `Accurate` , `Fast`)
|
||||
- Analog counters: `ExtendedResolution` (last digit is extended by sub comma value of CNN)
|
||||
- `config.ini`: additional parameter `hostname` (additional to wlan.ini)
|
||||
- Switching of GPIO12/13 via http-interface: `/GPIO?GPIO=12&Status=high/low`
|
||||
- Bug fixing: html configuration page, wlan password ("=" now possible)
|
||||
|
||||
## [6.0.0] Image Processing in Memory - (2021-01-02)
|
||||
|
||||
### Changed
|
||||
|
||||
- **Major change**: image processing fully in memory - no need of SD card buffer anymore
|
||||
|
||||
- Need to limit camera resolution to VGA (due to memory limits)
|
||||
|
||||
|
||||
- MQTT: Last Will Testament (LWT) implemented: "connection lost" in case of connection lost to `TopicError`
|
||||
- Disabled `CheckDigitIncreaseConsistency` in default configuration - must now be explicit enabled if needed
|
||||
- Update digital CNN to v7.2.1 (additional digital images trained)
|
||||
- Setting of arbitrary time server in `config.ini`
|
||||
- Option for fixed IP-, DNS-Settings in `wlan.ini`
|
||||
- Increased stability (internal image and camera handling)
|
||||
- Bug fixing: edit digits, handling PreValue, html-bugs
|
||||
|
||||
## [5.0.0] Setup Modus - (2020-12-06)
|
||||
|
||||
### Changed
|
||||
|
||||
- Implementation of initial setup modus for fresh installation
|
||||
|
||||
|
||||
- Code restructuring (full compatibility between pure ESP-IDF and Platformio w/ espressif)
|
||||
|
||||
## [4.1.1] Configuration editor - (2020-12-02)
|
||||
|
||||
### Changed
|
||||
|
||||
- Bug fixing: internal improvement of file handling (reduce not responding)
|
||||
|
||||
## [4.1.0] Configuration editor - (2020-11-30)
|
||||
|
||||
### Changed
|
||||
|
||||
- Implementation of configuration editor (including basic and expert mode)
|
||||
|
||||
|
||||
- Adjustable time zone to adjust to local time setting (incl. daylight saving time)
|
||||
|
||||
- MQTT: additional topic for error reporting
|
||||
|
||||
- standardized access to current logfile via `http://IP-ADRESS/logfileact`
|
||||
|
||||
- Update digital CNN to v7.2.0, analog CNN to 6.3.0
|
||||
|
||||
- Bug fixing: truncation error, CheckDigitConsistency & PreValue implementation
|
||||
|
||||
## [4.0.0] Tflite Core - (2020-11-15)
|
||||
|
||||
### Changed
|
||||
|
||||
- Implementation of rolling log-files
|
||||
|
||||
|
||||
- Update Tflite-Core to master@20201108 (v2.4)
|
||||
|
||||
- Bug-fixing for reducing reboots
|
||||
|
||||
## [3.1.0] MQTT-Client - (2020-10-26)
|
||||
|
||||
### Changed
|
||||
|
||||
- Update digital CNN to v6.5.0 and HTML (Info to hostname, IP, ssid)
|
||||
|
||||
- New implementation of "checkDigitConsistency" also for digits
|
||||
|
||||
- MQTT-Adapter: user and password for sign in MQTT-Broker
|
||||
|
||||
## [3.0.0] MQTT-Client (2020-10-14)
|
||||
|
||||
### Changed
|
||||
|
||||
- Implementation of MQTT Client
|
||||
|
||||
|
||||
- Improved Version Control
|
||||
- bug-fixing
|
||||
|
||||
## [2.2.1] Version Control (2020-09-27)
|
||||
|
||||
### Changed
|
||||
|
||||
- Bug-Fixing (hostname in wlan.ini and error handling inside flow)
|
||||
|
||||
## \[2.2.0| Version Control (2020-09-27)
|
||||
|
||||
### Changed
|
||||
|
||||
- Integrated automated versioning system (menu: SYSTEM --> INFO)
|
||||
|
||||
|
||||
- Update Build-System to PlatformIO - Espressif 32 v2.0.0 (ESP-IDF 4.1)
|
||||
|
||||
## [2.1.0] Decimal Shift, Chrome & Edge (2020-09-25)
|
||||
|
||||
### Changed
|
||||
|
||||
- Implementation of Decimal Shift
|
||||
|
||||
|
||||
- Update default CNN for digits to v6.4.0
|
||||
|
||||
- Improvement HTML
|
||||
|
||||
- Support for Chrome and Edge
|
||||
|
||||
- Reduce logging to minimum - extended logging on demand
|
||||
|
||||
- Implementation of hostname in wlan.ini (`hostname = "HOSTNAME")`
|
||||
|
||||
- Bug fixing, code corrections
|
||||
|
||||
## [2.0.0] Layout update (2020-09-12)
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to **new and modern layout**
|
||||
- Support for Chrome improved
|
||||
- Improved robustness: improved error handling in auto flow reduces spontaneous reboots
|
||||
- File server: Option for "DELETE ALL"
|
||||
- WLan: support of spaces in SSID and password
|
||||
- Reference Image: Option for mirror image, option for image update on the fly
|
||||
- additional parameter in `wasserzaehler.html?noerror=true` to suppress an potential error message
|
||||
- bug fixing
|
||||
|
||||
## [1.1.3](2020-09-09)
|
||||
|
||||
### Changed
|
||||
|
||||
- **Bug in configuration of analog ROIs corrected** - correction in v.1.0.2 did not work properly
|
||||
|
||||
|
||||
- Improved update page for the web server (`/html` can be updated via a zip-file, which is provided in `/firmware/html.zip`)
|
||||
- Improved Chrome support
|
||||
|
||||
## [1.1.0](2020-09-06)
|
||||
|
||||
### Changed
|
||||
|
||||
- Implementation of "delete complete directory"
|
||||
**Attention: beside the `firmware.bin`, also the content of `/html` needs to be updated!**
|
||||
|
||||
## [1.0.2](2020-09-06)
|
||||
|
||||
### Changed
|
||||
|
||||
- Bug in configuration of analog ROIs corrected
|
||||
|
||||
|
||||
- minor bug correction
|
||||
|
||||
## [1.0.1](2020-09-05)
|
||||
|
||||
### Changed
|
||||
|
||||
- preValue.ini Bug corrected
|
||||
|
||||
|
||||
- minor bug correction
|
||||
|
||||
## [1.0.0](2020-09-04)
|
||||
|
||||
### Changed
|
||||
|
||||
- **First usable version** - compatible to previous project (<https://github.com/jomjol/water-meter-system-complete>)
|
||||
|
||||
|
||||
- NEW:
|
||||
- no docker container for CNN calculation necessary
|
||||
- web based configuration editor on board
|
||||
|
||||
## [0.1.0](2020-08-07)
|
||||
|
||||
### Changed
|
||||
|
||||
- Initial Version
|
||||
|
||||
[Unreleased]: https://github.com/jomjol/AI-on-the-edge-device/compare/12.0.1...HEAD
|
||||
|
||||
[12.0.1]: https://github.com/jomjol/AI-on-the-edge-device/compare/11.3.1...12.0.1
|
||||
|
||||
[11.4.3]: https://github.com/haverland/AI-on-the-edge-device/compare/10.6.2...11.4.3
|
||||
|
||||
[11.4.2]: https://github.com/haverland/AI-on-the-edge-device/compare/10.6.2...11.4.2
|
||||
|
||||
[11.3.9]: https://github.com/haverland/AI-on-the-edge-device/compare/10.6.2...11.3.9
|
||||
|
||||
@@ -11,6 +11,149 @@
|
||||
|
||||
____
|
||||
|
||||
#### #33 Implement MATTER protocoll
|
||||
|
||||
* see [#1404](https://github.com/jomjol/AI-on-the-edge-device/issues/1404)
|
||||
|
||||
#### #32 Add feature to correct misinterpreted value
|
||||
|
||||
* If a value is misinterpreted, the user can manually correct the value.
|
||||
* The misinterpreted ROIs would be saved in a "training data" -folder on the SD-card
|
||||
* Stretch goal: make sending of saved training data as easy as pushing a button =)
|
||||
|
||||
#### #31 Implement InfluxDB v2.x interface
|
||||
|
||||
* Currently only InfluxDB v1.x is supportet, extend to v2.x
|
||||
* Remark: interface has changed
|
||||
* see [#1160](https://github.com/jomjol/AI-on-the-edge-device/issues/1160)
|
||||
|
||||
#### #30 Support meter clock over
|
||||
|
||||
* In case of meter clocking over, that is, reaching its max. value and starting over from 0,
|
||||
accept the new value and calculate correctly the difference.
|
||||
(see line 739 onwards in ClassFlowPostProcessing.cpp)
|
||||
|
||||
#### ~~#29 Add favicon and use the hostname for the website~~- implemented v11.3.1
|
||||
|
||||
~~* https://github.com/jomjol/AI-on-the-edge-device/issues/927~~
|
||||
|
||||
#### #28 Improved error handling for ROIs
|
||||
|
||||
* In case a ROI is out of the image, there is no error message, but a non sense image is used
|
||||
* Implement a error message for wrong configuratioin of ROI
|
||||
|
||||
#### #27 Use Homie Spec for Mqtt binding
|
||||
|
||||
* Use the standardized Home Protocol for the Mqtt binding
|
||||
* https://homieiot.github.io/
|
||||
|
||||
#### #26 Changes behaviour for "N" replacement
|
||||
|
||||
* in case the higher digits has already increased by minium 1 - don't set the "N" to the last value, but to "0"
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/792
|
||||
|
||||
|
||||
#### #25 Trigger Measurement via MQTT
|
||||
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/727
|
||||
|
||||
|
||||
#### #24 Show Mqtt state directly in Webserver
|
||||
|
||||
* Show MQTT log in Web page. E.g. connection established or failed to connect...
|
||||
|
||||
|
||||
|
||||
|
||||
#### #23 CPU Temp and Mqtt values
|
||||
|
||||
* Show the CPU Temp directly in Webpage. Also add the value to MQTT sending
|
||||
|
||||
|
||||
|
||||
#### ~~#22 Direct hint to the different neural network files in the other repositories~~- implemented >v11.3.1
|
||||
|
||||
~~* https://github.com/jomjol/AI-on-the-edge-device/issues/644~~
|
||||
|
||||
|
||||
|
||||
#### #21 Extended "CheckDigitalConsistency" Logik
|
||||
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/590
|
||||
|
||||
|
||||
|
||||
#### #20 Deep sleep and push mode
|
||||
|
||||
* Let the device be normally in deep sleep state, and wake it up periodically to collect data and push it via MQTT or HTTP post.
|
||||
* Support ESP-NOW to reduce the overhead of connecting to wifi and mqtt
|
||||
* the above should enable battery powered applications
|
||||
|
||||
* An other way to set deep sleep would be to enable it in a specific period (at night).
|
||||
|
||||
|
||||
#### #19 Extended log informations
|
||||
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/580
|
||||
|
||||
|
||||
|
||||
#### ~~#18 Document WLAN-strength in web page~~
|
||||
|
||||
* ~~https://github.com/jomjol/AI-on-the-edge-device/issues/563~~
|
||||
|
||||
|
||||
|
||||
#### ~~#17 Direct InfluxDB connection~~
|
||||
|
||||
* ~~Done in v10.6.0~~
|
||||
|
||||
|
||||
#### #16 Serial Communication
|
||||
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/512
|
||||
* Send the readout value via RX/TX interface with a dedicated TAG
|
||||
* Make dedicated communication FlowModule
|
||||
* Modification of RX/TX communication
|
||||
* Configuration interfache
|
||||
|
||||
|
||||
#### #15 Calibration for FishEye image
|
||||
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/507
|
||||
|
||||
1. The development of such a correction algorithm with the libraries, that are available for the ESP32 environment.
|
||||
2. New module for integration of the flow into the image processing flow.
|
||||
3. Extension of the configuration (config.ini) and html-pages
|
||||
4. Parameter adjustment and testing for every different fish-eye module
|
||||
5. Maintenance for further updates / modules, ...
|
||||
|
||||
|
||||
|
||||
#### ~~#14 Backup and restore option for configuration~~- implemented v11.3.1
|
||||
|
||||
* ~~https://github.com/jomjol/AI-on-the-edge-device/issues/459~~
|
||||
|
||||
* ~~Implement a zip file compression for store and restore~~
|
||||
|
||||
* ~~Update the html to handle it~~
|
||||
|
||||
|
||||
|
||||
#### #13 Manage non linear gauge without CNN re-training
|
||||
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/443
|
||||
|
||||
* Implement a look up table for non linear analog meters
|
||||
|
||||
|
||||
|
||||
#### ~~#12 Less reboots due to memory leakage~~
|
||||
|
||||
* ~~Issue: #414 & #425 #430~~
|
||||
|
||||
|
||||
|
||||
#### #11 MQTT - configurable payload
|
||||
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/344
|
||||
@@ -126,4 +269,4 @@ ____
|
||||
|
||||
* ~~Implementation of a software module for external light source (e.g. WS8132 LED controller, ...)~~
|
||||
* ~~Update of the camera module to use the external light instead of the internal flash light~~
|
||||
* ~~Adopt the configuration algorithm with a configurable light source~~
|
||||
* ~~Adopt the configuration algorithm with a configurable light source~~
|
||||
|
||||
191
README.md
191
README.md
@@ -1,26 +1,75 @@
|
||||
# AI-on-the-edge-device
|
||||
# Welcome to the AI-on-the-edge-device
|
||||
<img src="images/icon/watermeter.svg" width="100px">
|
||||
|
||||
This is an example of Artificial Intelligence (AI) calculations on a very cheap hardware.
|
||||
Artificial intelligence based systems have been established in our every days live. Just think of speech or image recognition. Most of the systems relay on either powerful processors or a direct connection to the cloud for doing the calculations up there. With the increasing power of modern processors the AI systems are coming closer to the end user - which is usually called **edge computing**.
|
||||
Here this edge computing is brought into a practical oriented example, where a AI network is implemented on a ESP32 device so: **AI on the edge**.
|
||||
|
||||
### Details on **function**, **installation** and **configuration** can be found on the **[Wiki Page](https://github.com/jomjol/AI-on-the-edge-device/wiki)**
|
||||
This projects allows you to digitalize your **analoge** water, gas, power and other meters using cheap and easily available hardware.
|
||||
|
||||
A 3d-printable housing can be found here: https://www.thingiverse.com/thing:4573481
|
||||
All you need is an [ESP32 board with a supported camera](https://github.com/jomjol/AI-on-the-edge-device/wiki/Hardware-Compatibility) and a bit of a practical hand.
|
||||
|
||||
respectively ESP32-Cam housing only: https://www.thingiverse.com/thing:4571627
|
||||
<img src="images/esp32-cam.png" width="200px">
|
||||
|
||||
## Key features
|
||||
- **Small** and **cheap** device (3x4.5x2 cm³, < 10 EUR)
|
||||
- camera and illumination integrated
|
||||
- Web surface for administration and control
|
||||
- OTA-Interface to update directly through the web interface
|
||||
- API for easy integration
|
||||
- Inline Image processing (feature detection, alignment, ROI extraction)
|
||||
- Tensorflow Lite (TFlite) integration - including easy to use wrapper
|
||||
|
||||
## Workflow
|
||||
The device takes a photo of your meter at a defined interval. It then extracts the Regions of Interest (ROI's) out of it and runs them through an artificial inteligence. As a result, you get the digitalized value of your meter.
|
||||
|
||||
There are several options what to do with that value. Either send it to a MQTT broker, write it to an InfluxDb or simply provide it throug a REST API.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/idea.jpg" width="600">
|
||||
|
||||
## Impressions
|
||||
### AI-on-the-edge-device on a Water Meter
|
||||
<img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/watermeter_all.jpg" width="200"><img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/main.jpg" width="200"><img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/size.png" width="200">
|
||||
|
||||
### Web Interface (Water Meter)
|
||||
<img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/watermeter.jpg" width="600">
|
||||
|
||||
### AI-on-the-edge-device on a Electrical Power Meter
|
||||
<img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/powermeter.jpg" width="600">
|
||||
|
||||
|
||||
## Setup
|
||||
There is a growing [wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki) which provides you with a lot of information.
|
||||
Head there to get a start, set it up and configure it.
|
||||
|
||||
There are also a articles in the German Heise magazine "make:" about the setup and the technical background (behind a paywall) : [DIY - Setup](https://www.heise.de/select/make/2021/2/2103513300897420296)
|
||||
|
||||
For further background information, head to [Neural Networks](https://www.heise.de/select/make/2021/6/2126410443385102621), [Training Neural Networks](https://www.heise.de/select/make/2022/1/2134114065999161585) and [Programming on the ESP32](https://www.heise.de/select/make/2022/2/2204010051597422030)
|
||||
|
||||
### Download
|
||||
The latest available version is available on the [Releases page](https://github.com/jomjol/AI-on-the-edge-device/releases).
|
||||
|
||||
### Flashing of the ESP32
|
||||
Initially you will have to flash the ESP32 through an USB connection. Later an update is possible directly over the Air (OTA).
|
||||
|
||||
There are different ways to flash your ESP32:
|
||||
- [Web Installer and Console](https://jomjol.github.io/AI-on-the-edge-device/index.html) (Webbrowser based tool to flash the ESP32 and extract the Log over USB)
|
||||
- Flash Tool from Espressif
|
||||
- ESPtool (Command Line Tool)
|
||||
|
||||
See the [Wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/Installation) for more information.
|
||||
|
||||
## Casing
|
||||
|
||||
A 3d-printable housing can be found here:
|
||||
- https://www.thingiverse.com/thing:4573481 (Water Meter)
|
||||
- https://www.thingiverse.com/thing:5028229 (Power Meter)
|
||||
- https://www.thingiverse.com/thing:5224101 (Gas Meter)
|
||||
- https://www.thingiverse.com/thing:4571627 (ESP32-Cam housing only)
|
||||
|
||||
## Build it yourself
|
||||
See [Build Instructions](code/README.md).
|
||||
|
||||
## Donate
|
||||
|
||||
------
|
||||
|
||||
If you would like to support the developer with a cup of coffee you can do that via [Paypal](https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL).
|
||||
|
||||
<form action="https://www.paypal.com/donate" method="post" target="_top">
|
||||
@@ -28,124 +77,20 @@ If you would like to support the developer with a cup of coffee you can do that
|
||||
<input type="image" src="https://www.paypalobjects.com/en_US/DK/i/btn/btn_donateCC_LG.gif" border="0" name="submit" title="PayPal - The safer, easier way to pay online!" alt="Donate with PayPal button" />
|
||||
<img alt="" border="0" src="https://www.paypal.com/en_DE/i/scr/pixel.gif" width="1" height="1" />
|
||||
</form>
|
||||
If you have any technical topics, you can file a issue in this repository.
|
||||
If you have any technical topics, you can create an [Issue](https://github.com/jomjol/AI-on-the-edge-device/issues).
|
||||
|
||||
In other cases you can contact the developer via email: <img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/mail.jpg" height="25">
|
||||
|
||||
## Change log
|
||||
## Changes and History
|
||||
See [Changelog](Changelog.md)
|
||||
|
||||
## Tools
|
||||
|
||||
* Logfile downloader and combiner (Thx to [reserve85](https://github.com/reserve85))
|
||||
* Files see ['/tools/logfile-tool'](tbd), How-to see [wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/Gasmeter-Log-Downloader)
|
||||
|
||||
## Additional Ideas
|
||||
There are some ideas and feature requests which are not followed currently - mainly due to capacity reasons on side of the developer. They are collected here: [FeatureRequest.md](FeatureRequest.md)
|
||||
|
||||
------
|
||||
|
||||
### Known Issues
|
||||
|
||||
* slow response of web server during picture analysis
|
||||
* spontaneous reboots (mostly due to html access during image processing) - self recovery implemented
|
||||
|
||||
------
|
||||
|
||||
**General remark:** Beside the `firmware.bin`, typically also the content of `/html` needs to be updated!
|
||||
|
||||
|
||||
|
||||
##### 8.5.0 - Multi Meter Support (2021-10-07)
|
||||
|
||||
* Upgrade digital CNN to v13.1.0 (added new images)
|
||||
* bug fix: wlan password with space, double digit output
|
||||
|
||||
##### 8.4.0 - Multi Meter Support (2021-09-25)
|
||||
|
||||
* License change (remove MIT license, remark see below)
|
||||
|
||||
* html: show hostname in title and main page
|
||||
|
||||
* configuration:
|
||||
|
||||
* moved setting `ExtendedResolution` to individual number settings
|
||||
* New parameter `IgnoreLeadingNaN` (delete leading NaN's specifically)
|
||||
* **ATTENTION**: update of the `config.ini` needed (open, adjust `ExtendedResolution`, save)
|
||||
|
||||
* Bug fixing (html, images of recognized numbers)
|
||||
|
||||
|
||||
|
||||
### **ATTENTION: LICENSE CHANGE - removal of MIT License.**
|
||||
|
||||
- Currently no licence published - copyright belongs to author
|
||||
- If you are interested in a commercial usage or dedicated versions please contact the developer
|
||||
- no limits to private usage
|
||||
|
||||
|
||||
|
||||
##### 8.3.0 - Multi Meter Support (2021-09-12)
|
||||
|
||||
* Upgrade digital CNN to v12.1.0 (added new images)
|
||||
* Dedicated NaN handling, internal refactoring (CNN-Handling)
|
||||
* HTML: confirmation after config.ini update
|
||||
* Bug fixing
|
||||
|
||||
##### 8.2.0 - Multi Meter Support (2021-08-24)
|
||||
|
||||
* Improve server responsiveness
|
||||
* Flow status and prevalue status in overview
|
||||
* Improved prevalue handling
|
||||
|
||||
##### 8.1.0 - Multi Meter Support (2021-08-12)
|
||||
|
||||
* GPIO: using the general mqtt main topic for GPIO
|
||||
|
||||
* Upgrade digital CNN to v12.0.0 (added new images)
|
||||
* Update tfmicro to new master (2021-08-07)
|
||||
* Bug fix: remove text in mqtt value, remove connect limit in wlan reconnet
|
||||
|
||||
##### 8.0.5 - Multi Meter Support (2021-08-01)
|
||||
|
||||
* NEW 8.0.5: bug fix: saving prevalue
|
||||
* NEW 8.0.4: bug fix: load config.ini after upgrade
|
||||
* NEW 8.0.3: bug fix: reboot during `config.ini` handling, html error
|
||||
* NEW 8.0.2: saving roundes prevalue, bug fix html server
|
||||
* NEW 8.0.1: bug fix: html handling of parameter `FixedExposure` and `ImageSize`
|
||||
* Dual / multi meter support (more than 1 number to be recognized)
|
||||
This is implemented with the feature "number" on the ROI definition as well as selected options
|
||||
* MQTT: standardization of the naming - including new topics (`json`, `freeMem `, `uptime`)c
|
||||
* Preparation for extended GPIO support (thanks to Zwerk2k) - not tested and fully functional yet
|
||||
* Bug fixing: html server, memory leak, MQTT connect, hostname, turn of flash LED
|
||||
|
||||
<span style="color: red;">**ATTENTION: the configuration and prevalue files are modified automatically and will not be backward compatible!**</span>
|
||||
|
||||
|
||||
## Additional ideas
|
||||
|
||||
There are some ideas and feature request, which are not followed currently - mainly due to capacity reasons on side of the developer. They are collected here: [FeatureRequest.md](FeatureRequest.md)
|
||||
|
||||
|
||||
|
||||
------
|
||||
|
||||
## History
|
||||
|
||||
##### 7.1.2 MQTT-Update - (2021-06-17)
|
||||
|
||||
**7.0.1 MQTT-Update - (2021-05-13)**
|
||||
|
||||
##### 6.7.2 Image Processing in Memory - (2021-05-01)
|
||||
|
||||
##### 5.0.0 Setup Modus - (2020-12-06)
|
||||
|
||||
##### 4.1.1 Configuration editor - (2020-12-02)
|
||||
|
||||
##### 4.0.0 Tflite Core - (2020-11-15)
|
||||
##### 3.1.0 MQTT-Client - (2020-10-26)
|
||||
|
||||
##### 2.2.1 Version Control - (2020-09-27)
|
||||
|
||||
|
||||
##### 2.1.0 Decimal Shift, Chrome & Edge - (2020-09-25)
|
||||
|
||||
|
||||
##### 2.0.0 Layout update - (2020-09-12)
|
||||
|
||||
##### 1.1.3 Initial Version - (2020-09-09)
|
||||
|
||||
|
||||
#### [Full Changelog](Changelog.md)
|
||||
|
||||
|
||||
2
code/.gitignore
vendored
2
code/.gitignore
vendored
@@ -3,3 +3,5 @@
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
version.cpp
|
||||
sdkconfig.esp32cam
|
||||
|
||||
@@ -1 +1 @@
|
||||
powershell Compress-Archive "..\..\sd-card\html\*.*" "..\..\firmware\html.zip"
|
||||
powershell Compress-Archive -Path "..\..\sd-card\html\*.*" -DestinationPath "..\..\firmware\html.zip"
|
||||
@@ -1,8 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.13.4)
|
||||
|
||||
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
||||
|
||||
set(PROJECT_VER "0.0.9.3")
|
||||
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common components/tflite-micro-esp-examples/components/tflite-lib)
|
||||
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/version.cpp
|
||||
|
||||
62
code/README.md
Normal file
62
code/README.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Build
|
||||
|
||||
## Preparations
|
||||
```
|
||||
git clone https://github.com/jomjol/AI-on-the-edge-device.git
|
||||
cd AI-on-the-edge-device
|
||||
git checkout rolling
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
## Build and Flash within terminal
|
||||
See further down to build it within an IDE.
|
||||
### Compile
|
||||
```
|
||||
cd code
|
||||
platformio run --environment esp32cam
|
||||
```
|
||||
|
||||
### Upload
|
||||
```
|
||||
pio run --target upload --upload-port /dev/ttyUSB0
|
||||
```
|
||||
|
||||
Alternatively you also can set the UART device in `platformio.ini`, eg. `upload_port = /dev/ttyUSB0`
|
||||
|
||||
### Monitor UART Log
|
||||
```
|
||||
pio device monitor -p /dev/ttyUSB0
|
||||
```
|
||||
|
||||
## Build and Flash with Visual Code IDE
|
||||
|
||||
- Download and install VS Code
|
||||
- https://code.visualstudio.com/Download
|
||||
- Install the VS Code platform io plugin
|
||||
- <img src="https://raw.githubusercontent.com/jomjol/ai-on-the-edge-device/master/images/platformio_plugin.jpg" width="200" align="middle">
|
||||
- Check for error messages, maybe you need to manually add some python libraries
|
||||
- e.g. in my Ubuntu a python3-env was missing: `sudo apt-get install python3-venv`
|
||||
- git clone this project
|
||||
- in Linux:
|
||||
|
||||
```
|
||||
git clone https://github.com/jomjol/AI-on-the-edge-device.git
|
||||
cd AI-on-the-edge-device
|
||||
git checkout rolling
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
- in VS code, open the `AI-on-the-edge-device/code`
|
||||
- from terminal: `cd AI-on-the-edge-device/code && code .`
|
||||
- open a pio terminal (click on the terminal sign in the bottom menu bar)
|
||||
- make sure you are in the `code` directory
|
||||
- To build, type `platformio run --environment esp32cam`
|
||||
- or use the graphical interface:
|
||||
<img src="https://raw.githubusercontent.com/jomjol/ai-on-the-edge-device/master/images/platformio_build.jpg" width="200" align="middle">
|
||||
- the build artifacts are stored in `code/.pio/build/esp32cam/`
|
||||
- Connect the device and type `pio device monitor`. There you will see your device and can copy the name to the next instruction
|
||||
- Add `upload_port = you_device_port` to the `platformio.ini` file
|
||||
- make sure an sd card with the contents of the `sd_card` folder is inserted and you have changed the wifi details
|
||||
- `pio run --target erase` to erase the flash
|
||||
- `pio run --target upload` this will upload the `bootloader.bin, partitions.bin,firmware.bin` from the `code/.pio/build/esp32cam/` folder.
|
||||
- `pio device monitor` to observe the logs via uart
|
||||
@@ -1,63 +0,0 @@
|
||||
#include "SmartLeds.h"
|
||||
|
||||
IsrCore SmartLed::_interruptCore = CoreCurrent;
|
||||
intr_handle_t SmartLed::_interruptHandle = NULL;
|
||||
|
||||
SmartLed*& IRAM_ATTR SmartLed::ledForChannel( int channel ) {
|
||||
static SmartLed* table[8] = { nullptr };
|
||||
assert( channel < 8 );
|
||||
return table[ channel ];
|
||||
}
|
||||
|
||||
void IRAM_ATTR SmartLed::interruptHandler(void*) {
|
||||
for (int channel = 0; channel != 8; channel++) {
|
||||
auto self = ledForChannel( channel );
|
||||
|
||||
if ( RMT.int_st.val & (1 << (24 + channel ) ) ) { // tx_thr_event
|
||||
if ( self )
|
||||
self->copyRmtHalfBlock();
|
||||
RMT.int_clr.val |= 1 << ( 24 + channel );
|
||||
} else if ( RMT.int_st.val & ( 1 << (3 * channel ) ) ) { // tx_end
|
||||
if ( self )
|
||||
xSemaphoreGiveFromISR( self->_finishedFlag, nullptr );
|
||||
RMT.int_clr.val |= 1 << ( 3 * channel );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR SmartLed::copyRmtHalfBlock() {
|
||||
int offset = detail::MAX_PULSES * _halfIdx;
|
||||
_halfIdx = !_halfIdx;
|
||||
int len = 3 - _componentPosition + 3 * ( _count - 1 );
|
||||
len = std::min( len, detail::MAX_PULSES / 8 );
|
||||
|
||||
if ( !len ) {
|
||||
for ( int i = 0; i < detail::MAX_PULSES; i++) {
|
||||
RMTMEM.chan[ _channel].data32[i + offset ].val = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int i;
|
||||
for ( i = 0; i != len && _pixelPosition != _count; i++ ) {
|
||||
uint8_t val = _buffer[ _pixelPosition ].getGrb( _componentPosition );
|
||||
for ( int j = 0; j != 8; j++, val <<= 1 ) {
|
||||
int bit = val >> 7;
|
||||
int idx = i * 8 + offset + j;
|
||||
RMTMEM.chan[ _channel ].data32[ idx ].val = _bitToRmt[ bit & 0x01 ].value;
|
||||
}
|
||||
if ( _pixelPosition == _count - 1 && _componentPosition == 2 ) {
|
||||
RMTMEM.chan[ _channel ].data32[ i * 8 + offset + 7 ].duration1 =
|
||||
_timing.TRS / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
}
|
||||
|
||||
_componentPosition++;
|
||||
if ( _componentPosition == 3 ) {
|
||||
_componentPosition = 0;
|
||||
_pixelPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
for ( i *= 8; i != detail::MAX_PULSES; i++ ) {
|
||||
RMTMEM.chan[ _channel ].data32[ i + offset ].val = 0;
|
||||
}
|
||||
}
|
||||
530
code/SmartLeds.h
530
code/SmartLeds.h
@@ -1,530 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* A C++ driver for the WS2812 LEDs using the RMT peripheral on the ESP32.
|
||||
*
|
||||
* Jan "yaqwsx" Mrázek <email@honzamrazek.cz>
|
||||
*
|
||||
* Based on the work by Martin F. Falatic - https://github.com/FozzTexx/ws2812-demo
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#if defined ( ARDUINO )
|
||||
extern "C" { // ...someone forgot to put in the includes...
|
||||
#include "esp32-hal.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_ipc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "soc/rmt_struct.h"
|
||||
#include <driver/spi_master.h>
|
||||
#include "esp_idf_version.h"
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 )
|
||||
#include "soc/dport_reg.h"
|
||||
#endif
|
||||
}
|
||||
#elif defined ( ESP_PLATFORM )
|
||||
extern "C" { // ...someone forgot to put in the includes...
|
||||
#include <esp_intr_alloc.h>
|
||||
#include <esp_ipc.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <soc/dport_reg.h>
|
||||
#include <soc/gpio_sig_map.h>
|
||||
#include <soc/rmt_struct.h>
|
||||
#include <driver/spi_master.h>
|
||||
}
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "Color.h"
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct TimingParams {
|
||||
uint32_t T0H;
|
||||
uint32_t T1H;
|
||||
uint32_t T0L;
|
||||
uint32_t T1L;
|
||||
uint32_t TRS;
|
||||
};
|
||||
|
||||
union RmtPulsePair {
|
||||
struct {
|
||||
int duration0:15;
|
||||
int level0:1;
|
||||
int duration1:15;
|
||||
int level1:1;
|
||||
};
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
static const int DIVIDER = 4; // 8 still seems to work, but timings become marginal
|
||||
static const int MAX_PULSES = 32; // A channel has a 64 "pulse" buffer - we use half per pass
|
||||
static const double RMT_DURATION_NS = 12.5; // minimum time of a single RMT duration based on clock ns
|
||||
|
||||
} // namespace detail
|
||||
|
||||
using LedType = detail::TimingParams;
|
||||
|
||||
static const LedType LED_WS2812 = { 350, 700, 800, 600, 50000 };
|
||||
static const LedType LED_WS2812B = { 400, 850, 850, 400, 50100 };
|
||||
static const LedType LED_SK6812 = { 300, 600, 900, 600, 80000 };
|
||||
static const LedType LED_WS2813 = { 350, 800, 350, 350, 300000 };
|
||||
|
||||
enum BufferType { SingleBuffer = 0, DoubleBuffer };
|
||||
|
||||
enum IsrCore { CoreFirst = 0, CoreSecond = 1, CoreCurrent = 2};
|
||||
|
||||
class SmartLed {
|
||||
public:
|
||||
// The RMT interrupt must not run on the same core as WiFi interrupts, otherwise SmartLeds
|
||||
// can't fill the RMT buffer fast enough, resulting in rendering artifacts.
|
||||
// Usually, that means you have to set isrCore == CoreSecond.
|
||||
//
|
||||
// If you use anything other than CoreCurrent, the FreeRTOS scheduler MUST be already running,
|
||||
// so you can't use it if you define SmartLed as global variable.
|
||||
SmartLed( const LedType& type, int count, int pin, int channel = 0, BufferType doubleBuffer = SingleBuffer, IsrCore isrCore = CoreCurrent)
|
||||
: _timing( type ),
|
||||
_channel( channel ),
|
||||
_count( count ),
|
||||
_firstBuffer( new Rgb[ count ] ),
|
||||
_secondBuffer( doubleBuffer ? new Rgb[ count ] : nullptr ),
|
||||
_finishedFlag( xSemaphoreCreateBinary() )
|
||||
{
|
||||
assert( channel >= 0 && channel < 8 );
|
||||
assert( ledForChannel( channel ) == nullptr );
|
||||
|
||||
xSemaphoreGive( _finishedFlag );
|
||||
|
||||
DPORT_SET_PERI_REG_MASK( DPORT_PERIP_CLK_EN_REG, DPORT_RMT_CLK_EN );
|
||||
DPORT_CLEAR_PERI_REG_MASK( DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST );
|
||||
|
||||
PIN_FUNC_SELECT( GPIO_PIN_MUX_REG[ pin ], 2 );
|
||||
gpio_set_direction( static_cast< gpio_num_t >( pin ), GPIO_MODE_OUTPUT );
|
||||
gpio_matrix_out( static_cast< gpio_num_t >( pin ), RMT_SIG_OUT0_IDX + _channel, 0, 0 );
|
||||
initChannel( _channel );
|
||||
|
||||
RMT.tx_lim_ch[ _channel ].limit = detail::MAX_PULSES;
|
||||
RMT.int_ena.val |= 1 << ( 24 + _channel );
|
||||
RMT.int_ena.val |= 1 << ( 3 * _channel );
|
||||
|
||||
_bitToRmt[ 0 ].level0 = 1;
|
||||
_bitToRmt[ 0 ].level1 = 0;
|
||||
_bitToRmt[ 0 ].duration0 = _timing.T0H / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
_bitToRmt[ 0 ].duration1 = _timing.T0L / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
|
||||
_bitToRmt[ 1 ].level0 = 1;
|
||||
_bitToRmt[ 1 ].level1 = 0;
|
||||
_bitToRmt[ 1 ].duration0 = _timing.T1H / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
_bitToRmt[ 1 ].duration1 = _timing.T1L / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
|
||||
if ( !anyAlive() ) {
|
||||
_interruptCore = isrCore;
|
||||
if(isrCore != CoreCurrent) {
|
||||
ESP_ERROR_CHECK(esp_ipc_call_blocking(isrCore, registerInterrupt, NULL));
|
||||
} else {
|
||||
registerInterrupt(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
ledForChannel( channel ) = this;
|
||||
}
|
||||
|
||||
~SmartLed() {
|
||||
ledForChannel( _channel ) = nullptr;
|
||||
if ( !anyAlive() ) {
|
||||
if(_interruptCore != CoreCurrent) {
|
||||
ESP_ERROR_CHECK(esp_ipc_call_blocking(_interruptCore, unregisterInterrupt, NULL));
|
||||
} else {
|
||||
unregisterInterrupt(NULL);
|
||||
}
|
||||
}
|
||||
vSemaphoreDelete( _finishedFlag );
|
||||
}
|
||||
|
||||
Rgb& operator[]( int idx ) {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
|
||||
const Rgb& operator[]( int idx ) const {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
|
||||
void show() {
|
||||
_buffer = _firstBuffer.get();
|
||||
startTransmission();
|
||||
swapBuffers();
|
||||
}
|
||||
|
||||
bool wait( TickType_t timeout = portMAX_DELAY ) {
|
||||
if( xSemaphoreTake( _finishedFlag, timeout ) == pdTRUE ) {
|
||||
xSemaphoreGive( _finishedFlag );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int size() const {
|
||||
return _count;
|
||||
}
|
||||
|
||||
Rgb *begin() { return _firstBuffer.get(); }
|
||||
const Rgb *begin() const { return _firstBuffer.get(); }
|
||||
const Rgb *cbegin() const { return _firstBuffer.get(); }
|
||||
|
||||
Rgb *end() { return _firstBuffer.get() + _count; }
|
||||
const Rgb *end() const { return _firstBuffer.get() + _count; }
|
||||
const Rgb *cend() const { return _firstBuffer.get() + _count; }
|
||||
|
||||
private:
|
||||
static intr_handle_t _interruptHandle;
|
||||
static IsrCore _interruptCore;
|
||||
|
||||
static void initChannel( int channel ) {
|
||||
RMT.apb_conf.fifo_mask = 1; //enable memory access, instead of FIFO mode.
|
||||
RMT.apb_conf.mem_tx_wrap_en = 1; //wrap around when hitting end of buffer
|
||||
RMT.conf_ch[ channel ].conf0.div_cnt = detail::DIVIDER;
|
||||
RMT.conf_ch[ channel ].conf0.mem_size = 1;
|
||||
RMT.conf_ch[ channel ].conf0.carrier_en = 0;
|
||||
RMT.conf_ch[ channel ].conf0.carrier_out_lv = 1;
|
||||
RMT.conf_ch[ channel ].conf0.mem_pd = 0;
|
||||
|
||||
RMT.conf_ch[ channel ].conf1.rx_en = 0;
|
||||
RMT.conf_ch[ channel ].conf1.mem_owner = 0;
|
||||
RMT.conf_ch[ channel ].conf1.tx_conti_mode = 0; //loop back mode.
|
||||
RMT.conf_ch[ channel ].conf1.ref_always_on = 1; // use apb clock: 80M
|
||||
RMT.conf_ch[ channel ].conf1.idle_out_en = 1;
|
||||
RMT.conf_ch[ channel ].conf1.idle_out_lv = 0;
|
||||
}
|
||||
|
||||
static void registerInterrupt(void *) {
|
||||
ESP_ERROR_CHECK(esp_intr_alloc( ETS_RMT_INTR_SOURCE, 0, interruptHandler, nullptr, &_interruptHandle));
|
||||
}
|
||||
|
||||
static void unregisterInterrupt(void*) {
|
||||
esp_intr_free( _interruptHandle );
|
||||
}
|
||||
|
||||
static SmartLed*& IRAM_ATTR ledForChannel( int channel );
|
||||
static void IRAM_ATTR interruptHandler( void* );
|
||||
|
||||
void IRAM_ATTR copyRmtHalfBlock();
|
||||
|
||||
void swapBuffers() {
|
||||
if ( _secondBuffer )
|
||||
_firstBuffer.swap( _secondBuffer );
|
||||
}
|
||||
|
||||
void startTransmission() {
|
||||
// Invalid use of the library
|
||||
if( xSemaphoreTake( _finishedFlag, 0 ) != pdTRUE )
|
||||
abort();
|
||||
|
||||
_pixelPosition = _componentPosition = _halfIdx = 0;
|
||||
copyRmtHalfBlock();
|
||||
if ( _pixelPosition < _count )
|
||||
copyRmtHalfBlock();
|
||||
|
||||
RMT.conf_ch[ _channel ].conf1.mem_rd_rst = 1;
|
||||
RMT.conf_ch[ _channel ].conf1.tx_start = 1;
|
||||
}
|
||||
|
||||
static bool anyAlive() {
|
||||
for ( int i = 0; i != 8; i++ )
|
||||
if ( ledForChannel( i ) != nullptr ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const LedType& _timing;
|
||||
int _channel;
|
||||
detail::RmtPulsePair _bitToRmt[ 2 ];
|
||||
int _count;
|
||||
std::unique_ptr< Rgb[] > _firstBuffer;
|
||||
std::unique_ptr< Rgb[] > _secondBuffer;
|
||||
Rgb *_buffer;
|
||||
|
||||
xSemaphoreHandle _finishedFlag;
|
||||
|
||||
int _pixelPosition;
|
||||
int _componentPosition;
|
||||
int _halfIdx;
|
||||
};
|
||||
|
||||
class Apa102 {
|
||||
public:
|
||||
struct ApaRgb {
|
||||
ApaRgb( uint8_t r = 0, uint8_t g = 0, uint32_t b = 0, uint32_t v = 0xFF )
|
||||
: v( 0xE0 | v ), b( b ), g( g ), r( r )
|
||||
{}
|
||||
|
||||
ApaRgb& operator=( const Rgb& o ) {
|
||||
r = o.r;
|
||||
g = o.g;
|
||||
b = o.b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ApaRgb& operator=( const Hsv& o ) {
|
||||
*this = Rgb{ o };
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint8_t v, b, g, r;
|
||||
};
|
||||
|
||||
static const int FINAL_FRAME_SIZE = 4;
|
||||
static const int TRANS_COUNT = 2 + 8;
|
||||
|
||||
Apa102( int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer )
|
||||
: _count( count ),
|
||||
_firstBuffer( new ApaRgb[ count ] ),
|
||||
_secondBuffer( doubleBuffer ? new ApaRgb[ count ] : nullptr ),
|
||||
_initFrame( 0 )
|
||||
{
|
||||
spi_bus_config_t buscfg;
|
||||
memset( &buscfg, 0, sizeof( buscfg ) );
|
||||
buscfg.mosi_io_num = datapin;
|
||||
buscfg.miso_io_num = -1;
|
||||
buscfg.sclk_io_num = clkpin;
|
||||
buscfg.quadwp_io_num = -1;
|
||||
buscfg.quadhd_io_num = -1;
|
||||
buscfg.max_transfer_sz = 65535;
|
||||
|
||||
spi_device_interface_config_t devcfg;
|
||||
memset( &devcfg, 0, sizeof( devcfg ) );
|
||||
devcfg.clock_speed_hz = 1000000;
|
||||
devcfg.mode = 0;
|
||||
devcfg.spics_io_num = -1;
|
||||
devcfg.queue_size = TRANS_COUNT;
|
||||
devcfg.pre_cb = nullptr;
|
||||
|
||||
auto ret = spi_bus_initialize( HSPI_HOST, &buscfg, 1 );
|
||||
assert( ret == ESP_OK );
|
||||
|
||||
ret = spi_bus_add_device( HSPI_HOST, &devcfg, &_spi );
|
||||
assert( ret == ESP_OK );
|
||||
|
||||
std::fill_n( _finalFrame, FINAL_FRAME_SIZE, 0xFFFFFFFF );
|
||||
}
|
||||
|
||||
~Apa102() {
|
||||
// ToDo
|
||||
}
|
||||
|
||||
ApaRgb& operator[]( int idx ) {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
|
||||
const ApaRgb& operator[]( int idx ) const {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
|
||||
void show() {
|
||||
_buffer = _firstBuffer.get();
|
||||
startTransmission();
|
||||
swapBuffers();
|
||||
}
|
||||
|
||||
void wait() {
|
||||
for ( int i = 0; i != _transCount; i++ ) {
|
||||
spi_transaction_t *t;
|
||||
spi_device_get_trans_result( _spi, &t, portMAX_DELAY );
|
||||
}
|
||||
}
|
||||
private:
|
||||
void swapBuffers() {
|
||||
if ( _secondBuffer )
|
||||
_firstBuffer.swap( _secondBuffer );
|
||||
}
|
||||
|
||||
void startTransmission() {
|
||||
for ( int i = 0; i != TRANS_COUNT; i++ ) {
|
||||
_transactions[ i ].cmd = 0;
|
||||
_transactions[ i ].addr = 0;
|
||||
_transactions[ i ].flags = 0;
|
||||
_transactions[ i ].rxlength = 0;
|
||||
_transactions[ i ].rx_buffer = nullptr;
|
||||
}
|
||||
// Init frame
|
||||
_transactions[ 0 ].length = 32;
|
||||
_transactions[ 0 ].tx_buffer = &_initFrame;
|
||||
spi_device_queue_trans( _spi, _transactions + 0, portMAX_DELAY );
|
||||
// Data
|
||||
_transactions[ 1 ].length = 32 * _count;
|
||||
_transactions[ 1 ].tx_buffer = _buffer;
|
||||
spi_device_queue_trans( _spi, _transactions + 1, portMAX_DELAY );
|
||||
_transCount = 2;
|
||||
// End frame
|
||||
for ( int i = 0; i != 1 + _count / 32 / FINAL_FRAME_SIZE; i++ ) {
|
||||
_transactions[ 2 + i ].length = 32 * FINAL_FRAME_SIZE;
|
||||
_transactions[ 2 + i ].tx_buffer = _finalFrame;
|
||||
spi_device_queue_trans( _spi, _transactions + 2 + i, portMAX_DELAY );
|
||||
_transCount++;
|
||||
}
|
||||
}
|
||||
|
||||
spi_device_handle_t _spi;
|
||||
int _count;
|
||||
std::unique_ptr< ApaRgb[] > _firstBuffer, _secondBuffer;
|
||||
ApaRgb *_buffer;
|
||||
|
||||
spi_transaction_t _transactions[ TRANS_COUNT ];
|
||||
int _transCount;
|
||||
|
||||
uint32_t _initFrame;
|
||||
uint32_t _finalFrame[ FINAL_FRAME_SIZE ];
|
||||
};
|
||||
|
||||
class LDP8806 {
|
||||
public:
|
||||
struct LDP8806_GRB {
|
||||
|
||||
LDP8806_GRB( uint8_t g_7bit = 0, uint8_t r_7bit = 0, uint32_t b_7bit = 0 )
|
||||
: g( g_7bit ), r( r_7bit ), b( b_7bit )
|
||||
{
|
||||
}
|
||||
|
||||
LDP8806_GRB& operator=( const Rgb& o ) {
|
||||
//Convert 8->7bit colour
|
||||
r = ( o.r * 127 / 256 ) | 0x80;
|
||||
g = ( o.g * 127 / 256 ) | 0x80;
|
||||
b = ( o.b * 127 / 256 ) | 0x80;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LDP8806_GRB& operator=( const Hsv& o ) {
|
||||
*this = Rgb{ o };
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint8_t g, r, b;
|
||||
};
|
||||
|
||||
static const int LED_FRAME_SIZE_BYTES = sizeof( LDP8806_GRB );
|
||||
static const int LATCH_FRAME_SIZE_BYTES = 3;
|
||||
static const int TRANS_COUNT_MAX = 20;//Arbitrary, supports up to 600 LED
|
||||
|
||||
LDP8806( int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer, uint32_t clock_speed_hz = 2000000 )
|
||||
: _count( count ),
|
||||
_firstBuffer( new LDP8806_GRB[ count ] ),
|
||||
_secondBuffer( doubleBuffer ? new LDP8806_GRB[ count ] : nullptr ),
|
||||
// one 'latch'/start-of-data mark frame for every 32 leds
|
||||
_latchFrames( ( count + 31 ) / 32 )
|
||||
{
|
||||
spi_bus_config_t buscfg;
|
||||
memset( &buscfg, 0, sizeof( buscfg ) );
|
||||
buscfg.mosi_io_num = datapin;
|
||||
buscfg.miso_io_num = -1;
|
||||
buscfg.sclk_io_num = clkpin;
|
||||
buscfg.quadwp_io_num = -1;
|
||||
buscfg.quadhd_io_num = -1;
|
||||
buscfg.max_transfer_sz = 65535;
|
||||
|
||||
spi_device_interface_config_t devcfg;
|
||||
memset( &devcfg, 0, sizeof( devcfg ) );
|
||||
devcfg.clock_speed_hz = clock_speed_hz;
|
||||
devcfg.mode = 0;
|
||||
devcfg.spics_io_num = -1;
|
||||
devcfg.queue_size = TRANS_COUNT_MAX;
|
||||
devcfg.pre_cb = nullptr;
|
||||
|
||||
auto ret = spi_bus_initialize( HSPI_HOST, &buscfg, 1 );
|
||||
assert( ret == ESP_OK );
|
||||
|
||||
ret = spi_bus_add_device( HSPI_HOST, &devcfg, &_spi );
|
||||
assert( ret == ESP_OK );
|
||||
|
||||
std::fill_n( _latchBuffer, LATCH_FRAME_SIZE_BYTES, 0x0 );
|
||||
}
|
||||
|
||||
~LDP8806() {
|
||||
// noop
|
||||
}
|
||||
|
||||
LDP8806_GRB& operator[]( int idx ) {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
|
||||
const LDP8806_GRB& operator[]( int idx ) const {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
|
||||
void show() {
|
||||
_buffer = _firstBuffer.get();
|
||||
startTransmission();
|
||||
swapBuffers();
|
||||
}
|
||||
|
||||
void wait() {
|
||||
while ( _transCount-- ) {
|
||||
spi_transaction_t *t;
|
||||
spi_device_get_trans_result( _spi, &t, portMAX_DELAY );
|
||||
}
|
||||
}
|
||||
private:
|
||||
void swapBuffers() {
|
||||
if ( _secondBuffer )
|
||||
_firstBuffer.swap( _secondBuffer );
|
||||
}
|
||||
|
||||
void startTransmission() {
|
||||
_transCount = 0;
|
||||
for ( int i = 0; i != TRANS_COUNT_MAX; i++ ) {
|
||||
_transactions[ i ].cmd = 0;
|
||||
_transactions[ i ].addr = 0;
|
||||
_transactions[ i ].flags = 0;
|
||||
_transactions[ i ].rxlength = 0;
|
||||
_transactions[ i ].rx_buffer = nullptr;
|
||||
}
|
||||
// LED Data
|
||||
_transactions[ 0 ].length = ( LED_FRAME_SIZE_BYTES * 8 ) * _count;
|
||||
_transactions[ 0 ].tx_buffer = _buffer;
|
||||
spi_device_queue_trans( _spi, _transactions + _transCount, portMAX_DELAY );
|
||||
_transCount++;
|
||||
|
||||
// 'latch'/start-of-data marker frames
|
||||
for ( int i = 0; i < _latchFrames; i++ ) {
|
||||
_transactions[ _transCount ].length = ( LATCH_FRAME_SIZE_BYTES * 8 );
|
||||
_transactions[ _transCount ].tx_buffer = _latchBuffer;
|
||||
spi_device_queue_trans( _spi, _transactions + _transCount, portMAX_DELAY );
|
||||
_transCount++;
|
||||
}
|
||||
}
|
||||
|
||||
spi_device_handle_t _spi;
|
||||
int _count;
|
||||
std::unique_ptr< LDP8806_GRB[] > _firstBuffer, _secondBuffer;
|
||||
LDP8806_GRB *_buffer;
|
||||
|
||||
spi_transaction_t _transactions[ TRANS_COUNT_MAX ];
|
||||
int _transCount;
|
||||
|
||||
int _latchFrames;
|
||||
uint8_t _latchBuffer[ LATCH_FRAME_SIZE_BYTES ];
|
||||
};
|
||||
1
code/components/esp-nn
Submodule
1
code/components/esp-nn
Submodule
Submodule code/components/esp-nn added at 6b3ef8e226
1
code/components/esp32-camera
Submodule
1
code/components/esp32-camera
Submodule
Submodule code/components/esp32-camera added at 5c8349f4cf
@@ -1 +0,0 @@
|
||||
*.DS_Store
|
||||
@@ -1,35 +0,0 @@
|
||||
if(IDF_TARGET STREQUAL "esp32")
|
||||
set(COMPONENT_SRCS
|
||||
driver/camera.c
|
||||
driver/sccb.c
|
||||
driver/sensor.c
|
||||
driver/xclk.c
|
||||
sensors/ov2640.c
|
||||
sensors/ov3660.c
|
||||
sensors/ov5640.c
|
||||
sensors/ov7725.c
|
||||
sensors/ov7670.c
|
||||
sensors/nt99141.c
|
||||
conversions/yuv.c
|
||||
conversions/to_jpg.cpp
|
||||
conversions/to_bmp.c
|
||||
conversions/jpge.cpp
|
||||
conversions/esp_jpg_decode.c
|
||||
)
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS
|
||||
driver/include
|
||||
conversions/include
|
||||
)
|
||||
|
||||
set(COMPONENT_PRIV_INCLUDEDIRS
|
||||
driver/private_include
|
||||
sensors/private_include
|
||||
conversions/private_include
|
||||
)
|
||||
|
||||
set(COMPONENT_REQUIRES driver)
|
||||
set(COMPONENT_PRIV_REQUIRES freertos nvs_flash)
|
||||
|
||||
register_component()
|
||||
endif()
|
||||
@@ -1,71 +0,0 @@
|
||||
menu "Camera configuration"
|
||||
|
||||
config OV7670_SUPPORT
|
||||
bool "Support OV7670 VGA"
|
||||
default y
|
||||
help
|
||||
Enable this option if you want to use the OV7670.
|
||||
Disable this option to safe memory.
|
||||
|
||||
config OV7725_SUPPORT
|
||||
bool "Support OV7725 SVGA"
|
||||
default n
|
||||
help
|
||||
Enable this option if you want to use the OV7725.
|
||||
Disable this option to save memory.
|
||||
|
||||
config NT99141_SUPPORT
|
||||
bool "Support NT99141 HD"
|
||||
default y
|
||||
help
|
||||
Enable this option if you want to use the NT99141.
|
||||
Disable this option to save memory.
|
||||
|
||||
config OV2640_SUPPORT
|
||||
bool "Support OV2640 2MP"
|
||||
default y
|
||||
help
|
||||
Enable this option if you want to use the OV2640.
|
||||
Disable this option to save memory.
|
||||
|
||||
config OV3660_SUPPORT
|
||||
bool "Support OV3660 3MP"
|
||||
default y
|
||||
help
|
||||
Enable this option if you want to use the OV3360.
|
||||
Disable this option to save memory.
|
||||
|
||||
config OV5640_SUPPORT
|
||||
bool "Support OV5640 5MP"
|
||||
default y
|
||||
help
|
||||
Enable this option if you want to use the OV5640.
|
||||
Disable this option to save memory.
|
||||
|
||||
choice SCCB_HARDWARE_I2C_PORT
|
||||
bool "I2C peripheral to use for SCCB"
|
||||
default SCCB_HARDWARE_I2C_PORT1
|
||||
|
||||
config SCCB_HARDWARE_I2C_PORT0
|
||||
bool "I2C0"
|
||||
config SCCB_HARDWARE_I2C_PORT1
|
||||
bool "I2C1"
|
||||
|
||||
endchoice
|
||||
|
||||
choice CAMERA_TASK_PINNED_TO_CORE
|
||||
bool "Camera task pinned to core"
|
||||
default CAMERA_CORE0
|
||||
help
|
||||
Pin the camera handle task to a certain core(0/1). It can also be done automatically choosing NO_AFFINITY.
|
||||
|
||||
config CAMERA_CORE0
|
||||
bool "CORE0"
|
||||
config CAMERA_CORE1
|
||||
bool "CORE1"
|
||||
config CAMERA_NO_AFFINITY
|
||||
bool "NO_AFFINITY"
|
||||
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,358 +0,0 @@
|
||||
# ESP32 Camera Driver
|
||||
|
||||
## General Information
|
||||
|
||||
This repository hosts ESP32 compatible driver for OV2640, OV3660, OV5640, OV7670 and OV7725 image sensors. Additionally it provides a few tools, which allow converting the captured frame data to the more common BMP and JPEG formats.
|
||||
|
||||
## Important to Remember
|
||||
|
||||
- Except when using CIF or lower resolution with JPEG, the driver requires PSRAM to be installed and activated.
|
||||
- Using YUV or RGB puts a lot of strain on the chip because writing to PSRAM is not particularly fast. The result is that image data might be missing. This is particularly true if WiFi is enabled. If you need RGB data, it is recommended that JPEG is captured and then turned into RGB using `fmt2rgb888` or `fmt2bmp`/`frame2bmp`.
|
||||
- When 1 frame buffer is used, the driver will wait for the current frame to finish (VSYNC) and start I2S DMA. After the frame is acquired, I2S will be stopped and the frame buffer returned to the application. This approach gives more control over the system, but results in longer time to get the frame.
|
||||
- When 2 or more frame bufers are used, I2S is running in continuous mode and each frame is pushed to a queue that the application can access. This approach puts more strain on the CPU/Memory, but allows for double the frame rate. Please use only with JPEG.
|
||||
|
||||
## Installation Instructions
|
||||
|
||||
|
||||
### Using esp-idf
|
||||
|
||||
- Clone or download and extract the repository to the components folder of your ESP-IDF project
|
||||
- Enable PSRAM in `menuconfig`
|
||||
- Include `esp_camera.h` in your code
|
||||
|
||||
### Using PlatformIO
|
||||
|
||||
The easy way -- on the `env` section of `platformio.ini`, add the following:
|
||||
|
||||
```ini
|
||||
[env]
|
||||
lib_deps =
|
||||
esp32-camera
|
||||
```
|
||||
|
||||
Now the `esp_camera.h` is available to be included:
|
||||
|
||||
```c
|
||||
#include "esp_camera.h"
|
||||
```
|
||||
|
||||
Enable PSRAM on `menuconfig` or type it direclty on `sdkconfig`. Check the [official doc](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/kconfig.html#config-esp32-spiram-support) for more info.
|
||||
|
||||
```
|
||||
CONFIG_ESP32_SPIRAM_SUPPORT=y
|
||||
```
|
||||
|
||||
***Arduino*** The easy-way (content above) only seems to work if you're using `framework=arduino` which seems to take a bunch of the guesswork out (thanks Arduino!) but also suck up a lot more memory and flash, almost crippling the performance. If you plan to use the `framework=espidf` then read the sections below carefully!!
|
||||
|
||||
## Platform.io lib/submodule (for framework=espidf)
|
||||
|
||||
It's probably easier to just skip the platform.io library registry version and link the git repo as a submodule. (i.e. using code outside the platform.io library management). In this example we will install this as a submodule inside the platform.io $project/lib folder:
|
||||
```
|
||||
cd $project\lib
|
||||
git submodule add -b master https://github.com/espressif/esp32-camera.git
|
||||
```
|
||||
|
||||
Then in `platformio.ini` file
|
||||
```
|
||||
build_flags =
|
||||
-I../lib/esp32-camera
|
||||
```
|
||||
After that `#include "esp_camera.h"` statement will be available. Now the module is included, and you're hopefully back to the same place as the easy-Arduino way.
|
||||
|
||||
**Warning about platform.io/espidf and fresh (not initialized) git repos**
|
||||
There is a sharp-edge on you'll discover in the platform.io build process (in espidf v3.3 & 4.0.1) where a project which has only had `git init` but nothing committed will crash platform.io build process with highly non-useful output. The cause is due to lack of a version (making you think you did something wrong, when you didn't at all) - the output is horribly non-descript. Solution: the devs want you to create a file called version.txt with a number in it, or simply commit any file to the projects git repo and use git. This happens because platform.io build process tries to be too clever and determine the build version number from the git repo - it's a sharp edge you'll only encounter if you're experimenting on a new project with no commits .. like wtf is my camera not working let's try a 'clean project'?! </rant>
|
||||
|
||||
## Platform.io Kconfig
|
||||
Kconfig is used by the platform.io menuconfig (accessed by running: `pio run -t menuconfig`) to interactively manage the various #ifdef statements throughout the espidf and supporting libraries (i.e. this repo: esp32-camera and arduino-esp32.git). The menuconfig process generates the `sdkconfig` file which is ultimately used behind the scenes by espidf compile+build process.
|
||||
|
||||
**Make sure to append or symlink** [this `Kconfig`](./Kconfig) content into the `Kconfig` of your project.
|
||||
|
||||
You symlink (or copy) the included Kconfig into your platform.io projects src directory. The file should be named `Kconfig.projbuild` in your projects src\ directory or you could also add the library path to a CMakefile.txt and hope the `Kconfig` (or `Kconfig.projbuild`) gets discovered by the menuconfig process, though this unpredictable for me.
|
||||
|
||||
The unpredictable wonky behavior in platform.io build process around Kconfig naming (Kconfig vs. Kconfig.projbuild) occurs between espidf versions 3.3 and 4.0 - but if you don't see "Camera configuration" in your `pio run -t menuconfig` then there is no point trying to test camera code (it may compile, but it probably won't work!) and it seems the platform.io devs (when they built their wrapper around the espidf menuconfig) didn't implement it properly. You've probably already figured out you can't use the espidf build tools since the files are in totally different locations and also different versions with sometimes different syntax. This is one of those times you might consider changing the `platformio.ini` from `platform=espressif32` to `platform=https://github.com/platformio/platform-espressif32.git#develop` to get a more recent version of the espidf 4.0 tools.
|
||||
|
||||
However with a bit of patience and experimenting you'll figure the Kconfig out. Once Kconfig (or Kconfig.projbuild) is working then you will be able to choose the configurations according to your setup or the camera libraries will be compiled. Although you might also need to delete your .pio/build directory before the options appear .. again, the `pio run -t menuconfig` doens't always notice the new Kconfig files!
|
||||
|
||||
If you miss-skip-ignore this critical step the camera module will compile but camera logic inside the library will be 'empty' because the Kconfig sets the proper #ifdef statements during the build process to initialize the selected cameras. It's very not optional!
|
||||
|
||||
### Kconfig options
|
||||
|
||||
| config | description | default |
|
||||
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------ |
|
||||
| CONFIG_OV2640_SUPPORT | Support for OV2640 camera | enabled |
|
||||
| CONFIG_OV7725_SUPPORT | Support for OV7725 camera | disabled |
|
||||
| CONFIG_OV3660_SUPPORT | Support for OV3660 camera | enabled |
|
||||
| CONFIG_OV5640_SUPPORT | Support for OV5640 camera | enabled |
|
||||
| CONFIG_SCCB_HARDWARE_I2C | Enable this option if you want to use hardware I2C to control the camera. Disable this option to use software I2C. | enabled |
|
||||
| CONFIG_SCCB_HARDWARE_I2C_PORT | I2C peripheral to use for SCCB. Can be I2C0 and I2C1. | CONFIG_SCCB_HARDWARE_I2C_PORT1 |
|
||||
| CONFIG_CAMERA_TASK_PINNED_TO_CORE | Pin the camera handle task to a certain core(0/1). It can also be done automatically choosing NO_AFFINITY. Can be CAMERA_CORE0, CAMERA_CORE1 or NO_AFFINITY. | CONFIG_CAMERA_CORE0 |
|
||||
|
||||
## Examples
|
||||
|
||||
### Initialization
|
||||
|
||||
```c
|
||||
#include "esp_camera.h"
|
||||
|
||||
//WROVER-KIT PIN Map
|
||||
#define CAM_PIN_PWDN -1 //power down is not used
|
||||
#define CAM_PIN_RESET -1 //software reset will be performed
|
||||
#define CAM_PIN_XCLK 21
|
||||
#define CAM_PIN_SIOD 26
|
||||
#define CAM_PIN_SIOC 27
|
||||
|
||||
#define CAM_PIN_D7 35
|
||||
#define CAM_PIN_D6 34
|
||||
#define CAM_PIN_D5 39
|
||||
#define CAM_PIN_D4 36
|
||||
#define CAM_PIN_D3 19
|
||||
#define CAM_PIN_D2 18
|
||||
#define CAM_PIN_D1 5
|
||||
#define CAM_PIN_D0 4
|
||||
#define CAM_PIN_VSYNC 25
|
||||
#define CAM_PIN_HREF 23
|
||||
#define CAM_PIN_PCLK 22
|
||||
|
||||
static camera_config_t camera_config = {
|
||||
.pin_pwdn = CAM_PIN_PWDN,
|
||||
.pin_reset = CAM_PIN_RESET,
|
||||
.pin_xclk = CAM_PIN_XCLK,
|
||||
.pin_sscb_sda = CAM_PIN_SIOD,
|
||||
.pin_sscb_scl = CAM_PIN_SIOC,
|
||||
|
||||
.pin_d7 = CAM_PIN_D7,
|
||||
.pin_d6 = CAM_PIN_D6,
|
||||
.pin_d5 = CAM_PIN_D5,
|
||||
.pin_d4 = CAM_PIN_D4,
|
||||
.pin_d3 = CAM_PIN_D3,
|
||||
.pin_d2 = CAM_PIN_D2,
|
||||
.pin_d1 = CAM_PIN_D1,
|
||||
.pin_d0 = CAM_PIN_D0,
|
||||
.pin_vsync = CAM_PIN_VSYNC,
|
||||
.pin_href = CAM_PIN_HREF,
|
||||
.pin_pclk = CAM_PIN_PCLK,
|
||||
|
||||
//XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental)
|
||||
.xclk_freq_hz = 20000000,
|
||||
.ledc_timer = LEDC_TIMER_0,
|
||||
.ledc_channel = LEDC_CHANNEL_0,
|
||||
|
||||
.pixel_format = PIXFORMAT_JPEG,//YUV422,GRAYSCALE,RGB565,JPEG
|
||||
.frame_size = FRAMESIZE_UXGA,//QQVGA-QXGA Do not use sizes above QVGA when not JPEG
|
||||
|
||||
.jpeg_quality = 12, //0-63 lower number means higher quality
|
||||
.fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG
|
||||
};
|
||||
|
||||
esp_err_t camera_init(){
|
||||
//power up the camera if PWDN pin is defined
|
||||
if(CAM_PIN_PWDN != -1){
|
||||
pinMode(CAM_PIN_PWDN, OUTPUT);
|
||||
digitalWrite(CAM_PIN_PWDN, LOW);
|
||||
}
|
||||
|
||||
//initialize the camera
|
||||
esp_err_t err = esp_camera_init(&camera_config);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Camera Init Failed");
|
||||
return err;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t camera_capture(){
|
||||
//acquire a frame
|
||||
camera_fb_t * fb = esp_camera_fb_get();
|
||||
if (!fb) {
|
||||
ESP_LOGE(TAG, "Camera Capture Failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
//replace this with your own function
|
||||
process_image(fb->width, fb->height, fb->format, fb->buf, fb->len);
|
||||
|
||||
//return the frame buffer back to the driver for reuse
|
||||
esp_camera_fb_return(fb);
|
||||
return ESP_OK;
|
||||
}
|
||||
```
|
||||
|
||||
### JPEG HTTP Capture
|
||||
|
||||
```c
|
||||
#include "esp_camera.h"
|
||||
#include "esp_http_server.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
typedef struct {
|
||||
httpd_req_t *req;
|
||||
size_t len;
|
||||
} jpg_chunking_t;
|
||||
|
||||
static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){
|
||||
jpg_chunking_t *j = (jpg_chunking_t *)arg;
|
||||
if(!index){
|
||||
j->len = 0;
|
||||
}
|
||||
if(httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK){
|
||||
return 0;
|
||||
}
|
||||
j->len += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
esp_err_t jpg_httpd_handler(httpd_req_t *req){
|
||||
camera_fb_t * fb = NULL;
|
||||
esp_err_t res = ESP_OK;
|
||||
size_t fb_len = 0;
|
||||
int64_t fr_start = esp_timer_get_time();
|
||||
|
||||
fb = esp_camera_fb_get();
|
||||
if (!fb) {
|
||||
ESP_LOGE(TAG, "Camera capture failed");
|
||||
httpd_resp_send_500(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
res = httpd_resp_set_type(req, "image/jpeg");
|
||||
if(res == ESP_OK){
|
||||
res = httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg");
|
||||
}
|
||||
|
||||
if(res == ESP_OK){
|
||||
if(fb->format == PIXFORMAT_JPEG){
|
||||
fb_len = fb->len;
|
||||
res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
|
||||
} else {
|
||||
jpg_chunking_t jchunk = {req, 0};
|
||||
res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL;
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
fb_len = jchunk.len;
|
||||
}
|
||||
}
|
||||
esp_camera_fb_return(fb);
|
||||
int64_t fr_end = esp_timer_get_time();
|
||||
ESP_LOGI(TAG, "JPG: %uKB %ums", (uint32_t)(fb_len/1024), (uint32_t)((fr_end - fr_start)/1000));
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
### JPEG HTTP Stream
|
||||
|
||||
```c
|
||||
#include "esp_camera.h"
|
||||
#include "esp_http_server.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
#define PART_BOUNDARY "123456789000000000000987654321"
|
||||
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
|
||||
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
|
||||
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
|
||||
|
||||
esp_err_t jpg_stream_httpd_handler(httpd_req_t *req){
|
||||
camera_fb_t * fb = NULL;
|
||||
esp_err_t res = ESP_OK;
|
||||
size_t _jpg_buf_len;
|
||||
uint8_t * _jpg_buf;
|
||||
char * part_buf[64];
|
||||
static int64_t last_frame = 0;
|
||||
if(!last_frame) {
|
||||
last_frame = esp_timer_get_time();
|
||||
}
|
||||
|
||||
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
|
||||
if(res != ESP_OK){
|
||||
return res;
|
||||
}
|
||||
|
||||
while(true){
|
||||
fb = esp_camera_fb_get();
|
||||
if (!fb) {
|
||||
ESP_LOGE(TAG, "Camera capture failed");
|
||||
res = ESP_FAIL;
|
||||
break;
|
||||
}
|
||||
if(fb->format != PIXFORMAT_JPEG){
|
||||
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
|
||||
if(!jpeg_converted){
|
||||
ESP_LOGE(TAG, "JPEG compression failed");
|
||||
esp_camera_fb_return(fb);
|
||||
res = ESP_FAIL;
|
||||
}
|
||||
} else {
|
||||
_jpg_buf_len = fb->len;
|
||||
_jpg_buf = fb->buf;
|
||||
}
|
||||
|
||||
if(res == ESP_OK){
|
||||
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
|
||||
}
|
||||
if(res == ESP_OK){
|
||||
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
|
||||
|
||||
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
|
||||
}
|
||||
if(res == ESP_OK){
|
||||
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
|
||||
}
|
||||
if(fb->format != PIXFORMAT_JPEG){
|
||||
free(_jpg_buf);
|
||||
}
|
||||
esp_camera_fb_return(fb);
|
||||
if(res != ESP_OK){
|
||||
break;
|
||||
}
|
||||
int64_t fr_end = esp_timer_get_time();
|
||||
int64_t frame_time = fr_end - last_frame;
|
||||
last_frame = fr_end;
|
||||
frame_time /= 1000;
|
||||
ESP_LOGI(TAG, "MJPG: %uKB %ums (%.1ffps)",
|
||||
(uint32_t)(_jpg_buf_len/1024),
|
||||
(uint32_t)frame_time, 1000.0 / (uint32_t)frame_time);
|
||||
}
|
||||
|
||||
last_frame = 0;
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
### BMP HTTP Capture
|
||||
|
||||
```c
|
||||
#include "esp_camera.h"
|
||||
#include "esp_http_server.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
esp_err_t bmp_httpd_handler(httpd_req_t *req){
|
||||
camera_fb_t * fb = NULL;
|
||||
esp_err_t res = ESP_OK;
|
||||
int64_t fr_start = esp_timer_get_time();
|
||||
|
||||
fb = esp_camera_fb_get();
|
||||
if (!fb) {
|
||||
ESP_LOGE(TAG, "Camera capture failed");
|
||||
httpd_resp_send_500(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
uint8_t * buf = NULL;
|
||||
size_t buf_len = 0;
|
||||
bool converted = frame2bmp(fb, &buf, &buf_len);
|
||||
esp_camera_fb_return(fb);
|
||||
if(!converted){
|
||||
ESP_LOGE(TAG, "BMP conversion failed");
|
||||
httpd_resp_send_500(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
res = httpd_resp_set_type(req, "image/x-windows-bmp")
|
||||
|| httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.bmp")
|
||||
|| httpd_resp_send(req, (const char *)buf, buf_len);
|
||||
free(buf);
|
||||
int64_t fr_end = esp_timer_get_time();
|
||||
ESP_LOGI(TAG, "BMP: %uKB %ums", (uint32_t)(buf_len/1024), (uint32_t)((fr_end - fr_start)/1000));
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS := driver/include conversions/include
|
||||
COMPONENT_PRIV_INCLUDEDIRS := driver/private_include conversions/private_include sensors/private_include
|
||||
COMPONENT_SRCDIRS := driver conversions sensors
|
||||
CXXFLAGS += -fno-rtti
|
||||
@@ -1,128 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "esp_jpg_decode.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4 // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/tjpgd.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/tjpgd.h"
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* TAG = "esp_jpg_decode";
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
jpg_scale_t scale;
|
||||
jpg_reader_cb reader;
|
||||
jpg_writer_cb writer;
|
||||
void * arg;
|
||||
size_t len;
|
||||
size_t index;
|
||||
} esp_jpg_decoder_t;
|
||||
|
||||
static const char * jd_errors[] = {
|
||||
"Succeeded",
|
||||
"Interrupted by output function",
|
||||
"Device error or wrong termination of input stream",
|
||||
"Insufficient memory pool for the image",
|
||||
"Insufficient stream input buffer",
|
||||
"Parameter error",
|
||||
"Data format error",
|
||||
"Right format but not supported",
|
||||
"Not supported JPEG standard"
|
||||
};
|
||||
|
||||
static uint32_t _jpg_write(JDEC *decoder, void *bitmap, JRECT *rect)
|
||||
{
|
||||
uint16_t x = rect->left;
|
||||
uint16_t y = rect->top;
|
||||
uint16_t w = rect->right + 1 - x;
|
||||
uint16_t h = rect->bottom + 1 - y;
|
||||
uint8_t *data = (uint8_t *)bitmap;
|
||||
|
||||
esp_jpg_decoder_t * jpeg = (esp_jpg_decoder_t *)decoder->device;
|
||||
|
||||
if (jpeg->writer) {
|
||||
return jpeg->writer(jpeg->arg, x, y, w, h, data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t _jpg_read(JDEC *decoder, uint8_t *buf, uint32_t len)
|
||||
{
|
||||
esp_jpg_decoder_t * jpeg = (esp_jpg_decoder_t *)decoder->device;
|
||||
if (jpeg->len && len > (jpeg->len - jpeg->index)) {
|
||||
len = jpeg->len - jpeg->index;
|
||||
}
|
||||
if (len) {
|
||||
len = jpeg->reader(jpeg->arg, jpeg->index, buf, len);
|
||||
if (!len) {
|
||||
ESP_LOGE(TAG, "Read Fail at %u/%u", jpeg->index, jpeg->len);
|
||||
}
|
||||
jpeg->index += len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
esp_err_t esp_jpg_decode(size_t len, jpg_scale_t scale, jpg_reader_cb reader, jpg_writer_cb writer, void * arg)
|
||||
{
|
||||
static uint8_t work[3100];
|
||||
JDEC decoder;
|
||||
esp_jpg_decoder_t jpeg;
|
||||
|
||||
jpeg.len = len;
|
||||
jpeg.reader = reader;
|
||||
jpeg.writer = writer;
|
||||
jpeg.arg = arg;
|
||||
jpeg.scale = scale;
|
||||
jpeg.index = 0;
|
||||
|
||||
JRESULT jres = jd_prepare(&decoder, _jpg_read, work, 3100, &jpeg);
|
||||
if(jres != JDR_OK){
|
||||
ESP_LOGE(TAG, "JPG Header Parse Failed! %s", jd_errors[jres]);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
uint16_t output_width = decoder.width / (1 << (uint8_t)(jpeg.scale));
|
||||
uint16_t output_height = decoder.height / (1 << (uint8_t)(jpeg.scale));
|
||||
|
||||
//output start
|
||||
writer(arg, 0, 0, output_width, output_height, NULL);
|
||||
//output write
|
||||
jres = jd_decomp(&decoder, _jpg_write, (uint8_t)jpeg.scale);
|
||||
//output end
|
||||
writer(arg, output_width, output_height, output_width, output_height, NULL);
|
||||
|
||||
if (jres != JDR_OK) {
|
||||
ESP_LOGE(TAG, "JPG Decompression Failed! %s", jd_errors[jres]);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
//check if all data has been consumed.
|
||||
if (len && jpeg.index < len) {
|
||||
_jpg_read(&decoder, NULL, len - jpeg.index);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#ifndef _ESP_JPG_DECODE_H_
|
||||
#define _ESP_JPG_DECODE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
typedef enum {
|
||||
JPG_SCALE_NONE,
|
||||
JPG_SCALE_2X,
|
||||
JPG_SCALE_4X,
|
||||
JPG_SCALE_8X,
|
||||
JPG_SCALE_MAX = JPG_SCALE_8X
|
||||
} jpg_scale_t;
|
||||
|
||||
typedef size_t (* jpg_reader_cb)(void * arg, size_t index, uint8_t *buf, size_t len);
|
||||
typedef bool (* jpg_writer_cb)(void * arg, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t *data);
|
||||
|
||||
esp_err_t esp_jpg_decode(size_t len, jpg_scale_t scale, jpg_reader_cb reader, jpg_writer_cb writer, void * arg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ESP_JPG_DECODE_H_ */
|
||||
@@ -1,127 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#ifndef _IMG_CONVERTERS_H_
|
||||
#define _IMG_CONVERTERS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_camera.h"
|
||||
|
||||
typedef size_t (* jpg_out_cb)(void * arg, size_t index, const void* data, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Convert image buffer to JPEG
|
||||
*
|
||||
* @param src Source buffer in RGB565, RGB888, YUYV or GRAYSCALE format
|
||||
* @param src_len Length in bytes of the source buffer
|
||||
* @param width Width in pixels of the source image
|
||||
* @param height Height in pixels of the source image
|
||||
* @param format Format of the source image
|
||||
* @param quality JPEG quality of the resulting image
|
||||
* @param cp Callback to be called to write the bytes of the output JPEG
|
||||
* @param arg Pointer to be passed to the callback
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
bool fmt2jpg_cb(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, jpg_out_cb cb, void * arg);
|
||||
|
||||
/**
|
||||
* @brief Convert camera frame buffer to JPEG
|
||||
*
|
||||
* @param fb Source camera frame buffer
|
||||
* @param quality JPEG quality of the resulting image
|
||||
* @param cp Callback to be called to write the bytes of the output JPEG
|
||||
* @param arg Pointer to be passed to the callback
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
bool frame2jpg_cb(camera_fb_t * fb, uint8_t quality, jpg_out_cb cb, void * arg);
|
||||
|
||||
/**
|
||||
* @brief Convert image buffer to JPEG buffer
|
||||
*
|
||||
* @param src Source buffer in RGB565, RGB888, YUYV or GRAYSCALE format
|
||||
* @param src_len Length in bytes of the source buffer
|
||||
* @param width Width in pixels of the source image
|
||||
* @param height Height in pixels of the source image
|
||||
* @param format Format of the source image
|
||||
* @param quality JPEG quality of the resulting image
|
||||
* @param out Pointer to be populated with the address of the resulting buffer.
|
||||
* You MUST free the pointer once you are done with it.
|
||||
* @param out_len Pointer to be populated with the length of the output buffer
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
bool fmt2jpg(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, uint8_t ** out, size_t * out_len);
|
||||
|
||||
/**
|
||||
* @brief Convert camera frame buffer to JPEG buffer
|
||||
*
|
||||
* @param fb Source camera frame buffer
|
||||
* @param quality JPEG quality of the resulting image
|
||||
* @param out Pointer to be populated with the address of the resulting buffer
|
||||
* @param out_len Pointer to be populated with the length of the output buffer
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
bool frame2jpg(camera_fb_t * fb, uint8_t quality, uint8_t ** out, size_t * out_len);
|
||||
|
||||
/**
|
||||
* @brief Convert image buffer to BMP buffer
|
||||
*
|
||||
* @param src Source buffer in JPEG, RGB565, RGB888, YUYV or GRAYSCALE format
|
||||
* @param src_len Length in bytes of the source buffer
|
||||
* @param width Width in pixels of the source image
|
||||
* @param height Height in pixels of the source image
|
||||
* @param format Format of the source image
|
||||
* @param out Pointer to be populated with the address of the resulting buffer
|
||||
* @param out_len Pointer to be populated with the length of the output buffer
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t ** out, size_t * out_len);
|
||||
|
||||
/**
|
||||
* @brief Convert camera frame buffer to BMP buffer
|
||||
*
|
||||
* @param fb Source camera frame buffer
|
||||
* @param out Pointer to be populated with the address of the resulting buffer
|
||||
* @param out_len Pointer to be populated with the length of the output buffer
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
bool frame2bmp(camera_fb_t * fb, uint8_t ** out, size_t * out_len);
|
||||
|
||||
/**
|
||||
* @brief Convert image buffer to RGB888 buffer (used for face detection)
|
||||
*
|
||||
* @param src Source buffer in JPEG, RGB565, RGB888, YUYV or GRAYSCALE format
|
||||
* @param src_len Length in bytes of the source buffer
|
||||
* @param format Format of the source image
|
||||
* @param rgb_buf Pointer to the output buffer (width * height * 3)
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint8_t * rgb_buf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _IMG_CONVERTERS_H_ */
|
||||
@@ -1,723 +0,0 @@
|
||||
// jpge.cpp - C++ class for JPEG compression.
|
||||
// Public domain, Rich Geldreich <richgel99@gmail.com>
|
||||
// v1.01, Dec. 18, 2010 - Initial release
|
||||
// v1.02, Apr. 6, 2011 - Removed 2x2 ordered dither in H2V1 chroma subsampling method load_block_16_8_8(). (The rounding factor was 2, when it should have been 1. Either way, it wasn't helping.)
|
||||
// v1.03, Apr. 16, 2011 - Added support for optimized Huffman code tables, optimized dynamic memory allocation down to only 1 alloc.
|
||||
// Also from Alex Evans: Added RGBA support, linear memory allocator (no longer needed in v1.03).
|
||||
// v1.04, May. 19, 2012: Forgot to set m_pFile ptr to NULL in cfile_stream::close(). Thanks to Owen Kaluza for reporting this bug.
|
||||
// Code tweaks to fix VS2008 static code analysis warnings (all looked harmless).
|
||||
// Code review revealed method load_block_16_8_8() (used for the non-default H2V1 sampling mode to downsample chroma) somehow didn't get the rounding factor fix from v1.02.
|
||||
|
||||
#include "jpge.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
#define JPGE_MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#define JPGE_MIN(a,b) (((a)<(b))?(a):(b))
|
||||
|
||||
namespace jpge {
|
||||
|
||||
static inline void *jpge_malloc(size_t nSize) {
|
||||
void * b = malloc(nSize);
|
||||
if(b){
|
||||
return b;
|
||||
}
|
||||
return heap_caps_malloc(nSize, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
}
|
||||
static inline void jpge_free(void *p) { free(p); }
|
||||
|
||||
// Various JPEG enums and tables.
|
||||
enum { M_SOF0 = 0xC0, M_DHT = 0xC4, M_SOI = 0xD8, M_EOI = 0xD9, M_SOS = 0xDA, M_DQT = 0xDB, M_APP0 = 0xE0 };
|
||||
enum { DC_LUM_CODES = 12, AC_LUM_CODES = 256, DC_CHROMA_CODES = 12, AC_CHROMA_CODES = 256, MAX_HUFF_SYMBOLS = 257, MAX_HUFF_CODESIZE = 32 };
|
||||
|
||||
static const uint8 s_zag[64] = { 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 };
|
||||
static const int16 s_std_lum_quant[64] = { 16,11,12,14,12,10,16,14,13,14,18,17,16,19,24,40,26,24,22,22,24,49,35,37,29,40,58,51,61,60,57,51,56,55,64,72,92,78,64,68,87,69,55,56,80,109,81,87,95,98,103,104,103,62,77,113,121,112,100,120,92,101,103,99 };
|
||||
static const int16 s_std_croma_quant[64] = { 17,18,18,24,21,24,47,26,26,47,99,66,56,66,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99 };
|
||||
static const uint8 s_dc_lum_bits[17] = { 0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0 };
|
||||
static const uint8 s_dc_lum_val[DC_LUM_CODES] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
|
||||
static const uint8 s_ac_lum_bits[17] = { 0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d };
|
||||
static const uint8 s_ac_lum_val[AC_LUM_CODES] = {
|
||||
0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,
|
||||
0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
|
||||
0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
|
||||
0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,
|
||||
0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
|
||||
0xf9,0xfa
|
||||
};
|
||||
static const uint8 s_dc_chroma_bits[17] = { 0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0 };
|
||||
static const uint8 s_dc_chroma_val[DC_CHROMA_CODES] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
|
||||
static const uint8 s_ac_chroma_bits[17] = { 0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77 };
|
||||
static const uint8 s_ac_chroma_val[AC_CHROMA_CODES] = {
|
||||
0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,
|
||||
0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,
|
||||
0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
|
||||
0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,
|
||||
0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
|
||||
0xf9,0xfa
|
||||
};
|
||||
|
||||
const int YR = 19595, YG = 38470, YB = 7471, CB_R = -11059, CB_G = -21709, CB_B = 32768, CR_R = 32768, CR_G = -27439, CR_B = -5329;
|
||||
|
||||
static int32 m_last_quality = 0;
|
||||
static int32 m_quantization_tables[2][64];
|
||||
|
||||
static bool m_huff_initialized = false;
|
||||
static uint m_huff_codes[4][256];
|
||||
static uint8 m_huff_code_sizes[4][256];
|
||||
static uint8 m_huff_bits[4][17];
|
||||
static uint8 m_huff_val[4][256];
|
||||
|
||||
static inline uint8 clamp(int i) {
|
||||
if (i < 0) {
|
||||
i = 0;
|
||||
} else if (i > 255){
|
||||
i = 255;
|
||||
}
|
||||
return static_cast<uint8>(i);
|
||||
}
|
||||
|
||||
static void RGB_to_YCC(uint8* pDst, const uint8 *pSrc, int num_pixels) {
|
||||
for ( ; num_pixels; pDst += 3, pSrc += 3, num_pixels--) {
|
||||
const int r = pSrc[0], g = pSrc[1], b = pSrc[2];
|
||||
pDst[0] = static_cast<uint8>((r * YR + g * YG + b * YB + 32768) >> 16);
|
||||
pDst[1] = clamp(128 + ((r * CB_R + g * CB_G + b * CB_B + 32768) >> 16));
|
||||
pDst[2] = clamp(128 + ((r * CR_R + g * CR_G + b * CR_B + 32768) >> 16));
|
||||
}
|
||||
}
|
||||
|
||||
static void RGB_to_Y(uint8* pDst, const uint8 *pSrc, int num_pixels) {
|
||||
for ( ; num_pixels; pDst++, pSrc += 3, num_pixels--) {
|
||||
pDst[0] = static_cast<uint8>((pSrc[0] * YR + pSrc[1] * YG + pSrc[2] * YB + 32768) >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
static void Y_to_YCC(uint8* pDst, const uint8* pSrc, int num_pixels) {
|
||||
for( ; num_pixels; pDst += 3, pSrc++, num_pixels--) {
|
||||
pDst[0] = pSrc[0];
|
||||
pDst[1] = 128;
|
||||
pDst[2] = 128;
|
||||
}
|
||||
}
|
||||
|
||||
// Forward DCT - DCT derived from jfdctint.
|
||||
enum { CONST_BITS = 13, ROW_BITS = 2 };
|
||||
#define DCT_DESCALE(x, n) (((x) + (((int32)1) << ((n) - 1))) >> (n))
|
||||
#define DCT_MUL(var, c) (static_cast<int16>(var) * static_cast<int32>(c))
|
||||
#define DCT1D(s0, s1, s2, s3, s4, s5, s6, s7) \
|
||||
int32 t0 = s0 + s7, t7 = s0 - s7, t1 = s1 + s6, t6 = s1 - s6, t2 = s2 + s5, t5 = s2 - s5, t3 = s3 + s4, t4 = s3 - s4; \
|
||||
int32 t10 = t0 + t3, t13 = t0 - t3, t11 = t1 + t2, t12 = t1 - t2; \
|
||||
int32 u1 = DCT_MUL(t12 + t13, 4433); \
|
||||
s2 = u1 + DCT_MUL(t13, 6270); \
|
||||
s6 = u1 + DCT_MUL(t12, -15137); \
|
||||
u1 = t4 + t7; \
|
||||
int32 u2 = t5 + t6, u3 = t4 + t6, u4 = t5 + t7; \
|
||||
int32 z5 = DCT_MUL(u3 + u4, 9633); \
|
||||
t4 = DCT_MUL(t4, 2446); t5 = DCT_MUL(t5, 16819); \
|
||||
t6 = DCT_MUL(t6, 25172); t7 = DCT_MUL(t7, 12299); \
|
||||
u1 = DCT_MUL(u1, -7373); u2 = DCT_MUL(u2, -20995); \
|
||||
u3 = DCT_MUL(u3, -16069); u4 = DCT_MUL(u4, -3196); \
|
||||
u3 += z5; u4 += z5; \
|
||||
s0 = t10 + t11; s1 = t7 + u1 + u4; s3 = t6 + u2 + u3; s4 = t10 - t11; s5 = t5 + u2 + u4; s7 = t4 + u1 + u3;
|
||||
|
||||
static void DCT2D(int32 *p) {
|
||||
int32 c, *q = p;
|
||||
for (c = 7; c >= 0; c--, q += 8) {
|
||||
int32 s0 = q[0], s1 = q[1], s2 = q[2], s3 = q[3], s4 = q[4], s5 = q[5], s6 = q[6], s7 = q[7];
|
||||
DCT1D(s0, s1, s2, s3, s4, s5, s6, s7);
|
||||
q[0] = s0 << ROW_BITS; q[1] = DCT_DESCALE(s1, CONST_BITS-ROW_BITS); q[2] = DCT_DESCALE(s2, CONST_BITS-ROW_BITS); q[3] = DCT_DESCALE(s3, CONST_BITS-ROW_BITS);
|
||||
q[4] = s4 << ROW_BITS; q[5] = DCT_DESCALE(s5, CONST_BITS-ROW_BITS); q[6] = DCT_DESCALE(s6, CONST_BITS-ROW_BITS); q[7] = DCT_DESCALE(s7, CONST_BITS-ROW_BITS);
|
||||
}
|
||||
for (q = p, c = 7; c >= 0; c--, q++) {
|
||||
int32 s0 = q[0*8], s1 = q[1*8], s2 = q[2*8], s3 = q[3*8], s4 = q[4*8], s5 = q[5*8], s6 = q[6*8], s7 = q[7*8];
|
||||
DCT1D(s0, s1, s2, s3, s4, s5, s6, s7);
|
||||
q[0*8] = DCT_DESCALE(s0, ROW_BITS+3); q[1*8] = DCT_DESCALE(s1, CONST_BITS+ROW_BITS+3); q[2*8] = DCT_DESCALE(s2, CONST_BITS+ROW_BITS+3); q[3*8] = DCT_DESCALE(s3, CONST_BITS+ROW_BITS+3);
|
||||
q[4*8] = DCT_DESCALE(s4, ROW_BITS+3); q[5*8] = DCT_DESCALE(s5, CONST_BITS+ROW_BITS+3); q[6*8] = DCT_DESCALE(s6, CONST_BITS+ROW_BITS+3); q[7*8] = DCT_DESCALE(s7, CONST_BITS+ROW_BITS+3);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the actual canonical Huffman codes/code sizes given the JPEG huff bits and val arrays.
|
||||
static void compute_huffman_table(uint *codes, uint8 *code_sizes, uint8 *bits, uint8 *val)
|
||||
{
|
||||
int i, l, last_p, si;
|
||||
static uint8 huff_size[257];
|
||||
static uint huff_code[257];
|
||||
uint code;
|
||||
|
||||
int p = 0;
|
||||
for (l = 1; l <= 16; l++) {
|
||||
for (i = 1; i <= bits[l]; i++) {
|
||||
huff_size[p++] = (char)l;
|
||||
}
|
||||
}
|
||||
|
||||
huff_size[p] = 0;
|
||||
last_p = p; // write sentinel
|
||||
|
||||
code = 0; si = huff_size[0]; p = 0;
|
||||
|
||||
while (huff_size[p]) {
|
||||
while (huff_size[p] == si) {
|
||||
huff_code[p++] = code++;
|
||||
}
|
||||
code <<= 1;
|
||||
si++;
|
||||
}
|
||||
|
||||
memset(codes, 0, sizeof(codes[0])*256);
|
||||
memset(code_sizes, 0, sizeof(code_sizes[0])*256);
|
||||
for (p = 0; p < last_p; p++) {
|
||||
codes[val[p]] = huff_code[p];
|
||||
code_sizes[val[p]] = huff_size[p];
|
||||
}
|
||||
}
|
||||
|
||||
void jpeg_encoder::flush_output_buffer()
|
||||
{
|
||||
if (m_out_buf_left != JPGE_OUT_BUF_SIZE) {
|
||||
m_all_stream_writes_succeeded = m_all_stream_writes_succeeded && m_pStream->put_buf(m_out_buf, JPGE_OUT_BUF_SIZE - m_out_buf_left);
|
||||
}
|
||||
m_pOut_buf = m_out_buf;
|
||||
m_out_buf_left = JPGE_OUT_BUF_SIZE;
|
||||
}
|
||||
|
||||
void jpeg_encoder::emit_byte(uint8 i)
|
||||
{
|
||||
*m_pOut_buf++ = i;
|
||||
if (--m_out_buf_left == 0) {
|
||||
flush_output_buffer();
|
||||
}
|
||||
}
|
||||
|
||||
void jpeg_encoder::put_bits(uint bits, uint len)
|
||||
{
|
||||
uint8 c = 0;
|
||||
m_bit_buffer |= ((uint32)bits << (24 - (m_bits_in += len)));
|
||||
while (m_bits_in >= 8) {
|
||||
c = (uint8)((m_bit_buffer >> 16) & 0xFF);
|
||||
emit_byte(c);
|
||||
if (c == 0xFF) {
|
||||
emit_byte(0);
|
||||
}
|
||||
m_bit_buffer <<= 8;
|
||||
m_bits_in -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void jpeg_encoder::emit_word(uint i)
|
||||
{
|
||||
emit_byte(uint8(i >> 8)); emit_byte(uint8(i & 0xFF));
|
||||
}
|
||||
|
||||
// JPEG marker generation.
|
||||
void jpeg_encoder::emit_marker(int marker)
|
||||
{
|
||||
emit_byte(uint8(0xFF)); emit_byte(uint8(marker));
|
||||
}
|
||||
|
||||
// Emit JFIF marker
|
||||
void jpeg_encoder::emit_jfif_app0()
|
||||
{
|
||||
emit_marker(M_APP0);
|
||||
emit_word(2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1);
|
||||
emit_byte(0x4A); emit_byte(0x46); emit_byte(0x49); emit_byte(0x46); /* Identifier: ASCII "JFIF" */
|
||||
emit_byte(0);
|
||||
emit_byte(1); /* Major version */
|
||||
emit_byte(1); /* Minor version */
|
||||
emit_byte(0); /* Density unit */
|
||||
emit_word(1);
|
||||
emit_word(1);
|
||||
emit_byte(0); /* No thumbnail image */
|
||||
emit_byte(0);
|
||||
}
|
||||
|
||||
// Emit quantization tables
|
||||
void jpeg_encoder::emit_dqt()
|
||||
{
|
||||
for (int i = 0; i < ((m_num_components == 3) ? 2 : 1); i++)
|
||||
{
|
||||
emit_marker(M_DQT);
|
||||
emit_word(64 + 1 + 2);
|
||||
emit_byte(static_cast<uint8>(i));
|
||||
for (int j = 0; j < 64; j++)
|
||||
emit_byte(static_cast<uint8>(m_quantization_tables[i][j]));
|
||||
}
|
||||
}
|
||||
|
||||
// Emit start of frame marker
|
||||
void jpeg_encoder::emit_sof()
|
||||
{
|
||||
emit_marker(M_SOF0); /* baseline */
|
||||
emit_word(3 * m_num_components + 2 + 5 + 1);
|
||||
emit_byte(8); /* precision */
|
||||
emit_word(m_image_y);
|
||||
emit_word(m_image_x);
|
||||
emit_byte(m_num_components);
|
||||
for (int i = 0; i < m_num_components; i++)
|
||||
{
|
||||
emit_byte(static_cast<uint8>(i + 1)); /* component ID */
|
||||
emit_byte((m_comp_h_samp[i] << 4) + m_comp_v_samp[i]); /* h and v sampling */
|
||||
emit_byte(i > 0); /* quant. table num */
|
||||
}
|
||||
}
|
||||
|
||||
// Emit Huffman table.
|
||||
void jpeg_encoder::emit_dht(uint8 *bits, uint8 *val, int index, bool ac_flag)
|
||||
{
|
||||
emit_marker(M_DHT);
|
||||
|
||||
int length = 0;
|
||||
for (int i = 1; i <= 16; i++)
|
||||
length += bits[i];
|
||||
|
||||
emit_word(length + 2 + 1 + 16);
|
||||
emit_byte(static_cast<uint8>(index + (ac_flag << 4)));
|
||||
|
||||
for (int i = 1; i <= 16; i++)
|
||||
emit_byte(bits[i]);
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
emit_byte(val[i]);
|
||||
}
|
||||
|
||||
// Emit all Huffman tables.
|
||||
void jpeg_encoder::emit_dhts()
|
||||
{
|
||||
emit_dht(m_huff_bits[0+0], m_huff_val[0+0], 0, false);
|
||||
emit_dht(m_huff_bits[2+0], m_huff_val[2+0], 0, true);
|
||||
if (m_num_components == 3) {
|
||||
emit_dht(m_huff_bits[0+1], m_huff_val[0+1], 1, false);
|
||||
emit_dht(m_huff_bits[2+1], m_huff_val[2+1], 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
// emit start of scan
|
||||
void jpeg_encoder::emit_sos()
|
||||
{
|
||||
emit_marker(M_SOS);
|
||||
emit_word(2 * m_num_components + 2 + 1 + 3);
|
||||
emit_byte(m_num_components);
|
||||
for (int i = 0; i < m_num_components; i++)
|
||||
{
|
||||
emit_byte(static_cast<uint8>(i + 1));
|
||||
if (i == 0)
|
||||
emit_byte((0 << 4) + 0);
|
||||
else
|
||||
emit_byte((1 << 4) + 1);
|
||||
}
|
||||
emit_byte(0); /* spectral selection */
|
||||
emit_byte(63);
|
||||
emit_byte(0);
|
||||
}
|
||||
|
||||
void jpeg_encoder::load_block_8_8_grey(int x)
|
||||
{
|
||||
uint8 *pSrc;
|
||||
sample_array_t *pDst = m_sample_array;
|
||||
x <<= 3;
|
||||
for (int i = 0; i < 8; i++, pDst += 8)
|
||||
{
|
||||
pSrc = m_mcu_lines[i] + x;
|
||||
pDst[0] = pSrc[0] - 128; pDst[1] = pSrc[1] - 128; pDst[2] = pSrc[2] - 128; pDst[3] = pSrc[3] - 128;
|
||||
pDst[4] = pSrc[4] - 128; pDst[5] = pSrc[5] - 128; pDst[6] = pSrc[6] - 128; pDst[7] = pSrc[7] - 128;
|
||||
}
|
||||
}
|
||||
|
||||
void jpeg_encoder::load_block_8_8(int x, int y, int c)
|
||||
{
|
||||
uint8 *pSrc;
|
||||
sample_array_t *pDst = m_sample_array;
|
||||
x = (x * (8 * 3)) + c;
|
||||
y <<= 3;
|
||||
for (int i = 0; i < 8; i++, pDst += 8)
|
||||
{
|
||||
pSrc = m_mcu_lines[y + i] + x;
|
||||
pDst[0] = pSrc[0 * 3] - 128; pDst[1] = pSrc[1 * 3] - 128; pDst[2] = pSrc[2 * 3] - 128; pDst[3] = pSrc[3 * 3] - 128;
|
||||
pDst[4] = pSrc[4 * 3] - 128; pDst[5] = pSrc[5 * 3] - 128; pDst[6] = pSrc[6 * 3] - 128; pDst[7] = pSrc[7 * 3] - 128;
|
||||
}
|
||||
}
|
||||
|
||||
void jpeg_encoder::load_block_16_8(int x, int c)
|
||||
{
|
||||
uint8 *pSrc1, *pSrc2;
|
||||
sample_array_t *pDst = m_sample_array;
|
||||
x = (x * (16 * 3)) + c;
|
||||
int a = 0, b = 2;
|
||||
for (int i = 0; i < 16; i += 2, pDst += 8)
|
||||
{
|
||||
pSrc1 = m_mcu_lines[i + 0] + x;
|
||||
pSrc2 = m_mcu_lines[i + 1] + x;
|
||||
pDst[0] = ((pSrc1[ 0 * 3] + pSrc1[ 1 * 3] + pSrc2[ 0 * 3] + pSrc2[ 1 * 3] + a) >> 2) - 128; pDst[1] = ((pSrc1[ 2 * 3] + pSrc1[ 3 * 3] + pSrc2[ 2 * 3] + pSrc2[ 3 * 3] + b) >> 2) - 128;
|
||||
pDst[2] = ((pSrc1[ 4 * 3] + pSrc1[ 5 * 3] + pSrc2[ 4 * 3] + pSrc2[ 5 * 3] + a) >> 2) - 128; pDst[3] = ((pSrc1[ 6 * 3] + pSrc1[ 7 * 3] + pSrc2[ 6 * 3] + pSrc2[ 7 * 3] + b) >> 2) - 128;
|
||||
pDst[4] = ((pSrc1[ 8 * 3] + pSrc1[ 9 * 3] + pSrc2[ 8 * 3] + pSrc2[ 9 * 3] + a) >> 2) - 128; pDst[5] = ((pSrc1[10 * 3] + pSrc1[11 * 3] + pSrc2[10 * 3] + pSrc2[11 * 3] + b) >> 2) - 128;
|
||||
pDst[6] = ((pSrc1[12 * 3] + pSrc1[13 * 3] + pSrc2[12 * 3] + pSrc2[13 * 3] + a) >> 2) - 128; pDst[7] = ((pSrc1[14 * 3] + pSrc1[15 * 3] + pSrc2[14 * 3] + pSrc2[15 * 3] + b) >> 2) - 128;
|
||||
int temp = a; a = b; b = temp;
|
||||
}
|
||||
}
|
||||
|
||||
void jpeg_encoder::load_block_16_8_8(int x, int c)
|
||||
{
|
||||
uint8 *pSrc1;
|
||||
sample_array_t *pDst = m_sample_array;
|
||||
x = (x * (16 * 3)) + c;
|
||||
for (int i = 0; i < 8; i++, pDst += 8)
|
||||
{
|
||||
pSrc1 = m_mcu_lines[i + 0] + x;
|
||||
pDst[0] = ((pSrc1[ 0 * 3] + pSrc1[ 1 * 3]) >> 1) - 128; pDst[1] = ((pSrc1[ 2 * 3] + pSrc1[ 3 * 3]) >> 1) - 128;
|
||||
pDst[2] = ((pSrc1[ 4 * 3] + pSrc1[ 5 * 3]) >> 1) - 128; pDst[3] = ((pSrc1[ 6 * 3] + pSrc1[ 7 * 3]) >> 1) - 128;
|
||||
pDst[4] = ((pSrc1[ 8 * 3] + pSrc1[ 9 * 3]) >> 1) - 128; pDst[5] = ((pSrc1[10 * 3] + pSrc1[11 * 3]) >> 1) - 128;
|
||||
pDst[6] = ((pSrc1[12 * 3] + pSrc1[13 * 3]) >> 1) - 128; pDst[7] = ((pSrc1[14 * 3] + pSrc1[15 * 3]) >> 1) - 128;
|
||||
}
|
||||
}
|
||||
|
||||
void jpeg_encoder::load_quantized_coefficients(int component_num)
|
||||
{
|
||||
int32 *q = m_quantization_tables[component_num > 0];
|
||||
int16 *pDst = m_coefficient_array;
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
sample_array_t j = m_sample_array[s_zag[i]];
|
||||
if (j < 0)
|
||||
{
|
||||
if ((j = -j + (*q >> 1)) < *q)
|
||||
*pDst++ = 0;
|
||||
else
|
||||
*pDst++ = static_cast<int16>(-(j / *q));
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((j = j + (*q >> 1)) < *q)
|
||||
*pDst++ = 0;
|
||||
else
|
||||
*pDst++ = static_cast<int16>((j / *q));
|
||||
}
|
||||
q++;
|
||||
}
|
||||
}
|
||||
|
||||
void jpeg_encoder::code_coefficients_pass_two(int component_num)
|
||||
{
|
||||
int i, j, run_len, nbits, temp1, temp2;
|
||||
int16 *pSrc = m_coefficient_array;
|
||||
uint *codes[2];
|
||||
uint8 *code_sizes[2];
|
||||
|
||||
if (component_num == 0)
|
||||
{
|
||||
codes[0] = m_huff_codes[0 + 0]; codes[1] = m_huff_codes[2 + 0];
|
||||
code_sizes[0] = m_huff_code_sizes[0 + 0]; code_sizes[1] = m_huff_code_sizes[2 + 0];
|
||||
}
|
||||
else
|
||||
{
|
||||
codes[0] = m_huff_codes[0 + 1]; codes[1] = m_huff_codes[2 + 1];
|
||||
code_sizes[0] = m_huff_code_sizes[0 + 1]; code_sizes[1] = m_huff_code_sizes[2 + 1];
|
||||
}
|
||||
|
||||
temp1 = temp2 = pSrc[0] - m_last_dc_val[component_num];
|
||||
m_last_dc_val[component_num] = pSrc[0];
|
||||
|
||||
if (temp1 < 0)
|
||||
{
|
||||
temp1 = -temp1; temp2--;
|
||||
}
|
||||
|
||||
nbits = 0;
|
||||
while (temp1)
|
||||
{
|
||||
nbits++; temp1 >>= 1;
|
||||
}
|
||||
|
||||
put_bits(codes[0][nbits], code_sizes[0][nbits]);
|
||||
if (nbits) put_bits(temp2 & ((1 << nbits) - 1), nbits);
|
||||
|
||||
for (run_len = 0, i = 1; i < 64; i++)
|
||||
{
|
||||
if ((temp1 = m_coefficient_array[i]) == 0)
|
||||
run_len++;
|
||||
else
|
||||
{
|
||||
while (run_len >= 16)
|
||||
{
|
||||
put_bits(codes[1][0xF0], code_sizes[1][0xF0]);
|
||||
run_len -= 16;
|
||||
}
|
||||
if ((temp2 = temp1) < 0)
|
||||
{
|
||||
temp1 = -temp1;
|
||||
temp2--;
|
||||
}
|
||||
nbits = 1;
|
||||
while (temp1 >>= 1)
|
||||
nbits++;
|
||||
j = (run_len << 4) + nbits;
|
||||
put_bits(codes[1][j], code_sizes[1][j]);
|
||||
put_bits(temp2 & ((1 << nbits) - 1), nbits);
|
||||
run_len = 0;
|
||||
}
|
||||
}
|
||||
if (run_len)
|
||||
put_bits(codes[1][0], code_sizes[1][0]);
|
||||
}
|
||||
|
||||
void jpeg_encoder::code_block(int component_num)
|
||||
{
|
||||
DCT2D(m_sample_array);
|
||||
load_quantized_coefficients(component_num);
|
||||
code_coefficients_pass_two(component_num);
|
||||
}
|
||||
|
||||
void jpeg_encoder::process_mcu_row()
|
||||
{
|
||||
if (m_num_components == 1)
|
||||
{
|
||||
for (int i = 0; i < m_mcus_per_row; i++)
|
||||
{
|
||||
load_block_8_8_grey(i); code_block(0);
|
||||
}
|
||||
}
|
||||
else if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 1))
|
||||
{
|
||||
for (int i = 0; i < m_mcus_per_row; i++)
|
||||
{
|
||||
load_block_8_8(i, 0, 0); code_block(0); load_block_8_8(i, 0, 1); code_block(1); load_block_8_8(i, 0, 2); code_block(2);
|
||||
}
|
||||
}
|
||||
else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 1))
|
||||
{
|
||||
for (int i = 0; i < m_mcus_per_row; i++)
|
||||
{
|
||||
load_block_8_8(i * 2 + 0, 0, 0); code_block(0); load_block_8_8(i * 2 + 1, 0, 0); code_block(0);
|
||||
load_block_16_8_8(i, 1); code_block(1); load_block_16_8_8(i, 2); code_block(2);
|
||||
}
|
||||
}
|
||||
else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 2))
|
||||
{
|
||||
for (int i = 0; i < m_mcus_per_row; i++)
|
||||
{
|
||||
load_block_8_8(i * 2 + 0, 0, 0); code_block(0); load_block_8_8(i * 2 + 1, 0, 0); code_block(0);
|
||||
load_block_8_8(i * 2 + 0, 1, 0); code_block(0); load_block_8_8(i * 2 + 1, 1, 0); code_block(0);
|
||||
load_block_16_8(i, 1); code_block(1); load_block_16_8(i, 2); code_block(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void jpeg_encoder::load_mcu(const void *pSrc)
|
||||
{
|
||||
const uint8* Psrc = reinterpret_cast<const uint8*>(pSrc);
|
||||
|
||||
uint8* pDst = m_mcu_lines[m_mcu_y_ofs]; // OK to write up to m_image_bpl_xlt bytes to pDst
|
||||
|
||||
if (m_num_components == 1) {
|
||||
if (m_image_bpp == 3)
|
||||
RGB_to_Y(pDst, Psrc, m_image_x);
|
||||
else
|
||||
memcpy(pDst, Psrc, m_image_x);
|
||||
} else {
|
||||
if (m_image_bpp == 3)
|
||||
RGB_to_YCC(pDst, Psrc, m_image_x);
|
||||
else
|
||||
Y_to_YCC(pDst, Psrc, m_image_x);
|
||||
}
|
||||
|
||||
// Possibly duplicate pixels at end of scanline if not a multiple of 8 or 16
|
||||
if (m_num_components == 1)
|
||||
memset(m_mcu_lines[m_mcu_y_ofs] + m_image_bpl_xlt, pDst[m_image_bpl_xlt - 1], m_image_x_mcu - m_image_x);
|
||||
else
|
||||
{
|
||||
const uint8 y = pDst[m_image_bpl_xlt - 3 + 0], cb = pDst[m_image_bpl_xlt - 3 + 1], cr = pDst[m_image_bpl_xlt - 3 + 2];
|
||||
uint8 *q = m_mcu_lines[m_mcu_y_ofs] + m_image_bpl_xlt;
|
||||
for (int i = m_image_x; i < m_image_x_mcu; i++)
|
||||
{
|
||||
*q++ = y; *q++ = cb; *q++ = cr;
|
||||
}
|
||||
}
|
||||
|
||||
if (++m_mcu_y_ofs == m_mcu_y)
|
||||
{
|
||||
process_mcu_row();
|
||||
m_mcu_y_ofs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Quantization table generation.
|
||||
void jpeg_encoder::compute_quant_table(int32 *pDst, const int16 *pSrc)
|
||||
{
|
||||
int32 q;
|
||||
if (m_params.m_quality < 50)
|
||||
q = 5000 / m_params.m_quality;
|
||||
else
|
||||
q = 200 - m_params.m_quality * 2;
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
int32 j = *pSrc++; j = (j * q + 50L) / 100L;
|
||||
*pDst++ = JPGE_MIN(JPGE_MAX(j, 1), 255);
|
||||
}
|
||||
}
|
||||
|
||||
// Higher-level methods.
|
||||
bool jpeg_encoder::jpg_open(int p_x_res, int p_y_res, int src_channels)
|
||||
{
|
||||
m_num_components = 3;
|
||||
switch (m_params.m_subsampling)
|
||||
{
|
||||
case Y_ONLY:
|
||||
{
|
||||
m_num_components = 1;
|
||||
m_comp_h_samp[0] = 1; m_comp_v_samp[0] = 1;
|
||||
m_mcu_x = 8; m_mcu_y = 8;
|
||||
break;
|
||||
}
|
||||
case H1V1:
|
||||
{
|
||||
m_comp_h_samp[0] = 1; m_comp_v_samp[0] = 1;
|
||||
m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1;
|
||||
m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1;
|
||||
m_mcu_x = 8; m_mcu_y = 8;
|
||||
break;
|
||||
}
|
||||
case H2V1:
|
||||
{
|
||||
m_comp_h_samp[0] = 2; m_comp_v_samp[0] = 1;
|
||||
m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1;
|
||||
m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1;
|
||||
m_mcu_x = 16; m_mcu_y = 8;
|
||||
break;
|
||||
}
|
||||
case H2V2:
|
||||
{
|
||||
m_comp_h_samp[0] = 2; m_comp_v_samp[0] = 2;
|
||||
m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1;
|
||||
m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1;
|
||||
m_mcu_x = 16; m_mcu_y = 16;
|
||||
}
|
||||
}
|
||||
|
||||
m_image_x = p_x_res; m_image_y = p_y_res;
|
||||
m_image_bpp = src_channels;
|
||||
m_image_bpl = m_image_x * src_channels;
|
||||
m_image_x_mcu = (m_image_x + m_mcu_x - 1) & (~(m_mcu_x - 1));
|
||||
m_image_y_mcu = (m_image_y + m_mcu_y - 1) & (~(m_mcu_y - 1));
|
||||
m_image_bpl_xlt = m_image_x * m_num_components;
|
||||
m_image_bpl_mcu = m_image_x_mcu * m_num_components;
|
||||
m_mcus_per_row = m_image_x_mcu / m_mcu_x;
|
||||
|
||||
if ((m_mcu_lines[0] = static_cast<uint8*>(jpge_malloc(m_image_bpl_mcu * m_mcu_y))) == NULL) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 1; i < m_mcu_y; i++)
|
||||
m_mcu_lines[i] = m_mcu_lines[i-1] + m_image_bpl_mcu;
|
||||
|
||||
if(m_last_quality != m_params.m_quality){
|
||||
m_last_quality = m_params.m_quality;
|
||||
compute_quant_table(m_quantization_tables[0], s_std_lum_quant);
|
||||
compute_quant_table(m_quantization_tables[1], s_std_croma_quant);
|
||||
}
|
||||
|
||||
if(!m_huff_initialized){
|
||||
m_huff_initialized = true;
|
||||
|
||||
memcpy(m_huff_bits[0+0], s_dc_lum_bits, 17); memcpy(m_huff_val[0+0], s_dc_lum_val, DC_LUM_CODES);
|
||||
memcpy(m_huff_bits[2+0], s_ac_lum_bits, 17); memcpy(m_huff_val[2+0], s_ac_lum_val, AC_LUM_CODES);
|
||||
memcpy(m_huff_bits[0+1], s_dc_chroma_bits, 17); memcpy(m_huff_val[0+1], s_dc_chroma_val, DC_CHROMA_CODES);
|
||||
memcpy(m_huff_bits[2+1], s_ac_chroma_bits, 17); memcpy(m_huff_val[2+1], s_ac_chroma_val, AC_CHROMA_CODES);
|
||||
|
||||
compute_huffman_table(&m_huff_codes[0+0][0], &m_huff_code_sizes[0+0][0], m_huff_bits[0+0], m_huff_val[0+0]);
|
||||
compute_huffman_table(&m_huff_codes[2+0][0], &m_huff_code_sizes[2+0][0], m_huff_bits[2+0], m_huff_val[2+0]);
|
||||
compute_huffman_table(&m_huff_codes[0+1][0], &m_huff_code_sizes[0+1][0], m_huff_bits[0+1], m_huff_val[0+1]);
|
||||
compute_huffman_table(&m_huff_codes[2+1][0], &m_huff_code_sizes[2+1][0], m_huff_bits[2+1], m_huff_val[2+1]);
|
||||
}
|
||||
|
||||
m_out_buf_left = JPGE_OUT_BUF_SIZE;
|
||||
m_pOut_buf = m_out_buf;
|
||||
m_bit_buffer = 0;
|
||||
m_bits_in = 0;
|
||||
m_mcu_y_ofs = 0;
|
||||
m_pass_num = 2;
|
||||
memset(m_last_dc_val, 0, 3 * sizeof(m_last_dc_val[0]));
|
||||
|
||||
// Emit all markers at beginning of image file.
|
||||
emit_marker(M_SOI);
|
||||
emit_jfif_app0();
|
||||
emit_dqt();
|
||||
emit_sof();
|
||||
emit_dhts();
|
||||
emit_sos();
|
||||
|
||||
return m_all_stream_writes_succeeded;
|
||||
}
|
||||
|
||||
bool jpeg_encoder::process_end_of_image()
|
||||
{
|
||||
if (m_mcu_y_ofs) {
|
||||
if (m_mcu_y_ofs < 16) { // check here just to shut up static analysis
|
||||
for (int i = m_mcu_y_ofs; i < m_mcu_y; i++) {
|
||||
memcpy(m_mcu_lines[i], m_mcu_lines[m_mcu_y_ofs - 1], m_image_bpl_mcu);
|
||||
}
|
||||
}
|
||||
process_mcu_row();
|
||||
}
|
||||
|
||||
put_bits(0x7F, 7);
|
||||
emit_marker(M_EOI);
|
||||
flush_output_buffer();
|
||||
m_all_stream_writes_succeeded = m_all_stream_writes_succeeded && m_pStream->put_buf(NULL, 0);
|
||||
m_pass_num++; // purposely bump up m_pass_num, for debugging
|
||||
return true;
|
||||
}
|
||||
|
||||
void jpeg_encoder::clear()
|
||||
{
|
||||
m_mcu_lines[0] = NULL;
|
||||
m_pass_num = 0;
|
||||
m_all_stream_writes_succeeded = true;
|
||||
}
|
||||
|
||||
jpeg_encoder::jpeg_encoder()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
jpeg_encoder::~jpeg_encoder()
|
||||
{
|
||||
deinit();
|
||||
}
|
||||
|
||||
bool jpeg_encoder::init(output_stream *pStream, int width, int height, int src_channels, const params &comp_params)
|
||||
{
|
||||
deinit();
|
||||
if (((!pStream) || (width < 1) || (height < 1)) || ((src_channels != 1) && (src_channels != 3) && (src_channels != 4)) || (!comp_params.check())) return false;
|
||||
m_pStream = pStream;
|
||||
m_params = comp_params;
|
||||
return jpg_open(width, height, src_channels);
|
||||
}
|
||||
|
||||
void jpeg_encoder::deinit()
|
||||
{
|
||||
jpge_free(m_mcu_lines[0]);
|
||||
clear();
|
||||
}
|
||||
|
||||
bool jpeg_encoder::process_scanline(const void* pScanline)
|
||||
{
|
||||
if ((m_pass_num < 1) || (m_pass_num > 2)) {
|
||||
return false;
|
||||
}
|
||||
if (m_all_stream_writes_succeeded) {
|
||||
if (!pScanline) {
|
||||
if (!process_end_of_image()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
load_mcu(pScanline);
|
||||
}
|
||||
}
|
||||
return m_all_stream_writes_succeeded;
|
||||
}
|
||||
|
||||
} // namespace jpge
|
||||
@@ -1,142 +0,0 @@
|
||||
// jpge.h - C++ class for JPEG compression.
|
||||
// Public domain, Rich Geldreich <richgel99@gmail.com>
|
||||
// Alex Evans: Added RGBA support, linear memory allocator.
|
||||
#ifndef JPEG_ENCODER_H
|
||||
#define JPEG_ENCODER_H
|
||||
|
||||
namespace jpge
|
||||
{
|
||||
typedef unsigned char uint8;
|
||||
typedef signed short int16;
|
||||
typedef signed int int32;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
typedef unsigned int uint;
|
||||
|
||||
// JPEG chroma subsampling factors. Y_ONLY (grayscale images) and H2V2 (color images) are the most common.
|
||||
enum subsampling_t { Y_ONLY = 0, H1V1 = 1, H2V1 = 2, H2V2 = 3 };
|
||||
|
||||
// JPEG compression parameters structure.
|
||||
struct params {
|
||||
inline params() : m_quality(85), m_subsampling(H2V2) { }
|
||||
|
||||
inline bool check() const {
|
||||
if ((m_quality < 1) || (m_quality > 100)) {
|
||||
return false;
|
||||
}
|
||||
if ((uint)m_subsampling > (uint)H2V2) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Quality: 1-100, higher is better. Typical values are around 50-95.
|
||||
int m_quality;
|
||||
|
||||
// m_subsampling:
|
||||
// 0 = Y (grayscale) only
|
||||
// 1 = H1V1 subsampling (YCbCr 1x1x1, 3 blocks per MCU)
|
||||
// 2 = H2V1 subsampling (YCbCr 2x1x1, 4 blocks per MCU)
|
||||
// 3 = H2V2 subsampling (YCbCr 4x1x1, 6 blocks per MCU-- very common)
|
||||
subsampling_t m_subsampling;
|
||||
};
|
||||
|
||||
// Output stream abstract class - used by the jpeg_encoder class to write to the output stream.
|
||||
// put_buf() is generally called with len==JPGE_OUT_BUF_SIZE bytes, but for headers it'll be called with smaller amounts.
|
||||
class output_stream {
|
||||
public:
|
||||
virtual ~output_stream() { };
|
||||
virtual bool put_buf(const void* Pbuf, int len) = 0;
|
||||
virtual uint get_size() const = 0;
|
||||
};
|
||||
|
||||
// Lower level jpeg_encoder class - useful if more control is needed than the above helper functions.
|
||||
class jpeg_encoder {
|
||||
public:
|
||||
jpeg_encoder();
|
||||
~jpeg_encoder();
|
||||
|
||||
// Initializes the compressor.
|
||||
// pStream: The stream object to use for writing compressed data.
|
||||
// params - Compression parameters structure, defined above.
|
||||
// width, height - Image dimensions.
|
||||
// channels - May be 1, or 3. 1 indicates grayscale, 3 indicates RGB source data.
|
||||
// Returns false on out of memory or if a stream write fails.
|
||||
bool init(output_stream *pStream, int width, int height, int src_channels, const params &comp_params = params());
|
||||
|
||||
// Call this method with each source scanline.
|
||||
// width * src_channels bytes per scanline is expected (RGB or Y format).
|
||||
// You must call with NULL after all scanlines are processed to finish compression.
|
||||
// Returns false on out of memory or if a stream write fails.
|
||||
bool process_scanline(const void* pScanline);
|
||||
|
||||
// Deinitializes the compressor, freeing any allocated memory. May be called at any time.
|
||||
void deinit();
|
||||
|
||||
private:
|
||||
jpeg_encoder(const jpeg_encoder &);
|
||||
jpeg_encoder &operator =(const jpeg_encoder &);
|
||||
|
||||
typedef int32 sample_array_t;
|
||||
enum { JPGE_OUT_BUF_SIZE = 512 };
|
||||
|
||||
output_stream *m_pStream;
|
||||
params m_params;
|
||||
uint8 m_num_components;
|
||||
uint8 m_comp_h_samp[3], m_comp_v_samp[3];
|
||||
int m_image_x, m_image_y, m_image_bpp, m_image_bpl;
|
||||
int m_image_x_mcu, m_image_y_mcu;
|
||||
int m_image_bpl_xlt, m_image_bpl_mcu;
|
||||
int m_mcus_per_row;
|
||||
int m_mcu_x, m_mcu_y;
|
||||
uint8 *m_mcu_lines[16];
|
||||
uint8 m_mcu_y_ofs;
|
||||
sample_array_t m_sample_array[64];
|
||||
int16 m_coefficient_array[64];
|
||||
|
||||
int m_last_dc_val[3];
|
||||
uint8 m_out_buf[JPGE_OUT_BUF_SIZE];
|
||||
uint8 *m_pOut_buf;
|
||||
uint m_out_buf_left;
|
||||
uint32 m_bit_buffer;
|
||||
uint m_bits_in;
|
||||
uint8 m_pass_num;
|
||||
bool m_all_stream_writes_succeeded;
|
||||
|
||||
bool jpg_open(int p_x_res, int p_y_res, int src_channels);
|
||||
|
||||
void flush_output_buffer();
|
||||
void put_bits(uint bits, uint len);
|
||||
|
||||
void emit_byte(uint8 i);
|
||||
void emit_word(uint i);
|
||||
void emit_marker(int marker);
|
||||
|
||||
void emit_jfif_app0();
|
||||
void emit_dqt();
|
||||
void emit_sof();
|
||||
void emit_dht(uint8 *bits, uint8 *val, int index, bool ac_flag);
|
||||
void emit_dhts();
|
||||
void emit_sos();
|
||||
|
||||
void compute_quant_table(int32 *dst, const int16 *src);
|
||||
void load_quantized_coefficients(int component_num);
|
||||
|
||||
void load_block_8_8_grey(int x);
|
||||
void load_block_8_8(int x, int y, int c);
|
||||
void load_block_16_8(int x, int c);
|
||||
void load_block_16_8_8(int x, int c);
|
||||
|
||||
void code_coefficients_pass_two(int component_num);
|
||||
void code_block(int component_num);
|
||||
|
||||
void process_mcu_row();
|
||||
bool process_end_of_image();
|
||||
void load_mcu(const void* src);
|
||||
void clear();
|
||||
void init();
|
||||
};
|
||||
|
||||
} // namespace jpge
|
||||
|
||||
#endif // JPEG_ENCODER
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#ifndef _CONVERSIONS_YUV_H_
|
||||
#define _CONVERSIONS_YUV_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void yuv2rgb(uint8_t y, uint8_t u, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _CONVERSIONS_YUV_H_ */
|
||||
@@ -1,326 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "img_converters.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "yuv.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_jpg_decode.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4 // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/spiram.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "esp_spiram.h"
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* TAG = "to_bmp";
|
||||
#endif
|
||||
|
||||
static const int BMP_HEADER_LEN = 54;
|
||||
|
||||
typedef struct {
|
||||
uint32_t filesize;
|
||||
uint32_t reserved;
|
||||
uint32_t fileoffset_to_pixelarray;
|
||||
uint32_t dibheadersize;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
uint16_t planes;
|
||||
uint16_t bitsperpixel;
|
||||
uint32_t compression;
|
||||
uint32_t imagesize;
|
||||
uint32_t ypixelpermeter;
|
||||
uint32_t xpixelpermeter;
|
||||
uint32_t numcolorspallette;
|
||||
uint32_t mostimpcolor;
|
||||
} bmp_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint16_t data_offset;
|
||||
const uint8_t *input;
|
||||
uint8_t *output;
|
||||
} rgb_jpg_decoder;
|
||||
|
||||
static void *_malloc(size_t size)
|
||||
{
|
||||
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
}
|
||||
|
||||
//output buffer and image width
|
||||
static bool _rgb_write(void * arg, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t *data)
|
||||
{
|
||||
rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg;
|
||||
if(!data){
|
||||
if(x == 0 && y == 0){
|
||||
//write start
|
||||
jpeg->width = w;
|
||||
jpeg->height = h;
|
||||
//if output is null, this is BMP
|
||||
if(!jpeg->output){
|
||||
jpeg->output = (uint8_t *)_malloc((w*h*3)+jpeg->data_offset);
|
||||
if(!jpeg->output){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//write end
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t jw = jpeg->width*3;
|
||||
size_t t = y * jw;
|
||||
size_t b = t + (h * jw);
|
||||
size_t l = x * 3;
|
||||
uint8_t *out = jpeg->output+jpeg->data_offset;
|
||||
uint8_t *o = out;
|
||||
size_t iy, ix;
|
||||
|
||||
w = w * 3;
|
||||
|
||||
for(iy=t; iy<b; iy+=jw) {
|
||||
o = out+iy+l;
|
||||
for(ix=0; ix<w; ix+= 3) {
|
||||
o[ix] = data[ix+2];
|
||||
o[ix+1] = data[ix+1];
|
||||
o[ix+2] = data[ix];
|
||||
}
|
||||
data+=w;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//input buffer
|
||||
static uint32_t _jpg_read(void * arg, size_t index, uint8_t *buf, size_t len)
|
||||
{
|
||||
rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg;
|
||||
if(buf) {
|
||||
memcpy(buf, jpeg->input + index, len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool jpg2rgb888(const uint8_t *src, size_t src_len, uint8_t * out, jpg_scale_t scale)
|
||||
{
|
||||
rgb_jpg_decoder jpeg;
|
||||
jpeg.width = 0;
|
||||
jpeg.height = 0;
|
||||
jpeg.input = src;
|
||||
jpeg.output = out;
|
||||
jpeg.data_offset = 0;
|
||||
|
||||
if(esp_jpg_decode(src_len, scale, _jpg_read, _rgb_write, (void*)&jpeg) != ESP_OK){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool jpg2bmp(const uint8_t *src, size_t src_len, uint8_t ** out, size_t * out_len)
|
||||
{
|
||||
|
||||
rgb_jpg_decoder jpeg;
|
||||
jpeg.width = 0;
|
||||
jpeg.height = 0;
|
||||
jpeg.input = src;
|
||||
jpeg.output = NULL;
|
||||
jpeg.data_offset = BMP_HEADER_LEN;
|
||||
|
||||
if(esp_jpg_decode(src_len, JPG_SCALE_NONE, _jpg_read, _rgb_write, (void*)&jpeg) != ESP_OK){
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t output_size = jpeg.width*jpeg.height*3;
|
||||
|
||||
jpeg.output[0] = 'B';
|
||||
jpeg.output[1] = 'M';
|
||||
bmp_header_t * bitmap = (bmp_header_t*)&jpeg.output[2];
|
||||
bitmap->reserved = 0;
|
||||
bitmap->filesize = output_size+BMP_HEADER_LEN;
|
||||
bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN;
|
||||
bitmap->dibheadersize = 40;
|
||||
bitmap->width = jpeg.width;
|
||||
bitmap->height = -jpeg.height;//set negative for top to bottom
|
||||
bitmap->planes = 1;
|
||||
bitmap->bitsperpixel = 24;
|
||||
bitmap->compression = 0;
|
||||
bitmap->imagesize = output_size;
|
||||
bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI
|
||||
bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI
|
||||
bitmap->numcolorspallette = 0;
|
||||
bitmap->mostimpcolor = 0;
|
||||
|
||||
*out = jpeg.output;
|
||||
*out_len = output_size+BMP_HEADER_LEN;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint8_t * rgb_buf)
|
||||
{
|
||||
int pix_count = 0;
|
||||
if(format == PIXFORMAT_JPEG) {
|
||||
return jpg2rgb888(src_buf, src_len, rgb_buf, JPG_SCALE_NONE);
|
||||
} else if(format == PIXFORMAT_RGB888) {
|
||||
memcpy(rgb_buf, src_buf, src_len);
|
||||
} else if(format == PIXFORMAT_RGB565) {
|
||||
int i;
|
||||
uint8_t hb, lb;
|
||||
pix_count = src_len / 2;
|
||||
for(i=0; i<pix_count; i++) {
|
||||
hb = *src_buf++;
|
||||
lb = *src_buf++;
|
||||
*rgb_buf++ = (lb & 0x1F) << 3;
|
||||
*rgb_buf++ = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||
*rgb_buf++ = hb & 0xF8;
|
||||
}
|
||||
} else if(format == PIXFORMAT_GRAYSCALE) {
|
||||
int i;
|
||||
uint8_t b;
|
||||
pix_count = src_len;
|
||||
for(i=0; i<pix_count; i++) {
|
||||
b = *src_buf++;
|
||||
*rgb_buf++ = b;
|
||||
*rgb_buf++ = b;
|
||||
*rgb_buf++ = b;
|
||||
}
|
||||
} else if(format == PIXFORMAT_YUV422) {
|
||||
pix_count = src_len / 2;
|
||||
int i, maxi = pix_count / 2;
|
||||
uint8_t y0, y1, u, v;
|
||||
uint8_t r, g, b;
|
||||
for(i=0; i<maxi; i++) {
|
||||
y0 = *src_buf++;
|
||||
u = *src_buf++;
|
||||
y1 = *src_buf++;
|
||||
v = *src_buf++;
|
||||
|
||||
yuv2rgb(y0, u, v, &r, &g, &b);
|
||||
*rgb_buf++ = b;
|
||||
*rgb_buf++ = g;
|
||||
*rgb_buf++ = r;
|
||||
|
||||
yuv2rgb(y1, u, v, &r, &g, &b);
|
||||
*rgb_buf++ = b;
|
||||
*rgb_buf++ = g;
|
||||
*rgb_buf++ = r;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t ** out, size_t * out_len)
|
||||
{
|
||||
if(format == PIXFORMAT_JPEG) {
|
||||
return jpg2bmp(src, src_len, out, out_len);
|
||||
}
|
||||
|
||||
*out = NULL;
|
||||
*out_len = 0;
|
||||
|
||||
int pix_count = width*height;
|
||||
size_t out_size = (pix_count * 3) + BMP_HEADER_LEN;
|
||||
uint8_t * out_buf = (uint8_t *)_malloc(out_size);
|
||||
if(!out_buf) {
|
||||
ESP_LOGE(TAG, "_malloc failed! %u", out_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
out_buf[0] = 'B';
|
||||
out_buf[1] = 'M';
|
||||
bmp_header_t * bitmap = (bmp_header_t*)&out_buf[2];
|
||||
bitmap->reserved = 0;
|
||||
bitmap->filesize = out_size;
|
||||
bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN;
|
||||
bitmap->dibheadersize = 40;
|
||||
bitmap->width = width;
|
||||
bitmap->height = -height;//set negative for top to bottom
|
||||
bitmap->planes = 1;
|
||||
bitmap->bitsperpixel = 24;
|
||||
bitmap->compression = 0;
|
||||
bitmap->imagesize = pix_count * 3;
|
||||
bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI
|
||||
bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI
|
||||
bitmap->numcolorspallette = 0;
|
||||
bitmap->mostimpcolor = 0;
|
||||
|
||||
uint8_t * rgb_buf = out_buf + BMP_HEADER_LEN;
|
||||
uint8_t * src_buf = src;
|
||||
|
||||
|
||||
//convert data to RGB888
|
||||
if(format == PIXFORMAT_RGB888) {
|
||||
memcpy(rgb_buf, src_buf, pix_count*3);
|
||||
} else if(format == PIXFORMAT_RGB565) {
|
||||
int i;
|
||||
uint8_t hb, lb;
|
||||
for(i=0; i<pix_count; i++) {
|
||||
hb = *src_buf++;
|
||||
lb = *src_buf++;
|
||||
*rgb_buf++ = (lb & 0x1F) << 3;
|
||||
*rgb_buf++ = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||
*rgb_buf++ = hb & 0xF8;
|
||||
}
|
||||
} else if(format == PIXFORMAT_GRAYSCALE) {
|
||||
int i;
|
||||
uint8_t b;
|
||||
for(i=0; i<pix_count; i++) {
|
||||
b = *src_buf++;
|
||||
*rgb_buf++ = b;
|
||||
*rgb_buf++ = b;
|
||||
*rgb_buf++ = b;
|
||||
}
|
||||
} else if(format == PIXFORMAT_YUV422) {
|
||||
int i, maxi = pix_count / 2;
|
||||
uint8_t y0, y1, u, v;
|
||||
uint8_t r, g, b;
|
||||
for(i=0; i<maxi; i++) {
|
||||
y0 = *src_buf++;
|
||||
u = *src_buf++;
|
||||
y1 = *src_buf++;
|
||||
v = *src_buf++;
|
||||
|
||||
yuv2rgb(y0, u, v, &r, &g, &b);
|
||||
*rgb_buf++ = b;
|
||||
*rgb_buf++ = g;
|
||||
*rgb_buf++ = r;
|
||||
|
||||
yuv2rgb(y1, u, v, &r, &g, &b);
|
||||
*rgb_buf++ = b;
|
||||
*rgb_buf++ = g;
|
||||
*rgb_buf++ = r;
|
||||
}
|
||||
}
|
||||
*out = out_buf;
|
||||
*out_len = out_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool frame2bmp(camera_fb_t * fb, uint8_t ** out, size_t * out_len)
|
||||
{
|
||||
return fmt2bmp(fb->buf, fb->len, fb->width, fb->height, fb->format, out, out_len);
|
||||
}
|
||||
@@ -1,241 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "esp_attr.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_camera.h"
|
||||
#include "img_converters.h"
|
||||
#include "jpge.h"
|
||||
#include "yuv.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4 // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/spiram.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "esp_spiram.h"
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* TAG = "to_jpg";
|
||||
#endif
|
||||
|
||||
static void *_malloc(size_t size)
|
||||
{
|
||||
void * res = malloc(size);
|
||||
if(res) {
|
||||
return res;
|
||||
}
|
||||
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
}
|
||||
|
||||
static IRAM_ATTR void convert_line_format(uint8_t * src, pixformat_t format, uint8_t * dst, size_t width, size_t in_channels, size_t line)
|
||||
{
|
||||
int i=0, o=0, l=0;
|
||||
if(format == PIXFORMAT_GRAYSCALE) {
|
||||
memcpy(dst, src + line * width, width);
|
||||
} else if(format == PIXFORMAT_RGB888) {
|
||||
l = width * 3;
|
||||
src += l * line;
|
||||
for(i=0; i<l; i+=3) {
|
||||
dst[o++] = src[i+2];
|
||||
dst[o++] = src[i+1];
|
||||
dst[o++] = src[i];
|
||||
}
|
||||
} else if(format == PIXFORMAT_RGB565) {
|
||||
l = width * 2;
|
||||
src += l * line;
|
||||
for(i=0; i<l; i+=2) {
|
||||
dst[o++] = src[i] & 0xF8;
|
||||
dst[o++] = (src[i] & 0x07) << 5 | (src[i+1] & 0xE0) >> 3;
|
||||
dst[o++] = (src[i+1] & 0x1F) << 3;
|
||||
}
|
||||
} else if(format == PIXFORMAT_YUV422) {
|
||||
uint8_t y0, y1, u, v;
|
||||
uint8_t r, g, b;
|
||||
l = width * 2;
|
||||
src += l * line;
|
||||
for(i=0; i<l; i+=4) {
|
||||
y0 = src[i];
|
||||
u = src[i+1];
|
||||
y1 = src[i+2];
|
||||
v = src[i+3];
|
||||
|
||||
yuv2rgb(y0, u, v, &r, &g, &b);
|
||||
dst[o++] = r;
|
||||
dst[o++] = g;
|
||||
dst[o++] = b;
|
||||
|
||||
yuv2rgb(y1, u, v, &r, &g, &b);
|
||||
dst[o++] = r;
|
||||
dst[o++] = g;
|
||||
dst[o++] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool convert_image(uint8_t *src, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, jpge::output_stream *dst_stream)
|
||||
{
|
||||
int num_channels = 3;
|
||||
jpge::subsampling_t subsampling = jpge::H2V2;
|
||||
|
||||
if(format == PIXFORMAT_GRAYSCALE) {
|
||||
num_channels = 1;
|
||||
subsampling = jpge::Y_ONLY;
|
||||
}
|
||||
|
||||
if(!quality) {
|
||||
quality = 1;
|
||||
} else if(quality > 100) {
|
||||
quality = 100;
|
||||
}
|
||||
|
||||
jpge::params comp_params = jpge::params();
|
||||
comp_params.m_subsampling = subsampling;
|
||||
comp_params.m_quality = quality;
|
||||
|
||||
jpge::jpeg_encoder dst_image;
|
||||
|
||||
if (!dst_image.init(dst_stream, width, height, num_channels, comp_params)) {
|
||||
ESP_LOGE(TAG, "JPG encoder init failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t* line = (uint8_t*)_malloc(width * num_channels);
|
||||
if(!line) {
|
||||
ESP_LOGE(TAG, "Scan line malloc failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < height; i++) {
|
||||
convert_line_format(src, format, line, width, num_channels, i);
|
||||
if (!dst_image.process_scanline(line)) {
|
||||
ESP_LOGE(TAG, "JPG process line %u failed", i);
|
||||
free(line);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
|
||||
if (!dst_image.process_scanline(NULL)) {
|
||||
ESP_LOGE(TAG, "JPG image finish failed");
|
||||
return false;
|
||||
}
|
||||
dst_image.deinit();
|
||||
return true;
|
||||
}
|
||||
|
||||
class callback_stream : public jpge::output_stream {
|
||||
protected:
|
||||
jpg_out_cb ocb;
|
||||
void * oarg;
|
||||
size_t index;
|
||||
|
||||
public:
|
||||
callback_stream(jpg_out_cb cb, void * arg) : ocb(cb), oarg(arg), index(0) { }
|
||||
virtual ~callback_stream() { }
|
||||
virtual bool put_buf(const void* data, int len)
|
||||
{
|
||||
index += ocb(oarg, index, data, len);
|
||||
return true;
|
||||
}
|
||||
virtual size_t get_size() const
|
||||
{
|
||||
return index;
|
||||
}
|
||||
};
|
||||
|
||||
bool fmt2jpg_cb(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, jpg_out_cb cb, void * arg)
|
||||
{
|
||||
callback_stream dst_stream(cb, arg);
|
||||
return convert_image(src, width, height, format, quality, &dst_stream);
|
||||
}
|
||||
|
||||
bool frame2jpg_cb(camera_fb_t * fb, uint8_t quality, jpg_out_cb cb, void * arg)
|
||||
{
|
||||
return fmt2jpg_cb(fb->buf, fb->len, fb->width, fb->height, fb->format, quality, cb, arg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class memory_stream : public jpge::output_stream {
|
||||
protected:
|
||||
uint8_t *out_buf;
|
||||
size_t max_len, index;
|
||||
|
||||
public:
|
||||
memory_stream(void *pBuf, uint buf_size) : out_buf(static_cast<uint8_t*>(pBuf)), max_len(buf_size), index(0) { }
|
||||
|
||||
virtual ~memory_stream() { }
|
||||
|
||||
virtual bool put_buf(const void* pBuf, int len)
|
||||
{
|
||||
if (!pBuf) {
|
||||
//end of image
|
||||
return true;
|
||||
}
|
||||
if ((size_t)len > (max_len - index)) {
|
||||
ESP_LOGW(TAG, "JPG output overflow: %d bytes", len - (max_len - index));
|
||||
len = max_len - index;
|
||||
}
|
||||
if (len) {
|
||||
memcpy(out_buf + index, pBuf, len);
|
||||
index += len;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual size_t get_size() const
|
||||
{
|
||||
return index;
|
||||
}
|
||||
};
|
||||
|
||||
bool fmt2jpg(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, uint8_t ** out, size_t * out_len)
|
||||
{
|
||||
//todo: allocate proper buffer for holding JPEG data
|
||||
//this should be enough for CIF frame size
|
||||
int jpg_buf_len = 64*1024;
|
||||
|
||||
|
||||
uint8_t * jpg_buf = (uint8_t *)_malloc(jpg_buf_len);
|
||||
if(jpg_buf == NULL) {
|
||||
ESP_LOGE(TAG, "JPG buffer malloc failed");
|
||||
return false;
|
||||
}
|
||||
memory_stream dst_stream(jpg_buf, jpg_buf_len);
|
||||
|
||||
if(!convert_image(src, width, height, format, quality, &dst_stream)) {
|
||||
free(jpg_buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = jpg_buf;
|
||||
*out_len = dst_stream.get_size();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool frame2jpg(camera_fb_t * fb, uint8_t quality, uint8_t ** out, size_t * out_len)
|
||||
{
|
||||
return fmt2jpg(fb->buf, fb->len, fb->width, fb->height, fb->format, quality, out, out_len);
|
||||
}
|
||||
@@ -1,298 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "yuv.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
typedef struct {
|
||||
int16_t vY;
|
||||
int16_t vVr;
|
||||
int16_t vVg;
|
||||
int16_t vUg;
|
||||
int16_t vUb;
|
||||
} yuv_table_row;
|
||||
|
||||
static const yuv_table_row yuv_table[256] = {
|
||||
// Y Vr Vg Ug Ub // #
|
||||
{ -18, -204, 50, 104, -258 }, // 0
|
||||
{ -17, -202, 49, 103, -256 }, // 1
|
||||
{ -16, -201, 49, 102, -254 }, // 2
|
||||
{ -15, -199, 48, 101, -252 }, // 3
|
||||
{ -13, -197, 48, 100, -250 }, // 4
|
||||
{ -12, -196, 48, 99, -248 }, // 5
|
||||
{ -11, -194, 47, 99, -246 }, // 6
|
||||
{ -10, -193, 47, 98, -244 }, // 7
|
||||
{ -9, -191, 46, 97, -242 }, // 8
|
||||
{ -8, -189, 46, 96, -240 }, // 9
|
||||
{ -6, -188, 46, 95, -238 }, // 10
|
||||
{ -5, -186, 45, 95, -236 }, // 11
|
||||
{ -4, -185, 45, 94, -234 }, // 12
|
||||
{ -3, -183, 44, 93, -232 }, // 13
|
||||
{ -2, -181, 44, 92, -230 }, // 14
|
||||
{ -1, -180, 44, 91, -228 }, // 15
|
||||
{ 0, -178, 43, 91, -226 }, // 16
|
||||
{ 1, -177, 43, 90, -223 }, // 17
|
||||
{ 2, -175, 43, 89, -221 }, // 18
|
||||
{ 3, -173, 42, 88, -219 }, // 19
|
||||
{ 4, -172, 42, 87, -217 }, // 20
|
||||
{ 5, -170, 41, 86, -215 }, // 21
|
||||
{ 6, -169, 41, 86, -213 }, // 22
|
||||
{ 8, -167, 41, 85, -211 }, // 23
|
||||
{ 9, -165, 40, 84, -209 }, // 24
|
||||
{ 10, -164, 40, 83, -207 }, // 25
|
||||
{ 11, -162, 39, 82, -205 }, // 26
|
||||
{ 12, -161, 39, 82, -203 }, // 27
|
||||
{ 13, -159, 39, 81, -201 }, // 28
|
||||
{ 15, -158, 38, 80, -199 }, // 29
|
||||
{ 16, -156, 38, 79, -197 }, // 30
|
||||
{ 17, -154, 37, 78, -195 }, // 31
|
||||
{ 18, -153, 37, 78, -193 }, // 32
|
||||
{ 19, -151, 37, 77, -191 }, // 33
|
||||
{ 20, -150, 36, 76, -189 }, // 34
|
||||
{ 22, -148, 36, 75, -187 }, // 35
|
||||
{ 23, -146, 35, 74, -185 }, // 36
|
||||
{ 24, -145, 35, 73, -183 }, // 37
|
||||
{ 25, -143, 35, 73, -181 }, // 38
|
||||
{ 26, -142, 34, 72, -179 }, // 39
|
||||
{ 27, -140, 34, 71, -177 }, // 40
|
||||
{ 29, -138, 34, 70, -175 }, // 41
|
||||
{ 30, -137, 33, 69, -173 }, // 42
|
||||
{ 31, -135, 33, 69, -171 }, // 43
|
||||
{ 32, -134, 32, 68, -169 }, // 44
|
||||
{ 33, -132, 32, 67, -167 }, // 45
|
||||
{ 34, -130, 32, 66, -165 }, // 46
|
||||
{ 36, -129, 31, 65, -163 }, // 47
|
||||
{ 37, -127, 31, 65, -161 }, // 48
|
||||
{ 38, -126, 30, 64, -159 }, // 49
|
||||
{ 39, -124, 30, 63, -157 }, // 50
|
||||
{ 40, -122, 30, 62, -155 }, // 51
|
||||
{ 41, -121, 29, 61, -153 }, // 52
|
||||
{ 43, -119, 29, 60, -151 }, // 53
|
||||
{ 44, -118, 28, 60, -149 }, // 54
|
||||
{ 45, -116, 28, 59, -147 }, // 55
|
||||
{ 46, -114, 28, 58, -145 }, // 56
|
||||
{ 47, -113, 27, 57, -143 }, // 57
|
||||
{ 48, -111, 27, 56, -141 }, // 58
|
||||
{ 50, -110, 26, 56, -139 }, // 59
|
||||
{ 51, -108, 26, 55, -137 }, // 60
|
||||
{ 52, -106, 26, 54, -135 }, // 61
|
||||
{ 53, -105, 25, 53, -133 }, // 62
|
||||
{ 54, -103, 25, 52, -131 }, // 63
|
||||
{ 55, -102, 25, 52, -129 }, // 64
|
||||
{ 57, -100, 24, 51, -127 }, // 65
|
||||
{ 58, -98, 24, 50, -125 }, // 66
|
||||
{ 59, -97, 23, 49, -123 }, // 67
|
||||
{ 60, -95, 23, 48, -121 }, // 68
|
||||
{ 61, -94, 23, 47, -119 }, // 69
|
||||
{ 62, -92, 22, 47, -117 }, // 70
|
||||
{ 64, -90, 22, 46, -115 }, // 71
|
||||
{ 65, -89, 21, 45, -113 }, // 72
|
||||
{ 66, -87, 21, 44, -110 }, // 73
|
||||
{ 67, -86, 21, 43, -108 }, // 74
|
||||
{ 68, -84, 20, 43, -106 }, // 75
|
||||
{ 69, -82, 20, 42, -104 }, // 76
|
||||
{ 71, -81, 19, 41, -102 }, // 77
|
||||
{ 72, -79, 19, 40, -100 }, // 78
|
||||
{ 73, -78, 19, 39, -98 }, // 79
|
||||
{ 74, -76, 18, 39, -96 }, // 80
|
||||
{ 75, -75, 18, 38, -94 }, // 81
|
||||
{ 76, -73, 17, 37, -92 }, // 82
|
||||
{ 77, -71, 17, 36, -90 }, // 83
|
||||
{ 79, -70, 17, 35, -88 }, // 84
|
||||
{ 80, -68, 16, 34, -86 }, // 85
|
||||
{ 81, -67, 16, 34, -84 }, // 86
|
||||
{ 82, -65, 16, 33, -82 }, // 87
|
||||
{ 83, -63, 15, 32, -80 }, // 88
|
||||
{ 84, -62, 15, 31, -78 }, // 89
|
||||
{ 86, -60, 14, 30, -76 }, // 90
|
||||
{ 87, -59, 14, 30, -74 }, // 91
|
||||
{ 88, -57, 14, 29, -72 }, // 92
|
||||
{ 89, -55, 13, 28, -70 }, // 93
|
||||
{ 90, -54, 13, 27, -68 }, // 94
|
||||
{ 91, -52, 12, 26, -66 }, // 95
|
||||
{ 93, -51, 12, 26, -64 }, // 96
|
||||
{ 94, -49, 12, 25, -62 }, // 97
|
||||
{ 95, -47, 11, 24, -60 }, // 98
|
||||
{ 96, -46, 11, 23, -58 }, // 99
|
||||
{ 97, -44, 10, 22, -56 }, // 100
|
||||
{ 98, -43, 10, 21, -54 }, // 101
|
||||
{ 100, -41, 10, 21, -52 }, // 102
|
||||
{ 101, -39, 9, 20, -50 }, // 103
|
||||
{ 102, -38, 9, 19, -48 }, // 104
|
||||
{ 103, -36, 8, 18, -46 }, // 105
|
||||
{ 104, -35, 8, 17, -44 }, // 106
|
||||
{ 105, -33, 8, 17, -42 }, // 107
|
||||
{ 107, -31, 7, 16, -40 }, // 108
|
||||
{ 108, -30, 7, 15, -38 }, // 109
|
||||
{ 109, -28, 7, 14, -36 }, // 110
|
||||
{ 110, -27, 6, 13, -34 }, // 111
|
||||
{ 111, -25, 6, 13, -32 }, // 112
|
||||
{ 112, -23, 5, 12, -30 }, // 113
|
||||
{ 114, -22, 5, 11, -28 }, // 114
|
||||
{ 115, -20, 5, 10, -26 }, // 115
|
||||
{ 116, -19, 4, 9, -24 }, // 116
|
||||
{ 117, -17, 4, 8, -22 }, // 117
|
||||
{ 118, -15, 3, 8, -20 }, // 118
|
||||
{ 119, -14, 3, 7, -18 }, // 119
|
||||
{ 121, -12, 3, 6, -16 }, // 120
|
||||
{ 122, -11, 2, 5, -14 }, // 121
|
||||
{ 123, -9, 2, 4, -12 }, // 122
|
||||
{ 124, -7, 1, 4, -10 }, // 123
|
||||
{ 125, -6, 1, 3, -8 }, // 124
|
||||
{ 126, -4, 1, 2, -6 }, // 125
|
||||
{ 128, -3, 0, 1, -4 }, // 126
|
||||
{ 129, -1, 0, 0, -2 }, // 127
|
||||
{ 130, 0, 0, 0, 0 }, // 128
|
||||
{ 131, 1, 0, 0, 2 }, // 129
|
||||
{ 132, 3, 0, -1, 4 }, // 130
|
||||
{ 133, 4, -1, -2, 6 }, // 131
|
||||
{ 135, 6, -1, -3, 8 }, // 132
|
||||
{ 136, 7, -1, -4, 10 }, // 133
|
||||
{ 137, 9, -2, -4, 12 }, // 134
|
||||
{ 138, 11, -2, -5, 14 }, // 135
|
||||
{ 139, 12, -3, -6, 16 }, // 136
|
||||
{ 140, 14, -3, -7, 18 }, // 137
|
||||
{ 142, 15, -3, -8, 20 }, // 138
|
||||
{ 143, 17, -4, -8, 22 }, // 139
|
||||
{ 144, 19, -4, -9, 24 }, // 140
|
||||
{ 145, 20, -5, -10, 26 }, // 141
|
||||
{ 146, 22, -5, -11, 28 }, // 142
|
||||
{ 147, 23, -5, -12, 30 }, // 143
|
||||
{ 148, 25, -6, -13, 32 }, // 144
|
||||
{ 150, 27, -6, -13, 34 }, // 145
|
||||
{ 151, 28, -7, -14, 36 }, // 146
|
||||
{ 152, 30, -7, -15, 38 }, // 147
|
||||
{ 153, 31, -7, -16, 40 }, // 148
|
||||
{ 154, 33, -8, -17, 42 }, // 149
|
||||
{ 155, 35, -8, -17, 44 }, // 150
|
||||
{ 157, 36, -8, -18, 46 }, // 151
|
||||
{ 158, 38, -9, -19, 48 }, // 152
|
||||
{ 159, 39, -9, -20, 50 }, // 153
|
||||
{ 160, 41, -10, -21, 52 }, // 154
|
||||
{ 161, 43, -10, -21, 54 }, // 155
|
||||
{ 162, 44, -10, -22, 56 }, // 156
|
||||
{ 164, 46, -11, -23, 58 }, // 157
|
||||
{ 165, 47, -11, -24, 60 }, // 158
|
||||
{ 166, 49, -12, -25, 62 }, // 159
|
||||
{ 167, 51, -12, -26, 64 }, // 160
|
||||
{ 168, 52, -12, -26, 66 }, // 161
|
||||
{ 169, 54, -13, -27, 68 }, // 162
|
||||
{ 171, 55, -13, -28, 70 }, // 163
|
||||
{ 172, 57, -14, -29, 72 }, // 164
|
||||
{ 173, 59, -14, -30, 74 }, // 165
|
||||
{ 174, 60, -14, -30, 76 }, // 166
|
||||
{ 175, 62, -15, -31, 78 }, // 167
|
||||
{ 176, 63, -15, -32, 80 }, // 168
|
||||
{ 178, 65, -16, -33, 82 }, // 169
|
||||
{ 179, 67, -16, -34, 84 }, // 170
|
||||
{ 180, 68, -16, -34, 86 }, // 171
|
||||
{ 181, 70, -17, -35, 88 }, // 172
|
||||
{ 182, 71, -17, -36, 90 }, // 173
|
||||
{ 183, 73, -17, -37, 92 }, // 174
|
||||
{ 185, 75, -18, -38, 94 }, // 175
|
||||
{ 186, 76, -18, -39, 96 }, // 176
|
||||
{ 187, 78, -19, -39, 98 }, // 177
|
||||
{ 188, 79, -19, -40, 100 }, // 178
|
||||
{ 189, 81, -19, -41, 102 }, // 179
|
||||
{ 190, 82, -20, -42, 104 }, // 180
|
||||
{ 192, 84, -20, -43, 106 }, // 181
|
||||
{ 193, 86, -21, -43, 108 }, // 182
|
||||
{ 194, 87, -21, -44, 110 }, // 183
|
||||
{ 195, 89, -21, -45, 113 }, // 184
|
||||
{ 196, 90, -22, -46, 115 }, // 185
|
||||
{ 197, 92, -22, -47, 117 }, // 186
|
||||
{ 199, 94, -23, -47, 119 }, // 187
|
||||
{ 200, 95, -23, -48, 121 }, // 188
|
||||
{ 201, 97, -23, -49, 123 }, // 189
|
||||
{ 202, 98, -24, -50, 125 }, // 190
|
||||
{ 203, 100, -24, -51, 127 }, // 191
|
||||
{ 204, 102, -25, -52, 129 }, // 192
|
||||
{ 206, 103, -25, -52, 131 }, // 193
|
||||
{ 207, 105, -25, -53, 133 }, // 194
|
||||
{ 208, 106, -26, -54, 135 }, // 195
|
||||
{ 209, 108, -26, -55, 137 }, // 196
|
||||
{ 210, 110, -26, -56, 139 }, // 197
|
||||
{ 211, 111, -27, -56, 141 }, // 198
|
||||
{ 213, 113, -27, -57, 143 }, // 199
|
||||
{ 214, 114, -28, -58, 145 }, // 200
|
||||
{ 215, 116, -28, -59, 147 }, // 201
|
||||
{ 216, 118, -28, -60, 149 }, // 202
|
||||
{ 217, 119, -29, -60, 151 }, // 203
|
||||
{ 218, 121, -29, -61, 153 }, // 204
|
||||
{ 219, 122, -30, -62, 155 }, // 205
|
||||
{ 221, 124, -30, -63, 157 }, // 206
|
||||
{ 222, 126, -30, -64, 159 }, // 207
|
||||
{ 223, 127, -31, -65, 161 }, // 208
|
||||
{ 224, 129, -31, -65, 163 }, // 209
|
||||
{ 225, 130, -32, -66, 165 }, // 210
|
||||
{ 226, 132, -32, -67, 167 }, // 211
|
||||
{ 228, 134, -32, -68, 169 }, // 212
|
||||
{ 229, 135, -33, -69, 171 }, // 213
|
||||
{ 230, 137, -33, -69, 173 }, // 214
|
||||
{ 231, 138, -34, -70, 175 }, // 215
|
||||
{ 232, 140, -34, -71, 177 }, // 216
|
||||
{ 233, 142, -34, -72, 179 }, // 217
|
||||
{ 235, 143, -35, -73, 181 }, // 218
|
||||
{ 236, 145, -35, -73, 183 }, // 219
|
||||
{ 237, 146, -35, -74, 185 }, // 220
|
||||
{ 238, 148, -36, -75, 187 }, // 221
|
||||
{ 239, 150, -36, -76, 189 }, // 222
|
||||
{ 240, 151, -37, -77, 191 }, // 223
|
||||
{ 242, 153, -37, -78, 193 }, // 224
|
||||
{ 243, 154, -37, -78, 195 }, // 225
|
||||
{ 244, 156, -38, -79, 197 }, // 226
|
||||
{ 245, 158, -38, -80, 199 }, // 227
|
||||
{ 246, 159, -39, -81, 201 }, // 228
|
||||
{ 247, 161, -39, -82, 203 }, // 229
|
||||
{ 249, 162, -39, -82, 205 }, // 230
|
||||
{ 250, 164, -40, -83, 207 }, // 231
|
||||
{ 251, 165, -40, -84, 209 }, // 232
|
||||
{ 252, 167, -41, -85, 211 }, // 233
|
||||
{ 253, 169, -41, -86, 213 }, // 234
|
||||
{ 254, 170, -41, -86, 215 }, // 235
|
||||
{ 256, 172, -42, -87, 217 }, // 236
|
||||
{ 257, 173, -42, -88, 219 }, // 237
|
||||
{ 258, 175, -43, -89, 221 }, // 238
|
||||
{ 259, 177, -43, -90, 223 }, // 239
|
||||
{ 260, 178, -43, -91, 226 }, // 240
|
||||
{ 261, 180, -44, -91, 228 }, // 241
|
||||
{ 263, 181, -44, -92, 230 }, // 242
|
||||
{ 264, 183, -44, -93, 232 }, // 243
|
||||
{ 265, 185, -45, -94, 234 }, // 244
|
||||
{ 266, 186, -45, -95, 236 }, // 245
|
||||
{ 267, 188, -46, -95, 238 }, // 246
|
||||
{ 268, 189, -46, -96, 240 }, // 247
|
||||
{ 270, 191, -46, -97, 242 }, // 248
|
||||
{ 271, 193, -47, -98, 244 }, // 249
|
||||
{ 272, 194, -47, -99, 246 }, // 250
|
||||
{ 273, 196, -48, -99, 248 }, // 251
|
||||
{ 274, 197, -48, -100, 250 }, // 252
|
||||
{ 275, 199, -48, -101, 252 }, // 253
|
||||
{ 277, 201, -49, -102, 254 }, // 254
|
||||
{ 278, 202, -49, -103, 256 } // 255
|
||||
};
|
||||
|
||||
#define YUYV_CONSTRAIN(v) ((v)<0)?0:(((v)>255)?255:(v))
|
||||
|
||||
void IRAM_ATTR yuv2rgb(uint8_t y, uint8_t u, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b)
|
||||
{
|
||||
int16_t ri, gi, bi;
|
||||
|
||||
ri = yuv_table[y].vY + yuv_table[v].vVr;
|
||||
gi = yuv_table[y].vY + yuv_table[u].vUg + yuv_table[v].vVg;
|
||||
bi = yuv_table[y].vY + yuv_table[u].vUb;
|
||||
|
||||
*r = YUYV_CONSTRAIN(ri);
|
||||
*g = YUYV_CONSTRAIN(gi);
|
||||
*b = YUYV_CONSTRAIN(bi);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,195 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
/*
|
||||
* Example Use
|
||||
*
|
||||
static camera_config_t camera_example_config = {
|
||||
.pin_pwdn = PIN_PWDN,
|
||||
.pin_reset = PIN_RESET,
|
||||
.pin_xclk = PIN_XCLK,
|
||||
.pin_sscb_sda = PIN_SIOD,
|
||||
.pin_sscb_scl = PIN_SIOC,
|
||||
.pin_d7 = PIN_D7,
|
||||
.pin_d6 = PIN_D6,
|
||||
.pin_d5 = PIN_D5,
|
||||
.pin_d4 = PIN_D4,
|
||||
.pin_d3 = PIN_D3,
|
||||
.pin_d2 = PIN_D2,
|
||||
.pin_d1 = PIN_D1,
|
||||
.pin_d0 = PIN_D0,
|
||||
.pin_vsync = PIN_VSYNC,
|
||||
.pin_href = PIN_HREF,
|
||||
.pin_pclk = PIN_PCLK,
|
||||
|
||||
.xclk_freq_hz = 20000000,
|
||||
.ledc_timer = LEDC_TIMER_0,
|
||||
.ledc_channel = LEDC_CHANNEL_0,
|
||||
.pixel_format = PIXFORMAT_JPEG,
|
||||
.frame_size = FRAMESIZE_SVGA,
|
||||
.jpeg_quality = 10,
|
||||
.fb_count = 2
|
||||
};
|
||||
|
||||
esp_err_t camera_example_init(){
|
||||
return esp_camera_init(&camera_example_config);
|
||||
}
|
||||
|
||||
esp_err_t camera_example_capture(){
|
||||
//capture a frame
|
||||
camera_fb_t * fb = esp_camera_fb_get();
|
||||
if (!fb) {
|
||||
ESP_LOGE(TAG, "Frame buffer could not be acquired");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
//replace this with your own function
|
||||
display_image(fb->width, fb->height, fb->pixformat, fb->buf, fb->len);
|
||||
|
||||
//return the frame buffer back to be reused
|
||||
esp_camera_fb_return(fb);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "sensor.h"
|
||||
#include "sys/time.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configuration structure for camera initialization
|
||||
*/
|
||||
typedef struct {
|
||||
int pin_pwdn; /*!< GPIO pin for camera power down line */
|
||||
int pin_reset; /*!< GPIO pin for camera reset line */
|
||||
int pin_xclk; /*!< GPIO pin for camera XCLK line */
|
||||
int pin_sscb_sda; /*!< GPIO pin for camera SDA line */
|
||||
int pin_sscb_scl; /*!< GPIO pin for camera SCL line */
|
||||
int pin_d7; /*!< GPIO pin for camera D7 line */
|
||||
int pin_d6; /*!< GPIO pin for camera D6 line */
|
||||
int pin_d5; /*!< GPIO pin for camera D5 line */
|
||||
int pin_d4; /*!< GPIO pin for camera D4 line */
|
||||
int pin_d3; /*!< GPIO pin for camera D3 line */
|
||||
int pin_d2; /*!< GPIO pin for camera D2 line */
|
||||
int pin_d1; /*!< GPIO pin for camera D1 line */
|
||||
int pin_d0; /*!< GPIO pin for camera D0 line */
|
||||
int pin_vsync; /*!< GPIO pin for camera VSYNC line */
|
||||
int pin_href; /*!< GPIO pin for camera HREF line */
|
||||
int pin_pclk; /*!< GPIO pin for camera PCLK line */
|
||||
|
||||
int xclk_freq_hz; /*!< Frequency of XCLK signal, in Hz. Either 20KHz or 10KHz for OV2640 double FPS (Experimental) */
|
||||
|
||||
ledc_timer_t ledc_timer; /*!< LEDC timer to be used for generating XCLK */
|
||||
ledc_channel_t ledc_channel; /*!< LEDC channel to be used for generating XCLK */
|
||||
|
||||
pixformat_t pixel_format; /*!< Format of the pixel data: PIXFORMAT_ + YUV422|GRAYSCALE|RGB565|JPEG */
|
||||
framesize_t frame_size; /*!< Size of the output image: FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA */
|
||||
|
||||
int jpeg_quality; /*!< Quality of JPEG output. 0-63 lower means higher quality */
|
||||
size_t fb_count; /*!< Number of frame buffers to be allocated. If more than one, then each frame will be acquired (double speed) */
|
||||
} camera_config_t;
|
||||
|
||||
/**
|
||||
* @brief Data structure of camera frame buffer
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t * buf; /*!< Pointer to the pixel data */
|
||||
size_t len; /*!< Length of the buffer in bytes */
|
||||
size_t width; /*!< Width of the buffer in pixels */
|
||||
size_t height; /*!< Height of the buffer in pixels */
|
||||
pixformat_t format; /*!< Format of the pixel data */
|
||||
struct timeval timestamp; /*!< Timestamp since boot of the first DMA buffer of the frame */
|
||||
} camera_fb_t;
|
||||
|
||||
#define ESP_ERR_CAMERA_BASE 0x20000
|
||||
#define ESP_ERR_CAMERA_NOT_DETECTED (ESP_ERR_CAMERA_BASE + 1)
|
||||
#define ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE (ESP_ERR_CAMERA_BASE + 2)
|
||||
#define ESP_ERR_CAMERA_FAILED_TO_SET_OUT_FORMAT (ESP_ERR_CAMERA_BASE + 3)
|
||||
#define ESP_ERR_CAMERA_NOT_SUPPORTED (ESP_ERR_CAMERA_BASE + 4)
|
||||
|
||||
/**
|
||||
* @brief Initialize the camera driver
|
||||
*
|
||||
* @note call camera_probe before calling this function
|
||||
*
|
||||
* This function detects and configures camera over I2C interface,
|
||||
* allocates framebuffer and DMA buffers,
|
||||
* initializes parallel I2S input, and sets up DMA descriptors.
|
||||
*
|
||||
* Currently this function can only be called once and there is
|
||||
* no way to de-initialize this module.
|
||||
*
|
||||
* @param config Camera configuration parameters
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_camera_init(const camera_config_t* config);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the camera driver
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_STATE if the driver hasn't been initialized yet
|
||||
*/
|
||||
esp_err_t esp_camera_deinit();
|
||||
|
||||
/**
|
||||
* @brief Obtain pointer to a frame buffer.
|
||||
*
|
||||
* @return pointer to the frame buffer
|
||||
*/
|
||||
camera_fb_t* esp_camera_fb_get();
|
||||
|
||||
/**
|
||||
* @brief Return the frame buffer to be reused again.
|
||||
*
|
||||
* @param fb Pointer to the frame buffer
|
||||
*/
|
||||
void esp_camera_fb_return(camera_fb_t * fb);
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the image sensor control structure
|
||||
*
|
||||
* @return pointer to the sensor
|
||||
*/
|
||||
sensor_t * esp_camera_sensor_get();
|
||||
|
||||
/**
|
||||
* @brief Save camera settings to non-volatile-storage (NVS)
|
||||
*
|
||||
* @param key A unique nvs key name for the camera settings
|
||||
*/
|
||||
esp_err_t esp_camera_save_to_nvs(const char *key);
|
||||
|
||||
/**
|
||||
* @brief Load camera settings from non-volatile-storage (NVS)
|
||||
*
|
||||
* @param key A unique nvs key name for the camera settings
|
||||
*/
|
||||
esp_err_t esp_camera_load_from_nvs(const char *key);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "img_converters.h"
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* Sensor abstraction layer.
|
||||
*
|
||||
*/
|
||||
#ifndef __SENSOR_H__
|
||||
#define __SENSOR_H__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define NT99141_PID (0x14)
|
||||
#define OV9650_PID (0x96)
|
||||
#define OV7725_PID (0x77)
|
||||
#define OV2640_PID (0x26)
|
||||
#define OV3660_PID (0x36)
|
||||
#define OV5640_PID (0x56)
|
||||
#define OV7670_PID (0x76)
|
||||
|
||||
typedef enum {
|
||||
PIXFORMAT_RGB565, // 2BPP/RGB565
|
||||
PIXFORMAT_YUV422, // 2BPP/YUV422
|
||||
PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE
|
||||
PIXFORMAT_JPEG, // JPEG/COMPRESSED
|
||||
PIXFORMAT_RGB888, // 3BPP/RGB888
|
||||
PIXFORMAT_RAW, // RAW
|
||||
PIXFORMAT_RGB444, // 3BP2P/RGB444
|
||||
PIXFORMAT_RGB555, // 3BP2P/RGB555
|
||||
} pixformat_t;
|
||||
|
||||
typedef enum {
|
||||
FRAMESIZE_96X96, // 96x96
|
||||
FRAMESIZE_QQVGA, // 160x120
|
||||
FRAMESIZE_QCIF, // 176x144
|
||||
FRAMESIZE_HQVGA, // 240x176
|
||||
FRAMESIZE_240X240, // 240x240
|
||||
FRAMESIZE_QVGA, // 320x240
|
||||
FRAMESIZE_CIF, // 400x296
|
||||
FRAMESIZE_HVGA, // 480x320
|
||||
FRAMESIZE_VGA, // 640x480
|
||||
FRAMESIZE_SVGA, // 800x600
|
||||
FRAMESIZE_XGA, // 1024x768
|
||||
FRAMESIZE_HD, // 1280x720
|
||||
FRAMESIZE_SXGA, // 1280x1024
|
||||
FRAMESIZE_UXGA, // 1600x1200
|
||||
// 3MP Sensors
|
||||
FRAMESIZE_FHD, // 1920x1080
|
||||
FRAMESIZE_P_HD, // 720x1280
|
||||
FRAMESIZE_P_3MP, // 864x1536
|
||||
FRAMESIZE_QXGA, // 2048x1536
|
||||
// 5MP Sensors
|
||||
FRAMESIZE_QHD, // 2560x1440
|
||||
FRAMESIZE_WQXGA, // 2560x1600
|
||||
FRAMESIZE_P_FHD, // 1080x1920
|
||||
FRAMESIZE_QSXGA, // 2560x1920
|
||||
FRAMESIZE_INVALID
|
||||
} framesize_t;
|
||||
|
||||
typedef enum {
|
||||
ASPECT_RATIO_4X3,
|
||||
ASPECT_RATIO_3X2,
|
||||
ASPECT_RATIO_16X10,
|
||||
ASPECT_RATIO_5X3,
|
||||
ASPECT_RATIO_16X9,
|
||||
ASPECT_RATIO_21X9,
|
||||
ASPECT_RATIO_5X4,
|
||||
ASPECT_RATIO_1X1,
|
||||
ASPECT_RATIO_9X16
|
||||
} aspect_ratio_t;
|
||||
|
||||
typedef enum {
|
||||
GAINCEILING_2X,
|
||||
GAINCEILING_4X,
|
||||
GAINCEILING_8X,
|
||||
GAINCEILING_16X,
|
||||
GAINCEILING_32X,
|
||||
GAINCEILING_64X,
|
||||
GAINCEILING_128X,
|
||||
} gainceiling_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t max_width;
|
||||
uint16_t max_height;
|
||||
uint16_t start_x;
|
||||
uint16_t start_y;
|
||||
uint16_t end_x;
|
||||
uint16_t end_y;
|
||||
uint16_t offset_x;
|
||||
uint16_t offset_y;
|
||||
uint16_t total_x;
|
||||
uint16_t total_y;
|
||||
} ratio_settings_t;
|
||||
|
||||
typedef struct {
|
||||
const uint16_t width;
|
||||
const uint16_t height;
|
||||
const aspect_ratio_t aspect_ratio;
|
||||
} resolution_info_t;
|
||||
|
||||
// Resolution table (in sensor.c)
|
||||
extern const resolution_info_t resolution[];
|
||||
|
||||
typedef struct {
|
||||
uint8_t MIDH;
|
||||
uint8_t MIDL;
|
||||
uint8_t PID;
|
||||
uint8_t VER;
|
||||
} sensor_id_t;
|
||||
|
||||
typedef struct {
|
||||
framesize_t framesize;//0 - 10
|
||||
bool scale;
|
||||
bool binning;
|
||||
uint8_t quality;//0 - 63
|
||||
int8_t brightness;//-2 - 2
|
||||
int8_t contrast;//-2 - 2
|
||||
int8_t saturation;//-2 - 2
|
||||
int8_t sharpness;//-2 - 2
|
||||
uint8_t denoise;
|
||||
uint8_t special_effect;//0 - 6
|
||||
uint8_t wb_mode;//0 - 4
|
||||
uint8_t awb;
|
||||
uint8_t awb_gain;
|
||||
uint8_t aec;
|
||||
uint8_t aec2;
|
||||
int8_t ae_level;//-2 - 2
|
||||
uint16_t aec_value;//0 - 1200
|
||||
uint8_t agc;
|
||||
uint8_t agc_gain;//0 - 30
|
||||
uint8_t gainceiling;//0 - 6
|
||||
uint8_t bpc;
|
||||
uint8_t wpc;
|
||||
uint8_t raw_gma;
|
||||
uint8_t lenc;
|
||||
uint8_t hmirror;
|
||||
uint8_t vflip;
|
||||
uint8_t dcw;
|
||||
uint8_t colorbar;
|
||||
} camera_status_t;
|
||||
|
||||
typedef struct _sensor sensor_t;
|
||||
typedef struct _sensor {
|
||||
sensor_id_t id; // Sensor ID.
|
||||
uint8_t slv_addr; // Sensor I2C slave address.
|
||||
pixformat_t pixformat;
|
||||
camera_status_t status;
|
||||
int xclk_freq_hz;
|
||||
|
||||
// Sensor function pointers
|
||||
int (*init_status) (sensor_t *sensor);
|
||||
int (*reset) (sensor_t *sensor);
|
||||
int (*set_pixformat) (sensor_t *sensor, pixformat_t pixformat);
|
||||
int (*set_framesize) (sensor_t *sensor, framesize_t framesize);
|
||||
int (*set_contrast) (sensor_t *sensor, int level);
|
||||
int (*set_brightness) (sensor_t *sensor, int level);
|
||||
int (*set_saturation) (sensor_t *sensor, int level);
|
||||
int (*set_sharpness) (sensor_t *sensor, int level);
|
||||
int (*set_denoise) (sensor_t *sensor, int level);
|
||||
int (*set_gainceiling) (sensor_t *sensor, gainceiling_t gainceiling);
|
||||
int (*set_quality) (sensor_t *sensor, int quality);
|
||||
int (*set_colorbar) (sensor_t *sensor, int enable);
|
||||
int (*set_whitebal) (sensor_t *sensor, int enable);
|
||||
int (*set_gain_ctrl) (sensor_t *sensor, int enable);
|
||||
int (*set_exposure_ctrl) (sensor_t *sensor, int enable);
|
||||
int (*set_hmirror) (sensor_t *sensor, int enable);
|
||||
int (*set_vflip) (sensor_t *sensor, int enable);
|
||||
|
||||
int (*set_aec2) (sensor_t *sensor, int enable);
|
||||
int (*set_awb_gain) (sensor_t *sensor, int enable);
|
||||
int (*set_agc_gain) (sensor_t *sensor, int gain);
|
||||
int (*set_aec_value) (sensor_t *sensor, int gain);
|
||||
|
||||
int (*set_special_effect) (sensor_t *sensor, int effect);
|
||||
int (*set_wb_mode) (sensor_t *sensor, int mode);
|
||||
int (*set_ae_level) (sensor_t *sensor, int level);
|
||||
|
||||
int (*set_dcw) (sensor_t *sensor, int enable);
|
||||
int (*set_bpc) (sensor_t *sensor, int enable);
|
||||
int (*set_wpc) (sensor_t *sensor, int enable);
|
||||
|
||||
int (*set_raw_gma) (sensor_t *sensor, int enable);
|
||||
int (*set_lenc) (sensor_t *sensor, int enable);
|
||||
|
||||
int (*get_reg) (sensor_t *sensor, int reg, int mask);
|
||||
int (*set_reg) (sensor_t *sensor, int reg, int mask, int value);
|
||||
int (*set_res_raw) (sensor_t *sensor, int startX, int startY, int endX, int endY, int offsetX, int offsetY, int totalX, int totalY, int outputX, int outputY, bool scale, bool binning);
|
||||
int (*set_pll) (sensor_t *sensor, int bypass, int mul, int sys, int root, int pre, int seld5, int pclken, int pclk);
|
||||
int (*set_xclk) (sensor_t *sensor, int timer, int xclk);
|
||||
} sensor_t;
|
||||
|
||||
#endif /* __SENSOR_H__ */
|
||||
@@ -1,49 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_camera.h"
|
||||
#include "sensor.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4 // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/lldesc.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/lldesc.h"
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t sample2;
|
||||
uint8_t unused2;
|
||||
uint8_t sample1;
|
||||
uint8_t unused1;
|
||||
};
|
||||
uint32_t val;
|
||||
} dma_elem_t;
|
||||
|
||||
typedef enum {
|
||||
/* camera sends byte sequence: s1, s2, s3, s4, ...
|
||||
* fifo receives: 00 s1 00 s2, 00 s2 00 s3, 00 s3 00 s4, ...
|
||||
*/
|
||||
SM_0A0B_0B0C = 0,
|
||||
/* camera sends byte sequence: s1, s2, s3, s4, ...
|
||||
* fifo receives: 00 s1 00 s2, 00 s3 00 s4, ...
|
||||
*/
|
||||
SM_0A0B_0C0D = 1,
|
||||
/* camera sends byte sequence: s1, s2, s3, s4, ...
|
||||
* fifo receives: 00 s1 00 00, 00 s2 00 00, 00 s3 00 00, ...
|
||||
*/
|
||||
SM_0A00_0B00 = 3,
|
||||
} i2s_sampling_mode_t;
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* SCCB (I2C like) driver.
|
||||
*
|
||||
*/
|
||||
#ifndef __SCCB_H__
|
||||
#define __SCCB_H__
|
||||
#include <stdint.h>
|
||||
int SCCB_Init(int pin_sda, int pin_scl);
|
||||
uint8_t SCCB_Probe();
|
||||
uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg);
|
||||
uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data);
|
||||
uint8_t SCCB_Read16(uint8_t slv_addr, uint16_t reg);
|
||||
uint8_t SCCB_Write16(uint8_t slv_addr, uint16_t reg, uint8_t data);
|
||||
#endif // __SCCB_H__
|
||||
@@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "camera_common.h"
|
||||
|
||||
esp_err_t camera_enable_out_clock();
|
||||
|
||||
void camera_disable_out_clock();
|
||||
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* SCCB (I2C like) driver.
|
||||
*
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include "sccb.h"
|
||||
#include <stdio.h>
|
||||
#include "sdkconfig.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* TAG = "sccb";
|
||||
#endif
|
||||
|
||||
#define LITTLETOBIG(x) ((x<<8)|(x>>8))
|
||||
|
||||
#include "driver/i2c.h"
|
||||
|
||||
#define SCCB_FREQ 100000 /*!< I2C master frequency*/
|
||||
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
|
||||
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
|
||||
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
|
||||
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
|
||||
#define ACK_VAL 0x0 /*!< I2C ack value */
|
||||
#define NACK_VAL 0x1 /*!< I2C nack value */
|
||||
#if CONFIG_SCCB_HARDWARE_I2C_PORT1
|
||||
const int SCCB_I2C_PORT = 1;
|
||||
#else
|
||||
const int SCCB_I2C_PORT = 0;
|
||||
#endif
|
||||
static uint8_t ESP_SLAVE_ADDR = 0x3c;
|
||||
|
||||
int SCCB_Init(int pin_sda, int pin_scl)
|
||||
{
|
||||
ESP_LOGI(TAG, "pin_sda %d pin_scl %d\n", pin_sda, pin_scl);
|
||||
//log_i("SCCB_Init start");
|
||||
i2c_config_t conf;
|
||||
memset(&conf, 0, sizeof(i2c_config_t));
|
||||
conf.mode = I2C_MODE_MASTER;
|
||||
conf.sda_io_num = pin_sda;
|
||||
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
|
||||
conf.scl_io_num = pin_scl;
|
||||
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
|
||||
conf.master.clk_speed = SCCB_FREQ;
|
||||
|
||||
i2c_param_config(SCCB_I2C_PORT, &conf);
|
||||
i2c_driver_install(SCCB_I2C_PORT, conf.mode, 0, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t SCCB_Probe()
|
||||
{
|
||||
uint8_t slave_addr = 0x0;
|
||||
while(slave_addr < 0x7f) {
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slave_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if( ret == ESP_OK) {
|
||||
ESP_SLAVE_ADDR = slave_addr;
|
||||
return ESP_SLAVE_ADDR;
|
||||
}
|
||||
slave_addr++;
|
||||
}
|
||||
return ESP_SLAVE_ADDR;
|
||||
}
|
||||
|
||||
uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg)
|
||||
{
|
||||
uint8_t data=0;
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) return -1;
|
||||
cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||
i2c_master_read_byte(cmd, &data, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SCCB_Read Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", slv_addr, reg, data, ret);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SCCB_Write Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", slv_addr, reg, data, ret);
|
||||
}
|
||||
return ret == ESP_OK ? 0 : -1;
|
||||
}
|
||||
|
||||
uint8_t SCCB_Read16(uint8_t slv_addr, uint16_t reg)
|
||||
{
|
||||
uint8_t data=0;
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
uint16_t reg_htons = LITTLETOBIG(reg);
|
||||
uint8_t *reg_u8 = (uint8_t *)®_htons;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg_u8[0], ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) return -1;
|
||||
cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||
i2c_master_read_byte(cmd, &data, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "W [%04x]=%02x fail\n", reg, data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t SCCB_Write16(uint8_t slv_addr, uint16_t reg, uint8_t data)
|
||||
{
|
||||
static uint16_t i = 0;
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
uint16_t reg_htons = LITTLETOBIG(reg);
|
||||
uint8_t *reg_u8 = (uint8_t *)®_htons;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg_u8[0], ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "W [%04x]=%02x %d fail\n", reg, data, i++);
|
||||
}
|
||||
return ret == ESP_OK ? 0 : -1;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#include "sensor.h"
|
||||
|
||||
const resolution_info_t resolution[FRAMESIZE_INVALID] = {
|
||||
{ 96, 96, ASPECT_RATIO_1X1 }, /* 96x96 */
|
||||
{ 160, 120, ASPECT_RATIO_4X3 }, /* QQVGA */
|
||||
{ 176, 144, ASPECT_RATIO_5X4 }, /* QCIF */
|
||||
{ 240, 176, ASPECT_RATIO_4X3 }, /* HQVGA */
|
||||
{ 240, 240, ASPECT_RATIO_1X1 }, /* 240x240 */
|
||||
{ 320, 240, ASPECT_RATIO_4X3 }, /* QVGA */
|
||||
{ 400, 296, ASPECT_RATIO_4X3 }, /* CIF */
|
||||
{ 480, 320, ASPECT_RATIO_3X2 }, /* HVGA */
|
||||
{ 640, 480, ASPECT_RATIO_4X3 }, /* VGA */
|
||||
{ 800, 600, ASPECT_RATIO_4X3 }, /* SVGA */
|
||||
{ 1024, 768, ASPECT_RATIO_4X3 }, /* XGA */
|
||||
{ 1280, 720, ASPECT_RATIO_16X9 }, /* HD */
|
||||
{ 1280, 1024, ASPECT_RATIO_5X4 }, /* SXGA */
|
||||
{ 1600, 1200, ASPECT_RATIO_4X3 }, /* UXGA */
|
||||
// 3MP Sensors
|
||||
{ 1920, 1080, ASPECT_RATIO_16X9 }, /* FHD */
|
||||
{ 720, 1280, ASPECT_RATIO_9X16 }, /* Portrait HD */
|
||||
{ 864, 1536, ASPECT_RATIO_9X16 }, /* Portrait 3MP */
|
||||
{ 2048, 1536, ASPECT_RATIO_4X3 }, /* QXGA */
|
||||
// 5MP Sensors
|
||||
{ 2560, 1440, ASPECT_RATIO_16X9 }, /* QHD */
|
||||
{ 2560, 1600, ASPECT_RATIO_16X10 }, /* WQXGA */
|
||||
{ 1088, 1920, ASPECT_RATIO_9X16 }, /* Portrait FHD */
|
||||
{ 2560, 1920, ASPECT_RATIO_4X3 }, /* QSXGA */
|
||||
};
|
||||
@@ -1,61 +0,0 @@
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "xclk.h"
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* TAG = "camera_xclk";
|
||||
#endif
|
||||
|
||||
esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz)
|
||||
{
|
||||
ledc_timer_config_t timer_conf;
|
||||
timer_conf.duty_resolution = 2;
|
||||
timer_conf.freq_hz = xclk_freq_hz;
|
||||
timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4
|
||||
timer_conf.clk_cfg = LEDC_AUTO_CLK;
|
||||
#endif
|
||||
timer_conf.timer_num = (ledc_timer_t)ledc_timer;
|
||||
esp_err_t err = ledc_timer_config(&timer_conf);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "ledc_timer_config failed for freq %d, rc=%x", xclk_freq_hz, err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t camera_enable_out_clock(camera_config_t* config)
|
||||
{
|
||||
periph_module_enable(PERIPH_LEDC_MODULE);
|
||||
|
||||
esp_err_t err = xclk_timer_conf(config->ledc_timer, config->xclk_freq_hz);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "ledc_timer_config failed, rc=%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ledc_channel_config_t ch_conf;
|
||||
ch_conf.gpio_num = config->pin_xclk;
|
||||
ch_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
|
||||
ch_conf.channel = config->ledc_channel;
|
||||
ch_conf.intr_type = LEDC_INTR_DISABLE;
|
||||
ch_conf.timer_sel = config->ledc_timer;
|
||||
ch_conf.duty = 2;
|
||||
ch_conf.hpoint = 0;
|
||||
err = ledc_channel_config(&ch_conf);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "ledc_channel_config failed, rc=%x", err);
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void camera_disable_out_clock()
|
||||
{
|
||||
periph_module_disable(PERIPH_LEDC_MODULE);
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
/**
|
||||
* This example takes a picture every 5s and print its size on serial monitor.
|
||||
*/
|
||||
|
||||
// =============================== SETUP ======================================
|
||||
|
||||
// 1. Board setup (Uncomment):
|
||||
// #define BOARD_WROVER_KIT
|
||||
// #define BOARD_ESP32CAM_AITHINKER
|
||||
|
||||
/**
|
||||
* 2. Kconfig setup
|
||||
*
|
||||
* If you have a Kconfig file, copy the content from
|
||||
* https://github.com/espressif/esp32-camera/blob/master/Kconfig into it.
|
||||
* In case you haven't, copy and paste this Kconfig file inside the src directory.
|
||||
* This Kconfig file has definitions that allows more control over the camera and
|
||||
* how it will be initialized.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 3. Enable PSRAM on sdkconfig:
|
||||
*
|
||||
* CONFIG_ESP32_SPIRAM_SUPPORT=y
|
||||
*
|
||||
* More info on
|
||||
* https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/kconfig.html#config-esp32-spiram-support
|
||||
*/
|
||||
|
||||
// ================================ CODE ======================================
|
||||
|
||||
#include <esp_event.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_system.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <sys/param.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "esp_camera.h"
|
||||
|
||||
// WROVER-KIT PIN Map
|
||||
#ifdef BOARD_WROVER_KIT
|
||||
|
||||
#define CAM_PIN_PWDN -1 //power down is not used
|
||||
#define CAM_PIN_RESET -1 //software reset will be performed
|
||||
#define CAM_PIN_XCLK 21
|
||||
#define CAM_PIN_SIOD 26
|
||||
#define CAM_PIN_SIOC 27
|
||||
|
||||
#define CAM_PIN_D7 35
|
||||
#define CAM_PIN_D6 34
|
||||
#define CAM_PIN_D5 39
|
||||
#define CAM_PIN_D4 36
|
||||
#define CAM_PIN_D3 19
|
||||
#define CAM_PIN_D2 18
|
||||
#define CAM_PIN_D1 5
|
||||
#define CAM_PIN_D0 4
|
||||
#define CAM_PIN_VSYNC 25
|
||||
#define CAM_PIN_HREF 23
|
||||
#define CAM_PIN_PCLK 22
|
||||
|
||||
#endif
|
||||
|
||||
// ESP32Cam (AiThinker) PIN Map
|
||||
#ifdef BOARD_ESP32CAM_AITHINKER
|
||||
|
||||
#define CAM_PIN_PWDN 32
|
||||
#define CAM_PIN_RESET -1 //software reset will be performed
|
||||
#define CAM_PIN_XCLK 0
|
||||
#define CAM_PIN_SIOD 26
|
||||
#define CAM_PIN_SIOC 27
|
||||
|
||||
#define CAM_PIN_D7 35
|
||||
#define CAM_PIN_D6 34
|
||||
#define CAM_PIN_D5 39
|
||||
#define CAM_PIN_D4 36
|
||||
#define CAM_PIN_D3 21
|
||||
#define CAM_PIN_D2 19
|
||||
#define CAM_PIN_D1 18
|
||||
#define CAM_PIN_D0 5
|
||||
#define CAM_PIN_VSYNC 25
|
||||
#define CAM_PIN_HREF 23
|
||||
#define CAM_PIN_PCLK 22
|
||||
|
||||
#endif
|
||||
|
||||
static const char *TAG = "example:take_picture";
|
||||
|
||||
static camera_config_t camera_config = {
|
||||
.pin_pwdn = CAM_PIN_PWDN,
|
||||
.pin_reset = CAM_PIN_RESET,
|
||||
.pin_xclk = CAM_PIN_XCLK,
|
||||
.pin_sscb_sda = CAM_PIN_SIOD,
|
||||
.pin_sscb_scl = CAM_PIN_SIOC,
|
||||
|
||||
.pin_d7 = CAM_PIN_D7,
|
||||
.pin_d6 = CAM_PIN_D6,
|
||||
.pin_d5 = CAM_PIN_D5,
|
||||
.pin_d4 = CAM_PIN_D4,
|
||||
.pin_d3 = CAM_PIN_D3,
|
||||
.pin_d2 = CAM_PIN_D2,
|
||||
.pin_d1 = CAM_PIN_D1,
|
||||
.pin_d0 = CAM_PIN_D0,
|
||||
.pin_vsync = CAM_PIN_VSYNC,
|
||||
.pin_href = CAM_PIN_HREF,
|
||||
.pin_pclk = CAM_PIN_PCLK,
|
||||
|
||||
//XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental)
|
||||
.xclk_freq_hz = 20000000,
|
||||
.ledc_timer = LEDC_TIMER_0,
|
||||
.ledc_channel = LEDC_CHANNEL_0,
|
||||
|
||||
.pixel_format = PIXFORMAT_JPEG, //YUV422,GRAYSCALE,RGB565,JPEG
|
||||
.frame_size = FRAMESIZE_VGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG
|
||||
|
||||
.jpeg_quality = 12, //0-63 lower number means higher quality
|
||||
.fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG
|
||||
};
|
||||
|
||||
static esp_err_t init_camera()
|
||||
{
|
||||
//initialize the camera
|
||||
esp_err_t err = esp_camera_init(&camera_config);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Camera Init Failed");
|
||||
return err;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void app_main()
|
||||
{
|
||||
init_camera();
|
||||
|
||||
while (1)
|
||||
{
|
||||
ESP_LOGI(TAG, "Taking picture...");
|
||||
camera_fb_t *pic = esp_camera_fb_get();
|
||||
|
||||
// use pic->buf to access the image
|
||||
ESP_LOGI(TAG, "Picture taken! Its size was: %zu bytes", pic->len);
|
||||
|
||||
vTaskDelay(5000 / portTICK_RATE_MS);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
version: "1.0.0"
|
||||
description: This package hosts ESP32 compatible driver for OV2640 image sensors. Additionally it provides a few tools, which allow converting the captured frame data to the more common BMP and JPEG formats.
|
||||
url: https://github.com/espressif/esp32-camera
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"name": "esp32-camera",
|
||||
"version": "1.0.0",
|
||||
"keywords": "esp32, camera, espressif, esp32-cam",
|
||||
"description": "ESP32 compatible driver for OV2640, OV3660, OV5640, OV7670 and OV7725 image sensors.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/espressif/esp32-camera"
|
||||
},
|
||||
"frameworks": "espidf",
|
||||
"platforms": "*",
|
||||
"build": {
|
||||
"flags": [
|
||||
"-Idriver/include",
|
||||
"-Iconversions/include",
|
||||
"-Idriver/private_include",
|
||||
"-Iconversions/private_include",
|
||||
"-Isensors/private_include",
|
||||
"-fno-rtti"
|
||||
],
|
||||
"includeDir": ".",
|
||||
"srcDir": ".",
|
||||
"srcFilter": ["-<*>", "+<driver>", "+<conversions>", "+<sensors>"]
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,580 +0,0 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* OV2640 driver.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sccb.h"
|
||||
#include "ov2640.h"
|
||||
#include "ov2640_regs.h"
|
||||
#include "ov2640_settings.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* TAG = "ov2640";
|
||||
#endif
|
||||
|
||||
static volatile ov2640_bank_t reg_bank = BANK_MAX;
|
||||
static int set_bank(sensor_t *sensor, ov2640_bank_t bank)
|
||||
{
|
||||
int res = 0;
|
||||
if (bank != reg_bank) {
|
||||
reg_bank = bank;
|
||||
res = SCCB_Write(sensor->slv_addr, BANK_SEL, bank);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int write_regs(sensor_t *sensor, const uint8_t (*regs)[2])
|
||||
{
|
||||
int i=0, res = 0;
|
||||
while (regs[i][0]) {
|
||||
if (regs[i][0] == BANK_SEL) {
|
||||
res = set_bank(sensor, regs[i][1]);
|
||||
} else {
|
||||
res = SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]);
|
||||
}
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int write_reg(sensor_t *sensor, ov2640_bank_t bank, uint8_t reg, uint8_t value)
|
||||
{
|
||||
int ret = set_bank(sensor, bank);
|
||||
if(!ret) {
|
||||
ret = SCCB_Write(sensor->slv_addr, reg, value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_reg_bits(sensor_t *sensor, uint8_t bank, uint8_t reg, uint8_t offset, uint8_t mask, uint8_t value)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t c_value, new_value;
|
||||
|
||||
ret = set_bank(sensor, bank);
|
||||
if(ret) {
|
||||
return ret;
|
||||
}
|
||||
c_value = SCCB_Read(sensor->slv_addr, reg);
|
||||
new_value = (c_value & ~(mask << offset)) | ((value & mask) << offset);
|
||||
ret = SCCB_Write(sensor->slv_addr, reg, new_value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_reg(sensor_t *sensor, ov2640_bank_t bank, uint8_t reg)
|
||||
{
|
||||
if(set_bank(sensor, bank)){
|
||||
return 0;
|
||||
}
|
||||
return SCCB_Read(sensor->slv_addr, reg);
|
||||
}
|
||||
|
||||
static uint8_t get_reg_bits(sensor_t *sensor, uint8_t bank, uint8_t reg, uint8_t offset, uint8_t mask)
|
||||
{
|
||||
return (read_reg(sensor, bank, reg) >> offset) & mask;
|
||||
}
|
||||
|
||||
static int write_reg_bits(sensor_t *sensor, uint8_t bank, uint8_t reg, uint8_t mask, int enable)
|
||||
{
|
||||
return set_reg_bits(sensor, bank, reg, 0, mask, enable?mask:0);
|
||||
}
|
||||
|
||||
#define WRITE_REGS_OR_RETURN(regs) ret = write_regs(sensor, regs); if(ret){return ret;}
|
||||
#define WRITE_REG_OR_RETURN(bank, reg, val) ret = write_reg(sensor, bank, reg, val); if(ret){return ret;}
|
||||
#define SET_REG_BITS_OR_RETURN(bank, reg, offset, mask, val) ret = set_reg_bits(sensor, bank, reg, offset, mask, val); if(ret){return ret;}
|
||||
|
||||
static int reset(sensor_t *sensor)
|
||||
{
|
||||
int ret = 0;
|
||||
WRITE_REG_OR_RETURN(BANK_SENSOR, COM7, COM7_SRST);
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
WRITE_REGS_OR_RETURN(ov2640_settings_cif);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
|
||||
{
|
||||
int ret = 0;
|
||||
sensor->pixformat = pixformat;
|
||||
switch (pixformat) {
|
||||
case PIXFORMAT_RGB565:
|
||||
case PIXFORMAT_RGB888:
|
||||
WRITE_REGS_OR_RETURN(ov2640_settings_rgb565);
|
||||
break;
|
||||
case PIXFORMAT_YUV422:
|
||||
case PIXFORMAT_GRAYSCALE:
|
||||
WRITE_REGS_OR_RETURN(ov2640_settings_yuv422);
|
||||
break;
|
||||
case PIXFORMAT_JPEG:
|
||||
WRITE_REGS_OR_RETURN(ov2640_settings_jpeg3);
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
if(!ret) {
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_window(sensor_t *sensor, ov2640_sensor_mode_t mode, int offset_x, int offset_y, int max_x, int max_y, int w, int h){
|
||||
int ret = 0;
|
||||
const uint8_t (*regs)[2];
|
||||
ov2640_clk_t c;
|
||||
c.reserved = 0;
|
||||
|
||||
max_x /= 4;
|
||||
max_y /= 4;
|
||||
w /= 4;
|
||||
h /= 4;
|
||||
uint8_t win_regs[][2] = {
|
||||
{BANK_SEL, BANK_DSP},
|
||||
{HSIZE, max_x & 0xFF},
|
||||
{VSIZE, max_y & 0xFF},
|
||||
{XOFFL, offset_x & 0xFF},
|
||||
{YOFFL, offset_y & 0xFF},
|
||||
{VHYX, ((max_y >> 1) & 0X80) | ((offset_y >> 4) & 0X70) | ((max_x >> 5) & 0X08) | ((offset_y >> 8) & 0X07)},
|
||||
{TEST, (max_x >> 2) & 0X80},
|
||||
{ZMOW, (w)&0xFF},
|
||||
{ZMOH, (h)&0xFF},
|
||||
{ZMHH, ((h>>6)&0x04)|((w>>8)&0x03)},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
c.pclk_auto = 0;
|
||||
c.pclk_div = 8;
|
||||
c.clk_2x = 0;
|
||||
c.clk_div = 0;
|
||||
|
||||
if(sensor->pixformat != PIXFORMAT_JPEG){
|
||||
c.pclk_auto = 1;
|
||||
c.clk_div = 7;
|
||||
}
|
||||
|
||||
if (mode == OV2640_MODE_CIF) {
|
||||
regs = ov2640_settings_to_cif;
|
||||
if(sensor->pixformat != PIXFORMAT_JPEG){
|
||||
c.clk_div = 3;
|
||||
}
|
||||
} else if (mode == OV2640_MODE_SVGA) {
|
||||
regs = ov2640_settings_to_svga;
|
||||
} else {
|
||||
regs = ov2640_settings_to_uxga;
|
||||
c.pclk_div = 12;
|
||||
}
|
||||
|
||||
WRITE_REG_OR_RETURN(BANK_DSP, R_BYPASS, R_BYPASS_DSP_BYPAS);
|
||||
WRITE_REGS_OR_RETURN(regs);
|
||||
WRITE_REGS_OR_RETURN(win_regs);
|
||||
WRITE_REG_OR_RETURN(BANK_SENSOR, CLKRC, c.clk);
|
||||
WRITE_REG_OR_RETURN(BANK_DSP, R_DVP_SP, c.pclk);
|
||||
WRITE_REG_OR_RETURN(BANK_DSP, R_BYPASS, R_BYPASS_DSP_EN);
|
||||
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
//required when changing resolution
|
||||
set_pixformat(sensor, sensor->pixformat);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_framesize(sensor_t *sensor, framesize_t framesize)
|
||||
{
|
||||
int ret = 0;
|
||||
uint16_t w = resolution[framesize].width;
|
||||
uint16_t h = resolution[framesize].height;
|
||||
aspect_ratio_t ratio = resolution[framesize].aspect_ratio;
|
||||
uint16_t max_x = ratio_table[ratio].max_x;
|
||||
uint16_t max_y = ratio_table[ratio].max_y;
|
||||
uint16_t offset_x = ratio_table[ratio].offset_x;
|
||||
uint16_t offset_y = ratio_table[ratio].offset_y;
|
||||
ov2640_sensor_mode_t mode = OV2640_MODE_UXGA;
|
||||
|
||||
sensor->status.framesize = framesize;
|
||||
|
||||
|
||||
|
||||
if (framesize <= FRAMESIZE_CIF) {
|
||||
mode = OV2640_MODE_CIF;
|
||||
max_x /= 4;
|
||||
max_y /= 4;
|
||||
offset_x /= 4;
|
||||
offset_y /= 4;
|
||||
if(max_y > 296){
|
||||
max_y = 296;
|
||||
}
|
||||
} else if (framesize <= FRAMESIZE_SVGA) {
|
||||
mode = OV2640_MODE_SVGA;
|
||||
max_x /= 2;
|
||||
max_y /= 2;
|
||||
offset_x /= 2;
|
||||
offset_y /= 2;
|
||||
}
|
||||
|
||||
ret = set_window(sensor, mode, offset_x, offset_y, max_x, max_y, w, h);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_contrast(sensor_t *sensor, int level)
|
||||
{
|
||||
int ret=0;
|
||||
level += 3;
|
||||
if (level <= 0 || level > NUM_CONTRAST_LEVELS) {
|
||||
return -1;
|
||||
}
|
||||
sensor->status.contrast = level-3;
|
||||
for (int i=0; i<7; i++) {
|
||||
WRITE_REG_OR_RETURN(BANK_DSP, contrast_regs[0][i], contrast_regs[level][i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_brightness(sensor_t *sensor, int level)
|
||||
{
|
||||
int ret=0;
|
||||
level += 3;
|
||||
if (level <= 0 || level > NUM_BRIGHTNESS_LEVELS) {
|
||||
return -1;
|
||||
}
|
||||
sensor->status.brightness = level-3;
|
||||
for (int i=0; i<5; i++) {
|
||||
WRITE_REG_OR_RETURN(BANK_DSP, brightness_regs[0][i], brightness_regs[level][i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_saturation(sensor_t *sensor, int level)
|
||||
{
|
||||
int ret=0;
|
||||
level += 3;
|
||||
if (level <= 0 || level > NUM_SATURATION_LEVELS) {
|
||||
return -1;
|
||||
}
|
||||
sensor->status.saturation = level-3;
|
||||
for (int i=0; i<5; i++) {
|
||||
WRITE_REG_OR_RETURN(BANK_DSP, saturation_regs[0][i], saturation_regs[level][i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_special_effect(sensor_t *sensor, int effect)
|
||||
{
|
||||
int ret=0;
|
||||
effect++;
|
||||
if (effect <= 0 || effect > NUM_SPECIAL_EFFECTS) {
|
||||
return -1;
|
||||
}
|
||||
sensor->status.special_effect = effect-1;
|
||||
for (int i=0; i<5; i++) {
|
||||
WRITE_REG_OR_RETURN(BANK_DSP, special_effects_regs[0][i], special_effects_regs[effect][i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_wb_mode(sensor_t *sensor, int mode)
|
||||
{
|
||||
int ret=0;
|
||||
if (mode < 0 || mode > NUM_WB_MODES) {
|
||||
return -1;
|
||||
}
|
||||
sensor->status.wb_mode = mode;
|
||||
SET_REG_BITS_OR_RETURN(BANK_DSP, 0XC7, 6, 1, mode?1:0);
|
||||
if(mode) {
|
||||
for (int i=0; i<3; i++) {
|
||||
WRITE_REG_OR_RETURN(BANK_DSP, wb_modes_regs[0][i], wb_modes_regs[mode][i]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_ae_level(sensor_t *sensor, int level)
|
||||
{
|
||||
int ret=0;
|
||||
level += 3;
|
||||
if (level <= 0 || level > NUM_AE_LEVELS) {
|
||||
return -1;
|
||||
}
|
||||
sensor->status.ae_level = level-3;
|
||||
for (int i=0; i<3; i++) {
|
||||
WRITE_REG_OR_RETURN(BANK_SENSOR, ae_levels_regs[0][i], ae_levels_regs[level][i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_quality(sensor_t *sensor, int quality)
|
||||
{
|
||||
if(quality < 0) {
|
||||
quality = 0;
|
||||
} else if(quality > 63) {
|
||||
quality = 63;
|
||||
}
|
||||
sensor->status.quality = quality;
|
||||
return write_reg(sensor, BANK_DSP, QS, quality);
|
||||
}
|
||||
|
||||
static int set_agc_gain(sensor_t *sensor, int gain)
|
||||
{
|
||||
if(gain < 0) {
|
||||
gain = 0;
|
||||
} else if(gain > 30) {
|
||||
gain = 30;
|
||||
}
|
||||
sensor->status.agc_gain = gain;
|
||||
return write_reg(sensor, BANK_SENSOR, GAIN, agc_gain_tbl[gain]);
|
||||
}
|
||||
|
||||
static int set_gainceiling_sensor(sensor_t *sensor, gainceiling_t gainceiling)
|
||||
{
|
||||
sensor->status.gainceiling = gainceiling;
|
||||
//return write_reg(sensor, BANK_SENSOR, COM9, COM9_AGC_SET(gainceiling));
|
||||
return set_reg_bits(sensor, BANK_SENSOR, COM9, 5, 7, gainceiling);
|
||||
}
|
||||
|
||||
static int set_aec_value(sensor_t *sensor, int value)
|
||||
{
|
||||
if(value < 0) {
|
||||
value = 0;
|
||||
} else if(value > 1200) {
|
||||
value = 1200;
|
||||
}
|
||||
sensor->status.aec_value = value;
|
||||
return set_reg_bits(sensor, BANK_SENSOR, REG04, 0, 3, value & 0x3)
|
||||
|| write_reg(sensor, BANK_SENSOR, AEC, (value >> 2) & 0xFF)
|
||||
|| set_reg_bits(sensor, BANK_SENSOR, REG45, 0, 0x3F, value >> 10);
|
||||
}
|
||||
|
||||
static int set_aec2(sensor_t *sensor, int enable)
|
||||
{
|
||||
sensor->status.aec2 = enable;
|
||||
return set_reg_bits(sensor, BANK_DSP, CTRL0, 6, 1, enable?0:1);
|
||||
}
|
||||
|
||||
static int set_colorbar(sensor_t *sensor, int enable)
|
||||
{
|
||||
sensor->status.colorbar = enable;
|
||||
return write_reg_bits(sensor, BANK_SENSOR, COM7, COM7_COLOR_BAR, enable?1:0);
|
||||
}
|
||||
|
||||
static int set_agc_sensor(sensor_t *sensor, int enable)
|
||||
{
|
||||
sensor->status.agc = enable;
|
||||
return write_reg_bits(sensor, BANK_SENSOR, COM8, COM8_AGC_EN, enable?1:0);
|
||||
}
|
||||
|
||||
static int set_aec_sensor(sensor_t *sensor, int enable)
|
||||
{
|
||||
sensor->status.aec = enable;
|
||||
return write_reg_bits(sensor, BANK_SENSOR, COM8, COM8_AEC_EN, enable?1:0);
|
||||
}
|
||||
|
||||
static int set_hmirror_sensor(sensor_t *sensor, int enable)
|
||||
{
|
||||
sensor->status.hmirror = enable;
|
||||
return write_reg_bits(sensor, BANK_SENSOR, REG04, REG04_HFLIP_IMG, enable?1:0);
|
||||
}
|
||||
|
||||
static int set_vflip_sensor(sensor_t *sensor, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
sensor->status.vflip = enable;
|
||||
ret = write_reg_bits(sensor, BANK_SENSOR, REG04, REG04_VREF_EN, enable?1:0);
|
||||
return ret & write_reg_bits(sensor, BANK_SENSOR, REG04, REG04_VFLIP_IMG, enable?1:0);
|
||||
}
|
||||
|
||||
static int set_raw_gma_dsp(sensor_t *sensor, int enable)
|
||||
{
|
||||
sensor->status.raw_gma = enable;
|
||||
return set_reg_bits(sensor, BANK_DSP, CTRL1, 5, 1, enable?1:0);
|
||||
}
|
||||
|
||||
static int set_awb_dsp(sensor_t *sensor, int enable)
|
||||
{
|
||||
sensor->status.awb = enable;
|
||||
return set_reg_bits(sensor, BANK_DSP, CTRL1, 3, 1, enable?1:0);
|
||||
}
|
||||
|
||||
static int set_awb_gain_dsp(sensor_t *sensor, int enable)
|
||||
{
|
||||
sensor->status.awb_gain = enable;
|
||||
return set_reg_bits(sensor, BANK_DSP, CTRL1, 2, 1, enable?1:0);
|
||||
}
|
||||
|
||||
static int set_lenc_dsp(sensor_t *sensor, int enable)
|
||||
{
|
||||
sensor->status.lenc = enable;
|
||||
return set_reg_bits(sensor, BANK_DSP, CTRL1, 1, 1, enable?1:0);
|
||||
}
|
||||
|
||||
static int set_dcw_dsp(sensor_t *sensor, int enable)
|
||||
{
|
||||
sensor->status.dcw = enable;
|
||||
return set_reg_bits(sensor, BANK_DSP, CTRL2, 5, 1, enable?1:0);
|
||||
}
|
||||
|
||||
static int set_bpc_dsp(sensor_t *sensor, int enable)
|
||||
{
|
||||
sensor->status.bpc = enable;
|
||||
return set_reg_bits(sensor, BANK_DSP, CTRL3, 7, 1, enable?1:0);
|
||||
}
|
||||
|
||||
static int set_wpc_dsp(sensor_t *sensor, int enable)
|
||||
{
|
||||
sensor->status.wpc = enable;
|
||||
return set_reg_bits(sensor, BANK_DSP, CTRL3, 6, 1, enable?1:0);
|
||||
}
|
||||
|
||||
//unsupported
|
||||
static int set_sharpness(sensor_t *sensor, int level)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int set_denoise(sensor_t *sensor, int level)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int get_reg(sensor_t *sensor, int reg, int mask)
|
||||
{
|
||||
int ret = read_reg(sensor, (reg >> 8) & 0x01, reg & 0xFF);
|
||||
if(ret > 0){
|
||||
ret &= mask;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_reg(sensor_t *sensor, int reg, int mask, int value)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = read_reg(sensor, (reg >> 8) & 0x01, reg & 0xFF);
|
||||
if(ret < 0){
|
||||
return ret;
|
||||
}
|
||||
value = (ret & ~mask) | (value & mask);
|
||||
ret = write_reg(sensor, (reg >> 8) & 0x01, reg & 0xFF, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_res_raw(sensor_t *sensor, int startX, int startY, int endX, int endY, int offsetX, int offsetY, int totalX, int totalY, int outputX, int outputY, bool scale, bool binning)
|
||||
{
|
||||
return set_window(sensor, (ov2640_sensor_mode_t)startX, offsetX, offsetY, totalX, totalY, outputX, outputY);
|
||||
}
|
||||
|
||||
static int _set_pll(sensor_t *sensor, int bypass, int multiplier, int sys_div, int root_2x, int pre_div, int seld5, int pclk_manual, int pclk_div)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz);
|
||||
static int set_xclk(sensor_t *sensor, int timer, int xclk)
|
||||
{
|
||||
int ret = 0;
|
||||
sensor->xclk_freq_hz = xclk * 1000000U;
|
||||
ret = xclk_timer_conf(timer, sensor->xclk_freq_hz);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int init_status(sensor_t *sensor){
|
||||
sensor->status.brightness = 0;
|
||||
sensor->status.contrast = 0;
|
||||
sensor->status.saturation = 0;
|
||||
sensor->status.ae_level = 0;
|
||||
sensor->status.special_effect = 0;
|
||||
sensor->status.wb_mode = 0;
|
||||
|
||||
sensor->status.agc_gain = 30;
|
||||
int agc_gain = read_reg(sensor, BANK_SENSOR, GAIN);
|
||||
for (int i=0; i<30; i++){
|
||||
if(agc_gain >= agc_gain_tbl[i] && agc_gain < agc_gain_tbl[i+1]){
|
||||
sensor->status.agc_gain = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sensor->status.aec_value = ((uint16_t)get_reg_bits(sensor, BANK_SENSOR, REG45, 0, 0x3F) << 10)
|
||||
| ((uint16_t)read_reg(sensor, BANK_SENSOR, AEC) << 2)
|
||||
| get_reg_bits(sensor, BANK_SENSOR, REG04, 0, 3);//0 - 1200
|
||||
sensor->status.quality = read_reg(sensor, BANK_DSP, QS);
|
||||
sensor->status.gainceiling = get_reg_bits(sensor, BANK_SENSOR, COM9, 5, 7);
|
||||
|
||||
sensor->status.awb = get_reg_bits(sensor, BANK_DSP, CTRL1, 3, 1);
|
||||
sensor->status.awb_gain = get_reg_bits(sensor, BANK_DSP, CTRL1, 2, 1);
|
||||
sensor->status.aec = get_reg_bits(sensor, BANK_SENSOR, COM8, 0, 1);
|
||||
sensor->status.aec2 = get_reg_bits(sensor, BANK_DSP, CTRL0, 6, 1);
|
||||
sensor->status.agc = get_reg_bits(sensor, BANK_SENSOR, COM8, 2, 1);
|
||||
sensor->status.bpc = get_reg_bits(sensor, BANK_DSP, CTRL3, 7, 1);
|
||||
sensor->status.wpc = get_reg_bits(sensor, BANK_DSP, CTRL3, 6, 1);
|
||||
sensor->status.raw_gma = get_reg_bits(sensor, BANK_DSP, CTRL1, 5, 1);
|
||||
sensor->status.lenc = get_reg_bits(sensor, BANK_DSP, CTRL1, 1, 1);
|
||||
sensor->status.hmirror = get_reg_bits(sensor, BANK_SENSOR, REG04, 7, 1);
|
||||
sensor->status.vflip = get_reg_bits(sensor, BANK_SENSOR, REG04, 6, 1);
|
||||
sensor->status.dcw = get_reg_bits(sensor, BANK_DSP, CTRL2, 5, 1);
|
||||
sensor->status.colorbar = get_reg_bits(sensor, BANK_SENSOR, COM7, 1, 1);
|
||||
|
||||
sensor->status.sharpness = 0;//not supported
|
||||
sensor->status.denoise = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ov2640_init(sensor_t *sensor)
|
||||
{
|
||||
sensor->reset = reset;
|
||||
sensor->init_status = init_status;
|
||||
sensor->set_pixformat = set_pixformat;
|
||||
sensor->set_framesize = set_framesize;
|
||||
sensor->set_contrast = set_contrast;
|
||||
sensor->set_brightness= set_brightness;
|
||||
sensor->set_saturation= set_saturation;
|
||||
|
||||
sensor->set_quality = set_quality;
|
||||
sensor->set_colorbar = set_colorbar;
|
||||
|
||||
sensor->set_gainceiling = set_gainceiling_sensor;
|
||||
sensor->set_gain_ctrl = set_agc_sensor;
|
||||
sensor->set_exposure_ctrl = set_aec_sensor;
|
||||
sensor->set_hmirror = set_hmirror_sensor;
|
||||
sensor->set_vflip = set_vflip_sensor;
|
||||
|
||||
sensor->set_whitebal = set_awb_dsp;
|
||||
sensor->set_aec2 = set_aec2;
|
||||
sensor->set_aec_value = set_aec_value;
|
||||
sensor->set_special_effect = set_special_effect;
|
||||
sensor->set_wb_mode = set_wb_mode;
|
||||
sensor->set_ae_level = set_ae_level;
|
||||
|
||||
sensor->set_dcw = set_dcw_dsp;
|
||||
sensor->set_bpc = set_bpc_dsp;
|
||||
sensor->set_wpc = set_wpc_dsp;
|
||||
sensor->set_awb_gain = set_awb_gain_dsp;
|
||||
sensor->set_agc_gain = set_agc_gain;
|
||||
|
||||
sensor->set_raw_gma = set_raw_gma_dsp;
|
||||
sensor->set_lenc = set_lenc_dsp;
|
||||
|
||||
//not supported
|
||||
sensor->set_sharpness = set_sharpness;
|
||||
sensor->set_denoise = set_denoise;
|
||||
|
||||
sensor->get_reg = get_reg;
|
||||
sensor->set_reg = set_reg;
|
||||
sensor->set_res_raw = set_res_raw;
|
||||
sensor->set_pll = _set_pll;
|
||||
sensor->set_xclk = set_xclk;
|
||||
ESP_LOGD(TAG, "OV2640 Attached");
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,439 +0,0 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* author: Juan Schiavoni <juanjoseschiavoni@hotmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* OV7725 driver.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sccb.h"
|
||||
#include "ov7670.h"
|
||||
#include "ov7670_regs.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* TAG = "ov7760";
|
||||
#endif
|
||||
|
||||
static int ov7670_clkrc = 0x01;
|
||||
|
||||
/*
|
||||
* The default register settings, as obtained from OmniVision. There
|
||||
* is really no making sense of most of these - lots of "reserved" values
|
||||
* and such.
|
||||
*
|
||||
* These settings give VGA YUYV.
|
||||
*/
|
||||
struct regval_list {
|
||||
uint8_t reg_num;
|
||||
uint8_t value;
|
||||
};
|
||||
|
||||
static struct regval_list ov7670_default_regs[] = {
|
||||
/* Sensor automatically sets output window when resolution changes. */
|
||||
{TSLB, 0x04},
|
||||
|
||||
/* Frame rate 30 fps at 12 Mhz clock */
|
||||
{CLKRC, 0x00},
|
||||
{DBLV, 0x4A},
|
||||
|
||||
{COM10, COM10_VSYNC_NEG | COM10_PCLK_MASK},
|
||||
|
||||
/* Improve white balance */
|
||||
{COM4, 0x40},
|
||||
|
||||
/* Improve color */
|
||||
{RSVD_B0, 0x84},
|
||||
|
||||
/* Enable 50/60 Hz auto detection */
|
||||
{COM11, COM11_EXP|COM11_HZAUTO},
|
||||
|
||||
/* Disable some delays */
|
||||
{HSYST, 0},
|
||||
{HSYEN, 0},
|
||||
|
||||
{MVFP, MVFP_SUN},
|
||||
|
||||
/* More reserved magic, some of which tweaks white balance */
|
||||
{AWBC1, 0x0a},
|
||||
{AWBC2, 0xf0},
|
||||
{AWBC3, 0x34},
|
||||
{AWBC4, 0x58},
|
||||
{AWBC5, 0x28},
|
||||
{AWBC6, 0x3a},
|
||||
|
||||
{AWBCTR3, 0x0a},
|
||||
{AWBCTR2, 0x55},
|
||||
{AWBCTR1, 0x11},
|
||||
{AWBCTR0, 0x9e},
|
||||
|
||||
{COM8, COM8_FAST_AUTO|COM8_STEP_UNLIMIT|COM8_AGC_EN|COM8_AEC_EN|COM8_AWB_EN},
|
||||
|
||||
/* End marker is FF because in ov7670 the address of GAIN 0 and default value too. */
|
||||
{0xFF, 0xFF},
|
||||
};
|
||||
|
||||
static struct regval_list ov7670_fmt_yuv422[] = {
|
||||
{ COM7, 0x0 }, /* Selects YUV mode */
|
||||
{ RGB444, 0 }, /* No RGB444 please */
|
||||
{ COM1, 0 }, /* CCIR601 */
|
||||
{ COM15, COM15_R00FF },
|
||||
{ MVFP, MVFP_SUN },
|
||||
{ COM9, 0x6A }, /* 128x gain ceiling; 0x8 is reserved bit */
|
||||
{ MTX1, 0x80 }, /* "matrix coefficient 1" */
|
||||
{ MTX2, 0x80 }, /* "matrix coefficient 2" */
|
||||
{ MTX3, 0 }, /* vb */
|
||||
{ MTX4, 0x22 }, /* "matrix coefficient 4" */
|
||||
{ MTX5, 0x5e }, /* "matrix coefficient 5" */
|
||||
{ MTX6, 0x80 }, /* "matrix coefficient 6" */
|
||||
{ COM13, COM13_UVSAT },
|
||||
{ 0xff, 0xff }, /* END MARKER */
|
||||
};
|
||||
|
||||
static struct regval_list ov7670_fmt_rgb565[] = {
|
||||
{ COM7, COM7_FMT_RGB565 }, /* Selects RGB mode */
|
||||
{ RGB444, 0 }, /* No RGB444 please */
|
||||
{ COM1, 0x0 }, /* CCIR601 */
|
||||
{ COM15, COM15_RGB565 |COM15_R00FF },
|
||||
{ MVFP, MVFP_SUN },
|
||||
{ COM9, 0x6A }, /* 128x gain ceiling; 0x8 is reserved bit */
|
||||
{ MTX1, 0xb3 }, /* "matrix coefficient 1" */
|
||||
{ MTX2, 0xb3 }, /* "matrix coefficient 2" */
|
||||
{ MTX3, 0 }, /* vb */
|
||||
{ MTX4, 0x3d }, /* "matrix coefficient 4" */
|
||||
{ MTX5, 0xa7 }, /* "matrix coefficient 5" */
|
||||
{ MTX6, 0xe4 }, /* "matrix coefficient 6" */
|
||||
{ COM13, COM13_UVSAT },
|
||||
{ 0xff, 0xff }, /* END MARKER */
|
||||
};
|
||||
|
||||
|
||||
static struct regval_list ov7670_vga[] = {
|
||||
{ COM3, 0x00 },
|
||||
{ COM14, 0x00 },
|
||||
{ SCALING_XSC, 0x3A },
|
||||
{ SCALING_YSC, 0x35 },
|
||||
{ SCALING_DCWCTR, 0x11 },
|
||||
{ SCALING_PCLK_DIV, 0xF0 },
|
||||
{ SCALING_PCLK_DELAY, 0x02 },
|
||||
{ 0xff, 0xff },
|
||||
};
|
||||
|
||||
static struct regval_list ov7670_qvga[] = {
|
||||
{ COM3, 0x04 },
|
||||
{ COM14, 0x19 },
|
||||
{ SCALING_XSC, 0x3A },
|
||||
{ SCALING_YSC, 0x35 },
|
||||
{ SCALING_DCWCTR, 0x11 },
|
||||
{ SCALING_PCLK_DIV, 0xF1 },
|
||||
{ SCALING_PCLK_DELAY, 0x02 },
|
||||
{ 0xff, 0xff },
|
||||
};
|
||||
|
||||
static struct regval_list ov7670_qqvga[] = {
|
||||
{ COM3, 0x04 }, //DCW enable
|
||||
{ COM14, 0x1a }, //pixel clock divided by 4, manual scaling enable, DCW and PCLK controlled by register
|
||||
{ SCALING_XSC, 0x3a },
|
||||
{ SCALING_YSC, 0x35 },
|
||||
{ SCALING_DCWCTR, 0x22 }, //downsample by 4
|
||||
{ SCALING_PCLK_DIV, 0xf2 }, //pixel clock divided by 4
|
||||
{ SCALING_PCLK_DELAY, 0x02 },
|
||||
{ 0xff, 0xff },
|
||||
};
|
||||
|
||||
/*
|
||||
* Write a list of register settings; ff/ff stops the process.
|
||||
*/
|
||||
static int ov7670_write_array(sensor_t *sensor, struct regval_list *vals)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
while ( (vals->reg_num != 0xff || vals->value != 0xff) && (ret == 0) ) {
|
||||
ret = SCCB_Write(sensor->slv_addr, vals->reg_num, vals->value);
|
||||
|
||||
ESP_LOGD(TAG, "reset reg %02X, W(%02X) R(%02X)", vals->reg_num,
|
||||
vals->value, SCCB_Read(sensor->slv_addr, vals->reg_num) );
|
||||
|
||||
vals++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the frame control registers.
|
||||
*/
|
||||
static int ov7670_frame_control(sensor_t *sensor, int hstart, int hstop, int vstart, int vstop)
|
||||
{
|
||||
struct regval_list frame[7];
|
||||
|
||||
frame[0].reg_num = HSTART;
|
||||
frame[0].value = (hstart >> 3);
|
||||
|
||||
frame[1].reg_num = HSTOP;
|
||||
frame[1].value = (hstop >> 3);
|
||||
|
||||
frame[2].reg_num = HREF;
|
||||
frame[2].value = (((hstop & 0x07) << 3) | (hstart & 0x07));
|
||||
|
||||
frame[3].reg_num = VSTART;
|
||||
frame[3].value = (vstart >> 2);
|
||||
|
||||
frame[4].reg_num = VSTOP;
|
||||
frame[4].value = (vstop >> 2);
|
||||
|
||||
frame[5].reg_num = VREF;
|
||||
frame[5].value = (((vstop & 0x02) << 2) | (vstart & 0x02));
|
||||
|
||||
/* End mark */
|
||||
frame[5].reg_num = 0xFF;
|
||||
frame[5].value = 0xFF;
|
||||
|
||||
return ov7670_write_array(sensor, frame);
|
||||
}
|
||||
|
||||
static int reset(sensor_t *sensor)
|
||||
{
|
||||
int ret;
|
||||
|
||||
// Reset all registers
|
||||
SCCB_Write(sensor->slv_addr, COM7, COM7_RESET);
|
||||
|
||||
// Delay 10 ms
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
ret = ov7670_write_array(sensor, ov7670_default_regs);
|
||||
|
||||
// Delay
|
||||
vTaskDelay(30 / portTICK_PERIOD_MS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (pixformat) {
|
||||
case PIXFORMAT_RGB565:
|
||||
case PIXFORMAT_RGB888:
|
||||
ret = ov7670_write_array(sensor, ov7670_fmt_rgb565);
|
||||
break;
|
||||
|
||||
case PIXFORMAT_YUV422:
|
||||
case PIXFORMAT_GRAYSCALE:
|
||||
default:
|
||||
ret = ov7670_write_array(sensor, ov7670_fmt_yuv422);
|
||||
break;
|
||||
}
|
||||
|
||||
vTaskDelay(30 / portTICK_PERIOD_MS);
|
||||
|
||||
/*
|
||||
* If we're running RGB565, we must rewrite clkrc after setting
|
||||
* the other parameters or the image looks poor. If we're *not*
|
||||
* doing RGB565, we must not rewrite clkrc or the image looks
|
||||
* *really* poor.
|
||||
*
|
||||
* (Update) Now that we retain clkrc state, we should be able
|
||||
* to write it unconditionally, and that will make the frame
|
||||
* rate persistent too.
|
||||
*/
|
||||
if (pixformat == PIXFORMAT_RGB565) {
|
||||
ret = SCCB_Write(sensor->slv_addr, CLKRC, ov7670_clkrc);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_framesize(sensor_t *sensor, framesize_t framesize)
|
||||
{
|
||||
int ret;
|
||||
|
||||
// store clkrc before changing window settings...
|
||||
ov7670_clkrc = SCCB_Read(sensor->slv_addr, CLKRC);
|
||||
|
||||
switch (framesize){
|
||||
case FRAMESIZE_VGA:
|
||||
if( (ret = ov7670_write_array(sensor, ov7670_vga)) == 0 ) {
|
||||
/* These values from Omnivision */
|
||||
ret = ov7670_frame_control(sensor, 158, 14, 10, 490);
|
||||
}
|
||||
break;
|
||||
case FRAMESIZE_QVGA:
|
||||
if( (ret = ov7670_write_array(sensor, ov7670_qvga)) == 0 ) {
|
||||
/* These values from Omnivision */
|
||||
ret = ov7670_frame_control(sensor, 158, 14, 10, 490);
|
||||
}
|
||||
break;
|
||||
case FRAMESIZE_QQVGA:
|
||||
if( (ret = ov7670_write_array(sensor, ov7670_qqvga)) == 0 ) {
|
||||
/* These values from Omnivision */
|
||||
ret = ov7670_frame_control(sensor, 158, 14, 10, 490);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
vTaskDelay(30 / portTICK_PERIOD_MS);
|
||||
|
||||
if (ret == 0) {
|
||||
sensor->status.framesize = framesize;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_colorbar(sensor_t *sensor, int enable)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
// Read register scaling_xsc
|
||||
uint8_t reg = SCCB_Read(sensor->slv_addr, SCALING_XSC);
|
||||
|
||||
// Pattern to set color bar bit[0]=0 in every case
|
||||
reg = SCALING_XSC_CBAR(reg);
|
||||
|
||||
// Write pattern to SCALING_XSC
|
||||
ret = SCCB_Write(sensor->slv_addr, SCALING_XSC, reg);
|
||||
|
||||
// Read register scaling_ysc
|
||||
reg = SCCB_Read(sensor->slv_addr, SCALING_YSC);
|
||||
|
||||
// Pattern to set color bar bit[0]=0 in every case
|
||||
reg = SCALING_YSC_CBAR(reg, enable);
|
||||
|
||||
// Write pattern to SCALING_YSC
|
||||
ret = ret | SCCB_Write(sensor->slv_addr, SCALING_YSC, reg);
|
||||
|
||||
// return 0 or 0xFF
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_whitebal(sensor_t *sensor, int enable)
|
||||
{
|
||||
// Read register COM8
|
||||
uint8_t reg = SCCB_Read(sensor->slv_addr, COM8);
|
||||
|
||||
// Set white bal on/off
|
||||
reg = COM8_SET_AWB(reg, enable);
|
||||
|
||||
// Write back register COM8
|
||||
return SCCB_Write(sensor->slv_addr, COM8, reg);
|
||||
}
|
||||
|
||||
static int set_gain_ctrl(sensor_t *sensor, int enable)
|
||||
{
|
||||
// Read register COM8
|
||||
uint8_t reg = SCCB_Read(sensor->slv_addr, COM8);
|
||||
|
||||
// Set white bal on/off
|
||||
reg = COM8_SET_AGC(reg, enable);
|
||||
|
||||
// Write back register COM8
|
||||
return SCCB_Write(sensor->slv_addr, COM8, reg);
|
||||
}
|
||||
|
||||
static int set_exposure_ctrl(sensor_t *sensor, int enable)
|
||||
{
|
||||
// Read register COM8
|
||||
uint8_t reg = SCCB_Read(sensor->slv_addr, COM8);
|
||||
|
||||
// Set white bal on/off
|
||||
reg = COM8_SET_AEC(reg, enable);
|
||||
|
||||
// Write back register COM8
|
||||
return SCCB_Write(sensor->slv_addr, COM8, reg);
|
||||
}
|
||||
|
||||
static int set_hmirror(sensor_t *sensor, int enable)
|
||||
{
|
||||
// Read register MVFP
|
||||
uint8_t reg = SCCB_Read(sensor->slv_addr, MVFP);
|
||||
|
||||
// Set mirror on/off
|
||||
reg = MVFP_SET_MIRROR(reg, enable);
|
||||
|
||||
// Write back register MVFP
|
||||
return SCCB_Write(sensor->slv_addr, MVFP, reg);
|
||||
}
|
||||
|
||||
static int set_vflip(sensor_t *sensor, int enable)
|
||||
{
|
||||
// Read register MVFP
|
||||
uint8_t reg = SCCB_Read(sensor->slv_addr, MVFP);
|
||||
|
||||
// Set mirror on/off
|
||||
reg = MVFP_SET_FLIP(reg, enable);
|
||||
|
||||
// Write back register MVFP
|
||||
return SCCB_Write(sensor->slv_addr, MVFP, reg);
|
||||
}
|
||||
|
||||
static int init_status(sensor_t *sensor)
|
||||
{
|
||||
sensor->status.awb = 0;
|
||||
sensor->status.aec = 0;
|
||||
sensor->status.agc = 0;
|
||||
sensor->status.hmirror = 0;
|
||||
sensor->status.vflip = 0;
|
||||
sensor->status.colorbar = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_dummy(sensor_t *sensor, int val){ return -1; }
|
||||
static int set_gainceiling_dummy(sensor_t *sensor, gainceiling_t val){ return -1; }
|
||||
|
||||
int ov7670_init(sensor_t *sensor)
|
||||
{
|
||||
// Set function pointers
|
||||
sensor->reset = reset;
|
||||
sensor->init_status = init_status;
|
||||
sensor->set_pixformat = set_pixformat;
|
||||
sensor->set_framesize = set_framesize;
|
||||
sensor->set_colorbar = set_colorbar;
|
||||
sensor->set_whitebal = set_whitebal;
|
||||
sensor->set_gain_ctrl = set_gain_ctrl;
|
||||
sensor->set_exposure_ctrl = set_exposure_ctrl;
|
||||
sensor->set_hmirror = set_hmirror;
|
||||
sensor->set_vflip = set_vflip;
|
||||
|
||||
//not supported
|
||||
sensor->set_brightness= set_dummy;
|
||||
sensor->set_saturation= set_dummy;
|
||||
sensor->set_quality = set_dummy;
|
||||
sensor->set_gainceiling = set_gainceiling_dummy;
|
||||
sensor->set_aec2 = set_dummy;
|
||||
sensor->set_aec_value = set_dummy;
|
||||
sensor->set_special_effect = set_dummy;
|
||||
sensor->set_wb_mode = set_dummy;
|
||||
sensor->set_ae_level = set_dummy;
|
||||
sensor->set_dcw = set_dummy;
|
||||
sensor->set_bpc = set_dummy;
|
||||
sensor->set_wpc = set_dummy;
|
||||
sensor->set_awb_gain = set_dummy;
|
||||
sensor->set_agc_gain = set_dummy;
|
||||
sensor->set_raw_gma = set_dummy;
|
||||
sensor->set_lenc = set_dummy;
|
||||
sensor->set_sharpness = set_dummy;
|
||||
sensor->set_denoise = set_dummy;
|
||||
|
||||
// Retrieve sensor's signature
|
||||
sensor->id.MIDH = SCCB_Read(sensor->slv_addr, REG_MIDH);
|
||||
sensor->id.MIDL = SCCB_Read(sensor->slv_addr, REG_MIDL);
|
||||
sensor->id.PID = SCCB_Read(sensor->slv_addr, REG_PID);
|
||||
sensor->id.VER = SCCB_Read(sensor->slv_addr, REG_VER);
|
||||
|
||||
ESP_LOGD(TAG, "OV7670 Attached");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,557 +0,0 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* OV7725 driver.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "sccb.h"
|
||||
#include "ov7725.h"
|
||||
#include "ov7725_regs.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* TAG = "ov7725";
|
||||
#endif
|
||||
|
||||
|
||||
static const uint8_t default_regs[][2] = {
|
||||
{COM3, COM3_SWAP_YUV},
|
||||
{COM7, COM7_RES_QVGA | COM7_FMT_YUV},
|
||||
|
||||
{COM4, 0x01 | 0x00}, /* bypass PLL (0x00:off, 0x40:4x, 0x80:6x, 0xC0:8x) */
|
||||
{CLKRC, 0x80 | 0x03}, /* Res/Bypass pre-scalar (0x40:bypass, 0x00-0x3F:prescaler PCLK=XCLK/(prescaler + 1)/2 ) */
|
||||
|
||||
// QVGA Window Size
|
||||
{HSTART, 0x3F},
|
||||
{HSIZE, 0x50},
|
||||
{VSTART, 0x03},
|
||||
{VSIZE, 0x78},
|
||||
{HREF, 0x00},
|
||||
|
||||
// Scale down to QVGA Resolution
|
||||
{HOUTSIZE, 0x50},
|
||||
{VOUTSIZE, 0x78},
|
||||
{EXHCH, 0x00},
|
||||
|
||||
{COM12, 0x03},
|
||||
{TGT_B, 0x7F},
|
||||
{FIXGAIN, 0x09},
|
||||
{AWB_CTRL0, 0xE0},
|
||||
{DSP_CTRL1, 0xFF},
|
||||
|
||||
{DSP_CTRL2, DSP_CTRL2_VDCW_EN | DSP_CTRL2_HDCW_EN | DSP_CTRL2_HZOOM_EN | DSP_CTRL2_VZOOM_EN},
|
||||
|
||||
{DSP_CTRL3, 0x00},
|
||||
{DSP_CTRL4, 0x00},
|
||||
{DSPAUTO, 0xFF},
|
||||
|
||||
{COM8, 0xF0},
|
||||
{COM6, 0xC5},
|
||||
{COM9, 0x11},
|
||||
{COM10, COM10_VSYNC_NEG | COM10_PCLK_MASK}, //Invert VSYNC and MASK PCLK
|
||||
{BDBASE, 0x7F},
|
||||
{DBSTEP, 0x03},
|
||||
{AEW, 0x96},
|
||||
{AEB, 0x64},
|
||||
{VPT, 0xA1},
|
||||
{EXHCL, 0x00},
|
||||
{AWB_CTRL3, 0xAA},
|
||||
{COM8, 0xFF},
|
||||
|
||||
//Gamma
|
||||
{GAM1, 0x0C},
|
||||
{GAM2, 0x16},
|
||||
{GAM3, 0x2A},
|
||||
{GAM4, 0x4E},
|
||||
{GAM5, 0x61},
|
||||
{GAM6, 0x6F},
|
||||
{GAM7, 0x7B},
|
||||
{GAM8, 0x86},
|
||||
{GAM9, 0x8E},
|
||||
{GAM10, 0x97},
|
||||
{GAM11, 0xA4},
|
||||
{GAM12, 0xAF},
|
||||
{GAM13, 0xC5},
|
||||
{GAM14, 0xD7},
|
||||
{GAM15, 0xE8},
|
||||
|
||||
{SLOP, 0x20},
|
||||
{EDGE1, 0x05},
|
||||
{EDGE2, 0x03},
|
||||
{EDGE3, 0x00},
|
||||
{DNSOFF, 0x01},
|
||||
|
||||
{MTX1, 0xB0},
|
||||
{MTX2, 0x9D},
|
||||
{MTX3, 0x13},
|
||||
{MTX4, 0x16},
|
||||
{MTX5, 0x7B},
|
||||
{MTX6, 0x91},
|
||||
{MTX_CTRL, 0x1E},
|
||||
|
||||
{BRIGHTNESS, 0x08},
|
||||
{CONTRAST, 0x30},
|
||||
{UVADJ0, 0x81},
|
||||
{SDE, (SDE_CONT_BRIGHT_EN | SDE_SATURATION_EN)},
|
||||
|
||||
// For 30 fps/60Hz
|
||||
{DM_LNL, 0x00},
|
||||
{DM_LNH, 0x00},
|
||||
{BDBASE, 0x7F},
|
||||
{DBSTEP, 0x03},
|
||||
|
||||
// Lens Correction, should be tuned with real camera module
|
||||
{LC_RADI, 0x10},
|
||||
{LC_COEF, 0x10},
|
||||
{LC_COEFB, 0x14},
|
||||
{LC_COEFR, 0x17},
|
||||
{LC_CTR, 0x05},
|
||||
{COM5, 0xF5}, //0x65
|
||||
|
||||
{0x00, 0x00},
|
||||
};
|
||||
|
||||
static int get_reg(sensor_t *sensor, int reg, int mask)
|
||||
{
|
||||
int ret = SCCB_Read(sensor->slv_addr, reg & 0xFF);
|
||||
if(ret > 0){
|
||||
ret &= mask;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_reg(sensor_t *sensor, int reg, int mask, int value)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = SCCB_Read(sensor->slv_addr, reg & 0xFF);
|
||||
if(ret < 0){
|
||||
return ret;
|
||||
}
|
||||
value = (ret & ~mask) | (value & mask);
|
||||
ret = SCCB_Write(sensor->slv_addr, reg & 0xFF, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_reg_bits(sensor_t *sensor, uint8_t reg, uint8_t offset, uint8_t length, uint8_t value)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = SCCB_Read(sensor->slv_addr, reg);
|
||||
if(ret < 0){
|
||||
return ret;
|
||||
}
|
||||
uint8_t mask = ((1 << length) - 1) << offset;
|
||||
value = (ret & ~mask) | ((value << offset) & mask);
|
||||
ret = SCCB_Write(sensor->slv_addr, reg & 0xFF, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_reg_bits(sensor_t *sensor, uint8_t reg, uint8_t offset, uint8_t length)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = SCCB_Read(sensor->slv_addr, reg);
|
||||
if(ret < 0){
|
||||
return ret;
|
||||
}
|
||||
uint8_t mask = ((1 << length) - 1) << offset;
|
||||
return (ret & mask) >> offset;
|
||||
}
|
||||
|
||||
|
||||
static int reset(sensor_t *sensor)
|
||||
{
|
||||
int i=0;
|
||||
const uint8_t (*regs)[2];
|
||||
|
||||
// Reset all registers
|
||||
SCCB_Write(sensor->slv_addr, COM7, COM7_RESET);
|
||||
|
||||
// Delay 10 ms
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
// Write default regsiters
|
||||
for (i=0, regs = default_regs; regs[i][0]; i++) {
|
||||
SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]);
|
||||
}
|
||||
|
||||
// Delay
|
||||
vTaskDelay(30 / portTICK_PERIOD_MS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
|
||||
{
|
||||
int ret=0;
|
||||
sensor->pixformat = pixformat;
|
||||
// Read register COM7
|
||||
uint8_t reg = SCCB_Read(sensor->slv_addr, COM7);
|
||||
|
||||
switch (pixformat) {
|
||||
case PIXFORMAT_RGB565:
|
||||
reg = COM7_SET_RGB(reg, COM7_FMT_RGB565);
|
||||
break;
|
||||
case PIXFORMAT_YUV422:
|
||||
case PIXFORMAT_GRAYSCALE:
|
||||
reg = COM7_SET_FMT(reg, COM7_FMT_YUV);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Write back register COM7
|
||||
ret = SCCB_Write(sensor->slv_addr, COM7, reg);
|
||||
|
||||
// Delay
|
||||
vTaskDelay(30 / portTICK_PERIOD_MS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_framesize(sensor_t *sensor, framesize_t framesize)
|
||||
{
|
||||
int ret=0;
|
||||
if (framesize > FRAMESIZE_VGA) {
|
||||
return -1;
|
||||
}
|
||||
uint16_t w = resolution[framesize].width;
|
||||
uint16_t h = resolution[framesize].height;
|
||||
uint8_t reg = SCCB_Read(sensor->slv_addr, COM7);
|
||||
|
||||
sensor->status.framesize = framesize;
|
||||
|
||||
// Write MSBs
|
||||
ret |= SCCB_Write(sensor->slv_addr, HOUTSIZE, w>>2);
|
||||
ret |= SCCB_Write(sensor->slv_addr, VOUTSIZE, h>>1);
|
||||
|
||||
ret |= SCCB_Write(sensor->slv_addr, HSIZE, w>>2);
|
||||
ret |= SCCB_Write(sensor->slv_addr, VSIZE, h>>1);
|
||||
|
||||
// Write LSBs
|
||||
ret |= SCCB_Write(sensor->slv_addr, HREF, ((w&0x3) | ((h&0x1) << 2)));
|
||||
|
||||
if (framesize < FRAMESIZE_VGA) {
|
||||
// Enable auto-scaling/zooming factors
|
||||
ret |= SCCB_Write(sensor->slv_addr, DSPAUTO, 0xFF);
|
||||
|
||||
ret |= SCCB_Write(sensor->slv_addr, HSTART, 0x3F);
|
||||
ret |= SCCB_Write(sensor->slv_addr, VSTART, 0x03);
|
||||
|
||||
ret |= SCCB_Write(sensor->slv_addr, COM7, reg | COM7_RES_QVGA);
|
||||
|
||||
ret |= SCCB_Write(sensor->slv_addr, CLKRC, 0x80 | 0x01);
|
||||
|
||||
} else {
|
||||
// Disable auto-scaling/zooming factors
|
||||
ret |= SCCB_Write(sensor->slv_addr, DSPAUTO, 0xF3);
|
||||
|
||||
// Clear auto-scaling/zooming factors
|
||||
ret |= SCCB_Write(sensor->slv_addr, SCAL0, 0x00);
|
||||
ret |= SCCB_Write(sensor->slv_addr, SCAL1, 0x00);
|
||||
ret |= SCCB_Write(sensor->slv_addr, SCAL2, 0x00);
|
||||
|
||||
ret |= SCCB_Write(sensor->slv_addr, HSTART, 0x23);
|
||||
ret |= SCCB_Write(sensor->slv_addr, VSTART, 0x07);
|
||||
|
||||
ret |= SCCB_Write(sensor->slv_addr, COM7, reg & ~COM7_RES_QVGA);
|
||||
|
||||
ret |= SCCB_Write(sensor->slv_addr, CLKRC, 0x80 | 0x03);
|
||||
}
|
||||
|
||||
// Delay
|
||||
vTaskDelay(30 / portTICK_PERIOD_MS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_colorbar(sensor_t *sensor, int enable)
|
||||
{
|
||||
int ret=0;
|
||||
uint8_t reg;
|
||||
sensor->status.colorbar = enable;
|
||||
|
||||
// Read reg COM3
|
||||
reg = SCCB_Read(sensor->slv_addr, COM3);
|
||||
// Enable colorbar test pattern output
|
||||
reg = COM3_SET_CBAR(reg, enable);
|
||||
// Write back COM3
|
||||
ret |= SCCB_Write(sensor->slv_addr, COM3, reg);
|
||||
|
||||
// Read reg DSP_CTRL3
|
||||
reg = SCCB_Read(sensor->slv_addr, DSP_CTRL3);
|
||||
// Enable DSP colorbar output
|
||||
reg = DSP_CTRL3_SET_CBAR(reg, enable);
|
||||
// Write back DSP_CTRL3
|
||||
ret |= SCCB_Write(sensor->slv_addr, DSP_CTRL3, reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_whitebal(sensor_t *sensor, int enable)
|
||||
{
|
||||
if(set_reg_bits(sensor, COM8, 1, 1, enable) >= 0){
|
||||
sensor->status.awb = !!enable;
|
||||
}
|
||||
return sensor->status.awb;
|
||||
}
|
||||
|
||||
static int set_gain_ctrl(sensor_t *sensor, int enable)
|
||||
{
|
||||
if(set_reg_bits(sensor, COM8, 2, 1, enable) >= 0){
|
||||
sensor->status.agc = !!enable;
|
||||
}
|
||||
return sensor->status.agc;
|
||||
}
|
||||
|
||||
static int set_exposure_ctrl(sensor_t *sensor, int enable)
|
||||
{
|
||||
if(set_reg_bits(sensor, COM8, 0, 1, enable) >= 0){
|
||||
sensor->status.aec = !!enable;
|
||||
}
|
||||
return sensor->status.aec;
|
||||
}
|
||||
|
||||
static int set_hmirror(sensor_t *sensor, int enable)
|
||||
{
|
||||
if(set_reg_bits(sensor, COM3, 6, 1, enable) >= 0){
|
||||
sensor->status.hmirror = !!enable;
|
||||
}
|
||||
return sensor->status.hmirror;
|
||||
}
|
||||
|
||||
static int set_vflip(sensor_t *sensor, int enable)
|
||||
{
|
||||
if(set_reg_bits(sensor, COM3, 7, 1, enable) >= 0){
|
||||
sensor->status.vflip = !!enable;
|
||||
}
|
||||
return sensor->status.vflip;
|
||||
}
|
||||
|
||||
static int set_dcw_dsp(sensor_t *sensor, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = set_reg_bits(sensor, 0x65, 2, 1, !enable);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Set dcw to: %d", enable);
|
||||
sensor->status.dcw = enable;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_aec2(sensor_t *sensor, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = set_reg_bits(sensor, COM8, 7, 1, enable);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Set aec2 to: %d", enable);
|
||||
sensor->status.aec2 = enable;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_bpc_dsp(sensor_t *sensor, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = set_reg_bits(sensor, 0x64, 1, 1, enable);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Set bpc to: %d", enable);
|
||||
sensor->status.bpc = enable;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_wpc_dsp(sensor_t *sensor, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = set_reg_bits(sensor, 0x64, 0, 1, enable);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Set wpc to: %d", enable);
|
||||
sensor->status.wpc = enable;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_raw_gma_dsp(sensor_t *sensor, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = set_reg_bits(sensor, 0x64, 2, 1, enable);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Set raw_gma to: %d", enable);
|
||||
sensor->status.raw_gma = enable;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_lenc_dsp(sensor_t *sensor, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = set_reg_bits(sensor, LC_CTR, 0, 1, enable);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Set lenc to: %d", enable);
|
||||
sensor->status.lenc = enable;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//real gain
|
||||
static int set_agc_gain(sensor_t *sensor, int gain)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = set_reg_bits(sensor, COM9, 4, 3, gain % 5);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Set gain to: %d", gain);
|
||||
sensor->status.agc_gain = gain;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_aec_value(sensor_t *sensor, int value)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = SCCB_Write(sensor->slv_addr, AEC, value & 0xff) | SCCB_Write(sensor->slv_addr, AECH, value >> 8);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Set aec_value to: %d", value);
|
||||
sensor->status.aec_value = value;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_awb_gain_dsp(sensor_t *sensor, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = set_reg_bits(sensor, 0x63, 7, 1, enable);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Set awb_gain to: %d", enable);
|
||||
sensor->status.awb_gain = enable;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_brightness(sensor_t *sensor, int level)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = SCCB_Write(sensor->slv_addr, 0x9B, level);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Set brightness to: %d", level);
|
||||
sensor->status.brightness = level;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_contrast(sensor_t *sensor, int level)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = SCCB_Write(sensor->slv_addr, 0x9C, level);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Set contrast to: %d", level);
|
||||
sensor->status.contrast = level;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int init_status(sensor_t *sensor)
|
||||
{
|
||||
sensor->status.brightness = SCCB_Read(sensor->slv_addr, 0x9B);
|
||||
sensor->status.contrast = SCCB_Read(sensor->slv_addr, 0x9C);
|
||||
sensor->status.saturation = 0;
|
||||
sensor->status.ae_level = 0;
|
||||
sensor->status.special_effect = get_reg_bits(sensor, 0x64, 5, 1);
|
||||
sensor->status.wb_mode = get_reg_bits(sensor, 0x6B, 7, 1);
|
||||
sensor->status.agc_gain = get_reg_bits(sensor, COM9, 4, 3);
|
||||
sensor->status.aec_value = SCCB_Read(sensor->slv_addr, AEC) | (SCCB_Read(sensor->slv_addr, AECH) << 8);
|
||||
sensor->status.gainceiling = SCCB_Read(sensor->slv_addr, 0x00);
|
||||
sensor->status.awb = get_reg_bits(sensor, COM8, 1, 1);
|
||||
sensor->status.awb_gain = get_reg_bits(sensor, 0x63, 7, 1);
|
||||
sensor->status.aec = get_reg_bits(sensor, COM8, 0, 1);
|
||||
sensor->status.aec2 = get_reg_bits(sensor, COM8, 7, 1);
|
||||
sensor->status.agc = get_reg_bits(sensor, COM8, 2, 1);
|
||||
sensor->status.bpc = get_reg_bits(sensor, 0x64, 1, 1);
|
||||
sensor->status.wpc = get_reg_bits(sensor, 0x64, 0, 1);
|
||||
sensor->status.raw_gma = get_reg_bits(sensor, 0x64, 2, 1);
|
||||
sensor->status.lenc = get_reg_bits(sensor, LC_CTR, 0, 1);
|
||||
sensor->status.hmirror = get_reg_bits(sensor, COM3, 6, 1);
|
||||
sensor->status.vflip = get_reg_bits(sensor, COM3, 7, 1);
|
||||
sensor->status.dcw = get_reg_bits(sensor, 0x65, 2, 1);
|
||||
sensor->status.colorbar = get_reg_bits(sensor, COM3, 0, 1);
|
||||
sensor->status.sharpness = get_reg_bits(sensor, EDGE0, 0, 5);
|
||||
sensor->status.denoise = SCCB_Read(sensor->slv_addr, 0x8E);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_dummy(sensor_t *sensor, int val){ return -1; }
|
||||
static int set_gainceiling_dummy(sensor_t *sensor, gainceiling_t val){ return -1; }
|
||||
static int set_res_raw(sensor_t *sensor, int startX, int startY, int endX, int endY, int offsetX, int offsetY, int totalX, int totalY, int outputX, int outputY, bool scale, bool binning){return -1;}
|
||||
static int _set_pll(sensor_t *sensor, int bypass, int multiplier, int sys_div, int root_2x, int pre_div, int seld5, int pclk_manual, int pclk_div){return -1;}
|
||||
|
||||
esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz);
|
||||
static int set_xclk(sensor_t *sensor, int timer, int xclk)
|
||||
{
|
||||
int ret = 0;
|
||||
sensor->xclk_freq_hz = xclk * 1000000U;
|
||||
ret = xclk_timer_conf(timer, sensor->xclk_freq_hz);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ov7725_init(sensor_t *sensor)
|
||||
{
|
||||
// Set function pointers
|
||||
sensor->reset = reset;
|
||||
sensor->init_status = init_status;
|
||||
sensor->set_pixformat = set_pixformat;
|
||||
sensor->set_framesize = set_framesize;
|
||||
sensor->set_colorbar = set_colorbar;
|
||||
sensor->set_whitebal = set_whitebal;
|
||||
sensor->set_gain_ctrl = set_gain_ctrl;
|
||||
sensor->set_exposure_ctrl = set_exposure_ctrl;
|
||||
sensor->set_hmirror = set_hmirror;
|
||||
sensor->set_vflip = set_vflip;
|
||||
|
||||
sensor->set_brightness = set_brightness;
|
||||
sensor->set_contrast = set_contrast;
|
||||
sensor->set_aec2 = set_aec2;
|
||||
sensor->set_aec_value = set_aec_value;
|
||||
sensor->set_awb_gain = set_awb_gain_dsp;
|
||||
sensor->set_agc_gain = set_agc_gain;
|
||||
sensor->set_dcw = set_dcw_dsp;
|
||||
sensor->set_bpc = set_bpc_dsp;
|
||||
sensor->set_wpc = set_wpc_dsp;
|
||||
sensor->set_raw_gma = set_raw_gma_dsp;
|
||||
sensor->set_lenc = set_lenc_dsp;
|
||||
|
||||
//not supported
|
||||
sensor->set_saturation= set_dummy;
|
||||
sensor->set_sharpness = set_dummy;
|
||||
sensor->set_denoise = set_dummy;
|
||||
sensor->set_quality = set_dummy;
|
||||
sensor->set_special_effect = set_dummy;
|
||||
sensor->set_wb_mode = set_dummy;
|
||||
sensor->set_ae_level = set_dummy;
|
||||
sensor->set_gainceiling = set_gainceiling_dummy;
|
||||
|
||||
|
||||
sensor->get_reg = get_reg;
|
||||
sensor->set_reg = set_reg;
|
||||
sensor->set_res_raw = set_res_raw;
|
||||
sensor->set_pll = _set_pll;
|
||||
sensor->set_xclk = set_xclk;
|
||||
|
||||
// Retrieve sensor's signature
|
||||
sensor->id.MIDH = SCCB_Read(sensor->slv_addr, REG_MIDH);
|
||||
sensor->id.MIDL = SCCB_Read(sensor->slv_addr, REG_MIDL);
|
||||
sensor->id.PID = SCCB_Read(sensor->slv_addr, REG_PID);
|
||||
sensor->id.VER = SCCB_Read(sensor->slv_addr, REG_VER);
|
||||
|
||||
ESP_LOGD(TAG, "OV7725 Attached");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* NT99141 driver.
|
||||
*
|
||||
*/
|
||||
#ifndef __NT99141_H__
|
||||
#define __NT99141_H__
|
||||
|
||||
#include "sensor.h"
|
||||
|
||||
int NT99141_init(sensor_t *sensor);
|
||||
|
||||
#endif // __NT99141_H__
|
||||
@@ -1,211 +0,0 @@
|
||||
/*
|
||||
* NT99141 register definitions.
|
||||
*/
|
||||
#ifndef __NT99141_REG_REGS_H__
|
||||
#define __NT99141_REG_REGS_H__
|
||||
|
||||
/* system control registers */
|
||||
#define SYSTEM_CTROL0 0x3021 // Bit[7]: Software reset
|
||||
// Bit[6]: Software power down
|
||||
// Bit[5]: Reserved
|
||||
// Bit[4]: SRB clock SYNC enable
|
||||
// Bit[3]: Isolation suspend select
|
||||
// Bit[2:0]: Not used
|
||||
|
||||
/* output format control registers */
|
||||
#define FORMAT_CTRL 0x501F // Format select
|
||||
// Bit[2:0]:
|
||||
// 000: YUV422
|
||||
// 001: RGB
|
||||
// 010: Dither
|
||||
// 011: RAW after DPC
|
||||
// 101: RAW after CIP
|
||||
|
||||
/* format control registers */
|
||||
#define FORMAT_CTRL00 0x4300
|
||||
|
||||
/* frame control registers */
|
||||
#define FRAME_CTRL01 0x4201 // Control Passed Frame Number When both ON and OFF number set to 0x00,frame control is in bypass mode
|
||||
// Bit[7:4]: Not used
|
||||
// Bit[3:0]: Frame ON number
|
||||
#define FRAME_CTRL02 0x4202 // Control Masked Frame Number When both ON and OFF number set to 0x00,frame control is in bypass mode
|
||||
// Bit[7:4]: Not used
|
||||
// BIT[3:0]: Frame OFF number
|
||||
|
||||
/* ISP top control registers */
|
||||
#define PRE_ISP_TEST_SETTING_1 0x3025 // Bit[7]: Test enable
|
||||
// 0: Test disable
|
||||
// 1: Color bar enable
|
||||
// Bit[6]: Rolling
|
||||
// Bit[5]: Transparent
|
||||
// Bit[4]: Square black and white
|
||||
// Bit[3:2]: Color bar style
|
||||
// 00: Standard 8 color bar
|
||||
// 01: Gradual change at vertical mode 1
|
||||
// 10: Gradual change at horizontal
|
||||
// 11: Gradual change at vertical mode 2
|
||||
// Bit[1:0]: Test select
|
||||
// 00: Color bar
|
||||
// 01: Random data
|
||||
// 10: Square data
|
||||
// 11: Black image
|
||||
|
||||
//exposure = {0x3500[3:0], 0x3501[7:0], 0x3502[7:0]} / 16 × tROW
|
||||
|
||||
/* AEC/AGC control functions */
|
||||
#define AEC_PK_MANUAL 0x3201 // AEC Manual Mode Control
|
||||
// Bit[7:6]: Reserved
|
||||
// Bit[5]: Gain delay option
|
||||
// Valid when 0x3503[4]=1’b0
|
||||
// 0: Delay one frame latch
|
||||
// 1: One frame latch
|
||||
// Bit[4:2]: Reserved
|
||||
// Bit[1]: AGC manual
|
||||
// 0: Auto enable
|
||||
// 1: Manual enable
|
||||
// Bit[0]: AEC manual
|
||||
// 0: Auto enable
|
||||
// 1: Manual enable
|
||||
|
||||
//gain = {0x350A[1:0], 0x350B[7:0]} / 16
|
||||
|
||||
/* mirror and flip registers */
|
||||
#define TIMING_TC_REG20 0x3022 // Timing Control Register
|
||||
// Bit[2:1]: Vertical flip enable
|
||||
// 00: Normal
|
||||
// 11: Vertical flip
|
||||
// Bit[0]: Vertical binning enable
|
||||
#define TIMING_TC_REG21 0x3022 // Timing Control Register
|
||||
// Bit[5]: Compression Enable
|
||||
// Bit[2:1]: Horizontal mirror enable
|
||||
// 00: Normal
|
||||
// 11: Horizontal mirror
|
||||
// Bit[0]: Horizontal binning enable
|
||||
|
||||
#define CLOCK_POL_CONTROL 0x3024// Bit[5]: PCLK polarity 0: active low
|
||||
// 1: active high
|
||||
// Bit[3]: Gate PCLK under VSYNC
|
||||
// Bit[2]: Gate PCLK under HREF
|
||||
// Bit[1]: HREF polarity
|
||||
// 0: active low
|
||||
// 1: active high
|
||||
// Bit[0] VSYNC polarity
|
||||
// 0: active low
|
||||
// 1: active high
|
||||
#define DRIVE_CAPABILITY 0x306a // Bit[7:6]:
|
||||
// 00: 1x
|
||||
// 01: 2x
|
||||
// 10: 3x
|
||||
// 11: 4x
|
||||
|
||||
|
||||
#define X_ADDR_ST_H 0x3800 //Bit[3:0]: X address start[11:8]
|
||||
#define X_ADDR_ST_L 0x3801 //Bit[7:0]: X address start[7:0]
|
||||
#define Y_ADDR_ST_H 0x3802 //Bit[2:0]: Y address start[10:8]
|
||||
#define Y_ADDR_ST_L 0x3803 //Bit[7:0]: Y address start[7:0]
|
||||
#define X_ADDR_END_H 0x3804 //Bit[3:0]: X address end[11:8]
|
||||
#define X_ADDR_END_L 0x3805 //Bit[7:0]:
|
||||
#define Y_ADDR_END_H 0x3806 //Bit[2:0]: Y address end[10:8]
|
||||
#define Y_ADDR_END_L 0x3807 //Bit[7:0]:
|
||||
// Size after scaling
|
||||
#define X_OUTPUT_SIZE_H 0x3808 //Bit[3:0]: DVP output horizontal width[11:8]
|
||||
#define X_OUTPUT_SIZE_L 0x3809 //Bit[7:0]:
|
||||
#define Y_OUTPUT_SIZE_H 0x380a //Bit[2:0]: DVP output vertical height[10:8]
|
||||
#define Y_OUTPUT_SIZE_L 0x380b //Bit[7:0]:
|
||||
#define X_TOTAL_SIZE_H 0x380c //Bit[3:0]: Total horizontal size[11:8]
|
||||
#define X_TOTAL_SIZE_L 0x380d //Bit[7:0]:
|
||||
#define Y_TOTAL_SIZE_H 0x380e //Bit[7:0]: Total vertical size[15:8]
|
||||
#define Y_TOTAL_SIZE_L 0x380f //Bit[7:0]:
|
||||
#define X_OFFSET_H 0x3810 //Bit[3:0]: ISP horizontal offset[11:8]
|
||||
#define X_OFFSET_L 0x3811 //Bit[7:0]:
|
||||
#define Y_OFFSET_H 0x3812 //Bit[2:0]: ISP vertical offset[10:8]
|
||||
#define Y_OFFSET_L 0x3813 //Bit[7:0]:
|
||||
#define X_INCREMENT 0x3814 //Bit[7:4]: Horizontal odd subsample increment
|
||||
//Bit[3:0]: Horizontal even subsample increment
|
||||
#define Y_INCREMENT 0x3815 //Bit[7:4]: Vertical odd subsample increment
|
||||
//Bit[3:0]: Vertical even subsample increment
|
||||
// Size before scaling
|
||||
//#define X_INPUT_SIZE (X_ADDR_END - X_ADDR_ST + 1 - (2 * X_OFFSET))
|
||||
//#define Y_INPUT_SIZE (Y_ADDR_END - Y_ADDR_ST + 1 - (2 * Y_OFFSET))
|
||||
|
||||
#define ISP_CONTROL_01 0x3021 // Bit[5]: Scale enable
|
||||
// 0: Disable
|
||||
// 1: Enable
|
||||
|
||||
#define SCALE_CTRL_1 0x5601 // Bit[6:4]: HDIV RW
|
||||
// DCW scale times
|
||||
// 000: DCW 1 time
|
||||
// 001: DCW 2 times
|
||||
// 010: DCW 4 times
|
||||
// 100: DCW 8 times
|
||||
// 101: DCW 16 times
|
||||
// Others: DCW 16 times
|
||||
// Bit[2:0]: VDIV RW
|
||||
// DCW scale times
|
||||
// 000: DCW 1 time
|
||||
// 001: DCW 2 times
|
||||
// 010: DCW 4 times
|
||||
// 100: DCW 8 times
|
||||
// 101: DCW 16 times
|
||||
// Others: DCW 16 times
|
||||
|
||||
#define SCALE_CTRL_2 0x5602 // X_SCALE High Bits
|
||||
#define SCALE_CTRL_3 0x5603 // X_SCALE Low Bits
|
||||
#define SCALE_CTRL_4 0x5604 // Y_SCALE High Bits
|
||||
#define SCALE_CTRL_5 0x5605 // Y_SCALE Low Bits
|
||||
#define SCALE_CTRL_6 0x5606 // Bit[3:0]: V Offset
|
||||
|
||||
#define PCLK_RATIO 0x3824 // Bit[4:0]: PCLK ratio manual
|
||||
#define VFIFO_CTRL0C 0x460C // Bit[1]: PCLK manual enable
|
||||
// 0: Auto
|
||||
// 1: Manual by PCLK_RATIO
|
||||
|
||||
#define VFIFO_X_SIZE_H 0x4602
|
||||
#define VFIFO_X_SIZE_L 0x4603
|
||||
#define VFIFO_Y_SIZE_H 0x4604
|
||||
#define VFIFO_Y_SIZE_L 0x4605
|
||||
|
||||
#define SC_PLLS_CTRL0 0x303a // Bit[7]: PLLS bypass
|
||||
#define SC_PLLS_CTRL1 0x303b // Bit[4:0]: PLLS multiplier
|
||||
#define SC_PLLS_CTRL2 0x303c // Bit[6:4]: PLLS charge pump control
|
||||
// Bit[3:0]: PLLS system divider
|
||||
#define SC_PLLS_CTRL3 0x303d // Bit[5:4]: PLLS pre-divider
|
||||
// 00: 1
|
||||
// 01: 1.5
|
||||
// 10: 2
|
||||
// 11: 3
|
||||
// Bit[2]: PLLS root-divider - 1
|
||||
// Bit[1:0]: PLLS seld5
|
||||
// 00: 1
|
||||
// 01: 1
|
||||
// 10: 2
|
||||
// 11: 2.5
|
||||
|
||||
#define COMPRESSION_CTRL00 0x4400 //
|
||||
#define COMPRESSION_CTRL01 0x4401 //
|
||||
#define COMPRESSION_CTRL02 0x4402 //
|
||||
#define COMPRESSION_CTRL03 0x4403 //
|
||||
#define COMPRESSION_CTRL04 0x4404 //
|
||||
#define COMPRESSION_CTRL05 0x4405 //
|
||||
#define COMPRESSION_CTRL06 0x4406 //
|
||||
#define COMPRESSION_CTRL07 0x3401 // Bit[5:0]: QS
|
||||
#define COMPRESSION_ISI_CTRL 0x4408 //
|
||||
#define COMPRESSION_CTRL09 0x4409 //
|
||||
#define COMPRESSION_CTRL0a 0x440a //
|
||||
#define COMPRESSION_CTRL0b 0x440b //
|
||||
#define COMPRESSION_CTRL0c 0x440c //
|
||||
#define COMPRESSION_CTRL0d 0x440d //
|
||||
#define COMPRESSION_CTRL0E 0x440e //
|
||||
|
||||
/**
|
||||
* @brief register value
|
||||
*/
|
||||
#define TEST_COLOR_BAR 0x02 /* Enable Color Bar roling Test */
|
||||
|
||||
#define AEC_PK_MANUAL_AGC_MANUALEN 0x02 /* Enable AGC Manual enable */
|
||||
#define AEC_PK_MANUAL_AEC_MANUALEN 0x01 /* Enable AEC Manual enable */
|
||||
|
||||
#define TIMING_TC_REG20_VFLIP 0x01 /* Vertical flip enable */
|
||||
#define TIMING_TC_REG21_HMIRROR 0x02 /* Horizontal mirror enable */
|
||||
|
||||
#endif // __NT99141_REG_REGS_H__
|
||||
@@ -1,825 +0,0 @@
|
||||
#ifndef _NT99141_SETTINGS_H_
|
||||
#define _NT99141_SETTINGS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_attr.h"
|
||||
#include "nt99141_regs.h"
|
||||
|
||||
static const ratio_settings_t ratio_table[] = {
|
||||
// mw, mh, sx, sy, ex, ey, ox, oy, tx, ty
|
||||
{ 1280, 720, 0, 4, 1283, 723, 0, 4, 1660, 963 },
|
||||
|
||||
};
|
||||
|
||||
#define REG_DLY 0xffff
|
||||
#define REGLIST_TAIL 0x0000
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_default_regs[][2] = {
|
||||
//initial
|
||||
{0x3021, 0x00},
|
||||
{REG_DLY, 100}, // delay 100ms
|
||||
{0x3109, 0x04},
|
||||
{0x3040, 0x04},
|
||||
{0x3041, 0x02},
|
||||
{0x3042, 0xFF},
|
||||
{0x3043, 0x08},
|
||||
{0x3052, 0xE0},
|
||||
{0x305F, 0x33},
|
||||
{0x3100, 0x07},
|
||||
{0x3106, 0x03},
|
||||
{0x3105, 0x01},
|
||||
{0x3108, 0x05},
|
||||
{0x3110, 0x22},
|
||||
{0x3111, 0x57},
|
||||
{0x3112, 0x22},
|
||||
{0x3113, 0x55},
|
||||
{0x3114, 0x05},
|
||||
{0x3135, 0x00},
|
||||
{0x32F0, 0x01},
|
||||
{0x3290, 0x01},
|
||||
{0x3291, 0x80},
|
||||
{0x3296, 0x01},
|
||||
{0x3297, 0x73},
|
||||
{0x3250, 0x80},
|
||||
{0x3251, 0x03},
|
||||
{0x3252, 0xFF},
|
||||
{0x3253, 0x00},
|
||||
{0x3254, 0x03},
|
||||
{0x3255, 0xFF},
|
||||
{0x3256, 0x00},
|
||||
{0x3257, 0x50},
|
||||
{0x3270, 0x00},
|
||||
{0x3271, 0x0C},
|
||||
{0x3272, 0x18},
|
||||
{0x3273, 0x32},
|
||||
{0x3274, 0x44},
|
||||
{0x3275, 0x54},
|
||||
{0x3276, 0x70},
|
||||
{0x3277, 0x88},
|
||||
{0x3278, 0x9D},
|
||||
{0x3279, 0xB0},
|
||||
{0x327A, 0xCF},
|
||||
{0x327B, 0xE2},
|
||||
{0x327C, 0xEF},
|
||||
{0x327D, 0xF7},
|
||||
{0x327E, 0xFF},
|
||||
{0x3302, 0x00},
|
||||
{0x3303, 0x40},
|
||||
{0x3304, 0x00},
|
||||
{0x3305, 0x96},
|
||||
{0x3306, 0x00},
|
||||
{0x3307, 0x29},
|
||||
{0x3308, 0x07},
|
||||
{0x3309, 0xBA},
|
||||
{0x330A, 0x06},
|
||||
{0x330B, 0xF5},
|
||||
{0x330C, 0x01},
|
||||
{0x330D, 0x51},
|
||||
{0x330E, 0x01},
|
||||
{0x330F, 0x30},
|
||||
{0x3310, 0x07},
|
||||
{0x3311, 0x16},
|
||||
{0x3312, 0x07},
|
||||
{0x3313, 0xBA},
|
||||
{0x3326, 0x02},
|
||||
{0x32F6, 0x0F},
|
||||
{0x32F9, 0x42},
|
||||
{0x32FA, 0x24},
|
||||
{0x3325, 0x4A},
|
||||
{0x3330, 0x00},
|
||||
{0x3331, 0x0A},
|
||||
{0x3332, 0xFF},
|
||||
{0x3338, 0x30},
|
||||
{0x3339, 0x84},
|
||||
{0x333A, 0x48},
|
||||
{0x333F, 0x07},
|
||||
{0x3360, 0x10},
|
||||
{0x3361, 0x18},
|
||||
{0x3362, 0x1f},
|
||||
{0x3363, 0x37},
|
||||
{0x3364, 0x80},
|
||||
{0x3365, 0x80},
|
||||
{0x3366, 0x68},
|
||||
{0x3367, 0x60},
|
||||
{0x3368, 0x30},
|
||||
{0x3369, 0x28},
|
||||
{0x336A, 0x20},
|
||||
{0x336B, 0x10},
|
||||
{0x336C, 0x00},
|
||||
{0x336D, 0x20},
|
||||
{0x336E, 0x1C},
|
||||
{0x336F, 0x18},
|
||||
{0x3370, 0x10},
|
||||
{0x3371, 0x38},
|
||||
{0x3372, 0x3C},
|
||||
{0x3373, 0x3F},
|
||||
{0x3374, 0x3F},
|
||||
{0x338A, 0x34},
|
||||
{0x338B, 0x7F},
|
||||
{0x338C, 0x10},
|
||||
{0x338D, 0x23},
|
||||
{0x338E, 0x7F},
|
||||
{0x338F, 0x14},
|
||||
{0x3375, 0x08},
|
||||
{0x3376, 0x0C},
|
||||
{0x3377, 0x18},
|
||||
{0x3378, 0x20},
|
||||
{0x3012, 0x02},
|
||||
{0x3013, 0xD0},
|
||||
{0x3025, 0x02}, //colorbar
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_jpeg[][2] = {
|
||||
{0x32F0, 0x70}, // YUV422
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_raw[][2] = {
|
||||
{0x32F0, 0x50}, // RAW
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_grayscale[][2] = {
|
||||
{0x32F1, 0x01},
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_yuv422[][2] = {
|
||||
{0x32F0, 0x00}, // YUV422
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_rgb565[][2] = {
|
||||
{0x32F0, 0x01}, // RGB
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint8_t sensor_saturation_levels[9][1] = {
|
||||
{0x60},//-4
|
||||
{0x68},//-3
|
||||
{0x70},//-2
|
||||
{0x78},//-1
|
||||
{0x80},//0
|
||||
{0x88},//+1
|
||||
{0x90},//+2
|
||||
{0x98},//+3
|
||||
{0xA0},//+4
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint8_t sensor_special_effects[7][4] = {
|
||||
{0x00, 0x80, 0x80, 0x01},//Normal
|
||||
{0x03, 0x80, 0x80, 0x01},//Negative
|
||||
{0x01, 0x80, 0x80, 0x01},//Grayscale
|
||||
{0x05, 0x2A, 0xF0, 0x01},//Red Tint
|
||||
{0x05, 0x60, 0x20, 0x01},//Green Tint
|
||||
{0x05, 0xF0, 0x80, 0x01},//Blue Tint
|
||||
{0x02, 0x80, 0x80, 0x01},//Sepia
|
||||
|
||||
};
|
||||
|
||||
// AE LEVEL
|
||||
static const DRAM_ATTR uint16_t sensor_ae_level[][2] = {
|
||||
|
||||
// 1. [AE_Target : 0x24]
|
||||
// Set_Device_Format = FORMAT_16_8
|
||||
// SET_Device_Addr = 0x54
|
||||
{0x32B8, 0x29 },
|
||||
{0x32B9, 0x1F },
|
||||
{0x32BC, 0x24 },
|
||||
{0x32BD, 0x27 },
|
||||
{0x32BE, 0x21 },
|
||||
//------------------------------------------------------------------------
|
||||
// 2. [AE_Target : 0x28]
|
||||
// Set_Device_Format = FORMAT_16_8
|
||||
// SET_Device_Addr = 0x54
|
||||
{0x32B8, 0x2D },
|
||||
{0x32B9, 0x23 },
|
||||
{0x32BC, 0x28 },
|
||||
{0x32BD, 0x2B },
|
||||
{0x32BE, 0x25 },
|
||||
//------------------------------------------------------------------------
|
||||
// 3. [AE_Target : 0x2C]
|
||||
// Set_Device_Format = FORMAT_16_8
|
||||
// SET_Device_Addr = 0x54
|
||||
{0x32B8, 0x32 },
|
||||
{0x32B9, 0x26 },
|
||||
{0x32BC, 0x2C },
|
||||
{0x32BD, 0x2F },
|
||||
{0x32BE, 0x29 },
|
||||
//------------------------------------------------------------------------
|
||||
// 4, [AE_Target : 0x30]
|
||||
// Set_Device_Format = FORMAT_16_8
|
||||
// SET_Device_Addr = 0x54
|
||||
{0x32B8, 0x36 },
|
||||
{0x32B9, 0x2A },
|
||||
{0x32BC, 0x30 },
|
||||
{0x32BD, 0x33 },
|
||||
{0x32BE, 0x2D },
|
||||
//------------------------------------------------------------------------
|
||||
// 5. [AE_Target : 0x34]
|
||||
// Set_Device_Format = FORMAT_16_8
|
||||
// SET_Device_Addr = 0x54
|
||||
{0x32B8, 0x3B },
|
||||
{0x32B9, 0x2D },
|
||||
{0x32BC, 0x34 },
|
||||
{0x32BD, 0x38 },
|
||||
{0x32BE, 0x30 },
|
||||
//------------------------------------------------------------------------
|
||||
// 6. [AE_Target : 0x38]
|
||||
// Set_Device_Format = FORMAT_16_8
|
||||
// SET_Device_Addr = 0x54
|
||||
{0x32B8, 0x3F },
|
||||
{0x32B9, 0x31 },
|
||||
{0x32BC, 0x38 },
|
||||
{0x32BD, 0x3C },
|
||||
{0x32BE, 0x34 },
|
||||
//------------------------------------------------------------------------
|
||||
// 7. [AE_Target : 0x3D]
|
||||
// Set_Device_Format = FORMAT_16_8
|
||||
// SET_Device_Addr = 0x54
|
||||
{0x32B8, 0x44 },
|
||||
{0x32B9, 0x34 },
|
||||
{0x32BC, 0x3C },
|
||||
{0x32BD, 0x40 },
|
||||
{0x32BE, 0x38 },
|
||||
//------------------------------------------------------------------------
|
||||
// 8. [AE_Target : 0x40]
|
||||
// Set_Device_Format = FORMAT_16_8
|
||||
// SET_Device_Addr = 0x54
|
||||
{0x32B8, 0x48 },
|
||||
{0x32B9, 0x38 },
|
||||
{0x32BC, 0x40 },
|
||||
{0x32BD, 0x44 },
|
||||
{0x32BE, 0x3C },
|
||||
//------------------------------------------------------------------------
|
||||
// 9. [AE_Target : 0x44]
|
||||
// Set_Device_Format = FORMAT_16_8
|
||||
// SET_Device_Addr = 0x54
|
||||
{0x32B8, 0x4D },
|
||||
{0x32B9, 0x3B },
|
||||
{0x32BC, 0x44 },
|
||||
{0x32BD, 0x49 },
|
||||
{0x32BE, 0x3F },
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_framesize_HD[][2] = {
|
||||
//[JPEG_1280x720_8.18_8.18_Fps]
|
||||
{0x3021, 0x00},
|
||||
{REG_DLY, 100}, // delay 100ms
|
||||
{0x32BF, 0x60},
|
||||
{0x32C0, 0x5A},
|
||||
{0x32C1, 0x5A},
|
||||
{0x32C2, 0x5A},
|
||||
{0x32C3, 0x00},
|
||||
{0x32C4, 0x20},
|
||||
{0x32C5, 0x20},
|
||||
{0x32C6, 0x20},
|
||||
{0x32C7, 0x00},
|
||||
{0x32C8, 0x3C},
|
||||
{0x32C9, 0x5A},
|
||||
{0x32CA, 0x7A},
|
||||
{0x32CB, 0x7A},
|
||||
{0x32CC, 0x7A},
|
||||
{0x32CD, 0x7A},
|
||||
{0x32DB, 0x5E},
|
||||
{0x32F0, 0x70},
|
||||
{0x3400, 0x08},
|
||||
{0x3400, 0x00},
|
||||
{0x3401, 0x4E},
|
||||
{0x3404, 0x00},
|
||||
{0x3405, 0x00},
|
||||
{0x3410, 0x00},
|
||||
{0x3200, 0x3E},
|
||||
{0x3201, 0x0F},
|
||||
{0x3028, 0x0F},
|
||||
{0x3029, 0x00},
|
||||
{0x302A, 0x08},
|
||||
{0x3022, 0x24},
|
||||
{0x3023, 0x24},
|
||||
{0x3002, 0x00},
|
||||
{0x3003, 0x04},
|
||||
{0x3004, 0x00},
|
||||
{0x3005, 0x04},
|
||||
{0x3006, 0x05},
|
||||
{0x3007, 0x03},
|
||||
{0x3008, 0x02},
|
||||
{0x3009, 0xD3},
|
||||
{0x300A, 0x06},
|
||||
{0x300B, 0x7C},
|
||||
{0x300C, 0x02},
|
||||
{0x300D, 0xE0},
|
||||
{0x300E, 0x05},
|
||||
{0x300F, 0x00},
|
||||
{0x3010, 0x02},
|
||||
{0x3011, 0xD0},
|
||||
{0x32B8, 0x3F},
|
||||
{0x32B9, 0x31},
|
||||
{0x32BB, 0x87},
|
||||
{0x32BC, 0x38},
|
||||
{0x32BD, 0x3C},
|
||||
{0x32BE, 0x34},
|
||||
{0x3201, 0x3F},
|
||||
{0x3021, 0x06},
|
||||
{0x3025, 0x00}, //normal
|
||||
{0x3400, 0x01},
|
||||
{0x3060, 0x01},
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_framesize_VGA[][2] = {
|
||||
//[JPEG_640x480_10.14_10.14_Fps]
|
||||
{0x3021, 0x00},
|
||||
{REG_DLY, 100}, // delay 100ms
|
||||
{0x32BF, 0x60},
|
||||
{0x32C0, 0x5A},
|
||||
{0x32C1, 0x5A},
|
||||
{0x32C2, 0x5A},
|
||||
{0x32C3, 0x00},
|
||||
{0x32C4, 0x20},
|
||||
{0x32C5, 0x20},
|
||||
{0x32C6, 0x20},
|
||||
{0x32C7, 0x00},
|
||||
{0x32C8, 0x4B},
|
||||
{0x32C9, 0x5A},
|
||||
{0x32CA, 0x7A},
|
||||
{0x32CB, 0x7A},
|
||||
{0x32CC, 0x7A},
|
||||
{0x32CD, 0x7A},
|
||||
{0x32DB, 0x62},
|
||||
{0x32F0, 0x70},
|
||||
{0x3400, 0x08},
|
||||
{0x3400, 0x00},
|
||||
{0x3401, 0x4E},
|
||||
{0x3404, 0x00},
|
||||
{0x3405, 0x00},
|
||||
{0x3410, 0x00},
|
||||
{0x32E0, 0x02},
|
||||
{0x32E1, 0x80},
|
||||
{0x32E2, 0x01},
|
||||
{0x32E3, 0xE0},
|
||||
{0x32E4, 0x00},
|
||||
{0x32E5, 0x80},
|
||||
{0x32E6, 0x00},
|
||||
{0x32E7, 0x80},
|
||||
{0x3200, 0x3E},
|
||||
{0x3201, 0x0F},
|
||||
{0x3028, 0x0F},
|
||||
{0x3029, 0x00},
|
||||
{0x302A, 0x08},
|
||||
{0x3022, 0x24},
|
||||
{0x3023, 0x24},
|
||||
{0x3002, 0x00},
|
||||
{0x3003, 0xA4},
|
||||
{0x3004, 0x00},
|
||||
{0x3005, 0x04},
|
||||
{0x3006, 0x04},
|
||||
{0x3007, 0x63},
|
||||
{0x3008, 0x02},
|
||||
{0x3009, 0xD3},
|
||||
{0x300A, 0x05},
|
||||
{0x300B, 0x3C},
|
||||
{0x300C, 0x02},
|
||||
{0x300D, 0xE0},
|
||||
{0x300E, 0x03},
|
||||
{0x300F, 0xC0},
|
||||
{0x3010, 0x02},
|
||||
{0x3011, 0xD0},
|
||||
{0x32B8, 0x3F},
|
||||
{0x32B9, 0x31},
|
||||
{0x32BB, 0x87},
|
||||
{0x32BC, 0x38},
|
||||
{0x32BD, 0x3C},
|
||||
{0x32BE, 0x34},
|
||||
{0x3201, 0x7F},
|
||||
{0x3021, 0x06},
|
||||
{0x3025, 0x00}, //normal
|
||||
{0x3400, 0x01},
|
||||
{0x3060, 0x01},
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_framesize_QVGA[][2] = {
|
||||
//[JPEG_320x240_10.14_10.14_Fps]
|
||||
{0x3021, 0x00},
|
||||
{REG_DLY, 100}, // delay 100ms
|
||||
{0x32BF, 0x60},
|
||||
{0x32C0, 0x5A},
|
||||
{0x32C1, 0x5A},
|
||||
{0x32C2, 0x5A},
|
||||
{0x32C3, 0x00},
|
||||
{0x32C4, 0x20},
|
||||
{0x32C5, 0x20},
|
||||
{0x32C6, 0x20},
|
||||
{0x32C7, 0x00},
|
||||
{0x32C8, 0x4B},
|
||||
{0x32C9, 0x5A},
|
||||
{0x32CA, 0x7A},
|
||||
{0x32CB, 0x7A},
|
||||
{0x32CC, 0x7A},
|
||||
{0x32CD, 0x7A},
|
||||
{0x32DB, 0x62},
|
||||
{0x32F0, 0x70},
|
||||
{0x3400, 0x08},
|
||||
{0x3400, 0x00},
|
||||
{0x3401, 0x4E},
|
||||
{0x3404, 0x00},
|
||||
{0x3405, 0x00},
|
||||
{0x3410, 0x00},
|
||||
{0x32E0, 0x01},
|
||||
{0x32E1, 0x40},
|
||||
{0x32E2, 0x00},
|
||||
{0x32E3, 0xF0},
|
||||
{0x32E4, 0x02},
|
||||
{0x32E5, 0x02},
|
||||
{0x32E6, 0x02},
|
||||
{0x32E7, 0x03},
|
||||
{0x3200, 0x3E},
|
||||
{0x3201, 0x0F},
|
||||
{0x3028, 0x0F},
|
||||
{0x3029, 0x00},
|
||||
{0x302A, 0x08},
|
||||
{0x3022, 0x24},
|
||||
{0x3023, 0x24},
|
||||
{0x3002, 0x00},
|
||||
{0x3003, 0xA4},
|
||||
{0x3004, 0x00},
|
||||
{0x3005, 0x04},
|
||||
{0x3006, 0x04},
|
||||
{0x3007, 0x63},
|
||||
{0x3008, 0x02},
|
||||
{0x3009, 0xD3},
|
||||
{0x300A, 0x05},
|
||||
{0x300B, 0x3C},
|
||||
{0x300C, 0x02},
|
||||
{0x300D, 0xE0},
|
||||
{0x300E, 0x03},
|
||||
{0x300F, 0xC0},
|
||||
{0x3010, 0x02},
|
||||
{0x3011, 0xD0},
|
||||
{0x32B8, 0x3F},
|
||||
{0x32B9, 0x31},
|
||||
{0x32BB, 0x87},
|
||||
{0x32BC, 0x38},
|
||||
{0x32BD, 0x3C},
|
||||
{0x32BE, 0x34},
|
||||
{0x3201, 0x7F},
|
||||
{0x3021, 0x06},
|
||||
{0x3025, 0x00}, //normal
|
||||
{0x3400, 0x01},
|
||||
{0x3060, 0x01},
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_framesize_VGA_xyskip[][2] = {
|
||||
// [JPEG_640x360_20.00_25.01_Fps_XY_Skip]
|
||||
// Set_Device_Format = FORMAT_16_8
|
||||
// SET_Device_Addr = 0x54
|
||||
{0x3021, 0x00},
|
||||
{REG_DLY, 100}, // delay 100ms
|
||||
{0x32BF, 0x60 },
|
||||
{0x320A, 0xB2 },
|
||||
{0x32C0, 0x64 },
|
||||
{0x32C1, 0x64 },
|
||||
{0x32C2, 0x64 },
|
||||
{0x32C3, 0x00 },
|
||||
{0x32C4, 0x20 },
|
||||
{0x32C5, 0x20 },
|
||||
{0x32C6, 0x20 },
|
||||
{0x32C7, 0x00 },
|
||||
{0x32C8, 0x62 },
|
||||
{0x32C9, 0x64 },
|
||||
{0x32CA, 0x84 },
|
||||
{0x32CB, 0x84 },
|
||||
{0x32CC, 0x84 },
|
||||
{0x32CD, 0x84 },
|
||||
{0x32DB, 0x68 },
|
||||
{0x32F0, 0x70 },
|
||||
{0x3400, 0x08 },
|
||||
{0x3400, 0x00 },
|
||||
{0x3401, 0x4E },
|
||||
{0x3404, 0x00 },
|
||||
{0x3405, 0x00 },
|
||||
{0x3410, 0x00 },
|
||||
{0x3200, 0x3E },
|
||||
{0x3201, 0x0F },
|
||||
{0x3028, 0x0F },
|
||||
{0x3029, 0x00 },
|
||||
{0x302A, 0x08 },
|
||||
{0x3022, 0x24 },
|
||||
{0x3023, 0x6C },
|
||||
{0x3002, 0x00 },
|
||||
{0x3003, 0x04 },
|
||||
{0x3004, 0x00 },
|
||||
{0x3005, 0x04 },
|
||||
{0x3006, 0x05 },
|
||||
{0x3007, 0x03 },
|
||||
{0x3008, 0x02 },
|
||||
{0x3009, 0xD3 },
|
||||
{0x300A, 0x03 },
|
||||
{0x300B, 0xFC },
|
||||
{0x300C, 0x01 },
|
||||
{0x300D, 0x88 },
|
||||
{0x300E, 0x02 },
|
||||
{0x300F, 0x80 },
|
||||
{0x3010, 0x01 },
|
||||
{0x3011, 0x68 },
|
||||
{0x32B8, 0x3F },
|
||||
{0x32B9, 0x31 },
|
||||
{0x32BB, 0x87 },
|
||||
{0x32BC, 0x38 },
|
||||
{0x32BD, 0x3C },
|
||||
{0x32BE, 0x34 },
|
||||
{0x3201, 0x3F },
|
||||
{0x3025, 0x00 }, //normal
|
||||
{0x3021, 0x06 },
|
||||
{0x3400, 0x01 },
|
||||
{0x3060, 0x01 },
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_framesize_VGA_xskip[][2] = {
|
||||
//[JPEG_640x480_Xskip_13.32_13.32_Fps]
|
||||
{0x3021, 0x00},
|
||||
{REG_DLY, 100}, // delay 100ms
|
||||
{0x32BF, 0x60},
|
||||
{0x32C0, 0x5A},
|
||||
{0x32C1, 0x5A},
|
||||
{0x32C2, 0x5A},
|
||||
{0x32C3, 0x00},
|
||||
{0x32C4, 0x20},
|
||||
{0x32C5, 0x20},
|
||||
{0x32C6, 0x20},
|
||||
{0x32C7, 0x00},
|
||||
{0x32C8, 0x62},
|
||||
{0x32C9, 0x5A},
|
||||
{0x32CA, 0x7A},
|
||||
{0x32CB, 0x7A},
|
||||
{0x32CC, 0x7A},
|
||||
{0x32CD, 0x7A},
|
||||
{0x32DB, 0x68},
|
||||
{0x32F0, 0x70},
|
||||
{0x3400, 0x08},
|
||||
{0x3400, 0x00},
|
||||
{0x3401, 0x4E},
|
||||
{0x3404, 0x00},
|
||||
{0x3405, 0x00},
|
||||
{0x3410, 0x00},
|
||||
{0x32E0, 0x02},
|
||||
{0x32E1, 0x80},
|
||||
{0x32E2, 0x01},
|
||||
{0x32E3, 0xE0},
|
||||
{0x32E4, 0x00},
|
||||
{0x32E5, 0x00},
|
||||
{0x32E6, 0x00},
|
||||
{0x32E7, 0x80},
|
||||
{0x3200, 0x3E},
|
||||
{0x3201, 0x0F},
|
||||
{0x3028, 0x0F},
|
||||
{0x3029, 0x00},
|
||||
{0x302A, 0x08},
|
||||
{0x3022, 0x24},
|
||||
{0x3023, 0x2C},
|
||||
{0x3002, 0x00},
|
||||
{0x3003, 0x04},
|
||||
{0x3004, 0x00},
|
||||
{0x3005, 0x04},
|
||||
{0x3006, 0x05},
|
||||
{0x3007, 0x03},
|
||||
{0x3008, 0x02},
|
||||
{0x3009, 0xD3},
|
||||
{0x300A, 0x03},
|
||||
{0x300B, 0xFC},
|
||||
{0x300C, 0x02},
|
||||
{0x300D, 0xE0},
|
||||
{0x300E, 0x02},
|
||||
{0x300F, 0x80},
|
||||
{0x3010, 0x02},
|
||||
{0x3011, 0xD0},
|
||||
{0x32B8, 0x3F},
|
||||
{0x32B9, 0x31},
|
||||
{0x32BB, 0x87},
|
||||
{0x32BC, 0x38},
|
||||
{0x32BD, 0x3C},
|
||||
{0x32BE, 0x34},
|
||||
{0x3201, 0x7F},
|
||||
{0x3021, 0x06},
|
||||
{0x3025, 0x00}, //normal
|
||||
{0x3400, 0x01},
|
||||
{0x3060, 0x01},
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_framesize_QVGA_xskip[][2] = {
|
||||
{0x3021, 0x00},
|
||||
{REG_DLY, 100}, // delay 100ms
|
||||
//[JPEG_320x240_Xskip_13.32_13.32_Fps]
|
||||
{0x32BF, 0x60},
|
||||
{0x32C0, 0x5A},
|
||||
{0x32C1, 0x5A},
|
||||
{0x32C2, 0x5A},
|
||||
{0x32C3, 0x00},
|
||||
{0x32C4, 0x20},
|
||||
{0x32C5, 0x20},
|
||||
{0x32C6, 0x20},
|
||||
{0x32C7, 0x00},
|
||||
{0x32C8, 0x62},
|
||||
{0x32C9, 0x5A},
|
||||
{0x32CA, 0x7A},
|
||||
{0x32CB, 0x7A},
|
||||
{0x32CC, 0x7A},
|
||||
{0x32CD, 0x7A},
|
||||
{0x32DB, 0x68},
|
||||
{0x32F0, 0x70},
|
||||
{0x3400, 0x08},
|
||||
{0x3400, 0x00},
|
||||
{0x3401, 0x4E},
|
||||
{0x3404, 0x00},
|
||||
{0x3405, 0x00},
|
||||
{0x3410, 0x00},
|
||||
{0x32E0, 0x01},
|
||||
{0x32E1, 0x40},
|
||||
{0x32E2, 0x00},
|
||||
{0x32E3, 0xF0},
|
||||
{0x32E4, 0x01},
|
||||
{0x32E5, 0x01},
|
||||
{0x32E6, 0x02},
|
||||
{0x32E7, 0x03},
|
||||
{0x3200, 0x3E},
|
||||
{0x3201, 0x0F},
|
||||
{0x3028, 0x0F},
|
||||
{0x3029, 0x00},
|
||||
{0x302A, 0x08},
|
||||
{0x3022, 0x24},
|
||||
{0x3023, 0x2C},
|
||||
{0x3002, 0x00},
|
||||
{0x3003, 0x04},
|
||||
{0x3004, 0x00},
|
||||
{0x3005, 0x04},
|
||||
{0x3006, 0x05},
|
||||
{0x3007, 0x03},
|
||||
{0x3008, 0x02},
|
||||
{0x3009, 0xD3},
|
||||
{0x300A, 0x03},
|
||||
{0x300B, 0xFC},
|
||||
{0x300C, 0x02},
|
||||
{0x300D, 0xE0},
|
||||
{0x300E, 0x02},
|
||||
{0x300F, 0x80},
|
||||
{0x3010, 0x02},
|
||||
{0x3011, 0xD0},
|
||||
{0x32B8, 0x3F},
|
||||
{0x32B9, 0x31},
|
||||
{0x32BB, 0x87},
|
||||
{0x32BC, 0x38},
|
||||
{0x32BD, 0x3C},
|
||||
{0x32BE, 0x34},
|
||||
{0x3201, 0x7F},
|
||||
{0x3021, 0x06},
|
||||
{0x3025, 0x00}, //normal
|
||||
{0x3400, 0x01},
|
||||
{0x3060, 0x01},
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_framesize_VGA_crop[][2] = {
|
||||
//[JPEG_640x480_Crop_19.77_19.77_Fps]
|
||||
{0x3021, 0x00},
|
||||
{REG_DLY, 100}, // delay 100ms
|
||||
{0x32BF, 0x60},
|
||||
{0x32C0, 0x5A},
|
||||
{0x32C1, 0x5A},
|
||||
{0x32C2, 0x5A},
|
||||
{0x32C3, 0x00},
|
||||
{0x32C4, 0x20},
|
||||
{0x32C5, 0x20},
|
||||
{0x32C6, 0x20},
|
||||
{0x32C7, 0x00},
|
||||
{0x32C8, 0x62},
|
||||
{0x32C9, 0x5A},
|
||||
{0x32CA, 0x7A},
|
||||
{0x32CB, 0x7A},
|
||||
{0x32CC, 0x7A},
|
||||
{0x32CD, 0x7A},
|
||||
{0x32DB, 0x68},
|
||||
{0x32F0, 0x70},
|
||||
{0x3400, 0x08},
|
||||
{0x3400, 0x00},
|
||||
{0x3401, 0x4E},
|
||||
{0x3404, 0x00},
|
||||
{0x3405, 0x00},
|
||||
{0x3410, 0x00},
|
||||
{0x3200, 0x3E},
|
||||
{0x3201, 0x0F},
|
||||
{0x3028, 0x0F},
|
||||
{0x3029, 0x00},
|
||||
{0x302A, 0x08},
|
||||
{0x3022, 0x24},
|
||||
{0x3023, 0x24},
|
||||
{0x3002, 0x01},
|
||||
{0x3003, 0x44},
|
||||
{0x3004, 0x00},
|
||||
{0x3005, 0x7C},
|
||||
{0x3006, 0x03},
|
||||
{0x3007, 0xC3},
|
||||
{0x3008, 0x02},
|
||||
{0x3009, 0x5B},
|
||||
{0x300A, 0x03},
|
||||
{0x300B, 0xFC},
|
||||
{0x300C, 0x01},
|
||||
{0x300D, 0xF0},
|
||||
{0x300E, 0x02},
|
||||
{0x300F, 0x80},
|
||||
{0x3010, 0x01},
|
||||
{0x3011, 0xE0},
|
||||
{0x32B8, 0x3F},
|
||||
{0x32B9, 0x31},
|
||||
{0x32BB, 0x87},
|
||||
{0x32BC, 0x38},
|
||||
{0x32BD, 0x3C},
|
||||
{0x32BE, 0x34},
|
||||
{0x3201, 0x3F},
|
||||
{0x3021, 0x06},
|
||||
{0x3025, 0x00}, //normal
|
||||
{0x3400, 0x01},
|
||||
{0x3060, 0x01},
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_framesize_QVGA_crop[][2] = {
|
||||
//[JPEG_320x240_Crop_19.77_19.77_Fps]
|
||||
{0x3021, 0x00},
|
||||
{REG_DLY, 100}, // delay 100ms
|
||||
{0x32BF, 0x60},
|
||||
{0x32C0, 0x5A},
|
||||
{0x32C1, 0x5A},
|
||||
{0x32C2, 0x5A},
|
||||
{0x32C3, 0x00},
|
||||
{0x32C4, 0x20},
|
||||
{0x32C5, 0x20},
|
||||
{0x32C6, 0x20},
|
||||
{0x32C7, 0x00},
|
||||
{0x32C8, 0x62},
|
||||
{0x32C9, 0x5A},
|
||||
{0x32CA, 0x7A},
|
||||
{0x32CB, 0x7A},
|
||||
{0x32CC, 0x7A},
|
||||
{0x32CD, 0x7A},
|
||||
{0x32DB, 0x68},
|
||||
{0x32F0, 0x70},
|
||||
{0x3400, 0x08},
|
||||
{0x3400, 0x00},
|
||||
{0x3401, 0x4E},
|
||||
{0x3404, 0x00},
|
||||
{0x3405, 0x00},
|
||||
{0x3410, 0x00},
|
||||
{0x32E0, 0x01},
|
||||
{0x32E1, 0x40},
|
||||
{0x32E2, 0x00},
|
||||
{0x32E3, 0xF0},
|
||||
{0x32E4, 0x01},
|
||||
{0x32E5, 0x01},
|
||||
{0x32E6, 0x01},
|
||||
{0x32E7, 0x02},
|
||||
{0x3200, 0x3E},
|
||||
{0x3201, 0x0F},
|
||||
{0x3028, 0x0F},
|
||||
{0x3029, 0x00},
|
||||
{0x302A, 0x08},
|
||||
{0x3022, 0x24},
|
||||
{0x3023, 0x24},
|
||||
{0x3002, 0x01},
|
||||
{0x3003, 0x44},
|
||||
{0x3004, 0x00},
|
||||
{0x3005, 0x7C},
|
||||
{0x3006, 0x03},
|
||||
{0x3007, 0xC3},
|
||||
{0x3008, 0x02},
|
||||
{0x3009, 0x5B},
|
||||
{0x300A, 0x03},
|
||||
{0x300B, 0xFC},
|
||||
{0x300C, 0x01},
|
||||
{0x300D, 0xF0},
|
||||
{0x300E, 0x02},
|
||||
{0x300F, 0x80},
|
||||
{0x3010, 0x01},
|
||||
{0x3011, 0xE0},
|
||||
{0x32B8, 0x3F},
|
||||
{0x32B9, 0x31},
|
||||
{0x32BB, 0x87},
|
||||
{0x32BC, 0x38},
|
||||
{0x32BD, 0x3C},
|
||||
{0x32BE, 0x34},
|
||||
{0x3201, 0x7F},
|
||||
{0x3021, 0x06},
|
||||
{0x3025, 0x00}, //normal
|
||||
{0x3400, 0x01},
|
||||
{0x3060, 0x01},
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* OV2640 driver.
|
||||
*
|
||||
*/
|
||||
#ifndef __OV2640_H__
|
||||
#define __OV2640_H__
|
||||
#include "sensor.h"
|
||||
int ov2640_init(sensor_t *sensor);
|
||||
#endif // __OV2640_H__
|
||||
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* OV2640 register definitions.
|
||||
*/
|
||||
#ifndef __REG_REGS_H__
|
||||
#define __REG_REGS_H__
|
||||
/* DSP register bank FF=0x00*/
|
||||
#define R_BYPASS 0x05
|
||||
#define QS 0x44
|
||||
#define CTRLI 0x50
|
||||
#define HSIZE 0x51
|
||||
#define VSIZE 0x52
|
||||
#define XOFFL 0x53
|
||||
#define YOFFL 0x54
|
||||
#define VHYX 0x55
|
||||
#define DPRP 0x56
|
||||
#define TEST 0x57
|
||||
#define ZMOW 0x5A
|
||||
#define ZMOH 0x5B
|
||||
#define ZMHH 0x5C
|
||||
#define BPADDR 0x7C
|
||||
#define BPDATA 0x7D
|
||||
#define CTRL2 0x86
|
||||
#define CTRL3 0x87
|
||||
#define SIZEL 0x8C
|
||||
#define HSIZE8 0xC0
|
||||
#define VSIZE8 0xC1
|
||||
#define CTRL0 0xC2
|
||||
#define CTRL1 0xC3
|
||||
#define R_DVP_SP 0xD3
|
||||
#define IMAGE_MODE 0xDA
|
||||
#define RESET 0xE0
|
||||
#define MS_SP 0xF0
|
||||
#define SS_ID 0xF7
|
||||
#define SS_CTRL 0xF7
|
||||
#define MC_BIST 0xF9
|
||||
#define MC_AL 0xFA
|
||||
#define MC_AH 0xFB
|
||||
#define MC_D 0xFC
|
||||
#define P_CMD 0xFD
|
||||
#define P_STATUS 0xFE
|
||||
#define BANK_SEL 0xFF
|
||||
|
||||
#define CTRLI_LP_DP 0x80
|
||||
#define CTRLI_ROUND 0x40
|
||||
|
||||
#define CTRL0_AEC_EN 0x80
|
||||
#define CTRL0_AEC_SEL 0x40
|
||||
#define CTRL0_STAT_SEL 0x20
|
||||
#define CTRL0_VFIRST 0x10
|
||||
#define CTRL0_YUV422 0x08
|
||||
#define CTRL0_YUV_EN 0x04
|
||||
#define CTRL0_RGB_EN 0x02
|
||||
#define CTRL0_RAW_EN 0x01
|
||||
|
||||
#define CTRL2_DCW_EN 0x20
|
||||
#define CTRL2_SDE_EN 0x10
|
||||
#define CTRL2_UV_ADJ_EN 0x08
|
||||
#define CTRL2_UV_AVG_EN 0x04
|
||||
#define CTRL2_CMX_EN 0x01
|
||||
|
||||
#define CTRL3_BPC_EN 0x80
|
||||
#define CTRL3_WPC_EN 0x40
|
||||
|
||||
#define R_DVP_SP_AUTO_MODE 0x80
|
||||
|
||||
#define R_BYPASS_DSP_EN 0x00
|
||||
#define R_BYPASS_DSP_BYPAS 0x01
|
||||
|
||||
#define IMAGE_MODE_Y8_DVP_EN 0x40
|
||||
#define IMAGE_MODE_JPEG_EN 0x10
|
||||
#define IMAGE_MODE_YUV422 0x00
|
||||
#define IMAGE_MODE_RAW10 0x04
|
||||
#define IMAGE_MODE_RGB565 0x08
|
||||
#define IMAGE_MODE_HREF_VSYNC 0x02
|
||||
#define IMAGE_MODE_LBYTE_FIRST 0x01
|
||||
|
||||
#define RESET_MICROC 0x40
|
||||
#define RESET_SCCB 0x20
|
||||
#define RESET_JPEG 0x10
|
||||
#define RESET_DVP 0x04
|
||||
#define RESET_IPU 0x02
|
||||
#define RESET_CIF 0x01
|
||||
|
||||
#define MC_BIST_RESET 0x80
|
||||
#define MC_BIST_BOOT_ROM_SEL 0x40
|
||||
#define MC_BIST_12KB_SEL 0x20
|
||||
#define MC_BIST_12KB_MASK 0x30
|
||||
#define MC_BIST_512KB_SEL 0x08
|
||||
#define MC_BIST_512KB_MASK 0x0C
|
||||
#define MC_BIST_BUSY_BIT_R 0x02
|
||||
#define MC_BIST_MC_RES_ONE_SH_W 0x02
|
||||
#define MC_BIST_LAUNCH 0x01
|
||||
|
||||
|
||||
typedef enum {
|
||||
BANK_DSP, BANK_SENSOR, BANK_MAX
|
||||
} ov2640_bank_t;
|
||||
|
||||
/* Sensor register bank FF=0x01*/
|
||||
#define GAIN 0x00
|
||||
#define COM1 0x03
|
||||
#define REG04 0x04
|
||||
#define REG08 0x08
|
||||
#define COM2 0x09
|
||||
#define REG_PID 0x0A
|
||||
#define REG_VER 0x0B
|
||||
#define COM3 0x0C
|
||||
#define COM4 0x0D
|
||||
#define AEC 0x10
|
||||
#define CLKRC 0x11
|
||||
#define COM7 0x12
|
||||
#define COM8 0x13
|
||||
#define COM9 0x14 /* AGC gain ceiling */
|
||||
#define COM10 0x15
|
||||
#define HSTART 0x17
|
||||
#define HSTOP 0x18
|
||||
#define VSTART 0x19
|
||||
#define VSTOP 0x1A
|
||||
#define MIDH 0x1C
|
||||
#define MIDL 0x1D
|
||||
#define AEW 0x24
|
||||
#define AEB 0x25
|
||||
#define VV 0x26
|
||||
#define REG2A 0x2A
|
||||
#define FRARL 0x2B
|
||||
#define ADDVSL 0x2D
|
||||
#define ADDVSH 0x2E
|
||||
#define YAVG 0x2F
|
||||
#define HSDY 0x30
|
||||
#define HEDY 0x31
|
||||
#define REG32 0x32
|
||||
#define ARCOM2 0x34
|
||||
#define REG45 0x45
|
||||
#define FLL 0x46
|
||||
#define FLH 0x47
|
||||
#define COM19 0x48
|
||||
#define ZOOMS 0x49
|
||||
#define COM22 0x4B
|
||||
#define COM25 0x4E
|
||||
#define BD50 0x4F
|
||||
#define BD60 0x50
|
||||
#define REG5D 0x5D
|
||||
#define REG5E 0x5E
|
||||
#define REG5F 0x5F
|
||||
#define REG60 0x60
|
||||
#define HISTO_LOW 0x61
|
||||
#define HISTO_HIGH 0x62
|
||||
|
||||
#define REG04_DEFAULT 0x28
|
||||
#define REG04_HFLIP_IMG 0x80
|
||||
#define REG04_VFLIP_IMG 0x40
|
||||
#define REG04_VREF_EN 0x10
|
||||
#define REG04_HREF_EN 0x08
|
||||
#define REG04_SET(x) (REG04_DEFAULT|x)
|
||||
|
||||
#define COM2_STDBY 0x10
|
||||
#define COM2_OUT_DRIVE_1x 0x00
|
||||
#define COM2_OUT_DRIVE_2x 0x01
|
||||
#define COM2_OUT_DRIVE_3x 0x02
|
||||
#define COM2_OUT_DRIVE_4x 0x03
|
||||
|
||||
#define COM3_DEFAULT 0x38
|
||||
#define COM3_BAND_50Hz 0x04
|
||||
#define COM3_BAND_60Hz 0x00
|
||||
#define COM3_BAND_AUTO 0x02
|
||||
#define COM3_BAND_SET(x) (COM3_DEFAULT|x)
|
||||
|
||||
#define COM7_SRST 0x80
|
||||
#define COM7_RES_UXGA 0x00 /* UXGA */
|
||||
#define COM7_RES_SVGA 0x40 /* SVGA */
|
||||
#define COM7_RES_CIF 0x20 /* CIF */
|
||||
#define COM7_ZOOM_EN 0x04 /* Enable Zoom */
|
||||
#define COM7_COLOR_BAR 0x02 /* Enable Color Bar Test */
|
||||
|
||||
#define COM8_DEFAULT 0xC0
|
||||
#define COM8_BNDF_EN 0x20 /* Enable Banding filter */
|
||||
#define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */
|
||||
#define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */
|
||||
#define COM8_SET(x) (COM8_DEFAULT|x)
|
||||
|
||||
#define COM9_DEFAULT 0x08
|
||||
#define COM9_AGC_GAIN_2x 0x00 /* AGC: 2x */
|
||||
#define COM9_AGC_GAIN_4x 0x01 /* AGC: 4x */
|
||||
#define COM9_AGC_GAIN_8x 0x02 /* AGC: 8x */
|
||||
#define COM9_AGC_GAIN_16x 0x03 /* AGC: 16x */
|
||||
#define COM9_AGC_GAIN_32x 0x04 /* AGC: 32x */
|
||||
#define COM9_AGC_GAIN_64x 0x05 /* AGC: 64x */
|
||||
#define COM9_AGC_GAIN_128x 0x06 /* AGC: 128x */
|
||||
#define COM9_AGC_SET(x) (COM9_DEFAULT|(x<<5))
|
||||
|
||||
#define COM10_HREF_EN 0x80 /* HSYNC changes to HREF */
|
||||
#define COM10_HSYNC_EN 0x40 /* HREF changes to HSYNC */
|
||||
#define COM10_PCLK_FREE 0x20 /* PCLK output option: free running PCLK */
|
||||
#define COM10_PCLK_EDGE 0x10 /* Data is updated at the rising edge of PCLK */
|
||||
#define COM10_HREF_NEG 0x08 /* HREF negative */
|
||||
#define COM10_VSYNC_NEG 0x02 /* VSYNC negative */
|
||||
#define COM10_HSYNC_NEG 0x01 /* HSYNC negative */
|
||||
|
||||
#define CTRL1_AWB 0x08 /* Enable AWB */
|
||||
|
||||
#define VV_AGC_TH_SET(h,l) ((h<<4)|(l&0x0F))
|
||||
|
||||
#define REG32_UXGA 0x36
|
||||
#define REG32_SVGA 0x09
|
||||
#define REG32_CIF 0x89
|
||||
|
||||
#define CLKRC_2X 0x80
|
||||
#define CLKRC_2X_UXGA (0x01 | CLKRC_2X)
|
||||
#define CLKRC_2X_SVGA CLKRC_2X
|
||||
#define CLKRC_2X_CIF CLKRC_2X
|
||||
|
||||
#endif //__REG_REGS_H__
|
||||
@@ -1,485 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#ifndef _OV2640_SETTINGS_H_
|
||||
#define _OV2640_SETTINGS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_attr.h"
|
||||
#include "ov2640_regs.h"
|
||||
|
||||
typedef enum {
|
||||
OV2640_MODE_UXGA, OV2640_MODE_SVGA, OV2640_MODE_CIF, OV2640_MODE_MAX
|
||||
} ov2640_sensor_mode_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint8_t pclk_div:7;
|
||||
uint8_t pclk_auto:1;
|
||||
};
|
||||
uint8_t pclk;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
uint8_t clk_div:6;
|
||||
uint8_t reserved:1;
|
||||
uint8_t clk_2x:1;
|
||||
};
|
||||
uint8_t clk;
|
||||
};
|
||||
} ov2640_clk_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t offset_x;
|
||||
uint16_t offset_y;
|
||||
uint16_t max_x;
|
||||
uint16_t max_y;
|
||||
} ov2640_ratio_settings_t;
|
||||
|
||||
static const DRAM_ATTR ov2640_ratio_settings_t ratio_table[] = {
|
||||
// ox, oy, mx, my
|
||||
{ 0, 0, 1600, 1200 }, //4x3
|
||||
{ 8, 72, 1584, 1056 }, //3x2
|
||||
{ 0, 100, 1600, 1000 }, //16x10
|
||||
{ 0, 120, 1600, 960 }, //5x3
|
||||
{ 0, 150, 1600, 900 }, //16x9
|
||||
{ 2, 258, 1596, 684 }, //21x9
|
||||
{ 50, 0, 1500, 1200 }, //5x4
|
||||
{ 200, 0, 1200, 1200 }, //1x1
|
||||
{ 462, 0, 676, 1200 } //9x16
|
||||
};
|
||||
|
||||
// 30fps@24MHz
|
||||
const DRAM_ATTR uint8_t ov2640_settings_cif[][2] = {
|
||||
{BANK_SEL, BANK_DSP},
|
||||
{0x2c, 0xff},
|
||||
{0x2e, 0xdf},
|
||||
{BANK_SEL, BANK_SENSOR},
|
||||
{0x3c, 0x32},
|
||||
{CLKRC, 0x01},
|
||||
{COM2, COM2_OUT_DRIVE_3x},
|
||||
{REG04, REG04_DEFAULT},
|
||||
{COM8, COM8_DEFAULT | COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN},
|
||||
{COM9, COM9_AGC_SET(COM9_AGC_GAIN_8x)},
|
||||
{0x2c, 0x0c},
|
||||
{0x33, 0x78},
|
||||
{0x3a, 0x33},
|
||||
{0x3b, 0xfB},
|
||||
{0x3e, 0x00},
|
||||
{0x43, 0x11},
|
||||
{0x16, 0x10},
|
||||
{0x39, 0x92},
|
||||
{0x35, 0xda},
|
||||
{0x22, 0x1a},
|
||||
{0x37, 0xc3},
|
||||
{0x23, 0x00},
|
||||
{ARCOM2, 0xc0},
|
||||
{0x06, 0x88},
|
||||
{0x07, 0xc0},
|
||||
{COM4, 0x87},
|
||||
{0x0e, 0x41},
|
||||
{0x4c, 0x00},
|
||||
{0x4a, 0x81},
|
||||
{0x21, 0x99},
|
||||
{AEW, 0x40},
|
||||
{AEB, 0x38},
|
||||
{VV, VV_AGC_TH_SET(8,2)},
|
||||
{0x5c, 0x00},
|
||||
{0x63, 0x00},
|
||||
{HISTO_LOW, 0x70},
|
||||
{HISTO_HIGH, 0x80},
|
||||
{0x7c, 0x05},
|
||||
{0x20, 0x80},
|
||||
{0x28, 0x30},
|
||||
{0x6c, 0x00},
|
||||
{0x6d, 0x80},
|
||||
{0x6e, 0x00},
|
||||
{0x70, 0x02},
|
||||
{0x71, 0x94},
|
||||
{0x73, 0xc1},
|
||||
{0x3d, 0x34},
|
||||
{0x5a, 0x57},
|
||||
{BD50, 0xbb},
|
||||
{BD60, 0x9c},
|
||||
{COM7, COM7_RES_CIF},
|
||||
{HSTART, 0x11},
|
||||
{HSTOP, 0x43},
|
||||
{VSTART, 0x00},
|
||||
{VSTOP, 0x25},
|
||||
{REG32, 0x89},
|
||||
{0x37, 0xc0},
|
||||
{BD50, 0xca},
|
||||
{BD60, 0xa8},
|
||||
{0x6d, 0x00},
|
||||
{0x3d, 0x38},
|
||||
{BANK_SEL, BANK_DSP},
|
||||
{0xe5, 0x7f},
|
||||
{MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL},
|
||||
{0x41, 0x24},
|
||||
{RESET, RESET_JPEG | RESET_DVP},
|
||||
{0x76, 0xff},
|
||||
{0x33, 0xa0},
|
||||
{0x42, 0x20},
|
||||
{0x43, 0x18},
|
||||
{0x4c, 0x00},
|
||||
{CTRL3, CTRL3_WPC_EN | 0x10 },
|
||||
{0x88, 0x3f},
|
||||
{0xd7, 0x03},
|
||||
{0xd9, 0x10},
|
||||
{R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x02},
|
||||
{0xc8, 0x08},
|
||||
{0xc9, 0x80},
|
||||
{BPADDR, 0x00},
|
||||
{BPDATA, 0x00},
|
||||
{BPADDR, 0x03},
|
||||
{BPDATA, 0x48},
|
||||
{BPDATA, 0x48},
|
||||
{BPADDR, 0x08},
|
||||
{BPDATA, 0x20},
|
||||
{BPDATA, 0x10},
|
||||
{BPDATA, 0x0e},
|
||||
{0x90, 0x00},
|
||||
{0x91, 0x0e},
|
||||
{0x91, 0x1a},
|
||||
{0x91, 0x31},
|
||||
{0x91, 0x5a},
|
||||
{0x91, 0x69},
|
||||
{0x91, 0x75},
|
||||
{0x91, 0x7e},
|
||||
{0x91, 0x88},
|
||||
{0x91, 0x8f},
|
||||
{0x91, 0x96},
|
||||
{0x91, 0xa3},
|
||||
{0x91, 0xaf},
|
||||
{0x91, 0xc4},
|
||||
{0x91, 0xd7},
|
||||
{0x91, 0xe8},
|
||||
{0x91, 0x20},
|
||||
{0x92, 0x00},
|
||||
{0x93, 0x06},
|
||||
{0x93, 0xe3},
|
||||
{0x93, 0x05},
|
||||
{0x93, 0x05},
|
||||
{0x93, 0x00},
|
||||
{0x93, 0x04},
|
||||
{0x93, 0x00},
|
||||
{0x93, 0x00},
|
||||
{0x93, 0x00},
|
||||
{0x93, 0x00},
|
||||
{0x93, 0x00},
|
||||
{0x93, 0x00},
|
||||
{0x93, 0x00},
|
||||
{0x96, 0x00},
|
||||
{0x97, 0x08},
|
||||
{0x97, 0x19},
|
||||
{0x97, 0x02},
|
||||
{0x97, 0x0c},
|
||||
{0x97, 0x24},
|
||||
{0x97, 0x30},
|
||||
{0x97, 0x28},
|
||||
{0x97, 0x26},
|
||||
{0x97, 0x02},
|
||||
{0x97, 0x98},
|
||||
{0x97, 0x80},
|
||||
{0x97, 0x00},
|
||||
{0x97, 0x00},
|
||||
{0xa4, 0x00},
|
||||
{0xa8, 0x00},
|
||||
{0xc5, 0x11},
|
||||
{0xc6, 0x51},
|
||||
{0xbf, 0x80},
|
||||
{0xc7, 0x10},
|
||||
{0xb6, 0x66},
|
||||
{0xb8, 0xA5},
|
||||
{0xb7, 0x64},
|
||||
{0xb9, 0x7C},
|
||||
{0xb3, 0xaf},
|
||||
{0xb4, 0x97},
|
||||
{0xb5, 0xFF},
|
||||
{0xb0, 0xC5},
|
||||
{0xb1, 0x94},
|
||||
{0xb2, 0x0f},
|
||||
{0xc4, 0x5c},
|
||||
{CTRL1, 0xfd},
|
||||
{0x7f, 0x00},
|
||||
{0xe5, 0x1f},
|
||||
{0xe1, 0x67},
|
||||
{0xdd, 0x7f},
|
||||
{IMAGE_MODE, 0x00},
|
||||
{RESET, 0x00},
|
||||
{R_BYPASS, R_BYPASS_DSP_EN},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
const DRAM_ATTR uint8_t ov2640_settings_to_cif[][2] = {
|
||||
{BANK_SEL, BANK_SENSOR},
|
||||
{COM7, COM7_RES_CIF},
|
||||
|
||||
//Set the sensor output window
|
||||
{COM1, 0x0A},
|
||||
{REG32, REG32_CIF},
|
||||
{HSTART, 0x11},
|
||||
{HSTOP, 0x43},
|
||||
{VSTART, 0x00},
|
||||
{VSTOP, 0x25},
|
||||
|
||||
//{CLKRC, 0x00},
|
||||
{BD50, 0xca},
|
||||
{BD60, 0xa8},
|
||||
{0x5a, 0x23},
|
||||
{0x6d, 0x00},
|
||||
{0x3d, 0x38},
|
||||
{0x39, 0x92},
|
||||
{0x35, 0xda},
|
||||
{0x22, 0x1a},
|
||||
{0x37, 0xc3},
|
||||
{0x23, 0x00},
|
||||
{ARCOM2, 0xc0},
|
||||
{0x06, 0x88},
|
||||
{0x07, 0xc0},
|
||||
{COM4, 0x87},
|
||||
{0x0e, 0x41},
|
||||
{0x4c, 0x00},
|
||||
{BANK_SEL, BANK_DSP},
|
||||
{RESET, RESET_DVP},
|
||||
|
||||
//Set the sensor resolution (UXGA, SVGA, CIF)
|
||||
{HSIZE8, 0x32},
|
||||
{VSIZE8, 0x25},
|
||||
{SIZEL, 0x00},
|
||||
|
||||
//Set the image window size >= output size
|
||||
{HSIZE, 0x64},
|
||||
{VSIZE, 0x4a},
|
||||
{XOFFL, 0x00},
|
||||
{YOFFL, 0x00},
|
||||
{VHYX, 0x00},
|
||||
{TEST, 0x00},
|
||||
|
||||
{CTRL2, CTRL2_DCW_EN | 0x1D},
|
||||
{CTRLI, CTRLI_LP_DP | 0x00},
|
||||
//{R_DVP_SP, 0x08},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
const DRAM_ATTR uint8_t ov2640_settings_to_svga[][2] = {
|
||||
{BANK_SEL, BANK_SENSOR},
|
||||
{COM7, COM7_RES_SVGA},
|
||||
|
||||
//Set the sensor output window
|
||||
{COM1, 0x0A},
|
||||
{REG32, REG32_SVGA},
|
||||
{HSTART, 0x11},
|
||||
{HSTOP, 0x43},
|
||||
{VSTART, 0x00},
|
||||
{VSTOP, 0x4b},
|
||||
|
||||
//{CLKRC, 0x00},
|
||||
{0x37, 0xc0},
|
||||
{BD50, 0xca},
|
||||
{BD60, 0xa8},
|
||||
{0x5a, 0x23},
|
||||
{0x6d, 0x00},
|
||||
{0x3d, 0x38},
|
||||
{0x39, 0x92},
|
||||
{0x35, 0xda},
|
||||
{0x22, 0x1a},
|
||||
{0x37, 0xc3},
|
||||
{0x23, 0x00},
|
||||
{ARCOM2, 0xc0},
|
||||
{0x06, 0x88},
|
||||
{0x07, 0xc0},
|
||||
{COM4, 0x87},
|
||||
{0x0e, 0x41},
|
||||
{0x42, 0x03},
|
||||
{0x4c, 0x00},
|
||||
{BANK_SEL, BANK_DSP},
|
||||
{RESET, RESET_DVP},
|
||||
|
||||
//Set the sensor resolution (UXGA, SVGA, CIF)
|
||||
{HSIZE8, 0x64},
|
||||
{VSIZE8, 0x4B},
|
||||
{SIZEL, 0x00},
|
||||
|
||||
//Set the image window size >= output size
|
||||
{HSIZE, 0xC8},
|
||||
{VSIZE, 0x96},
|
||||
{XOFFL, 0x00},
|
||||
{YOFFL, 0x00},
|
||||
{VHYX, 0x00},
|
||||
{TEST, 0x00},
|
||||
|
||||
{CTRL2, CTRL2_DCW_EN | 0x1D},
|
||||
{CTRLI, CTRLI_LP_DP | 0x00},
|
||||
//{R_DVP_SP, 0x08},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
const DRAM_ATTR uint8_t ov2640_settings_to_uxga[][2] = {
|
||||
{BANK_SEL, BANK_SENSOR},
|
||||
{COM7, COM7_RES_UXGA},
|
||||
|
||||
//Set the sensor output window
|
||||
{COM1, 0x0F},
|
||||
{REG32, REG32_UXGA},
|
||||
{HSTART, 0x11},
|
||||
{HSTOP, 0x75},
|
||||
{VSTART, 0x01},
|
||||
{VSTOP, 0x97},
|
||||
|
||||
//{CLKRC, 0x00},
|
||||
{0x3d, 0x34},
|
||||
{BD50, 0xbb},
|
||||
{BD60, 0x9c},
|
||||
{0x5a, 0x57},
|
||||
{0x6d, 0x80},
|
||||
{0x39, 0x82},
|
||||
{0x23, 0x00},
|
||||
{0x07, 0xc0},
|
||||
{0x4c, 0x00},
|
||||
{0x35, 0x88},
|
||||
{0x22, 0x0a},
|
||||
{0x37, 0x40},
|
||||
{ARCOM2, 0xa0},
|
||||
{0x06, 0x02},
|
||||
{COM4, 0xb7},
|
||||
{0x0e, 0x01},
|
||||
{0x42, 0x83},
|
||||
{BANK_SEL, BANK_DSP},
|
||||
{RESET, RESET_DVP},
|
||||
|
||||
//Set the sensor resolution (UXGA, SVGA, CIF)
|
||||
{HSIZE8, 0xc8},
|
||||
{VSIZE8, 0x96},
|
||||
{SIZEL, 0x00},
|
||||
|
||||
//Set the image window size >= output size
|
||||
{HSIZE, 0x90},
|
||||
{VSIZE, 0x2c},
|
||||
{XOFFL, 0x00},
|
||||
{YOFFL, 0x00},
|
||||
{VHYX, 0x88},
|
||||
{TEST, 0x00},
|
||||
|
||||
{CTRL2, CTRL2_DCW_EN | 0x1d},
|
||||
{CTRLI, 0x00},
|
||||
//{R_DVP_SP, 0x06},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
const DRAM_ATTR uint8_t ov2640_settings_jpeg3[][2] = {
|
||||
{BANK_SEL, BANK_DSP},
|
||||
{RESET, RESET_JPEG | RESET_DVP},
|
||||
{IMAGE_MODE, IMAGE_MODE_JPEG_EN | IMAGE_MODE_HREF_VSYNC},
|
||||
{0xD7, 0x03},
|
||||
{0xE1, 0x77},
|
||||
{0xE5, 0x1F},
|
||||
{0xD9, 0x10},
|
||||
{0xDF, 0x80},
|
||||
{0x33, 0x80},
|
||||
{0x3C, 0x10},
|
||||
{0xEB, 0x30},
|
||||
{0xDD, 0x7F},
|
||||
{RESET, 0x00},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static const uint8_t ov2640_settings_yuv422[][2] = {
|
||||
{BANK_SEL, BANK_DSP},
|
||||
{RESET, RESET_DVP},
|
||||
{IMAGE_MODE, IMAGE_MODE_YUV422},
|
||||
{0xD7, 0x01},
|
||||
{0xE1, 0x67},
|
||||
{RESET, 0x00},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
static const uint8_t ov2640_settings_rgb565[][2] = {
|
||||
{BANK_SEL, BANK_DSP},
|
||||
{RESET, RESET_DVP},
|
||||
{IMAGE_MODE, IMAGE_MODE_RGB565},
|
||||
{0xD7, 0x03},
|
||||
{0xE1, 0x77},
|
||||
{RESET, 0x00},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
#define NUM_BRIGHTNESS_LEVELS (5)
|
||||
static const uint8_t brightness_regs[NUM_BRIGHTNESS_LEVELS + 1][5] = {
|
||||
{BPADDR, BPDATA, BPADDR, BPDATA, BPDATA },
|
||||
{0x00, 0x04, 0x09, 0x00, 0x00 }, /* -2 */
|
||||
{0x00, 0x04, 0x09, 0x10, 0x00 }, /* -1 */
|
||||
{0x00, 0x04, 0x09, 0x20, 0x00 }, /* 0 */
|
||||
{0x00, 0x04, 0x09, 0x30, 0x00 }, /* +1 */
|
||||
{0x00, 0x04, 0x09, 0x40, 0x00 }, /* +2 */
|
||||
};
|
||||
|
||||
#define NUM_CONTRAST_LEVELS (5)
|
||||
static const uint8_t contrast_regs[NUM_CONTRAST_LEVELS + 1][7] = {
|
||||
{BPADDR, BPDATA, BPADDR, BPDATA, BPDATA, BPDATA, BPDATA },
|
||||
{0x00, 0x04, 0x07, 0x20, 0x18, 0x34, 0x06 }, /* -2 */
|
||||
{0x00, 0x04, 0x07, 0x20, 0x1c, 0x2a, 0x06 }, /* -1 */
|
||||
{0x00, 0x04, 0x07, 0x20, 0x20, 0x20, 0x06 }, /* 0 */
|
||||
{0x00, 0x04, 0x07, 0x20, 0x24, 0x16, 0x06 }, /* +1 */
|
||||
{0x00, 0x04, 0x07, 0x20, 0x28, 0x0c, 0x06 }, /* +2 */
|
||||
};
|
||||
|
||||
#define NUM_SATURATION_LEVELS (5)
|
||||
static const uint8_t saturation_regs[NUM_SATURATION_LEVELS + 1][5] = {
|
||||
{BPADDR, BPDATA, BPADDR, BPDATA, BPDATA },
|
||||
{0x00, 0x02, 0x03, 0x28, 0x28 }, /* -2 */
|
||||
{0x00, 0x02, 0x03, 0x38, 0x38 }, /* -1 */
|
||||
{0x00, 0x02, 0x03, 0x48, 0x48 }, /* 0 */
|
||||
{0x00, 0x02, 0x03, 0x58, 0x58 }, /* +1 */
|
||||
{0x00, 0x02, 0x03, 0x68, 0x68 }, /* +2 */
|
||||
};
|
||||
|
||||
#define NUM_SPECIAL_EFFECTS (7)
|
||||
static const uint8_t special_effects_regs[NUM_SPECIAL_EFFECTS + 1][5] = {
|
||||
{BPADDR, BPDATA, BPADDR, BPDATA, BPDATA },
|
||||
{0x00, 0X00, 0x05, 0X80, 0X80 }, /* no effect */
|
||||
{0x00, 0X40, 0x05, 0X80, 0X80 }, /* negative */
|
||||
{0x00, 0X18, 0x05, 0X80, 0X80 }, /* black and white */
|
||||
{0x00, 0X18, 0x05, 0X40, 0XC0 }, /* reddish */
|
||||
{0x00, 0X18, 0x05, 0X40, 0X40 }, /* greenish */
|
||||
{0x00, 0X18, 0x05, 0XA0, 0X40 }, /* blue */
|
||||
{0x00, 0X18, 0x05, 0X40, 0XA6 }, /* retro */
|
||||
};
|
||||
|
||||
#define NUM_WB_MODES (4)
|
||||
static const uint8_t wb_modes_regs[NUM_WB_MODES + 1][3] = {
|
||||
{0XCC, 0XCD, 0XCE },
|
||||
{0x5E, 0X41, 0x54 }, /* sunny */
|
||||
{0x65, 0X41, 0x4F }, /* cloudy */
|
||||
{0x52, 0X41, 0x66 }, /* office */
|
||||
{0x42, 0X3F, 0x71 }, /* home */
|
||||
};
|
||||
|
||||
#define NUM_AE_LEVELS (5)
|
||||
static const uint8_t ae_levels_regs[NUM_AE_LEVELS + 1][3] = {
|
||||
{ AEW, AEB, VV },
|
||||
{0x20, 0X18, 0x60 },
|
||||
{0x34, 0X1C, 0x00 },
|
||||
{0x3E, 0X38, 0x81 },
|
||||
{0x48, 0X40, 0x81 },
|
||||
{0x58, 0X50, 0x92 },
|
||||
};
|
||||
|
||||
const uint8_t agc_gain_tbl[31] = {
|
||||
0x00, 0x10, 0x18, 0x30, 0x34, 0x38, 0x3C, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7A, 0x7C, 0x7E, 0xF0,
|
||||
0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
|
||||
};
|
||||
|
||||
#endif /* _OV2640_SETTINGS_H_ */
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* OV3660 driver.
|
||||
*
|
||||
*/
|
||||
#ifndef __OV3660_H__
|
||||
#define __OV3660_H__
|
||||
|
||||
#include "sensor.h"
|
||||
|
||||
int ov3660_init(sensor_t *sensor);
|
||||
|
||||
#endif // __OV3660_H__
|
||||
@@ -1,211 +0,0 @@
|
||||
/*
|
||||
* OV3660 register definitions.
|
||||
*/
|
||||
#ifndef __OV3660_REG_REGS_H__
|
||||
#define __OV3660_REG_REGS_H__
|
||||
|
||||
/* system control registers */
|
||||
#define SYSTEM_CTROL0 0x3008 // Bit[7]: Software reset
|
||||
// Bit[6]: Software power down
|
||||
// Bit[5]: Reserved
|
||||
// Bit[4]: SRB clock SYNC enable
|
||||
// Bit[3]: Isolation suspend select
|
||||
// Bit[2:0]: Not used
|
||||
|
||||
/* output format control registers */
|
||||
#define FORMAT_CTRL 0x501F // Format select
|
||||
// Bit[2:0]:
|
||||
// 000: YUV422
|
||||
// 001: RGB
|
||||
// 010: Dither
|
||||
// 011: RAW after DPC
|
||||
// 101: RAW after CIP
|
||||
|
||||
/* format control registers */
|
||||
#define FORMAT_CTRL00 0x4300
|
||||
|
||||
/* frame control registers */
|
||||
#define FRAME_CTRL01 0x4201 // Control Passed Frame Number When both ON and OFF number set to 0x00,frame control is in bypass mode
|
||||
// Bit[7:4]: Not used
|
||||
// Bit[3:0]: Frame ON number
|
||||
#define FRAME_CTRL02 0x4202 // Control Masked Frame Number When both ON and OFF number set to 0x00,frame control is in bypass mode
|
||||
// Bit[7:4]: Not used
|
||||
// BIT[3:0]: Frame OFF number
|
||||
|
||||
/* ISP top control registers */
|
||||
#define PRE_ISP_TEST_SETTING_1 0x503D // Bit[7]: Test enable
|
||||
// 0: Test disable
|
||||
// 1: Color bar enable
|
||||
// Bit[6]: Rolling
|
||||
// Bit[5]: Transparent
|
||||
// Bit[4]: Square black and white
|
||||
// Bit[3:2]: Color bar style
|
||||
// 00: Standard 8 color bar
|
||||
// 01: Gradual change at vertical mode 1
|
||||
// 10: Gradual change at horizontal
|
||||
// 11: Gradual change at vertical mode 2
|
||||
// Bit[1:0]: Test select
|
||||
// 00: Color bar
|
||||
// 01: Random data
|
||||
// 10: Square data
|
||||
// 11: Black image
|
||||
|
||||
//exposure = {0x3500[3:0], 0x3501[7:0], 0x3502[7:0]} / 16 × tROW
|
||||
|
||||
/* AEC/AGC control functions */
|
||||
#define AEC_PK_MANUAL 0x3503 // AEC Manual Mode Control
|
||||
// Bit[7:6]: Reserved
|
||||
// Bit[5]: Gain delay option
|
||||
// Valid when 0x3503[4]=1’b0
|
||||
// 0: Delay one frame latch
|
||||
// 1: One frame latch
|
||||
// Bit[4:2]: Reserved
|
||||
// Bit[1]: AGC manual
|
||||
// 0: Auto enable
|
||||
// 1: Manual enable
|
||||
// Bit[0]: AEC manual
|
||||
// 0: Auto enable
|
||||
// 1: Manual enable
|
||||
|
||||
//gain = {0x350A[1:0], 0x350B[7:0]} / 16
|
||||
|
||||
/* mirror and flip registers */
|
||||
#define TIMING_TC_REG20 0x3820 // Timing Control Register
|
||||
// Bit[2:1]: Vertical flip enable
|
||||
// 00: Normal
|
||||
// 11: Vertical flip
|
||||
// Bit[0]: Vertical binning enable
|
||||
#define TIMING_TC_REG21 0x3821 // Timing Control Register
|
||||
// Bit[5]: Compression Enable
|
||||
// Bit[2:1]: Horizontal mirror enable
|
||||
// 00: Normal
|
||||
// 11: Horizontal mirror
|
||||
// Bit[0]: Horizontal binning enable
|
||||
|
||||
#define CLOCK_POL_CONTROL 0x4740// Bit[5]: PCLK polarity 0: active low
|
||||
// 1: active high
|
||||
// Bit[3]: Gate PCLK under VSYNC
|
||||
// Bit[2]: Gate PCLK under HREF
|
||||
// Bit[1]: HREF polarity
|
||||
// 0: active low
|
||||
// 1: active high
|
||||
// Bit[0] VSYNC polarity
|
||||
// 0: active low
|
||||
// 1: active high
|
||||
#define DRIVE_CAPABILITY 0x302c // Bit[7:6]:
|
||||
// 00: 1x
|
||||
// 01: 2x
|
||||
// 10: 3x
|
||||
// 11: 4x
|
||||
|
||||
|
||||
#define X_ADDR_ST_H 0x3800 //Bit[3:0]: X address start[11:8]
|
||||
#define X_ADDR_ST_L 0x3801 //Bit[7:0]: X address start[7:0]
|
||||
#define Y_ADDR_ST_H 0x3802 //Bit[2:0]: Y address start[10:8]
|
||||
#define Y_ADDR_ST_L 0x3803 //Bit[7:0]: Y address start[7:0]
|
||||
#define X_ADDR_END_H 0x3804 //Bit[3:0]: X address end[11:8]
|
||||
#define X_ADDR_END_L 0x3805 //Bit[7:0]:
|
||||
#define Y_ADDR_END_H 0x3806 //Bit[2:0]: Y address end[10:8]
|
||||
#define Y_ADDR_END_L 0x3807 //Bit[7:0]:
|
||||
// Size after scaling
|
||||
#define X_OUTPUT_SIZE_H 0x3808 //Bit[3:0]: DVP output horizontal width[11:8]
|
||||
#define X_OUTPUT_SIZE_L 0x3809 //Bit[7:0]:
|
||||
#define Y_OUTPUT_SIZE_H 0x380a //Bit[2:0]: DVP output vertical height[10:8]
|
||||
#define Y_OUTPUT_SIZE_L 0x380b //Bit[7:0]:
|
||||
#define X_TOTAL_SIZE_H 0x380c //Bit[3:0]: Total horizontal size[11:8]
|
||||
#define X_TOTAL_SIZE_L 0x380d //Bit[7:0]:
|
||||
#define Y_TOTAL_SIZE_H 0x380e //Bit[7:0]: Total vertical size[15:8]
|
||||
#define Y_TOTAL_SIZE_L 0x380f //Bit[7:0]:
|
||||
#define X_OFFSET_H 0x3810 //Bit[3:0]: ISP horizontal offset[11:8]
|
||||
#define X_OFFSET_L 0x3811 //Bit[7:0]:
|
||||
#define Y_OFFSET_H 0x3812 //Bit[2:0]: ISP vertical offset[10:8]
|
||||
#define Y_OFFSET_L 0x3813 //Bit[7:0]:
|
||||
#define X_INCREMENT 0x3814 //Bit[7:4]: Horizontal odd subsample increment
|
||||
//Bit[3:0]: Horizontal even subsample increment
|
||||
#define Y_INCREMENT 0x3815 //Bit[7:4]: Vertical odd subsample increment
|
||||
//Bit[3:0]: Vertical even subsample increment
|
||||
// Size before scaling
|
||||
//#define X_INPUT_SIZE (X_ADDR_END - X_ADDR_ST + 1 - (2 * X_OFFSET))
|
||||
//#define Y_INPUT_SIZE (Y_ADDR_END - Y_ADDR_ST + 1 - (2 * Y_OFFSET))
|
||||
|
||||
#define ISP_CONTROL_01 0x5001 // Bit[5]: Scale enable
|
||||
// 0: Disable
|
||||
// 1: Enable
|
||||
|
||||
#define SCALE_CTRL_1 0x5601 // Bit[6:4]: HDIV RW
|
||||
// DCW scale times
|
||||
// 000: DCW 1 time
|
||||
// 001: DCW 2 times
|
||||
// 010: DCW 4 times
|
||||
// 100: DCW 8 times
|
||||
// 101: DCW 16 times
|
||||
// Others: DCW 16 times
|
||||
// Bit[2:0]: VDIV RW
|
||||
// DCW scale times
|
||||
// 000: DCW 1 time
|
||||
// 001: DCW 2 times
|
||||
// 010: DCW 4 times
|
||||
// 100: DCW 8 times
|
||||
// 101: DCW 16 times
|
||||
// Others: DCW 16 times
|
||||
|
||||
#define SCALE_CTRL_2 0x5602 // X_SCALE High Bits
|
||||
#define SCALE_CTRL_3 0x5603 // X_SCALE Low Bits
|
||||
#define SCALE_CTRL_4 0x5604 // Y_SCALE High Bits
|
||||
#define SCALE_CTRL_5 0x5605 // Y_SCALE Low Bits
|
||||
#define SCALE_CTRL_6 0x5606 // Bit[3:0]: V Offset
|
||||
|
||||
#define PCLK_RATIO 0x3824 // Bit[4:0]: PCLK ratio manual
|
||||
#define VFIFO_CTRL0C 0x460C // Bit[1]: PCLK manual enable
|
||||
// 0: Auto
|
||||
// 1: Manual by PCLK_RATIO
|
||||
|
||||
#define VFIFO_X_SIZE_H 0x4602
|
||||
#define VFIFO_X_SIZE_L 0x4603
|
||||
#define VFIFO_Y_SIZE_H 0x4604
|
||||
#define VFIFO_Y_SIZE_L 0x4605
|
||||
|
||||
#define SC_PLLS_CTRL0 0x303a // Bit[7]: PLLS bypass
|
||||
#define SC_PLLS_CTRL1 0x303b // Bit[4:0]: PLLS multiplier
|
||||
#define SC_PLLS_CTRL2 0x303c // Bit[6:4]: PLLS charge pump control
|
||||
// Bit[3:0]: PLLS system divider
|
||||
#define SC_PLLS_CTRL3 0x303d // Bit[5:4]: PLLS pre-divider
|
||||
// 00: 1
|
||||
// 01: 1.5
|
||||
// 10: 2
|
||||
// 11: 3
|
||||
// Bit[2]: PLLS root-divider - 1
|
||||
// Bit[1:0]: PLLS seld5
|
||||
// 00: 1
|
||||
// 01: 1
|
||||
// 10: 2
|
||||
// 11: 2.5
|
||||
|
||||
#define COMPRESSION_CTRL00 0x4400 //
|
||||
#define COMPRESSION_CTRL01 0x4401 //
|
||||
#define COMPRESSION_CTRL02 0x4402 //
|
||||
#define COMPRESSION_CTRL03 0x4403 //
|
||||
#define COMPRESSION_CTRL04 0x4404 //
|
||||
#define COMPRESSION_CTRL05 0x4405 //
|
||||
#define COMPRESSION_CTRL06 0x4406 //
|
||||
#define COMPRESSION_CTRL07 0x4407 // Bit[5:0]: QS
|
||||
#define COMPRESSION_ISI_CTRL 0x4408 //
|
||||
#define COMPRESSION_CTRL09 0x4409 //
|
||||
#define COMPRESSION_CTRL0a 0x440a //
|
||||
#define COMPRESSION_CTRL0b 0x440b //
|
||||
#define COMPRESSION_CTRL0c 0x440c //
|
||||
#define COMPRESSION_CTRL0d 0x440d //
|
||||
#define COMPRESSION_CTRL0E 0x440e //
|
||||
|
||||
/**
|
||||
* @brief register value
|
||||
*/
|
||||
#define TEST_COLOR_BAR 0xC0 /* Enable Color Bar roling Test */
|
||||
|
||||
#define AEC_PK_MANUAL_AGC_MANUALEN 0x02 /* Enable AGC Manual enable */
|
||||
#define AEC_PK_MANUAL_AEC_MANUALEN 0x01 /* Enable AEC Manual enable */
|
||||
|
||||
#define TIMING_TC_REG20_VFLIP 0x06 /* Vertical flip enable */
|
||||
#define TIMING_TC_REG21_HMIRROR 0x06 /* Horizontal mirror enable */
|
||||
|
||||
#endif // __OV3660_REG_REGS_H__
|
||||
@@ -1,318 +0,0 @@
|
||||
#ifndef _OV3660_SETTINGS_H_
|
||||
#define _OV3660_SETTINGS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_attr.h"
|
||||
#include "ov3660_regs.h"
|
||||
|
||||
static const ratio_settings_t ratio_table[] = {
|
||||
// mw, mh, sx, sy, ex, ey, ox, oy, tx, ty
|
||||
{ 2048, 1536, 0, 0, 2079, 1547, 16, 6, 2300, 1564 }, //4x3
|
||||
{ 1920, 1280, 64, 128, 2015, 1419, 16, 6, 2172, 1436 }, //3x2
|
||||
{ 2048, 1280, 0, 128, 2079, 1419, 16, 6, 2300, 1436 }, //16x10
|
||||
{ 1920, 1152, 64, 192, 2015, 1355, 16, 6, 2172, 1372 }, //5x3
|
||||
{ 1920, 1080, 64, 242, 2015, 1333, 16, 6, 2172, 1322 }, //16x9
|
||||
{ 2048, 880, 0, 328, 2079, 1219, 16, 6, 2300, 1236 }, //21x9
|
||||
{ 1920, 1536, 64, 0, 2015, 1547, 16, 6, 2172, 1564 }, //5x4
|
||||
{ 1536, 1536, 256, 0, 1823, 1547, 16, 6, 2044, 1564 }, //1x1
|
||||
{ 864, 1536, 592, 0, 1487, 1547, 16, 6, 2044, 1564 } //9x16
|
||||
};
|
||||
|
||||
#define REG_DLY 0xffff
|
||||
#define REGLIST_TAIL 0x0000
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_default_regs[][2] = {
|
||||
{SYSTEM_CTROL0, 0x82}, // software reset
|
||||
{REG_DLY, 10}, // delay 10ms
|
||||
|
||||
{0x3103, 0x13},
|
||||
{SYSTEM_CTROL0, 0x42},
|
||||
{0x3017, 0xff},
|
||||
{0x3018, 0xff},
|
||||
{DRIVE_CAPABILITY, 0xc3},
|
||||
{CLOCK_POL_CONTROL, 0x21},
|
||||
|
||||
{0x3611, 0x01},
|
||||
{0x3612, 0x2d},
|
||||
|
||||
{0x3032, 0x00},
|
||||
{0x3614, 0x80},
|
||||
{0x3618, 0x00},
|
||||
{0x3619, 0x75},
|
||||
{0x3622, 0x80},
|
||||
{0x3623, 0x00},
|
||||
{0x3624, 0x03},
|
||||
{0x3630, 0x52},
|
||||
{0x3632, 0x07},
|
||||
{0x3633, 0xd2},
|
||||
{0x3704, 0x80},
|
||||
{0x3708, 0x66},
|
||||
{0x3709, 0x12},
|
||||
{0x370b, 0x12},
|
||||
{0x3717, 0x00},
|
||||
{0x371b, 0x60},
|
||||
{0x371c, 0x00},
|
||||
{0x3901, 0x13},
|
||||
|
||||
{0x3600, 0x08},
|
||||
{0x3620, 0x43},
|
||||
{0x3702, 0x20},
|
||||
{0x3739, 0x48},
|
||||
{0x3730, 0x20},
|
||||
{0x370c, 0x0c},
|
||||
|
||||
{0x3a18, 0x00},
|
||||
{0x3a19, 0xf8},
|
||||
|
||||
{0x3000, 0x10},
|
||||
{0x3004, 0xef},
|
||||
|
||||
{0x6700, 0x05},
|
||||
{0x6701, 0x19},
|
||||
{0x6702, 0xfd},
|
||||
{0x6703, 0xd1},
|
||||
{0x6704, 0xff},
|
||||
{0x6705, 0xff},
|
||||
|
||||
{0x3c01, 0x80},
|
||||
{0x3c00, 0x04},
|
||||
{0x3a08, 0x00}, {0x3a09, 0x62}, //50Hz Band Width Step (10bit)
|
||||
{0x3a0e, 0x08}, //50Hz Max Bands in One Frame (6 bit)
|
||||
{0x3a0a, 0x00}, {0x3a0b, 0x52}, //60Hz Band Width Step (10bit)
|
||||
{0x3a0d, 0x09}, //60Hz Max Bands in One Frame (6 bit)
|
||||
|
||||
{0x3a00, 0x3a},//night mode off
|
||||
{0x3a14, 0x09},
|
||||
{0x3a15, 0x30},
|
||||
{0x3a02, 0x09},
|
||||
{0x3a03, 0x30},
|
||||
|
||||
{COMPRESSION_CTRL0E, 0x08},
|
||||
{0x4520, 0x0b},
|
||||
{0x460b, 0x37},
|
||||
{0x4713, 0x02},
|
||||
{0x471c, 0xd0},
|
||||
{0x5086, 0x00},
|
||||
|
||||
{0x5002, 0x00},
|
||||
{0x501f, 0x00},
|
||||
|
||||
{SYSTEM_CTROL0, 0x02},
|
||||
|
||||
{0x5180, 0xff},
|
||||
{0x5181, 0xf2},
|
||||
{0x5182, 0x00},
|
||||
{0x5183, 0x14},
|
||||
{0x5184, 0x25},
|
||||
{0x5185, 0x24},
|
||||
{0x5186, 0x16},
|
||||
{0x5187, 0x16},
|
||||
{0x5188, 0x16},
|
||||
{0x5189, 0x68},
|
||||
{0x518a, 0x60},
|
||||
{0x518b, 0xe0},
|
||||
{0x518c, 0xb2},
|
||||
{0x518d, 0x42},
|
||||
{0x518e, 0x35},
|
||||
{0x518f, 0x56},
|
||||
{0x5190, 0x56},
|
||||
{0x5191, 0xf8},
|
||||
{0x5192, 0x04},
|
||||
{0x5193, 0x70},
|
||||
{0x5194, 0xf0},
|
||||
{0x5195, 0xf0},
|
||||
{0x5196, 0x03},
|
||||
{0x5197, 0x01},
|
||||
{0x5198, 0x04},
|
||||
{0x5199, 0x12},
|
||||
{0x519a, 0x04},
|
||||
{0x519b, 0x00},
|
||||
{0x519c, 0x06},
|
||||
{0x519d, 0x82},
|
||||
{0x519e, 0x38},
|
||||
|
||||
{0x5381, 0x1d},
|
||||
{0x5382, 0x60},
|
||||
{0x5383, 0x03},
|
||||
{0x5384, 0x0c},
|
||||
{0x5385, 0x78},
|
||||
{0x5386, 0x84},
|
||||
{0x5387, 0x7d},
|
||||
{0x5388, 0x6b},
|
||||
{0x5389, 0x12},
|
||||
{0x538a, 0x01},
|
||||
{0x538b, 0x98},
|
||||
|
||||
{0x5480, 0x01},
|
||||
// {0x5481, 0x05},
|
||||
// {0x5482, 0x09},
|
||||
// {0x5483, 0x10},
|
||||
// {0x5484, 0x3a},
|
||||
// {0x5485, 0x4c},
|
||||
// {0x5486, 0x5a},
|
||||
// {0x5487, 0x68},
|
||||
// {0x5488, 0x74},
|
||||
// {0x5489, 0x80},
|
||||
// {0x548a, 0x8e},
|
||||
// {0x548b, 0xa4},
|
||||
// {0x548c, 0xb4},
|
||||
// {0x548d, 0xc8},
|
||||
// {0x548e, 0xde},
|
||||
// {0x548f, 0xf0},
|
||||
// {0x5490, 0x15},
|
||||
|
||||
{0x5000, 0xa7},
|
||||
{0x5800, 0x0C},
|
||||
{0x5801, 0x09},
|
||||
{0x5802, 0x0C},
|
||||
{0x5803, 0x0C},
|
||||
{0x5804, 0x0D},
|
||||
{0x5805, 0x17},
|
||||
{0x5806, 0x06},
|
||||
{0x5807, 0x05},
|
||||
{0x5808, 0x04},
|
||||
{0x5809, 0x06},
|
||||
{0x580a, 0x09},
|
||||
{0x580b, 0x0E},
|
||||
{0x580c, 0x05},
|
||||
{0x580d, 0x01},
|
||||
{0x580e, 0x01},
|
||||
{0x580f, 0x01},
|
||||
{0x5810, 0x05},
|
||||
{0x5811, 0x0D},
|
||||
{0x5812, 0x05},
|
||||
{0x5813, 0x01},
|
||||
{0x5814, 0x01},
|
||||
{0x5815, 0x01},
|
||||
{0x5816, 0x05},
|
||||
{0x5817, 0x0D},
|
||||
{0x5818, 0x08},
|
||||
{0x5819, 0x06},
|
||||
{0x581a, 0x05},
|
||||
{0x581b, 0x07},
|
||||
{0x581c, 0x0B},
|
||||
{0x581d, 0x0D},
|
||||
{0x581e, 0x12},
|
||||
{0x581f, 0x0D},
|
||||
{0x5820, 0x0E},
|
||||
{0x5821, 0x10},
|
||||
{0x5822, 0x10},
|
||||
{0x5823, 0x1E},
|
||||
{0x5824, 0x53},
|
||||
{0x5825, 0x15},
|
||||
{0x5826, 0x05},
|
||||
{0x5827, 0x14},
|
||||
{0x5828, 0x54},
|
||||
{0x5829, 0x25},
|
||||
{0x582a, 0x33},
|
||||
{0x582b, 0x33},
|
||||
{0x582c, 0x34},
|
||||
{0x582d, 0x16},
|
||||
{0x582e, 0x24},
|
||||
{0x582f, 0x41},
|
||||
{0x5830, 0x50},
|
||||
{0x5831, 0x42},
|
||||
{0x5832, 0x15},
|
||||
{0x5833, 0x25},
|
||||
{0x5834, 0x34},
|
||||
{0x5835, 0x33},
|
||||
{0x5836, 0x24},
|
||||
{0x5837, 0x26},
|
||||
{0x5838, 0x54},
|
||||
{0x5839, 0x25},
|
||||
{0x583a, 0x15},
|
||||
{0x583b, 0x25},
|
||||
{0x583c, 0x53},
|
||||
{0x583d, 0xCF},
|
||||
|
||||
{0x3a0f, 0x30},
|
||||
{0x3a10, 0x28},
|
||||
{0x3a1b, 0x30},
|
||||
{0x3a1e, 0x28},
|
||||
{0x3a11, 0x60},
|
||||
{0x3a1f, 0x14},
|
||||
|
||||
{0x5302, 0x28},
|
||||
{0x5303, 0x20},
|
||||
|
||||
{0x5306, 0x1c}, //de-noise offset 1
|
||||
{0x5307, 0x28}, //de-noise offset 2
|
||||
|
||||
{0x4002, 0xc5},
|
||||
{0x4003, 0x81},
|
||||
{0x4005, 0x12},
|
||||
|
||||
{0x5688, 0x11},
|
||||
{0x5689, 0x11},
|
||||
{0x568a, 0x11},
|
||||
{0x568b, 0x11},
|
||||
{0x568c, 0x11},
|
||||
{0x568d, 0x11},
|
||||
{0x568e, 0x11},
|
||||
{0x568f, 0x11},
|
||||
|
||||
{0x5580, 0x06},
|
||||
{0x5588, 0x00},
|
||||
{0x5583, 0x40},
|
||||
{0x5584, 0x2c},
|
||||
|
||||
{ISP_CONTROL_01, 0x83}, // turn color matrix, awb and SDE
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_jpeg[][2] = {
|
||||
{FORMAT_CTRL, 0x00}, // YUV422
|
||||
{FORMAT_CTRL00, 0x30}, // YUYV
|
||||
{0x3002, 0x00},//0x1c to 0x00 !!!
|
||||
{0x3006, 0xff},//0xc3 to 0xff !!!
|
||||
{0x471c, 0x50},//0xd0 to 0x50 !!!
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_raw[][2] = {
|
||||
{FORMAT_CTRL00, 0x00}, // RAW
|
||||
{REGLIST_TAIL, 0x00}
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_grayscale[][2] = {
|
||||
{FORMAT_CTRL, 0x00}, // YUV422
|
||||
{FORMAT_CTRL00, 0x10}, // Y8
|
||||
{REGLIST_TAIL, 0x00}
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_yuv422[][2] = {
|
||||
{FORMAT_CTRL, 0x00}, // YUV422
|
||||
{FORMAT_CTRL00, 0x30}, // YUYV
|
||||
{REGLIST_TAIL, 0x00}
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_rgb565[][2] = {
|
||||
{FORMAT_CTRL, 0x01}, // RGB
|
||||
{FORMAT_CTRL00, 0x61}, // RGB565 (BGR)
|
||||
{REGLIST_TAIL, 0x00}
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint8_t sensor_saturation_levels[9][11] = {
|
||||
{0x1d, 0x60, 0x03, 0x07, 0x48, 0x4f, 0x4b, 0x40, 0x0b, 0x01, 0x98},//-4
|
||||
{0x1d, 0x60, 0x03, 0x08, 0x54, 0x5c, 0x58, 0x4b, 0x0d, 0x01, 0x98},//-3
|
||||
{0x1d, 0x60, 0x03, 0x0a, 0x60, 0x6a, 0x64, 0x56, 0x0e, 0x01, 0x98},//-2
|
||||
{0x1d, 0x60, 0x03, 0x0b, 0x6c, 0x77, 0x70, 0x60, 0x10, 0x01, 0x98},//-1
|
||||
{0x1d, 0x60, 0x03, 0x0c, 0x78, 0x84, 0x7d, 0x6b, 0x12, 0x01, 0x98},//0
|
||||
{0x1d, 0x60, 0x03, 0x0d, 0x84, 0x91, 0x8a, 0x76, 0x14, 0x01, 0x98},//+1
|
||||
{0x1d, 0x60, 0x03, 0x0e, 0x90, 0x9e, 0x96, 0x80, 0x16, 0x01, 0x98},//+2
|
||||
{0x1d, 0x60, 0x03, 0x10, 0x9c, 0xac, 0xa2, 0x8b, 0x17, 0x01, 0x98},//+3
|
||||
{0x1d, 0x60, 0x03, 0x11, 0xa8, 0xb9, 0xaf, 0x96, 0x19, 0x01, 0x98},//+4
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint8_t sensor_special_effects[7][4] = {
|
||||
{0x06, 0x40, 0x2c, 0x08},//Normal
|
||||
{0x46, 0x40, 0x28, 0x08},//Negative
|
||||
{0x1e, 0x80, 0x80, 0x08},//Grayscale
|
||||
{0x1e, 0x80, 0xc0, 0x08},//Red Tint
|
||||
{0x1e, 0x60, 0x60, 0x08},//Green Tint
|
||||
{0x1e, 0xa0, 0x40, 0x08},//Blue Tint
|
||||
{0x1e, 0x40, 0xa0, 0x08},//Sepia
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
#ifndef __OV5640_H__
|
||||
#define __OV5640_H__
|
||||
|
||||
#include "sensor.h"
|
||||
|
||||
int ov5640_init(sensor_t *sensor);
|
||||
|
||||
#endif // __OV5640_H__
|
||||
@@ -1,213 +0,0 @@
|
||||
/*
|
||||
* OV5640 register definitions.
|
||||
*/
|
||||
#ifndef __OV5640_REG_REGS_H__
|
||||
#define __OV5640_REG_REGS_H__
|
||||
|
||||
/* system control registers */
|
||||
#define SYSTEM_CTROL0 0x3008 // Bit[7]: Software reset
|
||||
// Bit[6]: Software power down
|
||||
// Bit[5]: Reserved
|
||||
// Bit[4]: SRB clock SYNC enable
|
||||
// Bit[3]: Isolation suspend select
|
||||
// Bit[2:0]: Not used
|
||||
|
||||
#define DRIVE_CAPABILITY 0x302c // Bit[7:6]:
|
||||
// 00: 1x
|
||||
// 01: 2x
|
||||
// 10: 3x
|
||||
// 11: 4x
|
||||
|
||||
#define SC_PLLS_CTRL0 0x303a // Bit[7]: PLLS bypass
|
||||
#define SC_PLLS_CTRL1 0x303b // Bit[4:0]: PLLS multiplier
|
||||
#define SC_PLLS_CTRL2 0x303c // Bit[6:4]: PLLS charge pump control
|
||||
// Bit[3:0]: PLLS system divider
|
||||
#define SC_PLLS_CTRL3 0x303d // Bit[5:4]: PLLS pre-divider
|
||||
// 00: 1
|
||||
// 01: 1.5
|
||||
// 10: 2
|
||||
// 11: 3
|
||||
// Bit[2]: PLLS root-divider - 1
|
||||
// Bit[1:0]: PLLS seld5
|
||||
// 00: 1
|
||||
// 01: 1
|
||||
// 10: 2
|
||||
// 11: 2.5
|
||||
|
||||
/* AEC/AGC control functions */
|
||||
#define AEC_PK_MANUAL 0x3503 // AEC Manual Mode Control
|
||||
// Bit[7:6]: Reserved
|
||||
// Bit[5]: Gain delay option
|
||||
// Valid when 0x3503[4]=1’b0
|
||||
// 0: Delay one frame latch
|
||||
// 1: One frame latch
|
||||
// Bit[4:2]: Reserved
|
||||
// Bit[1]: AGC manual
|
||||
// 0: Auto enable
|
||||
// 1: Manual enable
|
||||
// Bit[0]: AEC manual
|
||||
// 0: Auto enable
|
||||
// 1: Manual enable
|
||||
|
||||
//gain = {0x350A[1:0], 0x350B[7:0]} / 16
|
||||
|
||||
|
||||
#define X_ADDR_ST_H 0x3800 //Bit[3:0]: X address start[11:8]
|
||||
#define X_ADDR_ST_L 0x3801 //Bit[7:0]: X address start[7:0]
|
||||
#define Y_ADDR_ST_H 0x3802 //Bit[2:0]: Y address start[10:8]
|
||||
#define Y_ADDR_ST_L 0x3803 //Bit[7:0]: Y address start[7:0]
|
||||
#define X_ADDR_END_H 0x3804 //Bit[3:0]: X address end[11:8]
|
||||
#define X_ADDR_END_L 0x3805 //Bit[7:0]:
|
||||
#define Y_ADDR_END_H 0x3806 //Bit[2:0]: Y address end[10:8]
|
||||
#define Y_ADDR_END_L 0x3807 //Bit[7:0]:
|
||||
// Size after scaling
|
||||
#define X_OUTPUT_SIZE_H 0x3808 //Bit[3:0]: DVP output horizontal width[11:8]
|
||||
#define X_OUTPUT_SIZE_L 0x3809 //Bit[7:0]:
|
||||
#define Y_OUTPUT_SIZE_H 0x380a //Bit[2:0]: DVP output vertical height[10:8]
|
||||
#define Y_OUTPUT_SIZE_L 0x380b //Bit[7:0]:
|
||||
#define X_TOTAL_SIZE_H 0x380c //Bit[3:0]: Total horizontal size[11:8]
|
||||
#define X_TOTAL_SIZE_L 0x380d //Bit[7:0]:
|
||||
#define Y_TOTAL_SIZE_H 0x380e //Bit[7:0]: Total vertical size[15:8]
|
||||
#define Y_TOTAL_SIZE_L 0x380f //Bit[7:0]:
|
||||
#define X_OFFSET_H 0x3810 //Bit[3:0]: ISP horizontal offset[11:8]
|
||||
#define X_OFFSET_L 0x3811 //Bit[7:0]:
|
||||
#define Y_OFFSET_H 0x3812 //Bit[2:0]: ISP vertical offset[10:8]
|
||||
#define Y_OFFSET_L 0x3813 //Bit[7:0]:
|
||||
#define X_INCREMENT 0x3814 //Bit[7:4]: Horizontal odd subsample increment
|
||||
//Bit[3:0]: Horizontal even subsample increment
|
||||
#define Y_INCREMENT 0x3815 //Bit[7:4]: Vertical odd subsample increment
|
||||
//Bit[3:0]: Vertical even subsample increment
|
||||
// Size before scaling
|
||||
//#define X_INPUT_SIZE (X_ADDR_END - X_ADDR_ST + 1 - (2 * X_OFFSET))
|
||||
//#define Y_INPUT_SIZE (Y_ADDR_END - Y_ADDR_ST + 1 - (2 * Y_OFFSET))
|
||||
|
||||
/* mirror and flip registers */
|
||||
#define TIMING_TC_REG20 0x3820 // Timing Control Register
|
||||
// Bit[2:1]: Vertical flip enable
|
||||
// 00: Normal
|
||||
// 11: Vertical flip
|
||||
// Bit[0]: Vertical binning enable
|
||||
#define TIMING_TC_REG21 0x3821 // Timing Control Register
|
||||
// Bit[5]: Compression Enable
|
||||
// Bit[2:1]: Horizontal mirror enable
|
||||
// 00: Normal
|
||||
// 11: Horizontal mirror
|
||||
// Bit[0]: Horizontal binning enable
|
||||
|
||||
#define PCLK_RATIO 0x3824 // Bit[4:0]: PCLK ratio manual
|
||||
|
||||
/* frame control registers */
|
||||
#define FRAME_CTRL01 0x4201 // Control Passed Frame Number When both ON and OFF number set to 0x00,frame control is in bypass mode
|
||||
// Bit[7:4]: Not used
|
||||
// Bit[3:0]: Frame ON number
|
||||
#define FRAME_CTRL02 0x4202 // Control Masked Frame Number When both ON and OFF number set to 0x00,frame control is in bypass mode
|
||||
// Bit[7:4]: Not used
|
||||
// BIT[3:0]: Frame OFF number
|
||||
|
||||
/* format control registers */
|
||||
#define FORMAT_CTRL00 0x4300
|
||||
|
||||
#define CLOCK_POL_CONTROL 0x4740// Bit[5]: PCLK polarity 0: active low
|
||||
// 1: active high
|
||||
// Bit[3]: Gate PCLK under VSYNC
|
||||
// Bit[2]: Gate PCLK under HREF
|
||||
// Bit[1]: HREF polarity
|
||||
// 0: active low
|
||||
// 1: active high
|
||||
// Bit[0] VSYNC polarity
|
||||
// 0: active low
|
||||
// 1: active high
|
||||
|
||||
#define ISP_CONTROL_01 0x5001 // Bit[5]: Scale enable
|
||||
// 0: Disable
|
||||
// 1: Enable
|
||||
|
||||
/* output format control registers */
|
||||
#define FORMAT_CTRL 0x501F // Format select
|
||||
// Bit[2:0]:
|
||||
// 000: YUV422
|
||||
// 001: RGB
|
||||
// 010: Dither
|
||||
// 011: RAW after DPC
|
||||
// 101: RAW after CIP
|
||||
|
||||
/* ISP top control registers */
|
||||
#define PRE_ISP_TEST_SETTING_1 0x503D // Bit[7]: Test enable
|
||||
// 0: Test disable
|
||||
// 1: Color bar enable
|
||||
// Bit[6]: Rolling
|
||||
// Bit[5]: Transparent
|
||||
// Bit[4]: Square black and white
|
||||
// Bit[3:2]: Color bar style
|
||||
// 00: Standard 8 color bar
|
||||
// 01: Gradual change at vertical mode 1
|
||||
// 10: Gradual change at horizontal
|
||||
// 11: Gradual change at vertical mode 2
|
||||
// Bit[1:0]: Test select
|
||||
// 00: Color bar
|
||||
// 01: Random data
|
||||
// 10: Square data
|
||||
// 11: Black image
|
||||
|
||||
//exposure = {0x3500[3:0], 0x3501[7:0], 0x3502[7:0]} / 16 × tROW
|
||||
|
||||
#define SCALE_CTRL_1 0x5601 // Bit[6:4]: HDIV RW
|
||||
// DCW scale times
|
||||
// 000: DCW 1 time
|
||||
// 001: DCW 2 times
|
||||
// 010: DCW 4 times
|
||||
// 100: DCW 8 times
|
||||
// 101: DCW 16 times
|
||||
// Others: DCW 16 times
|
||||
// Bit[2:0]: VDIV RW
|
||||
// DCW scale times
|
||||
// 000: DCW 1 time
|
||||
// 001: DCW 2 times
|
||||
// 010: DCW 4 times
|
||||
// 100: DCW 8 times
|
||||
// 101: DCW 16 times
|
||||
// Others: DCW 16 times
|
||||
|
||||
#define SCALE_CTRL_2 0x5602 // X_SCALE High Bits
|
||||
#define SCALE_CTRL_3 0x5603 // X_SCALE Low Bits
|
||||
#define SCALE_CTRL_4 0x5604 // Y_SCALE High Bits
|
||||
#define SCALE_CTRL_5 0x5605 // Y_SCALE Low Bits
|
||||
#define SCALE_CTRL_6 0x5606 // Bit[3:0]: V Offset
|
||||
|
||||
#define VFIFO_CTRL0C 0x460C // Bit[1]: PCLK manual enable
|
||||
// 0: Auto
|
||||
// 1: Manual by PCLK_RATIO
|
||||
|
||||
#define VFIFO_X_SIZE_H 0x4602
|
||||
#define VFIFO_X_SIZE_L 0x4603
|
||||
#define VFIFO_Y_SIZE_H 0x4604
|
||||
#define VFIFO_Y_SIZE_L 0x4605
|
||||
|
||||
#define COMPRESSION_CTRL00 0x4400 //
|
||||
#define COMPRESSION_CTRL01 0x4401 //
|
||||
#define COMPRESSION_CTRL02 0x4402 //
|
||||
#define COMPRESSION_CTRL03 0x4403 //
|
||||
#define COMPRESSION_CTRL04 0x4404 //
|
||||
#define COMPRESSION_CTRL05 0x4405 //
|
||||
#define COMPRESSION_CTRL06 0x4406 //
|
||||
#define COMPRESSION_CTRL07 0x4407 // Bit[5:0]: QS
|
||||
#define COMPRESSION_ISI_CTRL 0x4408 //
|
||||
#define COMPRESSION_CTRL09 0x4409 //
|
||||
#define COMPRESSION_CTRL0a 0x440a //
|
||||
#define COMPRESSION_CTRL0b 0x440b //
|
||||
#define COMPRESSION_CTRL0c 0x440c //
|
||||
#define COMPRESSION_CTRL0d 0x440d //
|
||||
#define COMPRESSION_CTRL0E 0x440e //
|
||||
|
||||
/**
|
||||
* @brief register value
|
||||
*/
|
||||
#define TEST_COLOR_BAR 0xC0 /* Enable Color Bar roling Test */
|
||||
|
||||
#define AEC_PK_MANUAL_AGC_MANUALEN 0x02 /* Enable AGC Manual enable */
|
||||
#define AEC_PK_MANUAL_AEC_MANUALEN 0x01 /* Enable AEC Manual enable */
|
||||
|
||||
#define TIMING_TC_REG20_VFLIP 0x06 /* Vertical flip enable */
|
||||
#define TIMING_TC_REG21_HMIRROR 0x06 /* Horizontal mirror enable */
|
||||
|
||||
#endif // __OV3660_REG_REGS_H__
|
||||
@@ -1,334 +0,0 @@
|
||||
#ifndef _OV5640_SETTINGS_H_
|
||||
#define _OV5640_SETTINGS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_attr.h"
|
||||
#include "ov5640_regs.h"
|
||||
|
||||
static const ratio_settings_t ratio_table[] = {
|
||||
// mw, mh, sx, sy, ex, ey, ox, oy, tx, ty
|
||||
{ 2560, 1920, 0, 0, 2623, 1951, 32, 16, 2844, 1968 }, //4x3
|
||||
{ 2560, 1704, 0, 110, 2623, 1843, 32, 16, 2844, 1752 }, //3x2
|
||||
{ 2560, 1600, 0, 160, 2623, 1791, 32, 16, 2844, 1648 }, //16x10
|
||||
{ 2560, 1536, 0, 192, 2623, 1759, 32, 16, 2844, 1584 }, //5x3
|
||||
{ 2560, 1440, 0, 240, 2623, 1711, 32, 16, 2844, 1488 }, //16x9
|
||||
{ 2560, 1080, 0, 420, 2623, 1531, 32, 16, 2844, 1128 }, //21x9
|
||||
{ 2400, 1920, 80, 0, 2543, 1951, 32, 16, 2684, 1968 }, //5x4
|
||||
{ 1920, 1920, 320, 0, 2543, 1951, 32, 16, 2684, 1968 }, //1x1
|
||||
{ 1088, 1920, 736, 0, 1887, 1951, 32, 16, 1884, 1968 } //9x16
|
||||
};
|
||||
|
||||
#define REG_DLY 0xffff
|
||||
#define REGLIST_TAIL 0x0000
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_default_regs[][2] = {
|
||||
{SYSTEM_CTROL0, 0x82}, // software reset
|
||||
{REG_DLY, 10}, // delay 10ms
|
||||
{SYSTEM_CTROL0, 0x42}, // power down
|
||||
|
||||
//enable pll
|
||||
{0x3103, 0x13},
|
||||
|
||||
//io direction
|
||||
{0x3017, 0xff},
|
||||
{0x3018, 0xff},
|
||||
|
||||
{DRIVE_CAPABILITY, 0xc3},
|
||||
{CLOCK_POL_CONTROL, 0x21},
|
||||
|
||||
{0x4713, 0x02},//jpg mode select
|
||||
|
||||
{ISP_CONTROL_01, 0x83}, // turn color matrix, awb and SDE
|
||||
|
||||
//sys reset
|
||||
{0x3000, 0x00},
|
||||
{0x3002, 0x1c},
|
||||
|
||||
//clock enable
|
||||
{0x3004, 0xff},
|
||||
{0x3006, 0xc3},
|
||||
|
||||
//isp control
|
||||
{0x5000, 0xa7},
|
||||
{ISP_CONTROL_01, 0xa3},//+scaling?
|
||||
{0x5003, 0x08},//special_effect
|
||||
|
||||
//unknown
|
||||
{0x370c, 0x02},//!!IMPORTANT
|
||||
{0x3634, 0x40},//!!IMPORTANT
|
||||
|
||||
//AEC/AGC
|
||||
{0x3a02, 0x03},
|
||||
{0x3a03, 0xd8},
|
||||
{0x3a08, 0x01},
|
||||
{0x3a09, 0x27},
|
||||
{0x3a0a, 0x00},
|
||||
{0x3a0b, 0xf6},
|
||||
{0x3a0d, 0x04},
|
||||
{0x3a0e, 0x03},
|
||||
{0x3a0f, 0x30},//ae_level
|
||||
{0x3a10, 0x28},//ae_level
|
||||
{0x3a11, 0x60},//ae_level
|
||||
{0x3a13, 0x43},
|
||||
{0x3a14, 0x03},
|
||||
{0x3a15, 0xd8},
|
||||
{0x3a18, 0x00},//gainceiling
|
||||
{0x3a19, 0xf8},//gainceiling
|
||||
{0x3a1b, 0x30},//ae_level
|
||||
{0x3a1e, 0x26},//ae_level
|
||||
{0x3a1f, 0x14},//ae_level
|
||||
|
||||
//vcm debug
|
||||
{0x3600, 0x08},
|
||||
{0x3601, 0x33},
|
||||
|
||||
//50/60Hz
|
||||
{0x3c01, 0xa4},
|
||||
{0x3c04, 0x28},
|
||||
{0x3c05, 0x98},
|
||||
{0x3c06, 0x00},
|
||||
{0x3c07, 0x08},
|
||||
{0x3c08, 0x00},
|
||||
{0x3c09, 0x1c},
|
||||
{0x3c0a, 0x9c},
|
||||
{0x3c0b, 0x40},
|
||||
|
||||
{0x460c, 0x22},//disable jpeg footer
|
||||
|
||||
//BLC
|
||||
{0x4001, 0x02},
|
||||
{0x4004, 0x02},
|
||||
|
||||
//AWB
|
||||
{0x5180, 0xff},
|
||||
{0x5181, 0xf2},
|
||||
{0x5182, 0x00},
|
||||
{0x5183, 0x14},
|
||||
{0x5184, 0x25},
|
||||
{0x5185, 0x24},
|
||||
{0x5186, 0x09},
|
||||
{0x5187, 0x09},
|
||||
{0x5188, 0x09},
|
||||
{0x5189, 0x75},
|
||||
{0x518a, 0x54},
|
||||
{0x518b, 0xe0},
|
||||
{0x518c, 0xb2},
|
||||
{0x518d, 0x42},
|
||||
{0x518e, 0x3d},
|
||||
{0x518f, 0x56},
|
||||
{0x5190, 0x46},
|
||||
{0x5191, 0xf8},
|
||||
{0x5192, 0x04},
|
||||
{0x5193, 0x70},
|
||||
{0x5194, 0xf0},
|
||||
{0x5195, 0xf0},
|
||||
{0x5196, 0x03},
|
||||
{0x5197, 0x01},
|
||||
{0x5198, 0x04},
|
||||
{0x5199, 0x12},
|
||||
{0x519a, 0x04},
|
||||
{0x519b, 0x00},
|
||||
{0x519c, 0x06},
|
||||
{0x519d, 0x82},
|
||||
{0x519e, 0x38},
|
||||
|
||||
//color matrix (Saturation)
|
||||
{0x5381, 0x1e},
|
||||
{0x5382, 0x5b},
|
||||
{0x5383, 0x08},
|
||||
{0x5384, 0x0a},
|
||||
{0x5385, 0x7e},
|
||||
{0x5386, 0x88},
|
||||
{0x5387, 0x7c},
|
||||
{0x5388, 0x6c},
|
||||
{0x5389, 0x10},
|
||||
{0x538a, 0x01},
|
||||
{0x538b, 0x98},
|
||||
|
||||
//CIP control (Sharpness)
|
||||
{0x5300, 0x10},//sharpness
|
||||
{0x5301, 0x10},//sharpness
|
||||
{0x5302, 0x18},//sharpness
|
||||
{0x5303, 0x19},//sharpness
|
||||
{0x5304, 0x10},
|
||||
{0x5305, 0x10},
|
||||
{0x5306, 0x08},//denoise
|
||||
{0x5307, 0x16},
|
||||
{0x5308, 0x40},
|
||||
{0x5309, 0x10},//sharpness
|
||||
{0x530a, 0x10},//sharpness
|
||||
{0x530b, 0x04},//sharpness
|
||||
{0x530c, 0x06},//sharpness
|
||||
|
||||
//GAMMA
|
||||
{0x5480, 0x01},
|
||||
{0x5481, 0x00},
|
||||
{0x5482, 0x1e},
|
||||
{0x5483, 0x3b},
|
||||
{0x5484, 0x58},
|
||||
{0x5485, 0x66},
|
||||
{0x5486, 0x71},
|
||||
{0x5487, 0x7d},
|
||||
{0x5488, 0x83},
|
||||
{0x5489, 0x8f},
|
||||
{0x548a, 0x98},
|
||||
{0x548b, 0xa6},
|
||||
{0x548c, 0xb8},
|
||||
{0x548d, 0xca},
|
||||
{0x548e, 0xd7},
|
||||
{0x548f, 0xe3},
|
||||
{0x5490, 0x1d},
|
||||
|
||||
//Special Digital Effects (SDE) (UV adjust)
|
||||
{0x5580, 0x06},//enable brightness and contrast
|
||||
{0x5583, 0x40},//special_effect
|
||||
{0x5584, 0x10},//special_effect
|
||||
{0x5586, 0x20},//contrast
|
||||
{0x5587, 0x00},//brightness
|
||||
{0x5588, 0x00},//brightness
|
||||
{0x5589, 0x10},
|
||||
{0x558a, 0x00},
|
||||
{0x558b, 0xf8},
|
||||
{0x501d, 0x40},// enable manual offset of contrast
|
||||
|
||||
//power on
|
||||
{0x3008, 0x02},
|
||||
|
||||
//50Hz
|
||||
{0x3c00, 0x04},
|
||||
|
||||
{REG_DLY, 300},
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_jpeg[][2] = {
|
||||
{FORMAT_CTRL, 0x00}, // YUV422
|
||||
{FORMAT_CTRL00, 0x30}, // YUYV
|
||||
{0x3002, 0x00},//0x1c to 0x00 !!!
|
||||
{0x3006, 0xff},//0xc3 to 0xff !!!
|
||||
{0x471c, 0x50},//0xd0 to 0x50 !!!
|
||||
{REGLIST_TAIL, 0x00}, // tail
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_raw[][2] = {
|
||||
{FORMAT_CTRL, 0x03}, // RAW (DPC)
|
||||
{FORMAT_CTRL00, 0x00}, // RAW
|
||||
{REGLIST_TAIL, 0x00}
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_grayscale[][2] = {
|
||||
{FORMAT_CTRL, 0x00}, // YUV422
|
||||
{FORMAT_CTRL00, 0x10}, // Y8
|
||||
{REGLIST_TAIL, 0x00}
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_yuv422[][2] = {
|
||||
{FORMAT_CTRL, 0x00}, // YUV422
|
||||
{FORMAT_CTRL00, 0x30}, // YUYV
|
||||
{REGLIST_TAIL, 0x00}
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_fmt_rgb565[][2] = {
|
||||
{FORMAT_CTRL, 0x01}, // RGB
|
||||
{FORMAT_CTRL00, 0x61}, // RGB565 (BGR)
|
||||
{REGLIST_TAIL, 0x00}
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint8_t sensor_saturation_levels[9][11] = {
|
||||
{0x1d, 0x60, 0x03, 0x07, 0x48, 0x4f, 0x4b, 0x40, 0x0b, 0x01, 0x98},//-4
|
||||
{0x1d, 0x60, 0x03, 0x08, 0x54, 0x5c, 0x58, 0x4b, 0x0d, 0x01, 0x98},//-3
|
||||
{0x1d, 0x60, 0x03, 0x0a, 0x60, 0x6a, 0x64, 0x56, 0x0e, 0x01, 0x98},//-2
|
||||
{0x1d, 0x60, 0x03, 0x0b, 0x6c, 0x77, 0x70, 0x60, 0x10, 0x01, 0x98},//-1
|
||||
{0x1d, 0x60, 0x03, 0x0c, 0x78, 0x84, 0x7d, 0x6b, 0x12, 0x01, 0x98},//0
|
||||
{0x1d, 0x60, 0x03, 0x0d, 0x84, 0x91, 0x8a, 0x76, 0x14, 0x01, 0x98},//+1
|
||||
{0x1d, 0x60, 0x03, 0x0e, 0x90, 0x9e, 0x96, 0x80, 0x16, 0x01, 0x98},//+2
|
||||
{0x1d, 0x60, 0x03, 0x10, 0x9c, 0xac, 0xa2, 0x8b, 0x17, 0x01, 0x98},//+3
|
||||
{0x1d, 0x60, 0x03, 0x11, 0xa8, 0xb9, 0xaf, 0x96, 0x19, 0x01, 0x98},//+4
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint8_t sensor_special_effects[7][4] = {
|
||||
{0x06, 0x40, 0x2c, 0x08},//Normal
|
||||
{0x46, 0x40, 0x28, 0x08},//Negative
|
||||
{0x1e, 0x80, 0x80, 0x08},//Grayscale
|
||||
{0x1e, 0x80, 0xc0, 0x08},//Red Tint
|
||||
{0x1e, 0x60, 0x60, 0x08},//Green Tint
|
||||
{0x1e, 0xa0, 0x40, 0x08},//Blue Tint
|
||||
{0x1e, 0x40, 0xa0, 0x08},//Sepia
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_regs_gamma0[][2] = {
|
||||
{0x5480, 0x01},
|
||||
{0x5481, 0x08},
|
||||
{0x5482, 0x14},
|
||||
{0x5483, 0x28},
|
||||
{0x5484, 0x51},
|
||||
{0x5485, 0x65},
|
||||
{0x5486, 0x71},
|
||||
{0x5487, 0x7d},
|
||||
{0x5488, 0x87},
|
||||
{0x5489, 0x91},
|
||||
{0x548a, 0x9a},
|
||||
{0x548b, 0xaa},
|
||||
{0x548c, 0xb8},
|
||||
{0x548d, 0xcd},
|
||||
{0x548e, 0xdd},
|
||||
{0x548f, 0xea},
|
||||
{0x5490, 0x1d}
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_regs_gamma1[][2] = {
|
||||
{0x5480, 0x1},
|
||||
{0x5481, 0x0},
|
||||
{0x5482, 0x1e},
|
||||
{0x5483, 0x3b},
|
||||
{0x5484, 0x58},
|
||||
{0x5485, 0x66},
|
||||
{0x5486, 0x71},
|
||||
{0x5487, 0x7d},
|
||||
{0x5488, 0x83},
|
||||
{0x5489, 0x8f},
|
||||
{0x548a, 0x98},
|
||||
{0x548b, 0xa6},
|
||||
{0x548c, 0xb8},
|
||||
{0x548d, 0xca},
|
||||
{0x548e, 0xd7},
|
||||
{0x548f, 0xe3},
|
||||
{0x5490, 0x1d}
|
||||
};
|
||||
|
||||
static const DRAM_ATTR uint16_t sensor_regs_awb0[][2] = {
|
||||
{0x5180, 0xff},
|
||||
{0x5181, 0xf2},
|
||||
{0x5182, 0x00},
|
||||
{0x5183, 0x14},
|
||||
{0x5184, 0x25},
|
||||
{0x5185, 0x24},
|
||||
{0x5186, 0x09},
|
||||
{0x5187, 0x09},
|
||||
{0x5188, 0x09},
|
||||
{0x5189, 0x75},
|
||||
{0x518a, 0x54},
|
||||
{0x518b, 0xe0},
|
||||
{0x518c, 0xb2},
|
||||
{0x518d, 0x42},
|
||||
{0x518e, 0x3d},
|
||||
{0x518f, 0x56},
|
||||
{0x5190, 0x46},
|
||||
{0x5191, 0xf8},
|
||||
{0x5192, 0x04},
|
||||
{0x5193, 0x70},
|
||||
{0x5194, 0xf0},
|
||||
{0x5195, 0xf0},
|
||||
{0x5196, 0x03},
|
||||
{0x5197, 0x01},
|
||||
{0x5198, 0x04},
|
||||
{0x5199, 0x12},
|
||||
{0x519a, 0x04},
|
||||
{0x519b, 0x00},
|
||||
{0x519c, 0x06},
|
||||
{0x519d, 0x82},
|
||||
{0x519e, 0x38}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,14 +0,0 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* author: Juan Schiavoni <juanjoseschiavoni@hotmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* OV7670 driver.
|
||||
*
|
||||
*/
|
||||
#ifndef __OV7670_H__
|
||||
#define __OV7670_H__
|
||||
#include "sensor.h"
|
||||
|
||||
int ov7670_init(sensor_t *sensor);
|
||||
#endif // __OV7670_H__
|
||||
@@ -1,354 +0,0 @@
|
||||
/*
|
||||
* This file is for the OpenMV project so the OV7670 can be used
|
||||
* author: Juan Schiavoni <juanjoseschiavoni@hotmail.com>
|
||||
*
|
||||
* OV7670 register definitions.
|
||||
*/
|
||||
#ifndef __OV7670_REG_REGS_H__
|
||||
#define __OV7670_REG_REGS_H__
|
||||
#define GAIN 0x00 /* AGC – Gain control gain setting */
|
||||
#define BLUE 0x01 /* AWB – Blue channel gain setting */
|
||||
#define RED 0x02 /* AWB – Red channel gain setting */
|
||||
#define VREF 0x03 /* AWB – Green channel gain setting */
|
||||
#define COM1 0x04 /* Common Control 1 */
|
||||
#define BAVG 0x05 /* U/B Average Level */
|
||||
#define GAVG 0x06 /* Y/Gb Average Level */
|
||||
#define AECH 0x07 /* Exposure VAlue - AEC MSB 5 bits */
|
||||
#define RAVG 0x08 /* V/R Average Level */
|
||||
|
||||
#define COM2 0x09 /* Common Control 2 */
|
||||
#define COM2_SOFT_SLEEP 0x10 /* Soft sleep mode */
|
||||
#define COM2_OUT_DRIVE_1x 0x00 /* Output drive capability 1x */
|
||||
#define COM2_OUT_DRIVE_2x 0x01 /* Output drive capability 2x */
|
||||
#define COM2_OUT_DRIVE_3x 0x02 /* Output drive capability 3x */
|
||||
#define COM2_OUT_DRIVE_4x 0x03 /* Output drive capability 4x */
|
||||
|
||||
#define REG_PID 0x0A /* Product ID Number MSB */
|
||||
#define REG_VER 0x0B /* Product ID Number LSB */
|
||||
|
||||
#define COM3 0x0C /* Common Control 3 */
|
||||
#define COM3_SWAP_OUT 0x40 /* Output data MSB/LSB swap */
|
||||
#define COM3_TRI_CLK 0x20 /* Tri-state output clock */
|
||||
#define COM3_TRI_DATA 0x10 /* Tri-state option output */
|
||||
#define COM3_SCALE_EN 0x08 /* Scale enable */
|
||||
#define COM3_DCW 0x04 /* DCW enable */
|
||||
|
||||
#define COM4 0x0D /* Common Control 4 */
|
||||
#define COM4_PLL_BYPASS 0x00 /* Bypass PLL */
|
||||
#define COM4_PLL_4x 0x40 /* PLL frequency 4x */
|
||||
#define COM4_PLL_6x 0x80 /* PLL frequency 6x */
|
||||
#define COM4_PLL_8x 0xc0 /* PLL frequency 8x */
|
||||
#define COM4_AEC_FULL 0x00 /* AEC evaluate full window */
|
||||
#define COM4_AEC_1_2 0x10 /* AEC evaluate 1/2 window */
|
||||
#define COM4_AEC_1_4 0x20 /* AEC evaluate 1/4 window */
|
||||
#define COM4_AEC_2_3 0x30 /* AEC evaluate 2/3 window */
|
||||
|
||||
#define COM5 0x0E /* Common Control 5 */
|
||||
#define COM5_AFR 0x80 /* Auto frame rate control ON/OFF selection (night mode) */
|
||||
#define COM5_AFR_SPEED 0x40 /* Auto frame rate control speed selection */
|
||||
#define COM5_AFR_0 0x00 /* No reduction of frame rate */
|
||||
#define COM5_AFR_1_2 0x10 /* Max reduction to 1/2 frame rate */
|
||||
#define COM5_AFR_1_4 0x20 /* Max reduction to 1/4 frame rate */
|
||||
#define COM5_AFR_1_8 0x30 /* Max reduction to 1/8 frame rate */
|
||||
#define COM5_AFR_4x 0x04 /* Add frame when AGC reaches 4x gain */
|
||||
#define COM5_AFR_8x 0x08 /* Add frame when AGC reaches 8x gain */
|
||||
#define COM5_AFR_16x 0x0c /* Add frame when AGC reaches 16x gain */
|
||||
#define COM5_AEC_NO_LIMIT 0x01 /* No limit to AEC increase step */
|
||||
|
||||
#define COM6 0x0F /* Common Control 6 */
|
||||
#define COM6_AUTO_WINDOW 0x01 /* Auto window setting ON/OFF selection when format changes */
|
||||
|
||||
#define AEC 0x10 /* AEC[7:0] (see register AECH for AEC[15:8]) */
|
||||
#define CLKRC 0x11 /* Internal Clock */
|
||||
|
||||
#define COM7 0x12 /* Common Control 7 */
|
||||
#define COM7_RESET 0x80 /* SCCB Register Reset */
|
||||
#define COM7_RES_VGA 0x00 /* Resolution VGA */
|
||||
#define COM7_RES_QVGA 0x40 /* Resolution QVGA */
|
||||
#define COM7_BT656 0x20 /* BT.656 protocol ON/OFF */
|
||||
#define COM7_SENSOR_RAW 0x10 /* Sensor RAW */
|
||||
#define COM7_FMT_GBR422 0x00 /* RGB output format GBR422 */
|
||||
#define COM7_FMT_RGB565 0x04 /* RGB output format RGB565 */
|
||||
#define COM7_FMT_RGB555 0x08 /* RGB output format RGB555 */
|
||||
#define COM7_FMT_RGB444 0x0C /* RGB output format RGB444 */
|
||||
#define COM7_FMT_YUV 0x00 /* Output format YUV */
|
||||
#define COM7_FMT_P_BAYER 0x01 /* Output format Processed Bayer RAW */
|
||||
#define COM7_FMT_RGB 0x04 /* Output format RGB */
|
||||
#define COM7_FMT_R_BAYER 0x03 /* Output format Bayer RAW */
|
||||
#define COM7_SET_FMT(r, x) ((r&0xFC)|((x&0x5)<<0))
|
||||
|
||||
#define COM8 0x13 /* Common Control 8 */
|
||||
#define COM8_FAST_AUTO 0x80 /* Enable fast AGC/AEC algorithm */
|
||||
#define COM8_STEP_VSYNC 0x00 /* AEC - Step size limited to vertical blank */
|
||||
#define COM8_STEP_UNLIMIT 0x40 /* AEC - Step size unlimited step size */
|
||||
#define COM8_BANDF_EN 0x20 /* Banding filter ON/OFF */
|
||||
#define COM8_AEC_BANDF 0x10 /* Enable AEC below banding value */
|
||||
#define COM8_AEC_FINE_EN 0x08 /* Fine AEC ON/OFF control */
|
||||
#define COM8_AGC_EN 0x04 /* AGC Enable */
|
||||
#define COM8_AWB_EN 0x02 /* AWB Enable */
|
||||
#define COM8_AEC_EN 0x01 /* AEC Enable */
|
||||
#define COM8_SET_AGC(r, x) ((r&0xFB)|((x&0x1)<<2))
|
||||
#define COM8_SET_AWB(r, x) ((r&0xFD)|((x&0x1)<<1))
|
||||
#define COM8_SET_AEC(r, x) ((r&0xFE)|((x&0x1)<<0))
|
||||
|
||||
#define COM9 0x14 /* Common Control 9 */
|
||||
#define COM9_HISTO_AVG 0x80 /* Histogram or average based AEC/AGC selection */
|
||||
#define COM9_AGC_GAIN_2x 0x00 /* Automatic Gain Ceiling 2x */
|
||||
#define COM9_AGC_GAIN_4x 0x10 /* Automatic Gain Ceiling 4x */
|
||||
#define COM9_AGC_GAIN_8x 0x20 /* Automatic Gain Ceiling 8x */
|
||||
#define COM9_AGC_GAIN_16x 0x30 /* Automatic Gain Ceiling 16x */
|
||||
#define COM9_AGC_GAIN_32x 0x40 /* Automatic Gain Ceiling 32x */
|
||||
#define COM9_DROP_VSYNC 0x04 /* Drop VSYNC output of corrupt frame */
|
||||
#define COM9_DROP_HREF 0x02 /* Drop HREF output of corrupt frame */
|
||||
#define COM9_SET_AGC(r, x) ((r&0x8F)|((x&0x07)<<4))
|
||||
|
||||
#define COM10 0x15 /* Common Control 10 */
|
||||
#define COM10_NEGATIVE 0x80 /* Output negative data */
|
||||
#define COM10_HSYNC_EN 0x40 /* HREF changes to HSYNC */
|
||||
#define COM10_PCLK_FREE 0x00 /* PCLK output option: free running PCLK */
|
||||
#define COM10_PCLK_MASK 0x20 /* PCLK output option: masked during horizontal blank */
|
||||
#define COM10_PCLK_REV 0x10 /* PCLK reverse */
|
||||
#define COM10_HREF_REV 0x08 /* HREF reverse */
|
||||
#define COM10_VSYNC_FALLING 0x00 /* VSYNC changes on falling edge of PCLK */
|
||||
#define COM10_VSYNC_RISING 0x04 /* VSYNC changes on rising edge of PCLK */
|
||||
#define COM10_VSYNC_NEG 0x02 /* VSYNC negative */
|
||||
#define COM10_OUT_RANGE_8 0x01 /* Output data range: Full range */
|
||||
#define COM10_OUT_RANGE_10 0x00 /* Output data range: Data from [10] to [F0] (8 MSBs) */
|
||||
|
||||
#define RSVD_16 0x16 /* Reserved register */
|
||||
|
||||
#define HSTART 0x17 /* Horizontal Frame (HREF column) Start high 8-bit(low 3 bits are at HREF[2:0]) */
|
||||
#define HSTOP 0x18 /* Horizontal Frame (HREF column) end high 8-bit (low 3 bits are at HREF[5:3]) */
|
||||
#define VSTART 0x19 /* Vertical Frame (row) Start high 8-bit (low 2 bits are at VREF[1:0]) */
|
||||
#define VSTOP 0x1A /* Vertical Frame (row) End high 8-bit (low 2 bits are at VREF[3:2]) */
|
||||
#define PSHFT 0x1B /* Data Format - Pixel Delay Select */
|
||||
#define REG_MIDH 0x1C /* Manufacturer ID Byte – High */
|
||||
#define REG_MIDL 0x1D /* Manufacturer ID Byte – Low */
|
||||
|
||||
#define MVFP 0x1E /* Mirror/Vflip Enable */
|
||||
#define MVFP_MIRROR 0x20 /* Mirror image */
|
||||
#define MVFP_FLIP 0x10 /* Vertical flip */
|
||||
#define MVFP_SUN 0x02 /* Black sun enable */
|
||||
#define MVFP_SET_MIRROR(r,x) ((r&0xDF)|((x&1)<<5)) /* change only bit5 according to x */
|
||||
#define MVFP_SET_FLIP(r,x) ((r&0xEF)|((x&1)<<4)) /* change only bit4 according to x */
|
||||
|
||||
#define LAEC 0x1F /* Fine AEC Value - defines exposure value less than one row period (Reserved?) */
|
||||
#define ADCCTR0 0x20 /* ADC control */
|
||||
#define ADCCTR1 0x21 /* reserved */
|
||||
#define ADCCTR2 0x22 /* reserved */
|
||||
#define ADCCTR3 0x23 /* reserved */
|
||||
#define AEW 0x24 /* AGC/AEC - Stable Operating Region (Upper Limit) */
|
||||
#define AEB 0x25 /* AGC/AEC - Stable Operating Region (Lower Limit) */
|
||||
#define VPT 0x26 /* AGC/AEC Fast Mode Operating Region */
|
||||
#define BBIAS 0x27 /* B channel signal output bias (effective only when COM6[3]=1) */
|
||||
#define GbBIAS 0x28 /* Gb channel signal output bias (effective only when COM6[3]=1) */
|
||||
#define RSVD_29 0x29 /* reserved */
|
||||
#define EXHCH 0x2A /* Dummy Pixel Insert MSB */
|
||||
#define EXHCL 0x2B /* Dummy Pixel Insert LSB */
|
||||
#define RBIAS 0x2C /* R channel signal output bias (effective only when COM6[3]=1) */
|
||||
#define ADVFL 0x2D /* LSB of Insert Dummy Rows in Vertical Sync (1 bit equals 1 row) */
|
||||
#define ADVFH 0x2E /* MSB of Insert Dummy Rows in Vertical Sync */
|
||||
#define YAVE 0x2F /* Y/G Channel Average Value */
|
||||
#define HSYST 0x30 /* HSync rising edge delay */
|
||||
#define HSYEN 0x31 /* HSync falling edge delay */
|
||||
#define HREF 0x32 /* Image Start and Size Control DIFFERENT CONTROL SEQUENCE */
|
||||
#define CHLF 0x33 /* Array Current control */
|
||||
#define ARBLM 0x34 /* Array reference control */
|
||||
#define RSVD_35 0x35 /* Reserved */
|
||||
#define RSVD_36 0x36 /* Reserved */
|
||||
#define ADC 0x37 /* ADC control */
|
||||
#define ACOM 0x38 /* ADC and analog common mode control */
|
||||
#define OFON 0x39 /* ADC offset control */
|
||||
#define TSLB 0x3A /* Line buffer test option */
|
||||
|
||||
#define COM11 0x3B /* Common control 11 */
|
||||
#define COM11_EXP 0x02
|
||||
#define COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */
|
||||
|
||||
#define COM12 0x3C /* Common control 12 */
|
||||
|
||||
#define COM13 0x3D /* Common control 13 */
|
||||
#define COM13_GAMMA 0x80 /* Gamma enable */
|
||||
#define COM13_UVSAT 0x40 /* UV saturation auto adjustment */
|
||||
|
||||
#define COM14 0x3E /* Common Control 14 */
|
||||
|
||||
#define EDGE 0x3F /* edge enhancement adjustment */
|
||||
#define COM15 0x40 /* Common Control 15 DIFFERENT CONTROLS */
|
||||
#define COM15_SET_RGB565(r,x) ((r&0xEF)|((x&1)<<4)) /* set rgb565 mode */
|
||||
#define COM15_RGB565 0x10 /* RGB565 output */
|
||||
#define COM15_R00FF 0xC0 /* Output range: [00] to [FF] */
|
||||
|
||||
#define COM16 0x41 /* Common Control 16 DIFFERENT CONTROLS */
|
||||
#define COM16_AWBGAIN 0x08 /* AWB gain enable */
|
||||
#define COM17 0x42 /* Common Control 17 */
|
||||
|
||||
#define AWBC1 0x43 /* Reserved */
|
||||
#define AWBC2 0x44 /* Reserved */
|
||||
#define AWBC3 0x45 /* Reserved */
|
||||
#define AWBC4 0x46 /* Reserved */
|
||||
#define AWBC5 0x47 /* Reserved */
|
||||
#define AWBC6 0x48 /* Reserved */
|
||||
|
||||
#define RSVD_49 0x49 /* Reserved */
|
||||
#define RSVD_4A 0x4A /* Reserved */
|
||||
|
||||
#define REG4B 0x4B /* Register 4B */
|
||||
#define DNSTH 0x4C /* Denoise strength */
|
||||
|
||||
#define RSVD_4D 0x4D /* Reserved */
|
||||
#define RSVD_4E 0x4E /* Reserved */
|
||||
|
||||
#define MTX1 0x4F /* Matrix coefficient 1 */
|
||||
#define MTX2 0x50 /* Matrix coefficient 2 */
|
||||
#define MTX3 0x51 /* Matrix coefficient 3 */
|
||||
#define MTX4 0x52 /* Matrix coefficient 4 */
|
||||
#define MTX5 0x53 /* Matrix coefficient 5 */
|
||||
#define MTX6 0x54 /* Matrix coefficient 6 */
|
||||
#define BRIGHTNESS 0x55 /* Brightness control */
|
||||
#define CONTRAST 0x56 /* Contrast control */
|
||||
#define CONTRASCENTER 0x57 /* Contrast center */
|
||||
#define MTXS 0x58 /* Matrix coefficient sign for coefficient 5 to 0*/
|
||||
|
||||
#define RSVD_59 0x59 /* Reserved */
|
||||
#define RSVD_5A 0x5A /* Reserved */
|
||||
#define RSVD_5B 0x5B /* Reserved */
|
||||
#define RSVD_5C 0x5C /* Reserved */
|
||||
#define RSVD_5D 0x5D /* Reserved */
|
||||
#define RSVD_5E 0x5E /* Reserved */
|
||||
#define RSVD_5F 0x5F /* Reserved */
|
||||
#define RSVD_60 0x60 /* Reserved */
|
||||
#define RSVD_61 0x61 /* Reserved */
|
||||
|
||||
#define LCC1 0x62 /* Lens correction option 1 */
|
||||
|
||||
#define LCC2 0x63 /* Lens correction option 2 */
|
||||
#define LCC3 0x64 /* Lens correction option 3 */
|
||||
#define LCC4 0x65 /* Lens correction option 4 */
|
||||
#define LCC5 0x66 /* Lens correction option 5 */
|
||||
|
||||
#define MANU 0x67 /* Manual U Value */
|
||||
#define MANV 0x68 /* Manual V Value */
|
||||
#define GFIX 0x69 /* Fix gain control */
|
||||
#define GGAIN 0x6A /* G channel AWB gain */
|
||||
|
||||
#define DBLV 0x6B /* PLL and clock ? */
|
||||
|
||||
#define AWBCTR3 0x6C /* AWB Control 3 */
|
||||
#define AWBCTR2 0x6D /* AWB Control 2 */
|
||||
#define AWBCTR1 0x6E /* AWB Control 1 */
|
||||
#define AWBCTR0 0x6F /* AWB Control 0 */
|
||||
#define SCALING_XSC 0x70 /* test pattern and horizontal scaling factor */
|
||||
#define SCALING_XSC_CBAR(r) (r&0x7F) /* make sure bit7 is 0 for color bar */
|
||||
#define SCALING_YSC 0x71 /* test pattern and vertical scaling factor */
|
||||
#define SCALING_YSC_CBAR(r,x) ((r&0x7F)|((x&1)<<7)) /* change bit7 for color bar on/off */
|
||||
#define SCALING_DCWCTR 0x72 /* DCW control */
|
||||
#define SCALING_PCLK_DIV 0x73 /* */
|
||||
#define REG74 0x74 /* */
|
||||
#define REG75 0x75 /* */
|
||||
#define REG76 0x76 /* */
|
||||
#define REG77 0x77 /* */
|
||||
|
||||
#define RSVD_78 0x78 /* Reserved */
|
||||
#define RSVD_79 0x79 /* Reserved */
|
||||
|
||||
#define SLOP 0x7A /* Gamma curve highest segment slope */
|
||||
#define GAM1 0x7B /* Gamma Curve 1st Segment Input End Point 0x04 Output Value */
|
||||
#define GAM2 0x7C /* Gamma Curve 2nd Segment Input End Point 0x08 Output Value */
|
||||
#define GAM3 0x7D /* Gamma Curve 3rd Segment Input End Point 0x10 Output Value */
|
||||
#define GAM4 0x7E /* Gamma Curve 4th Segment Input End Point 0x20 Output Value */
|
||||
#define GAM5 0x7F /* Gamma Curve 5th Segment Input End Point 0x28 Output Value */
|
||||
#define GAM6 0x80 /* Gamma Curve 6rd Segment Input End Point 0x30 Output Value */
|
||||
#define GAM7 0x81 /* Gamma Curve 7th Segment Input End Point 0x38 Output Value */
|
||||
#define GAM8 0x82 /* Gamma Curve 8th Segment Input End Point 0x40 Output Value */
|
||||
#define GAM9 0x83 /* Gamma Curve 9th Segment Input End Point 0x48 Output Value */
|
||||
#define GAM10 0x84 /* Gamma Curve 10th Segment Input End Point 0x50 Output Value */
|
||||
#define GAM11 0x85 /* Gamma Curve 11th Segment Input End Point 0x60 Output Value */
|
||||
#define GAM12 0x86 /* Gamma Curve 12th Segment Input End Point 0x70 Output Value */
|
||||
#define GAM13 0x87 /* Gamma Curve 13th Segment Input End Point 0x90 Output Value */
|
||||
#define GAM14 0x88 /* Gamma Curve 14th Segment Input End Point 0xB0 Output Value */
|
||||
#define GAM15 0x89 /* Gamma Curve 15th Segment Input End Point 0xD0 Output Value */
|
||||
|
||||
#define RSVD_8A 0x8A /* Reserved */
|
||||
#define RSVD_8B 0x8B /* Reserved */
|
||||
|
||||
#define RGB444 0x8C /* */
|
||||
|
||||
#define RSVD_8D 0x8D /* Reserved */
|
||||
#define RSVD_8E 0x8E /* Reserved */
|
||||
#define RSVD_8F 0x8F /* Reserved */
|
||||
#define RSVD_90 0x90 /* Reserved */
|
||||
#define RSVD_91 0x91 /* Reserved */
|
||||
|
||||
#define DM_LNL 0x92 /* Dummy line low 8 bit */
|
||||
#define DM_LNH 0x93 /* Dummy line high 8 bit */
|
||||
#define LCC6 0x94 /* Lens correction option 6 */
|
||||
#define LCC7 0x95 /* Lens correction option 7 */
|
||||
|
||||
#define RSVD_96 0x96 /* Reserved */
|
||||
#define RSVD_97 0x97 /* Reserved */
|
||||
#define RSVD_98 0x98 /* Reserved */
|
||||
#define RSVD_99 0x99 /* Reserved */
|
||||
#define RSVD_9A 0x9A /* Reserved */
|
||||
#define RSVD_9B 0x9B /* Reserved */
|
||||
#define RSVD_9C 0x9C /* Reserved */
|
||||
|
||||
#define BD50ST 0x9D /* 50 Hz banding filter value */
|
||||
#define BD60ST 0x9E /* 60 Hz banding filter value */
|
||||
#define HAECC1 0x9F /* Histogram-based AEC/AGC control 1 */
|
||||
#define HAECC2 0xA0 /* Histogram-based AEC/AGC control 2 */
|
||||
|
||||
#define RSVD_A1 0xA1 /* Reserved */
|
||||
|
||||
#define SCALING_PCLK_DELAY 0xA2 /* Pixel clock delay */
|
||||
|
||||
#define RSVD_A3 0xA3 /* Reserved */
|
||||
|
||||
#define NT_CNTRL 0xA4 /* */
|
||||
#define BD50MAX 0xA5 /* 50 Hz banding step limit */
|
||||
#define HAECC3 0xA6 /* Histogram-based AEC/AGC control 3 */
|
||||
#define HAECC4 0xA7 /* Histogram-based AEC/AGC control 4 */
|
||||
#define HAECC5 0xA8 /* Histogram-based AEC/AGC control 5 */
|
||||
#define HAECC6 0xA9 /* Histogram-based AEC/AGC control 6 */
|
||||
|
||||
#define HAECC7 0xAA /* Histogram-based AEC/AGC control 7 */
|
||||
#define HAECC_EN 0x80 /* Histogram-based AEC algorithm enable */
|
||||
|
||||
#define BD60MAX 0xAB /* 60 Hz banding step limit */
|
||||
|
||||
#define STR_OPT 0xAC /* Register AC */
|
||||
#define STR_R 0xAD /* R gain for led output frame */
|
||||
#define STR_G 0xAE /* G gain for led output frame */
|
||||
#define STR_B 0xAF /* B gain for led output frame */
|
||||
#define RSVD_B0 0xB0 /* Reserved */
|
||||
#define ABLC1 0xB1 /* */
|
||||
#define RSVD_B2 0xB2 /* Reserved */
|
||||
#define THL_ST 0xB3 /* ABLC target */
|
||||
#define THL_DLT 0xB5 /* ABLC stable range */
|
||||
|
||||
#define RSVD_B6 0xB6 /* Reserved */
|
||||
#define RSVD_B7 0xB7 /* Reserved */
|
||||
#define RSVD_B8 0xB8 /* Reserved */
|
||||
#define RSVD_B9 0xB9 /* Reserved */
|
||||
#define RSVD_BA 0xBA /* Reserved */
|
||||
#define RSVD_BB 0xBB /* Reserved */
|
||||
#define RSVD_BC 0xBC /* Reserved */
|
||||
#define RSVD_BD 0xBD /* Reserved */
|
||||
|
||||
#define AD_CHB 0xBE /* blue channel black level compensation */
|
||||
#define AD_CHR 0xBF /* Red channel black level compensation */
|
||||
#define AD_CHGb 0xC0 /* Gb channel black level compensation */
|
||||
#define AD_CHGr 0xC1 /* Gr channel black level compensation */
|
||||
|
||||
#define RSVD_C2 0xC2 /* Reserved */
|
||||
#define RSVD_C3 0xC3 /* Reserved */
|
||||
#define RSVD_C4 0xC4 /* Reserved */
|
||||
#define RSVD_C5 0xC5 /* Reserved */
|
||||
#define RSVD_C6 0xC6 /* Reserved */
|
||||
#define RSVD_C7 0xC7 /* Reserved */
|
||||
#define RSVD_C8 0xC8 /* Reserved */
|
||||
|
||||
#define SATCTR 0xC9 /* Saturation control */
|
||||
#define SET_REG(reg, x) (##reg_DEFAULT|x)
|
||||
|
||||
#endif //__OV7670_REG_REGS_H__
|
||||
@@ -1,14 +0,0 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* OV7725 driver.
|
||||
*
|
||||
*/
|
||||
#ifndef __OV7725_H__
|
||||
#define __OV7725_H__
|
||||
#include "sensor.h"
|
||||
|
||||
int ov7725_init(sensor_t *sensor);
|
||||
#endif // __OV7725_H__
|
||||
@@ -1,335 +0,0 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* OV2640 register definitions.
|
||||
*/
|
||||
#ifndef __REG_REGS_H__
|
||||
#define __REG_REGS_H__
|
||||
#define GAIN 0x00 /* AGC – Gain control gain setting */
|
||||
#define BLUE 0x01 /* AWB – Blue channel gain setting */
|
||||
#define RED 0x02 /* AWB – Red channel gain setting */
|
||||
#define GREEN 0x03 /* AWB – Green channel gain setting */
|
||||
#define BAVG 0x05 /* U/B Average Level */
|
||||
#define GAVG 0x06 /* Y/Gb Average Level */
|
||||
#define RAVG 0x07 /* V/R Average Level */
|
||||
#define AECH 0x08 /* Exposure Value – AEC MSBs */
|
||||
|
||||
#define COM2 0x09 /* Common Control 2 */
|
||||
#define COM2_SOFT_SLEEP 0x10 /* Soft sleep mode */
|
||||
#define COM2_OUT_DRIVE_1x 0x00 /* Output drive capability 1x */
|
||||
#define COM2_OUT_DRIVE_2x 0x01 /* Output drive capability 2x */
|
||||
#define COM2_OUT_DRIVE_3x 0x02 /* Output drive capability 3x */
|
||||
#define COM2_OUT_DRIVE_4x 0x03 /* Output drive capability 4x */
|
||||
|
||||
#define REG_PID 0x0A /* Product ID Number MSB */
|
||||
#define REG_VER 0x0B /* Product ID Number LSB */
|
||||
|
||||
#define COM3 0x0C /* Common Control 3 */
|
||||
#define COM3_VFLIP 0x80 /* Vertical flip image ON/OFF selection */
|
||||
#define COM3_MIRROR 0x40 /* Horizontal mirror image ON/OFF selection */
|
||||
#define COM3_SWAP_BR 0x20 /* Swap B/R output sequence in RGB output mode */
|
||||
#define COM3_SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV output mode */
|
||||
#define COM3_SWAP_MSB 0x08 /* Swap output MSB/LSB */
|
||||
#define COM3_TRI_CLOCK 0x04 /* Tri-state option for output clock at power-down period */
|
||||
#define COM3_TRI_DATA 0x02 /* Tri-state option for output data at power-down period */
|
||||
#define COM3_COLOR_BAR 0x01 /* Sensor color bar test pattern output enable */
|
||||
#define COM3_SET_CBAR(r, x) ((r&0xFE)|((x&1)<<0))
|
||||
#define COM3_SET_MIRROR(r, x) ((r&0xBF)|((x&1)<<6))
|
||||
#define COM3_SET_FLIP(r, x) ((r&0x7F)|((x&1)<<7))
|
||||
|
||||
#define COM4 0x0D /* Common Control 4 */
|
||||
#define COM4_PLL_BYPASS 0x00 /* Bypass PLL */
|
||||
#define COM4_PLL_4x 0x40 /* PLL frequency 4x */
|
||||
#define COM4_PLL_6x 0x80 /* PLL frequency 6x */
|
||||
#define COM4_PLL_8x 0xc0 /* PLL frequency 8x */
|
||||
#define COM4_AEC_FULL 0x00 /* AEC evaluate full window */
|
||||
#define COM4_AEC_1_2 0x10 /* AEC evaluate 1/2 window */
|
||||
#define COM4_AEC_1_4 0x20 /* AEC evaluate 1/4 window */
|
||||
#define COM4_AEC_2_3 0x30 /* AEC evaluate 2/3 window */
|
||||
|
||||
#define COM5 0x0E /* Common Control 5 */
|
||||
#define COM5_AFR 0x80 /* Auto frame rate control ON/OFF selection (night mode) */
|
||||
#define COM5_AFR_SPEED 0x40 /* Auto frame rate control speed selection */
|
||||
#define COM5_AFR_0 0x00 /* No reduction of frame rate */
|
||||
#define COM5_AFR_1_2 0x10 /* Max reduction to 1/2 frame rate */
|
||||
#define COM5_AFR_1_4 0x20 /* Max reduction to 1/4 frame rate */
|
||||
#define COM5_AFR_1_8 0x30 /* Max reduction to 1/8 frame rate */
|
||||
#define COM5_AFR_4x 0x04 /* Add frame when AGC reaches 4x gain */
|
||||
#define COM5_AFR_8x 0x08 /* Add frame when AGC reaches 8x gain */
|
||||
#define COM5_AFR_16x 0x0c /* Add frame when AGC reaches 16x gain */
|
||||
#define COM5_AEC_NO_LIMIT 0x01 /* No limit to AEC increase step */
|
||||
|
||||
#define COM6 0x0F /* Common Control 6 */
|
||||
#define COM6_AUTO_WINDOW 0x01 /* Auto window setting ON/OFF selection when format changes */
|
||||
|
||||
#define AEC 0x10 /* AEC[7:0] (see register AECH for AEC[15:8]) */
|
||||
#define CLKRC 0x11 /* Internal Clock */
|
||||
|
||||
#define COM7 0x12 /* Common Control 7 */
|
||||
#define COM7_RESET 0x80 /* SCCB Register Reset */
|
||||
#define COM7_RES_VGA 0x00 /* Resolution VGA */
|
||||
#define COM7_RES_QVGA 0x40 /* Resolution QVGA */
|
||||
#define COM7_BT656 0x20 /* BT.656 protocol ON/OFF */
|
||||
#define COM7_SENSOR_RAW 0x10 /* Sensor RAW */
|
||||
#define COM7_FMT_GBR422 0x00 /* RGB output format GBR422 */
|
||||
#define COM7_FMT_RGB565 0x04 /* RGB output format RGB565 */
|
||||
#define COM7_FMT_RGB555 0x08 /* RGB output format RGB555 */
|
||||
#define COM7_FMT_RGB444 0x0C /* RGB output format RGB444 */
|
||||
#define COM7_FMT_YUV 0x00 /* Output format YUV */
|
||||
#define COM7_FMT_P_BAYER 0x01 /* Output format Processed Bayer RAW */
|
||||
#define COM7_FMT_RGB 0x02 /* Output format RGB */
|
||||
#define COM7_FMT_R_BAYER 0x03 /* Output format Bayer RAW */
|
||||
#define COM7_SET_FMT(r, x) ((r&0xFC)|((x&0x3)<<0))
|
||||
#define COM7_SET_RGB(r, x) ((r&0xF0)|(x&0x0C)|COM7_FMT_RGB)
|
||||
|
||||
#define COM8 0x13 /* Common Control 8 */
|
||||
#define COM8_FAST_AUTO 0x80 /* Enable fast AGC/AEC algorithm */
|
||||
#define COM8_STEP_VSYNC 0x00 /* AEC - Step size limited to vertical blank */
|
||||
#define COM8_STEP_UNLIMIT 0x40 /* AEC - Step size unlimited step size */
|
||||
#define COM8_BANDF_EN 0x20 /* Banding filter ON/OFF */
|
||||
#define COM8_AEC_BANDF 0x10 /* Enable AEC below banding value */
|
||||
#define COM8_AEC_FINE_EN 0x08 /* Fine AEC ON/OFF control */
|
||||
#define COM8_AGC_EN 0x04 /* AGC Enable */
|
||||
#define COM8_AWB_EN 0x02 /* AWB Enable */
|
||||
#define COM8_AEC_EN 0x01 /* AEC Enable */
|
||||
#define COM8_SET_AGC(r, x) ((r&0xFB)|((x&0x1)<<2))
|
||||
#define COM8_SET_AWB(r, x) ((r&0xFD)|((x&0x1)<<1))
|
||||
#define COM8_SET_AEC(r, x) ((r&0xFE)|((x&0x1)<<0))
|
||||
|
||||
#define COM9 0x14 /* Common Control 9 */
|
||||
#define COM9_HISTO_AVG 0x80 /* Histogram or average based AEC/AGC selection */
|
||||
#define COM9_AGC_GAIN_2x 0x00 /* Automatic Gain Ceiling 2x */
|
||||
#define COM9_AGC_GAIN_4x 0x10 /* Automatic Gain Ceiling 4x */
|
||||
#define COM9_AGC_GAIN_8x 0x20 /* Automatic Gain Ceiling 8x */
|
||||
#define COM9_AGC_GAIN_16x 0x30 /* Automatic Gain Ceiling 16x */
|
||||
#define COM9_AGC_GAIN_32x 0x40 /* Automatic Gain Ceiling 32x */
|
||||
#define COM9_DROP_VSYNC 0x04 /* Drop VSYNC output of corrupt frame */
|
||||
#define COM9_DROP_HREF 0x02 /* Drop HREF output of corrupt frame */
|
||||
#define COM9_SET_AGC(r, x) ((r&0x8F)|((x&0x07)<<4))
|
||||
|
||||
#define COM10 0x15 /* Common Control 10 */
|
||||
#define COM10_NEGATIVE 0x80 /* Output negative data */
|
||||
#define COM10_HSYNC_EN 0x40 /* HREF changes to HSYNC */
|
||||
#define COM10_PCLK_FREE 0x00 /* PCLK output option: free running PCLK */
|
||||
#define COM10_PCLK_MASK 0x20 /* PCLK output option: masked during horizontal blank */
|
||||
#define COM10_PCLK_REV 0x10 /* PCLK reverse */
|
||||
#define COM10_HREF_REV 0x08 /* HREF reverse */
|
||||
#define COM10_VSYNC_FALLING 0x00 /* VSYNC changes on falling edge of PCLK */
|
||||
#define COM10_VSYNC_RISING 0x04 /* VSYNC changes on rising edge of PCLK */
|
||||
#define COM10_VSYNC_NEG 0x02 /* VSYNC negative */
|
||||
#define COM10_OUT_RANGE_8 0x01 /* Output data range: Full range */
|
||||
#define COM10_OUT_RANGE_10 0x00 /* Output data range: Data from [10] to [F0] (8 MSBs) */
|
||||
|
||||
#define REG16 0x16 /* Register 16 */
|
||||
#define REG16_BIT_SHIFT 0x80 /* Bit shift test pattern options */
|
||||
#define HSTART 0x17 /* Horizontal Frame (HREF column) Start 8 MSBs (2 LSBs are at HREF[5:4]) */
|
||||
#define HSIZE 0x18 /* Horizontal Sensor Size (2 LSBs are at HREF[1:0]) */
|
||||
#define VSTART 0x19 /* Vertical Frame (row) Start 8 MSBs (1 LSB is at HREF[6]) */
|
||||
#define VSIZE 0x1A /* Vertical Sensor Size (1 LSB is at HREF[2]) */
|
||||
#define PSHFT 0x1B /* Data Format - Pixel Delay Select */
|
||||
#define REG_MIDH 0x1C /* Manufacturer ID Byte – High */
|
||||
#define REG_MIDL 0x1D /* Manufacturer ID Byte – Low */
|
||||
#define LAEC 0x1F /* Fine AEC Value - defines exposure value less than one row period */
|
||||
|
||||
#define COM11 0x20 /* Common Control 11 */
|
||||
#define COM11_SNGL_FRAME_EN 0x02 /* Single frame ON/OFF selection */
|
||||
#define COM11_SNGL_XFR_TRIG 0x01 /* Single frame transfer trigger */
|
||||
|
||||
#define BDBASE 0x22 /* Banding Filter Minimum AEC Value */
|
||||
#define DBSTEP 0x23 /* Banding Filter Maximum Step */
|
||||
#define AEW 0x24 /* AGC/AEC - Stable Operating Region (Upper Limit) */
|
||||
#define AEB 0x25 /* AGC/AEC - Stable Operating Region (Lower Limit) */
|
||||
#define VPT 0x26 /* AGC/AEC Fast Mode Operating Region */
|
||||
#define REG28 0x28 /* Selection on the number of dummy rows, N */
|
||||
#define HOUTSIZE 0x29 /* Horizontal Data Output Size MSBs (2 LSBs at register EXHCH[1:0]) */
|
||||
#define EXHCH 0x2A /* Dummy Pixel Insert MSB */
|
||||
#define EXHCL 0x2B /* Dummy Pixel Insert LSB */
|
||||
#define VOUTSIZE 0x2C /* Vertical Data Output Size MSBs (LSB at register EXHCH[2]) */
|
||||
#define ADVFL 0x2D /* LSB of Insert Dummy Rows in Vertical Sync (1 bit equals 1 row) */
|
||||
#define ADVFH 0x2E /* MSB of Insert Dummy Rows in Vertical Sync */
|
||||
#define YAVE 0x2F /* Y/G Channel Average Value */
|
||||
#define LUMHTH 0x30 /* Histogram AEC/AGC Luminance High Level Threshold */
|
||||
#define LUMLTH 0x31 /* Histogram AEC/AGC Luminance Low Level Threshold */
|
||||
#define HREF 0x32 /* Image Start and Size Control */
|
||||
#define DM_LNL 0x33 /* Dummy Row Low 8 Bits */
|
||||
#define DM_LNH 0x34 /* Dummy Row High 8 Bits */
|
||||
#define ADOFF_B 0x35 /* AD Offset Compensation Value for B Channel */
|
||||
#define ADOFF_R 0x36 /* AD Offset Compensation Value for R Channel */
|
||||
#define ADOFF_GB 0x37 /* AD Offset Compensation Value for GB Channel */
|
||||
#define ADOFF_GR 0x38 /* AD Offset Compensation Value for GR Channel */
|
||||
#define OFF_B 0x39 /* AD Offset Compensation Value for B Channel */
|
||||
#define OFF_R 0x3A /* AD Offset Compensation Value for R Channel */
|
||||
#define OFF_GB 0x3B /* AD Offset Compensation Value for GB Channel */
|
||||
#define OFF_GR 0x3C /* AD Offset Compensation Value for GR Channel */
|
||||
#define COM12 0x3D /* DC offset compensation for analog process */
|
||||
|
||||
#define COM13 0x3E /* Common Control 13 */
|
||||
#define COM13_BLC_EN 0x80 /* BLC enable */
|
||||
#define COM13_ADC_EN 0x40 /* ADC channel BLC ON/OFF control */
|
||||
#define COM13_ANALOG_BLC 0x20 /* Analog processing channel BLC ON/OFF control */
|
||||
#define COM13_ABLC_GAIN_EN 0x04 /* ABLC gain trigger enable */
|
||||
|
||||
#define COM14 0x3F /* Common Control 14 */
|
||||
#define COM15 0x40 /* Common Control 15 */
|
||||
#define COM16 0x41 /* Common Control 16 */
|
||||
#define TGT_B 0x42 /* BLC Blue Channel Target Value */
|
||||
#define TGT_R 0x43 /* BLC Red Channel Target Value */
|
||||
#define TGT_GB 0x44 /* BLC Gb Channel Target Value */
|
||||
#define TGT_GR 0x45 /* BLC Gr Channel Target Value */
|
||||
|
||||
#define LC_CTR 0x46 /* Lens Correction Control */
|
||||
#define LC_CTR_RGB_COMP_1 0x00 /* R, G, and B channel compensation coefficient is set by LC_COEF (0x49) */
|
||||
#define LC_CTR_RGB_COMP_3 0x04 /* R, G, and B channel compensation coefficient is set by registers
|
||||
LC_COEFB (0x4B), LC_COEF (0x49), and LC_COEFR (0x4C), respectively */
|
||||
#define LC_CTR_EN 0x01 /* Lens correction enable */
|
||||
#define LC_XC 0x47 /* X Coordinate of Lens Correction Center Relative to Array Center */
|
||||
#define LC_YC 0x48 /* Y Coordinate of Lens Correction Center Relative to Array Center */
|
||||
#define LC_COEF 0x49 /* Lens Correction Coefficient */
|
||||
#define LC_RADI 0x4A /* Lens Correction Radius */
|
||||
#define LC_COEFB 0x4B /* Lens Correction B Channel Compensation Coefficient */
|
||||
#define LC_COEFR 0x4C /* Lens Correction R Channel Compensation Coefficient */
|
||||
|
||||
#define FIXGAIN 0x4D /* Analog Fix Gain Amplifier */
|
||||
#define AREF0 0x4E /* Sensor Reference Control */
|
||||
#define AREF1 0x4F /* Sensor Reference Current Control */
|
||||
#define AREF2 0x50 /* Analog Reference Control */
|
||||
#define AREF3 0x51 /* ADC Reference Control */
|
||||
#define AREF4 0x52 /* ADC Reference Control */
|
||||
#define AREF5 0x53 /* ADC Reference Control */
|
||||
#define AREF6 0x54 /* Analog Reference Control */
|
||||
#define AREF7 0x55 /* Analog Reference Control */
|
||||
#define UFIX 0x60 /* U Channel Fixed Value Output */
|
||||
#define VFIX 0x61 /* V Channel Fixed Value Output */
|
||||
#define AWBB_BLK 0x62 /* AWB Option for Advanced AWB */
|
||||
|
||||
#define AWB_CTRL0 0x63 /* AWB Control Byte 0 */
|
||||
#define AWB_CTRL0_GAIN_EN 0x80 /* AWB gain enable */
|
||||
#define AWB_CTRL0_CALC_EN 0x40 /* AWB calculate enable */
|
||||
#define AWB_CTRL0_WBC_MASK 0x0F /* WBC threshold 2 */
|
||||
|
||||
#define DSP_CTRL1 0x64 /* DSP Control Byte 1 */
|
||||
#define DSP_CTRL1_FIFO_EN 0x80 /* FIFO enable/disable selection */
|
||||
#define DSP_CTRL1_UV_EN 0x40 /* UV adjust function ON/OFF selection */
|
||||
#define DSP_CTRL1_SDE_EN 0x20 /* SDE enable */
|
||||
#define DSP_CTRL1_MTRX_EN 0x10 /* Color matrix ON/OFF selection */
|
||||
#define DSP_CTRL1_INTRP_EN 0x08 /* Interpolation ON/OFF selection */
|
||||
#define DSP_CTRL1_GAMMA_EN 0x04 /* Gamma function ON/OFF selection */
|
||||
#define DSP_CTRL1_BLACK_EN 0x02 /* Black defect auto correction ON/OFF */
|
||||
#define DSP_CTRL1_WHITE_EN 0x01 /* White defect auto correction ON/OFF */
|
||||
|
||||
#define DSP_CTRL2 0x65 /* DSP Control Byte 2 */
|
||||
#define DSP_CTRL2_VDCW_EN 0x08 /* Vertical DCW enable */
|
||||
#define DSP_CTRL2_HDCW_EN 0x04 /* Horizontal DCW enable */
|
||||
#define DSP_CTRL2_VZOOM_EN 0x02 /* Vertical zoom out enable */
|
||||
#define DSP_CTRL2_HZOOM_EN 0x01 /* Horizontal zoom out enable */
|
||||
|
||||
#define DSP_CTRL3 0x66 /* DSP Control Byte 3 */
|
||||
#define DSP_CTRL3_UV_EN 0x80 /* UV output sequence option */
|
||||
#define DSP_CTRL3_CBAR_EN 0x20 /* DSP color bar ON/OFF selection */
|
||||
#define DSP_CTRL3_FIFO_EN 0x08 /* FIFO power down ON/OFF selection */
|
||||
#define DSP_CTRL3_SCAL1_PWDN 0x04 /* Scaling module power down control 1 */
|
||||
#define DSP_CTRL3_SCAL2_PWDN 0x02 /* Scaling module power down control 2 */
|
||||
#define DSP_CTRL3_INTRP_PWDN 0x01 /* Interpolation module power down control */
|
||||
#define DSP_CTRL3_SET_CBAR(r, x) ((r&0xDF)|((x&1)<<5))
|
||||
|
||||
|
||||
#define DSP_CTRL4 0x67 /* DSP Control Byte 4 */
|
||||
#define DSP_CTRL4_YUV_RGB 0x00 /* Output selection YUV or RGB */
|
||||
#define DSP_CTRL4_RAW8 0x02 /* Output selection RAW8 */
|
||||
#define DSP_CTRL4_RAW10 0x03 /* Output selection RAW10 */
|
||||
|
||||
|
||||
#define AWB_BIAS 0x68 /* AWB BLC Level Clip */
|
||||
#define AWB_CTRL1 0x69 /* AWB Control 1 */
|
||||
#define AWB_CTRL2 0x6A /* AWB Control 2 */
|
||||
|
||||
#define AWB_CTRL3 0x6B /* AWB Control 3 */
|
||||
#define AWB_CTRL3_ADVANCED 0x80 /* AWB mode select - Advanced AWB */
|
||||
#define AWB_CTRL3_SIMPLE 0x00 /* AWB mode select - Simple AWB */
|
||||
|
||||
#define AWB_CTRL4 0x6C /* AWB Control 4 */
|
||||
#define AWB_CTRL5 0x6D /* AWB Control 5 */
|
||||
#define AWB_CTRL6 0x6E /* AWB Control 6 */
|
||||
#define AWB_CTRL7 0x6F /* AWB Control 7 */
|
||||
#define AWB_CTRL8 0x70 /* AWB Control 8 */
|
||||
#define AWB_CTRL9 0x71 /* AWB Control 9 */
|
||||
#define AWB_CTRL10 0x72 /* AWB Control 10 */
|
||||
#define AWB_CTRL11 0x73 /* AWB Control 11 */
|
||||
#define AWB_CTRL12 0x74 /* AWB Control 12 */
|
||||
#define AWB_CTRL13 0x75 /* AWB Control 13 */
|
||||
#define AWB_CTRL14 0x76 /* AWB Control 14 */
|
||||
#define AWB_CTRL15 0x77 /* AWB Control 15 */
|
||||
#define AWB_CTRL16 0x78 /* AWB Control 16 */
|
||||
#define AWB_CTRL17 0x79 /* AWB Control 17 */
|
||||
#define AWB_CTRL18 0x7A /* AWB Control 18 */
|
||||
#define AWB_CTRL19 0x7B /* AWB Control 19 */
|
||||
#define AWB_CTRL20 0x7C /* AWB Control 20 */
|
||||
#define AWB_CTRL21 0x7D /* AWB Control 21 */
|
||||
#define GAM1 0x7E /* Gamma Curve 1st Segment Input End Point 0x04 Output Value */
|
||||
#define GAM2 0x7F /* Gamma Curve 2nd Segment Input End Point 0x08 Output Value */
|
||||
#define GAM3 0x80 /* Gamma Curve 3rd Segment Input End Point 0x10 Output Value */
|
||||
#define GAM4 0x81 /* Gamma Curve 4th Segment Input End Point 0x20 Output Value */
|
||||
#define GAM5 0x82 /* Gamma Curve 5th Segment Input End Point 0x28 Output Value */
|
||||
#define GAM6 0x83 /* Gamma Curve 6th Segment Input End Point 0x30 Output Value */
|
||||
#define GAM7 0x84 /* Gamma Curve 7th Segment Input End Point 0x38 Output Value */
|
||||
#define GAM8 0x85 /* Gamma Curve 8th Segment Input End Point 0x40 Output Value */
|
||||
#define GAM9 0x86 /* Gamma Curve 9th Segment Input End Point 0x48 Output Value */
|
||||
#define GAM10 0x87 /* Gamma Curve 10th Segment Input End Point 0x50 Output Value */
|
||||
#define GAM11 0x88 /* Gamma Curve 11th Segment Input End Point 0x60 Output Value */
|
||||
#define GAM12 0x89 /* Gamma Curve 12th Segment Input End Point 0x70 Output Value */
|
||||
#define GAM13 0x8A /* Gamma Curve 13th Segment Input End Point 0x90 Output Value */
|
||||
#define GAM14 0x8B /* Gamma Curve 14th Segment Input End Point 0xB0 Output Value */
|
||||
#define GAM15 0x8C /* Gamma Curve 15th Segment Input End Point 0xD0 Output Value */
|
||||
#define SLOP 0x8D /* Gamma Curve Highest Segment Slope */
|
||||
#define DNSTH 0x8E /* De-noise Threshold */
|
||||
#define EDGE0 0x8F /* Edge Enhancement Strength Control */
|
||||
#define EDGE1 0x90 /* Edge Enhancement Threshold Control */
|
||||
#define DNSOFF 0x91 /* Auto De-noise Threshold Control */
|
||||
#define EDGE2 0x92 /* Edge Enhancement Strength Upper Limit */
|
||||
#define EDGE3 0x93 /* Edge Enhancement Strength Upper Limit */
|
||||
#define MTX1 0x94 /* Matrix Coefficient 1 */
|
||||
#define MTX2 0x95 /* Matrix Coefficient 2 */
|
||||
#define MTX3 0x96 /* Matrix Coefficient 3 */
|
||||
#define MTX4 0x97 /* Matrix Coefficient 4 */
|
||||
#define MTX5 0x98 /* Matrix Coefficient 5 */
|
||||
#define MTX6 0x99 /* Matrix Coefficient 6 */
|
||||
|
||||
#define MTX_CTRL 0x9A /* Matrix Control */
|
||||
#define MTX_CTRL_DBL_EN 0x80 /* Matrix double ON/OFF selection */
|
||||
|
||||
#define BRIGHTNESS 0x9B /* Brightness Control */
|
||||
#define CONTRAST 0x9C /* Contrast Gain */
|
||||
#define UVADJ0 0x9E /* Auto UV Adjust Control 0 */
|
||||
#define UVADJ1 0x9F /* Auto UV Adjust Control 1 */
|
||||
#define SCAL0 0xA0 /* DCW Ratio Control */
|
||||
#define SCAL1 0xA1 /* Horizontal Zoom Out Control */
|
||||
#define SCAL2 0xA2 /* Vertical Zoom Out Control */
|
||||
#define FIFODLYM 0xA3 /* FIFO Manual Mode Delay Control */
|
||||
#define FIFODLYA 0xA4 /* FIFO Auto Mode Delay Control */
|
||||
|
||||
#define SDE 0xA6 /* Special Digital Effect Control */
|
||||
#define SDE_NEGATIVE_EN 0x40 /* Negative image enable */
|
||||
#define SDE_GRAYSCALE_EN 0x20 /* Gray scale image enable */
|
||||
#define SDE_V_FIXED_EN 0x10 /* V fixed value enable */
|
||||
#define SDE_U_FIXED_EN 0x08 /* U fixed value enable */
|
||||
#define SDE_CONT_BRIGHT_EN 0x04 /* Contrast/Brightness enable */
|
||||
#define SDE_SATURATION_EN 0x02 /* Saturation enable */
|
||||
#define SDE_HUE_EN 0x01 /* Hue enable */
|
||||
|
||||
#define USAT 0xA7 /* U Component Saturation Gain */
|
||||
#define VSAT 0xA8 /* V Component Saturation Gain */
|
||||
#define HUECOS 0xA9 /* Cosine value × 0x80 */
|
||||
#define HUESIN 0xAA /* Sine value × 0x80 */
|
||||
#define SIGN_BIT 0xAB /* Sign Bit for Hue and Brightness */
|
||||
|
||||
#define DSPAUTO 0xAC /* DSP Auto Function ON/OFF Control */
|
||||
#define DSPAUTO_AWB_EN 0x80 /* AWB auto threshold control */
|
||||
#define DSPAUTO_DENOISE_EN 0x40 /* De-noise auto threshold control */
|
||||
#define DSPAUTO_EDGE_EN 0x20 /* Sharpness (edge enhancement) auto strength control */
|
||||
#define DSPAUTO_UV_EN 0x10 /* UV adjust auto slope control */
|
||||
#define DSPAUTO_SCAL0_EN 0x08 /* Auto scaling factor control (register SCAL0 (0xA0)) */
|
||||
#define DSPAUTO_SCAL1_EN 0x04 /* Auto scaling factor control (registers SCAL1 (0xA1 and SCAL2 (0xA2))*/
|
||||
#define SET_REG(reg, x) (##reg_DEFAULT|x)
|
||||
#endif //__REG_REGS_H__
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
#include "Helper.h"
|
||||
#include "configFile.h"
|
||||
#include <esp_log.h>
|
||||
|
||||
//static const char *TAGCONFIGFILE = "configFile";
|
||||
static const char *TAG = "CONFIG";
|
||||
|
||||
ConfigFile::ConfigFile(std::string filePath)
|
||||
{
|
||||
@@ -48,7 +49,7 @@ bool ConfigFile::getNextLine(std::string *rt, bool &disabled, bool &eof)
|
||||
|
||||
if (fgets(zw, 1024, pFile))
|
||||
{
|
||||
printf("%s", zw);
|
||||
ESP_LOGD(TAG, "%s", zw);
|
||||
if ((strlen(zw) == 0) && feof(pFile))
|
||||
{
|
||||
*rt = "";
|
||||
@@ -67,7 +68,7 @@ bool ConfigFile::getNextLine(std::string *rt, bool &disabled, bool &eof)
|
||||
while ((zw[0] == ';' || zw[0] == '#' || (rt->size() == 0)) && !(zw[1] == '[')) // Kommentarzeilen (; oder #) und Leerzeilen überspringen, es sei denn es ist ein neuer auskommentierter Paragraph
|
||||
{
|
||||
fgets(zw, 1024, pFile);
|
||||
printf("%s", zw);
|
||||
ESP_LOGD(TAG, "%s", zw);
|
||||
if (feof(pFile))
|
||||
{
|
||||
*rt = "";
|
||||
@@ -81,25 +82,3 @@ bool ConfigFile::getNextLine(std::string *rt, bool &disabled, bool &eof)
|
||||
disabled = ((*rt)[0] == ';');
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<string> ConfigFile::ZerlegeZeile(std::string input, std::string delimiter)
|
||||
{
|
||||
std::vector<string> Output;
|
||||
// std::string delimiter = " =,";
|
||||
|
||||
input = trim(input, delimiter);
|
||||
size_t pos = findDelimiterPos(input, delimiter);
|
||||
std::string token;
|
||||
while (pos != std::string::npos) {
|
||||
token = input.substr(0, pos);
|
||||
token = trim(token, delimiter);
|
||||
Output.push_back(token);
|
||||
input.erase(0, pos + 1);
|
||||
input = trim(input, delimiter);
|
||||
pos = findDelimiterPos(input, delimiter);
|
||||
}
|
||||
Output.push_back(input);
|
||||
|
||||
return Output;
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ public:
|
||||
bool isNewParagraph(std::string input);
|
||||
bool GetNextParagraph(std::string& aktparamgraph, bool &disabled, bool &eof);
|
||||
bool getNextLine(std::string* rt, bool &disabled, bool &eof);
|
||||
std::vector<std::string> ZerlegeZeile(std::string input, std::string delimiter = " =, \t");
|
||||
|
||||
private:
|
||||
FILE* pFile;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "Helper.h"
|
||||
#include "interface_mqtt.h"
|
||||
|
||||
static const char *TAG_SERVERGPIO = "server_GPIO";
|
||||
static const char *TAG = "GPIO";
|
||||
QueueHandle_t gpio_queue_handle = NULL;
|
||||
|
||||
#define DEBUG_DETAIL_ON
|
||||
@@ -43,7 +43,7 @@ GpioPin::GpioPin(gpio_num_t gpio, const char* name, gpio_pin_mode_t mode, gpio_i
|
||||
|
||||
GpioPin::~GpioPin()
|
||||
{
|
||||
ESP_LOGD(TAG_SERVERGPIO,"reset GPIO pin %d", _gpio);
|
||||
ESP_LOGD(TAG,"reset GPIO pin %d", _gpio);
|
||||
if (_interruptType != GPIO_INTR_DISABLE) {
|
||||
//hook isr handler for specific gpio pin
|
||||
gpio_isr_handler_remove(_gpio);
|
||||
@@ -66,13 +66,13 @@ static void IRAM_ATTR gpio_isr_handler(void* arg)
|
||||
}
|
||||
|
||||
static void gpioHandlerTask(void *arg) {
|
||||
ESP_LOGD(TAG_SERVERGPIO,"start interrupt task");
|
||||
ESP_LOGD(TAG,"start interrupt task");
|
||||
while(1){
|
||||
if(uxQueueMessagesWaiting(gpio_queue_handle)){
|
||||
while(uxQueueMessagesWaiting(gpio_queue_handle)){
|
||||
GpioResult gpioResult;
|
||||
xQueueReceive(gpio_queue_handle,(void*)&gpioResult,10);
|
||||
ESP_LOGD(TAG_SERVERGPIO,"gpio: %d state: %d", gpioResult.gpio, gpioResult.value);
|
||||
ESP_LOGD(TAG,"gpio: %d state: %d", gpioResult.gpio, gpioResult.value);
|
||||
((GpioHandler*)arg)->gpioInterrupt(&gpioResult);
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ static void gpioHandlerTask(void *arg) {
|
||||
|
||||
void GpioPin::gpioInterrupt(int value) {
|
||||
if (_mqttTopic != "") {
|
||||
ESP_LOGD(TAG_SERVERGPIO, "gpioInterrupt %s %d", _mqttTopic.c_str(), value);
|
||||
ESP_LOGD(TAG, "gpioInterrupt %s %d", _mqttTopic.c_str(), value);
|
||||
|
||||
MQTTPublish(_mqttTopic, value ? "true" : "false");
|
||||
currentState = value;
|
||||
@@ -110,7 +110,7 @@ void GpioPin::init()
|
||||
// if (_interruptType != GPIO_INTR_DISABLE) { // ohne GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X, wenn das genutzt wird, dann soll auch der Handler hier nicht initialisiert werden, da das dann über SmartLED erfolgt.
|
||||
if ((_interruptType != GPIO_INTR_DISABLE) && (_interruptType != GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X)) {
|
||||
//hook isr handler for specific gpio pin
|
||||
ESP_LOGD(TAG_SERVERGPIO, "GpioPin::init add isr handler for GPIO %d\r\n", _gpio);
|
||||
ESP_LOGD(TAG, "GpioPin::init add isr handler for GPIO %d", _gpio);
|
||||
gpio_isr_handler_add(_gpio, gpio_isr_handler, (void*)&_gpio);
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ bool GpioPin::getValue(std::string* errorText)
|
||||
|
||||
void GpioPin::setValue(bool value, gpio_set_source setSource, std::string* errorText)
|
||||
{
|
||||
ESP_LOGD(TAG_SERVERGPIO, "GpioPin::setValue %d\r\n", value);
|
||||
ESP_LOGD(TAG, "GpioPin::setValue %d", value);
|
||||
|
||||
if ((_mode != GPIO_PIN_MODE_OUTPUT) && (_mode != GPIO_PIN_MODE_OUTPUT_PWM) && (_mode != GPIO_PIN_MODE_BUILT_IN_FLASH_LED)) {
|
||||
(*errorText) = "GPIO is not in output mode";
|
||||
@@ -147,14 +147,14 @@ void GpioPin::setValue(bool value, gpio_set_source setSource, std::string* error
|
||||
void GpioPin::publishState() {
|
||||
int newState = gpio_get_level(_gpio);
|
||||
if (newState != currentState) {
|
||||
ESP_LOGD(TAG_SERVERGPIO,"publish state of GPIO %d new state %d", _gpio, newState);
|
||||
ESP_LOGD(TAG,"publish state of GPIO %d new state %d", _gpio, newState);
|
||||
MQTTPublish(_mqttTopic, newState ? "true" : "false");
|
||||
currentState = newState;
|
||||
}
|
||||
}
|
||||
|
||||
bool GpioPin::handleMQTT(std::string, char* data, int data_len) {
|
||||
ESP_LOGD(TAG_SERVERGPIO, "GpioPin::handleMQTT data %.*s\r\n", data_len, data);
|
||||
ESP_LOGD(TAG, "GpioPin::handleMQTT data %.*s", data_len, data);
|
||||
|
||||
std::string dataStr(data, data_len);
|
||||
dataStr = toLower(dataStr);
|
||||
@@ -169,7 +169,7 @@ bool GpioPin::handleMQTT(std::string, char* data, int data_len) {
|
||||
}
|
||||
|
||||
if (errorText != "") {
|
||||
ESP_LOGE(TAG_SERVERGPIO, "%s", errorText.c_str());
|
||||
ESP_LOGE(TAG, "%s", errorText.c_str());
|
||||
}
|
||||
|
||||
return (errorText == "");
|
||||
@@ -178,7 +178,7 @@ bool GpioPin::handleMQTT(std::string, char* data, int data_len) {
|
||||
|
||||
esp_err_t callHandleHttpRequest(httpd_req_t *req)
|
||||
{
|
||||
ESP_LOGD(TAG_SERVERGPIO,"callHandleHttpRequest");
|
||||
ESP_LOGD(TAG,"callHandleHttpRequest");
|
||||
|
||||
GpioHandler *gpioHandler = (GpioHandler*)req->user_ctx;
|
||||
return gpioHandler->handleHttpRequest(req);
|
||||
@@ -186,17 +186,17 @@ esp_err_t callHandleHttpRequest(httpd_req_t *req)
|
||||
|
||||
void taskGpioHandler(void *pvParameter)
|
||||
{
|
||||
ESP_LOGD(TAG_SERVERGPIO,"taskGpioHandler");
|
||||
ESP_LOGD(TAG,"taskGpioHandler");
|
||||
((GpioHandler*)pvParameter)->init();
|
||||
}
|
||||
|
||||
GpioHandler::GpioHandler(std::string configFile, httpd_handle_t httpServer)
|
||||
{
|
||||
ESP_LOGI(TAG_SERVERGPIO,"start GpioHandler");
|
||||
ESP_LOGI(TAG,"start GpioHandler");
|
||||
_configFile = configFile;
|
||||
_httpServer = httpServer;
|
||||
|
||||
ESP_LOGI(TAG_SERVERGPIO, "register GPIO Uri");
|
||||
ESP_LOGI(TAG, "register GPIO Uri");
|
||||
registerGpioUri();
|
||||
}
|
||||
|
||||
@@ -210,10 +210,10 @@ GpioHandler::~GpioHandler() {
|
||||
void GpioHandler::init()
|
||||
{
|
||||
// TickType_t xDelay = 60000 / portTICK_PERIOD_MS;
|
||||
// printf("wait before start %ldms\r\n", (long) xDelay);
|
||||
// ESP_LOGD(TAG, "wait before start %ldms", (long) xDelay);
|
||||
// vTaskDelay( xDelay );
|
||||
|
||||
printf("*************** Start GPIOHandler_Init *****************\n");
|
||||
ESP_LOGD(TAG, "*************** Start GPIOHandler_Init *****************");
|
||||
|
||||
if (gpioMap == NULL) {
|
||||
gpioMap = new std::map<gpio_num_t, GpioPin*>();
|
||||
@@ -222,12 +222,12 @@ void GpioHandler::init()
|
||||
}
|
||||
|
||||
|
||||
ESP_LOGI(TAG_SERVERGPIO, "read GPIO config and init GPIO");
|
||||
ESP_LOGI(TAG, "read GPIO config and init GPIO");
|
||||
if (!readConfig()) {
|
||||
clear();
|
||||
delete gpioMap;
|
||||
gpioMap = NULL;
|
||||
ESP_LOGI(TAG_SERVERGPIO, "GPIO init comleted, handler is disabled");
|
||||
ESP_LOGI(TAG, "GPIO init completed, handler is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -243,13 +243,13 @@ void GpioHandler::init()
|
||||
gpio_queue_handle = xQueueCreate(10,sizeof(GpioResult));
|
||||
BaseType_t xReturned = xTaskCreate(&gpioHandlerTask, "gpio_int", configMINIMAL_STACK_SIZE * 8, (void *)this, tskIDLE_PRIORITY + 2, &xHandleTaskGpio);
|
||||
if(xReturned == pdPASS ) {
|
||||
ESP_LOGD(TAG_SERVERGPIO, "xHandletaskGpioHandler started");
|
||||
ESP_LOGD(TAG, "xHandletaskGpioHandler started");
|
||||
} else {
|
||||
ESP_LOGD(TAG_SERVERGPIO, "xHandletaskGpioHandler not started %d ", (int)xHandleTaskGpio);
|
||||
ESP_LOGD(TAG, "xHandletaskGpioHandler not started %d ", (int)xHandleTaskGpio);
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_SERVERGPIO, "GPIO init comleted, is enabled");
|
||||
ESP_LOGI(TAG, "GPIO init completed, is enabled");
|
||||
}
|
||||
|
||||
void GpioHandler::taskHandler() {
|
||||
@@ -300,13 +300,13 @@ bool GpioHandler::readConfig()
|
||||
bool eof = false;
|
||||
gpio_num_t gpioExtLED = (gpio_num_t) 0;
|
||||
|
||||
// printf("readConfig - Start 1\n");
|
||||
// ESP_LOGD(TAG, "readConfig - Start 1");
|
||||
|
||||
while ((!configFile.GetNextParagraph(line, disabledLine, eof) || (line.compare("[GPIO]") != 0)) && !eof) {}
|
||||
if (eof)
|
||||
return false;
|
||||
|
||||
// printf("readConfig - Start 2 line: %s, disabbledLine: %d\n", line.c_str(), (int) disabledLine);
|
||||
// ESP_LOGD(TAG, "readConfig - Start 2 line: %s, disabbledLine: %d", line.c_str(), (int) disabledLine);
|
||||
|
||||
|
||||
_isEnabled = !disabledLine;
|
||||
@@ -314,32 +314,32 @@ bool GpioHandler::readConfig()
|
||||
if (!_isEnabled)
|
||||
return false;
|
||||
|
||||
// printf("readConfig - Start 3\n");
|
||||
// ESP_LOGD(TAG, "readConfig - Start 3");
|
||||
|
||||
// std::string mainTopicMQTT = "";
|
||||
std::string mainTopicMQTT = GetMQTTMainTopic();
|
||||
if (mainTopicMQTT.length() > 0)
|
||||
{
|
||||
mainTopicMQTT = mainTopicMQTT + "/GPIO";
|
||||
ESP_LOGD(TAG_SERVERGPIO, "MAINTOPICMQTT found\r\n");
|
||||
ESP_LOGD(TAG, "MAINTOPICMQTT found");
|
||||
}
|
||||
|
||||
bool registerISR = false;
|
||||
while (configFile.getNextLine(&line, disabledLine, eof) && !configFile.isNewParagraph(line))
|
||||
{
|
||||
zerlegt = configFile.ZerlegeZeile(line);
|
||||
zerlegt = ZerlegeZeile(line);
|
||||
// const std::regex pieces_regex("IO([0-9]{1,2})");
|
||||
// std::smatch pieces_match;
|
||||
// if (std::regex_match(zerlegt[0], pieces_match, pieces_regex) && (pieces_match.size() == 2))
|
||||
// {
|
||||
// std::string gpioStr = pieces_match[1];
|
||||
ESP_LOGD(TAG_SERVERGPIO, "conf param %s\r\n", toUpper(zerlegt[0]).c_str());
|
||||
ESP_LOGD(TAG, "conf param %s", toUpper(zerlegt[0]).c_str());
|
||||
if (toUpper(zerlegt[0]) == "MAINTOPICMQTT") {
|
||||
// ESP_LOGD(TAG_SERVERGPIO, "MAINTOPICMQTT found\r\n");
|
||||
// ESP_LOGD(TAG, "MAINTOPICMQTT found");
|
||||
// mainTopicMQTT = zerlegt[1];
|
||||
} else if ((zerlegt[0].rfind("IO", 0) == 0) && (zerlegt.size() >= 6))
|
||||
{
|
||||
ESP_LOGI(TAG_SERVERGPIO,"Enable GP%s in %s mode", zerlegt[0].c_str(), zerlegt[1].c_str());
|
||||
ESP_LOGI(TAG,"Enable GP%s in %s mode", zerlegt[0].c_str(), zerlegt[1].c_str());
|
||||
std::string gpioStr = zerlegt[0].substr(2, 2);
|
||||
gpio_num_t gpioNr = (gpio_num_t)atoi(gpioStr.c_str());
|
||||
gpio_pin_mode_t pinMode = resolvePinMode(toLower(zerlegt[1]));
|
||||
@@ -359,7 +359,7 @@ bool GpioHandler::readConfig()
|
||||
|
||||
if (pinMode == GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X)
|
||||
{
|
||||
printf("Set WS2812 to GPIO %d\n", gpioNr);
|
||||
ESP_LOGD(TAG, "Set WS2812 to GPIO %d", gpioNr);
|
||||
gpioExtLED = gpioNr;
|
||||
}
|
||||
|
||||
@@ -400,24 +400,19 @@ bool GpioHandler::readConfig()
|
||||
|
||||
if (gpioExtLED > 0)
|
||||
{
|
||||
// LogFile.WriteToFile("Startsequence 06");
|
||||
// LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Startsequence 06"); // Nremove
|
||||
// vTaskDelay( xDelay );
|
||||
// xDelay = 5000 / portTICK_PERIOD_MS;
|
||||
// printf("main: sleep for : %ldms\n", (long) xDelay);
|
||||
// ESP_LOGD(TAG, "main: sleep for: %ldms", (long) xDelay);
|
||||
|
||||
SmartLed leds( LED_WS2812, 2, GPIO_NUM_12, 0, DoubleBuffer );
|
||||
// SmartLed leds( LED_WS2812, 2, GPIO_NUM_12, 0, DoubleBuffer );
|
||||
|
||||
|
||||
leds[ 0 ] = Rgb{ 255, 0, 0 };
|
||||
leds[ 1 ] = Rgb{ 255, 255, 255 };
|
||||
leds.show();
|
||||
/*
|
||||
// _SmartLED = new SmartLed(LEDType, LEDNumbers, gpioExtLED, 0, DoubleBuffer);
|
||||
_SmartLED = new SmartLed( LED_WS2812, 2, GPIO_NUM_12, 0, DoubleBuffer );
|
||||
(*_SmartLED)[ 0 ] = Rgb{ 255, 0, 0 };
|
||||
(*_SmartLED)[ 1 ] = LEDColor;
|
||||
_SmartLED->show();
|
||||
*/
|
||||
// leds[ 0 ] = Rgb{ 255, 0, 0 };
|
||||
// leds[ 1 ] = Rgb{ 255, 255, 255 };
|
||||
// leds.show();
|
||||
// SmartLed leds = new SmartLed(LEDType, LEDNumbers, gpioExtLED, 0, DoubleBuffer);
|
||||
// _SmartLED = new SmartLed( LED_WS2812, 2, GPIO_NUM_12, 0, DoubleBuffer );
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -425,7 +420,7 @@ bool GpioHandler::readConfig()
|
||||
|
||||
void GpioHandler::clear()
|
||||
{
|
||||
ESP_LOGD(TAG_SERVERGPIO, "GpioHandler::clear\r\n");
|
||||
ESP_LOGD(TAG, "GpioHandler::clear");
|
||||
|
||||
if (gpioMap != NULL) {
|
||||
for(std::map<gpio_num_t, GpioPin*>::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) {
|
||||
@@ -439,7 +434,7 @@ void GpioHandler::clear()
|
||||
|
||||
void GpioHandler::registerGpioUri()
|
||||
{
|
||||
ESP_LOGI(TAG_SERVERGPIO, "server_GPIO - Registering URI handlers");
|
||||
ESP_LOGI(TAG, "server_GPIO - Registering URI handlers");
|
||||
|
||||
httpd_uri_t camuri = { };
|
||||
camuri.method = HTTP_GET;
|
||||
@@ -451,7 +446,7 @@ void GpioHandler::registerGpioUri()
|
||||
|
||||
esp_err_t GpioHandler::handleHttpRequest(httpd_req_t *req)
|
||||
{
|
||||
ESP_LOGD(TAG_SERVERGPIO, "handleHttpRequest");
|
||||
ESP_LOGD(TAG, "handleHttpRequest");
|
||||
|
||||
if (gpioMap == NULL) {
|
||||
std::string resp_str = "GPIO handler not initialized";
|
||||
@@ -463,18 +458,18 @@ esp_err_t GpioHandler::handleHttpRequest(httpd_req_t *req)
|
||||
LogFile.WriteHeapInfo("handler_switch_GPIO - Start");
|
||||
#endif
|
||||
|
||||
LogFile.WriteToFile("handler_switch_GPIO");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_switch_GPIO");
|
||||
char _query[200];
|
||||
char _valueGPIO[30];
|
||||
char _valueStatus[30];
|
||||
std::string gpio, status;
|
||||
|
||||
if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK) {
|
||||
ESP_LOGD(TAG_SERVERGPIO, "Query: %s", _query);
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
|
||||
if (httpd_query_key_value(_query, "GPIO", _valueGPIO, 30) == ESP_OK)
|
||||
{
|
||||
ESP_LOGD(TAG_SERVERGPIO, "GPIO is found %s", _valueGPIO);
|
||||
ESP_LOGD(TAG, "GPIO is found %s", _valueGPIO);
|
||||
gpio = std::string(_valueGPIO);
|
||||
} else {
|
||||
std::string resp_str = "GPIO No is not defined";
|
||||
@@ -483,7 +478,7 @@ esp_err_t GpioHandler::handleHttpRequest(httpd_req_t *req)
|
||||
}
|
||||
if (httpd_query_key_value(_query, "Status", _valueStatus, 30) == ESP_OK)
|
||||
{
|
||||
ESP_LOGD(TAG_SERVERGPIO, "Status is found %s", _valueStatus);
|
||||
ESP_LOGD(TAG, "Status is found %s", _valueStatus);
|
||||
status = std::string(_valueStatus);
|
||||
}
|
||||
} else {
|
||||
@@ -507,7 +502,7 @@ esp_err_t GpioHandler::handleHttpRequest(httpd_req_t *req)
|
||||
gpio_num_t gpio_num = resolvePinNr(gpionum);
|
||||
if (gpio_num == GPIO_NUM_NC)
|
||||
{
|
||||
std::string zw = "GPIO" + std::to_string(gpionum) + " not support - only 12 & 13 free";
|
||||
std::string zw = "GPIO" + std::to_string(gpionum) + " unsupported - only 12 & 13 free";
|
||||
httpd_resp_sendstr_chunk(req, zw.c_str());
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
return ESP_OK;
|
||||
@@ -546,7 +541,7 @@ esp_err_t GpioHandler::handleHttpRequest(httpd_req_t *req)
|
||||
|
||||
void GpioHandler::flashLightEnable(bool value)
|
||||
{
|
||||
ESP_LOGD(TAG_SERVERGPIO, "GpioHandler::flashLightEnable %s\r\n", value ? "true" : "false");
|
||||
ESP_LOGD(TAG, "GpioHandler::flashLightEnable %s", value ? "true" : "false");
|
||||
|
||||
if (gpioMap != NULL) {
|
||||
for(std::map<gpio_num_t, GpioPin*>::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it)
|
||||
@@ -557,26 +552,49 @@ void GpioHandler::flashLightEnable(bool value)
|
||||
it->second->setValue(value, GPIO_SET_SOURCE_INTERNAL, &resp_str);
|
||||
|
||||
if (resp_str == "") {
|
||||
ESP_LOGD(TAG_SERVERGPIO, "Flash light pin GPIO %d switched to %s\r\n", (int)it->first, (value ? "on" : "off"));
|
||||
ESP_LOGD(TAG, "Flash light pin GPIO %d switched to %s", (int)it->first, (value ? "on" : "off"));
|
||||
} else {
|
||||
ESP_LOGE(TAG_SERVERGPIO, "Can't set flash light pin GPIO %d. Error: %s\r\n", (int)it->first, resp_str.c_str());
|
||||
ESP_LOGE(TAG, "Can't set flash light pin GPIO %d. Error: %s", (int)it->first, resp_str.c_str());
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (it->second->getMode() == GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X)
|
||||
{
|
||||
#ifdef __LEDGLOBAL
|
||||
if (leds_global == NULL) {
|
||||
ESP_LOGI(TAG, "init SmartLed: LEDNumber=%d, GPIO=%d", LEDNumbers, (int)it->second->getGPIO());
|
||||
leds_global = new SmartLed( LEDType, LEDNumbers, it->second->getGPIO(), 0, DoubleBuffer );
|
||||
} else {
|
||||
// wait until we can update: https://github.com/RoboticsBrno/SmartLeds/issues/10#issuecomment-386921623
|
||||
leds_global->wait();
|
||||
}
|
||||
#else
|
||||
SmartLed leds( LEDType, LEDNumbers, it->second->getGPIO(), 0, DoubleBuffer );
|
||||
#endif
|
||||
|
||||
if (value)
|
||||
{
|
||||
for (int i = 0; i < LEDNumbers; ++i)
|
||||
#ifdef __LEDGLOBAL
|
||||
(*leds_global)[i] = LEDColor;
|
||||
#else
|
||||
leds[i] = LEDColor;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < LEDNumbers; ++i)
|
||||
#ifdef __LEDGLOBAL
|
||||
(*leds_global)[i] = Rgb{0, 0, 0};
|
||||
#else
|
||||
leds[i] = Rgb{0, 0, 0};
|
||||
#endif
|
||||
}
|
||||
leds.show();
|
||||
#ifdef __LEDGLOBAL
|
||||
leds_global->show();
|
||||
#else
|
||||
leds.show();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
//#include "ClassControllCamera.h"
|
||||
|
||||
// wenn __LEDGLOBAL definiert ist, wird eine globale Variable für die LED-Ansteuerung verwendet, ansonsten lokal und jedesmal neu
|
||||
#define __LEDGLOBAL
|
||||
|
||||
typedef enum {
|
||||
GPIO_PIN_MODE_DISABLED = 0x0,
|
||||
GPIO_PIN_MODE_INPUT = 0x1,
|
||||
@@ -86,7 +89,9 @@ private:
|
||||
int LEDNumbers = 2;
|
||||
Rgb LEDColor = Rgb{ 255, 255, 255 };
|
||||
LedType LEDType = LED_WS2812;
|
||||
|
||||
#ifdef __LEDGLOBAL
|
||||
SmartLed *leds_global = NULL;
|
||||
#endif
|
||||
|
||||
bool readConfig();
|
||||
void clear();
|
||||
|
||||
@@ -4,6 +4,6 @@ list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/proto
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES esp32-camera-master esp_http_server jomjol_logfile jomjol_image_proc nvs_flash jomjol_fileserver_ota jomjol_controlGPIO)
|
||||
REQUIRES esp32-camera esp_http_server jomjol_logfile jomjol_image_proc nvs_flash jomjol_fileserver_ota jomjol_controlGPIO)
|
||||
|
||||
|
||||
|
||||
@@ -30,10 +30,26 @@
|
||||
|
||||
// #define DEBUG_DETAIL_ON
|
||||
|
||||
#define USE_PWM_LEDFLASH
|
||||
|
||||
#ifdef USE_PWM_LEDFLASH
|
||||
|
||||
//// PWM für Flash-LED
|
||||
#define LEDC_TIMER LEDC_TIMER_1 // LEDC_TIMER_0
|
||||
#define LEDC_MODE LEDC_LOW_SPEED_MODE
|
||||
#define LEDC_OUTPUT_IO (4) // Define the output GPIO
|
||||
#define LEDC_CHANNEL LEDC_CHANNEL_1
|
||||
#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // Set duty resolution to 13 bits
|
||||
//#define LEDC_DUTY (195) // Set duty to 50%. ((2 ** 13) - 1) * 50% = 4095
|
||||
#define LEDC_FREQUENCY (5000) // Frequency in Hertz. Set frequency at 5 kHz
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// ESP32Cam (AiThinker) PIN Map
|
||||
|
||||
#define CAM_PIN_PWDN (gpio_num_t) 32
|
||||
#define CAM_PIN_PWDN 32
|
||||
#define CAM_PIN_RESET -1 //software reset will be performed
|
||||
#define CAM_PIN_XCLK 0
|
||||
#define CAM_PIN_SIOD 26
|
||||
@@ -51,7 +67,8 @@
|
||||
#define CAM_PIN_HREF 23
|
||||
#define CAM_PIN_PCLK 22
|
||||
|
||||
static const char *TAGCAMERACLASS = "server_part_camera";
|
||||
|
||||
static const char *TAG = "CAM";
|
||||
|
||||
static camera_config_t camera_config = {
|
||||
.pin_pwdn = CAM_PIN_PWDN,
|
||||
@@ -73,19 +90,20 @@ static camera_config_t camera_config = {
|
||||
.pin_pclk = CAM_PIN_PCLK,
|
||||
|
||||
//XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental)
|
||||
// .xclk_freq_hz = 20000000, // Orginalwert
|
||||
.xclk_freq_hz = 5000000, // Test, um die Bildfehler los zu werden !!!!
|
||||
.xclk_freq_hz = 20000000, // Orginalwert
|
||||
// .xclk_freq_hz = 5000000, // Test, um die Bildfehler los zu werden !!!! Hängt in Version 9.2 !!!!
|
||||
.ledc_timer = LEDC_TIMER_0,
|
||||
.ledc_channel = LEDC_CHANNEL_0,
|
||||
|
||||
.pixel_format = PIXFORMAT_JPEG, //YUV422,GRAYSCALE,RGB565,JPEG
|
||||
.frame_size = FRAMESIZE_VGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG
|
||||
// .frame_size = FRAMESIZE_UXGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG
|
||||
|
||||
.jpeg_quality = 12, //0-63 lower number means higher quality
|
||||
.fb_count = 1, //if more than one, i2s runs in continuous mode. Use only with JPEG
|
||||
.fb_location = CAMERA_FB_IN_PSRAM, /*!< The location where the frame buffer will be allocated */
|
||||
// .grab_mode = CAMERA_GRAB_WHEN_EMPTY,
|
||||
.grab_mode = CAMERA_GRAB_LATEST, // erst ab neuer esp32cam-version
|
||||
|
||||
|
||||
.jpeg_quality = 5, //0-63 lower number means higher quality
|
||||
.fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG
|
||||
};
|
||||
|
||||
|
||||
@@ -102,29 +120,36 @@ typedef struct {
|
||||
} jpg_chunking_t;
|
||||
|
||||
|
||||
#define LEDC_LS_CH2_GPIO (4)
|
||||
#define LEDC_LS_CH2_CHANNEL LEDC_CHANNEL_2
|
||||
#define LEDC_LS_TIMER LEDC_TIMER_1
|
||||
#define LEDC_LS_MODE LEDC_LOW_SPEED_MODE
|
||||
#define LEDC_TEST_DUTY (4000)
|
||||
void CCamera::ledc_init(void)
|
||||
{
|
||||
#ifdef USE_PWM_LEDFLASH
|
||||
|
||||
void test(){
|
||||
// Prepare and then apply the LEDC PWM timer configuration
|
||||
ledc_timer_config_t ledc_timer = { };
|
||||
|
||||
ledc_timer.speed_mode = LEDC_MODE;
|
||||
ledc_timer.timer_num = LEDC_TIMER;
|
||||
ledc_timer.duty_resolution = LEDC_DUTY_RES;
|
||||
ledc_timer.freq_hz = LEDC_FREQUENCY; // Set output frequency at 5 kHz
|
||||
ledc_timer.clk_cfg = LEDC_AUTO_CLK;
|
||||
|
||||
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
|
||||
|
||||
// Prepare and then apply the LEDC PWM channel configuration
|
||||
ledc_channel_config_t ledc_channel = { };
|
||||
|
||||
ledc_channel.channel = LEDC_LS_CH2_CHANNEL;
|
||||
ledc_channel.duty = 0;
|
||||
ledc_channel.gpio_num = FLASH_GPIO;
|
||||
ledc_channel.speed_mode = LEDC_LS_MODE;
|
||||
ledc_channel.hpoint = 0;
|
||||
ledc_channel.timer_sel = LEDC_LS_TIMER;
|
||||
ledc_channel.speed_mode = LEDC_MODE;
|
||||
ledc_channel.channel = LEDC_CHANNEL;
|
||||
ledc_channel.timer_sel = LEDC_TIMER;
|
||||
ledc_channel.intr_type = LEDC_INTR_DISABLE;
|
||||
ledc_channel.gpio_num = LEDC_OUTPUT_IO;
|
||||
ledc_channel.duty = 0; // Set duty to 0%
|
||||
ledc_channel.hpoint = 0;
|
||||
|
||||
ledc_channel_config(&ledc_channel);
|
||||
|
||||
ledc_set_duty(ledc_channel.speed_mode, ledc_channel.channel, LEDC_TEST_DUTY);
|
||||
ledc_update_duty(ledc_channel.speed_mode, ledc_channel.channel);
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
};
|
||||
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){
|
||||
@@ -147,9 +172,11 @@ bool CCamera::SetBrightnessContrastSaturation(int _brightness, int _contrast, in
|
||||
_brightness = min(2, max(-2, _brightness));
|
||||
if (_contrast > -100)
|
||||
_contrast = min(2, max(-2, _contrast));
|
||||
// _saturation = min(2, max(-2, _saturation));
|
||||
if (_saturation > -100)
|
||||
_saturation = min(2, max(-2, _saturation));
|
||||
|
||||
// s->set_saturation(s, _saturation);
|
||||
if (_saturation > -100)
|
||||
s->set_saturation(s, _saturation);
|
||||
if (_contrast > -100)
|
||||
s->set_contrast(s, _contrast);
|
||||
if (_brightness > -100)
|
||||
@@ -222,6 +249,7 @@ void CCamera::SetQualitySize(int qual, framesize_t resol)
|
||||
|
||||
void CCamera::EnableAutoExposure(int flashdauer)
|
||||
{
|
||||
ESP_LOGD(TAG, "EnableAutoExposure");
|
||||
LEDOnOff(true);
|
||||
if (flashdauer > 0)
|
||||
LightOnOff(true);
|
||||
@@ -229,11 +257,15 @@ void CCamera::EnableAutoExposure(int flashdauer)
|
||||
vTaskDelay( xDelay );
|
||||
|
||||
camera_fb_t * fb = esp_camera_fb_get();
|
||||
esp_camera_fb_return(fb);
|
||||
fb = esp_camera_fb_get();
|
||||
if (!fb) {
|
||||
ESP_LOGE(TAGCAMERACLASS, "Camera Capture Failed");
|
||||
ESP_LOGE(TAG, "Camera Capture Failed");
|
||||
LEDOnOff(false);
|
||||
LightOnOff(false);
|
||||
doReboot();
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Capture Failed (Procedure 'EnableAutoExposure') --> Reboot! "
|
||||
"Check that your camera module is working and connected properly.");
|
||||
//doReboot();
|
||||
}
|
||||
esp_camera_fb_return(fb);
|
||||
|
||||
@@ -275,10 +307,15 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay)
|
||||
#endif
|
||||
|
||||
camera_fb_t * fb = esp_camera_fb_get();
|
||||
esp_camera_fb_return(fb);
|
||||
fb = esp_camera_fb_get();
|
||||
if (!fb) {
|
||||
ESP_LOGE(TAGCAMERACLASS, "CaptureToBasisImage: Camera Capture Failed");
|
||||
ESP_LOGE(TAG, "CaptureToBasisImage: Capture Failed");
|
||||
LEDOnOff(false);
|
||||
LightOnOff(false);
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "is not working anymore (CCamera::CaptureToBasisImage) - most probably caused by a hardware problem (instablility, ...). "
|
||||
"System will reboot.");
|
||||
doReboot();
|
||||
|
||||
return ESP_FAIL;
|
||||
@@ -286,6 +323,11 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay)
|
||||
|
||||
int _size = fb->len;
|
||||
zwischenspeicher = (uint8_t*) malloc(_size);
|
||||
if (!zwischenspeicher)
|
||||
{
|
||||
ESP_LOGE(TAG, "Insufficient memory space for image in function CaptureToBasisImage()");
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Insufficient memory space for image in function CaptureToBasisImage()");
|
||||
}
|
||||
for (int i = 0; i < _size; ++i)
|
||||
*(zwischenspeicher + i) = *(fb->buf + i);
|
||||
esp_camera_fb_return(fb);
|
||||
@@ -321,7 +363,7 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay)
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
std::string _zw = "Targetimage: " + std::to_string((int) _Image->rgb_image) + " Size: " + std::to_string(_Image->width) + ", " + std::to_string(_Image->height);
|
||||
_zw = _zw + " _zwImage: " + std::to_string((int) _zwImage.rgb_image) + " Size: " + std::to_string(_zwImage.width) + ", " + std::to_string(_zwImage.height);
|
||||
LogFile.WriteToFile(_zw);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, _zw);
|
||||
#endif
|
||||
|
||||
for (int x = 0; x < width; ++x)
|
||||
@@ -362,30 +404,34 @@ esp_err_t CCamera::CaptureToFile(std::string nm, int delay)
|
||||
}
|
||||
|
||||
camera_fb_t * fb = esp_camera_fb_get();
|
||||
esp_camera_fb_return(fb);
|
||||
fb = esp_camera_fb_get();
|
||||
if (!fb) {
|
||||
ESP_LOGE(TAGCAMERACLASS, "CaptureToFile: Camera Capture Failed");
|
||||
ESP_LOGE(TAG, "CaptureToFile: Camera Capture Failed");
|
||||
LEDOnOff(false);
|
||||
LightOnOff(false);
|
||||
doReboot();
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Capture Failed (CCamera::CaptureToFile) --> Reboot! "
|
||||
"Check that your camera module is working and connected properly.");
|
||||
//doReboot();
|
||||
|
||||
return ESP_FAIL;
|
||||
}
|
||||
LEDOnOff(false);
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
printf("w %d, h %d, size %d\n", fb->width, fb->height, fb->len);
|
||||
ESP_LOGD(TAG, "w %d, h %d, size %d", fb->width, fb->height, fb->len);
|
||||
#endif
|
||||
|
||||
nm = FormatFileName(nm);
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
printf("Save Camera to : %s\n", nm.c_str());
|
||||
ESP_LOGD(TAG, "Save Camera to : %s", nm.c_str());
|
||||
#endif
|
||||
|
||||
ftype = toUpper(getFileType(nm));
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
printf("Filetype: %s\n", ftype.c_str());
|
||||
ESP_LOGD(TAG, "Filetype: %s", ftype.c_str());
|
||||
#endif
|
||||
|
||||
uint8_t * buf = NULL;
|
||||
@@ -403,7 +449,7 @@ esp_err_t CCamera::CaptureToFile(std::string nm, int delay)
|
||||
bool jpeg_converted = frame2jpg(fb, ActualQuality, &buf, &buf_len);
|
||||
converted = true;
|
||||
if(!jpeg_converted){
|
||||
ESP_LOGE(TAGCAMERACLASS, "JPEG compression failed");
|
||||
ESP_LOGE(TAG, "JPEG compression failed");
|
||||
}
|
||||
} else {
|
||||
buf_len = fb->len;
|
||||
@@ -453,9 +499,11 @@ esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay)
|
||||
}
|
||||
|
||||
|
||||
fb = esp_camera_fb_get();
|
||||
esp_camera_fb_return(fb);
|
||||
fb = esp_camera_fb_get();
|
||||
if (!fb) {
|
||||
ESP_LOGE(TAGCAMERACLASS, "Camera capture failed");
|
||||
ESP_LOGE(TAG, "Camera capture failed");
|
||||
LEDOnOff(false);
|
||||
LightOnOff(false);
|
||||
httpd_resp_send_500(req);
|
||||
@@ -485,7 +533,7 @@ esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay)
|
||||
esp_camera_fb_return(fb);
|
||||
int64_t fr_end = esp_timer_get_time();
|
||||
|
||||
ESP_LOGI(TAGCAMERACLASS, "JPG: %uKB %ums", (uint32_t)(fb_len/1024), (uint32_t)((fr_end - fr_start)/1000));
|
||||
ESP_LOGI(TAG, "JPG: %uKB %ums", (uint32_t)(fb_len/1024), (uint32_t)((fr_end - fr_start)/1000));
|
||||
|
||||
if (delay > 0)
|
||||
{
|
||||
@@ -499,18 +547,34 @@ void CCamera::LightOnOff(bool status)
|
||||
{
|
||||
GpioHandler* gpioHandler = gpio_handler_get();
|
||||
if ((gpioHandler != NULL) && (gpioHandler->isEnabled())) {
|
||||
printf("Use gpioHandler flashLigh\n");
|
||||
ESP_LOGD(TAG, "Use gpioHandler flashLigh");
|
||||
gpioHandler->flashLightEnable(status);
|
||||
} else {
|
||||
#ifdef USE_PWM_LEDFLASH
|
||||
if (status)
|
||||
{
|
||||
ESP_LOGD(TAG, "Internal Flash-LED turn on with PWM %d", led_intensity);
|
||||
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, led_intensity));
|
||||
// Update duty to apply the new value
|
||||
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGD(TAG, "Internal Flash-LED turn off PWM");
|
||||
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0));
|
||||
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
|
||||
}
|
||||
#else
|
||||
// Init the GPIO
|
||||
gpio_pad_select_gpio(FLASH_GPIO);
|
||||
/* Set the GPIO as a push/pull output */
|
||||
// Set the GPIO as a push/pull output
|
||||
gpio_set_direction(FLASH_GPIO, GPIO_MODE_OUTPUT);
|
||||
|
||||
if (status)
|
||||
gpio_set_level(FLASH_GPIO, 1);
|
||||
else
|
||||
gpio_set_level(FLASH_GPIO, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,11 +604,11 @@ void CCamera::GetCameraParameter(httpd_req_t *req, int &qual, framesize_t &resol
|
||||
|
||||
if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
|
||||
{
|
||||
printf("Query: "); printf(_query); printf("\n");
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
if (httpd_query_key_value(_query, "size", _size, 10) == ESP_OK)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
printf("Size: "); printf(_size); printf("\n");
|
||||
ESP_LOGD(TAG, "Size: %s", _size);
|
||||
#endif
|
||||
if (strcmp(_size, "QVGA") == 0)
|
||||
resol = FRAMESIZE_QVGA; // 320x240
|
||||
@@ -562,7 +626,7 @@ void CCamera::GetCameraParameter(httpd_req_t *req, int &qual, framesize_t &resol
|
||||
if (httpd_query_key_value(_query, "quality", _qual, 10) == ESP_OK)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
printf("Quality: "); printf(_qual); printf("\n");
|
||||
ESP_LOGD(TAG, "Quality: %s", _qual);
|
||||
#endif
|
||||
qual = atoi(_qual);
|
||||
|
||||
@@ -595,33 +659,37 @@ framesize_t CCamera::TextToFramesize(const char * _size)
|
||||
CCamera::CCamera()
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
printf("CreateClassCamera\n");
|
||||
ESP_LOGD(TAG, "CreateClassCamera");
|
||||
#endif
|
||||
brightness = -5;
|
||||
contrast = -5;
|
||||
saturation = -5;
|
||||
isFixedExposure = false;
|
||||
|
||||
ledc_init();
|
||||
}
|
||||
|
||||
esp_err_t CCamera::InitCam()
|
||||
{
|
||||
if(CAM_PIN_PWDN != -1){
|
||||
// Init the GPIO
|
||||
gpio_pad_select_gpio(CAM_PIN_PWDN);
|
||||
/* Set the GPIO as a push/pull output */
|
||||
gpio_set_direction(CAM_PIN_PWDN, GPIO_MODE_OUTPUT);
|
||||
gpio_set_level(CAM_PIN_PWDN, 0);
|
||||
}
|
||||
|
||||
printf("Init Camera\n");
|
||||
ESP_LOGD(TAG, "Init Camera");
|
||||
ActualQuality = camera_config.jpeg_quality;
|
||||
ActualResolution = camera_config.frame_size;
|
||||
//initialize the camera
|
||||
esp_err_t err = esp_camera_init(&camera_config);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAGCAMERACLASS, "Camera Init Failed");
|
||||
ESP_LOGE(TAG, "Camera Init Failed");
|
||||
return err;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
|
||||
void CCamera::SetLEDIntensity(float _intrel)
|
||||
{
|
||||
_intrel = min(_intrel, (float) 100);
|
||||
_intrel = max(_intrel, (float) 0);
|
||||
_intrel = _intrel / 100;
|
||||
led_intensity = (int) (_intrel * 8191);
|
||||
ESP_LOGD(TAG, "Set led_intensity to %d of 8191", led_intensity);
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ class CCamera {
|
||||
int brightness, contrast, saturation;
|
||||
bool isFixedExposure;
|
||||
int waitbeforepicture_org;
|
||||
int led_intensity = 4095;
|
||||
|
||||
void ledc_init(void);
|
||||
|
||||
public:
|
||||
int image_height, image_width;
|
||||
@@ -36,6 +39,7 @@ class CCamera {
|
||||
void SetQualitySize(int qual, framesize_t resol);
|
||||
bool SetBrightnessContrastSaturation(int _brightness, int _contrast, int _saturation);
|
||||
void GetCameraParameter(httpd_req_t *req, int &qual, framesize_t &resol);
|
||||
void SetLEDIntensity(float _intrel);
|
||||
|
||||
void EnableAutoExposure(int flashdauer);
|
||||
|
||||
|
||||
@@ -11,11 +11,48 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define OV9650_PID (0x96)
|
||||
#define OV7725_PID (0x77)
|
||||
#define OV2640_PID (0x26)
|
||||
#define OV3660_PID (0x36)
|
||||
#define OV5640_PID (0x56)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
OV9650_PID = 0x96,
|
||||
OV7725_PID = 0x77,
|
||||
OV2640_PID = 0x26,
|
||||
OV3660_PID = 0x3660,
|
||||
OV5640_PID = 0x5640,
|
||||
OV7670_PID = 0x76,
|
||||
NT99141_PID = 0x1410,
|
||||
GC2145_PID = 0x2145,
|
||||
GC032A_PID = 0x232a,
|
||||
GC0308_PID = 0x9b,
|
||||
} camera_pid_t;
|
||||
|
||||
typedef enum {
|
||||
CAMERA_OV7725,
|
||||
CAMERA_OV2640,
|
||||
CAMERA_OV3660,
|
||||
CAMERA_OV5640,
|
||||
CAMERA_OV7670,
|
||||
CAMERA_NT99141,
|
||||
CAMERA_GC2145,
|
||||
CAMERA_GC032A,
|
||||
CAMERA_GC0308,
|
||||
CAMERA_MODEL_MAX,
|
||||
CAMERA_NONE,
|
||||
} camera_model_t;
|
||||
|
||||
typedef enum {
|
||||
OV2640_SCCB_ADDR = 0x30,// 0x60 >> 1
|
||||
OV5640_SCCB_ADDR = 0x3C,// 0x78 >> 1
|
||||
OV3660_SCCB_ADDR = 0x3C,// 0x78 >> 1
|
||||
OV7725_SCCB_ADDR = 0x21,// 0x42 >> 1
|
||||
OV7670_SCCB_ADDR = 0x21,// 0x42 >> 1
|
||||
NT99141_SCCB_ADDR = 0x2A,// 0x54 >> 1
|
||||
GC2145_SCCB_ADDR = 0x3C,// 0x78 >> 1
|
||||
GC032A_SCCB_ADDR = 0x21,// 0x42 >> 1
|
||||
GC0308_SCCB_ADDR = 0x21,// 0x42 >> 1
|
||||
} camera_sccb_addr_t;
|
||||
|
||||
typedef enum {
|
||||
PIXFORMAT_RGB565, // 2BPP/RGB565
|
||||
@@ -56,6 +93,15 @@ typedef enum {
|
||||
FRAMESIZE_INVALID
|
||||
} framesize_t;
|
||||
|
||||
typedef struct {
|
||||
const camera_model_t model;
|
||||
const char *name;
|
||||
const camera_sccb_addr_t sccb_addr;
|
||||
const camera_pid_t pid;
|
||||
const framesize_t max_size;
|
||||
const bool support_jpeg;
|
||||
} camera_sensor_info_t;
|
||||
|
||||
typedef enum {
|
||||
ASPECT_RATIO_4X3,
|
||||
ASPECT_RATIO_3X2,
|
||||
@@ -99,11 +145,13 @@ typedef struct {
|
||||
|
||||
// Resolution table (in sensor.c)
|
||||
extern const resolution_info_t resolution[];
|
||||
// camera sensor table (in sensor.c)
|
||||
extern const camera_sensor_info_t camera_sensor[];
|
||||
|
||||
typedef struct {
|
||||
uint8_t MIDH;
|
||||
uint8_t MIDL;
|
||||
uint8_t PID;
|
||||
uint16_t PID;
|
||||
uint8_t VER;
|
||||
} sensor_id_t;
|
||||
|
||||
@@ -188,4 +236,10 @@ typedef struct _sensor {
|
||||
int (*set_xclk) (sensor_t *sensor, int timer, int xclk);
|
||||
} sensor_t;
|
||||
|
||||
camera_sensor_info_t *esp_camera_sensor_get_info(sensor_id_t *id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SENSOR_H__ */
|
||||
@@ -7,16 +7,18 @@
|
||||
#include "ClassControllCamera.h"
|
||||
|
||||
#include "ClassLogFile.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "server_cam";
|
||||
|
||||
#define SCRATCH_BUFSIZE2 8192
|
||||
char scratch2[SCRATCH_BUFSIZE2];
|
||||
|
||||
//#define DEBUG_DETAIL_ON
|
||||
static const char *TAGPARTCAMERA = "server_camera";
|
||||
|
||||
|
||||
void PowerResetCamera(){
|
||||
ESP_LOGD(TAGPARTCAMERA, "Resetting camera by power down line");
|
||||
ESP_LOGD(TAG, "Resetting camera by power down line");
|
||||
gpio_config_t conf;
|
||||
conf.intr_type = GPIO_INTR_DISABLE;
|
||||
conf.pin_bit_mask = 1LL << GPIO_NUM_32;
|
||||
@@ -37,7 +39,7 @@ esp_err_t handler_lightOn(httpd_req_t *req)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_lightOn - Start");
|
||||
printf("handler_lightOn uri:\n"); printf(req->uri); printf("\n");
|
||||
ESP_LOGD(TAG, "handler_lightOn uri: %s", req->uri);
|
||||
#endif
|
||||
|
||||
Camera.LightOnOff(true);
|
||||
@@ -55,7 +57,7 @@ esp_err_t handler_lightOff(httpd_req_t *req)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_lightOff - Start");
|
||||
printf("handler_lightOff uri:\n"); printf(req->uri); printf("\n");
|
||||
ESP_LOGD(TAG, "handler_lightOff uri: %s", req->uri);
|
||||
#endif
|
||||
Camera.LightOnOff(false);
|
||||
const char* resp_str = (const char*) req->user_ctx;
|
||||
@@ -80,7 +82,7 @@ esp_err_t handler_capture(httpd_req_t *req)
|
||||
Camera.GetCameraParameter(req, quality, res);
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
printf("Size: %d", res); printf(" Quality: %d\n", quality);
|
||||
ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality);
|
||||
#endif
|
||||
|
||||
Camera.SetQualitySize(quality, res);
|
||||
@@ -110,11 +112,11 @@ esp_err_t handler_capture_with_ligth(httpd_req_t *req)
|
||||
|
||||
if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
|
||||
{
|
||||
printf("Query: "); printf(_query); printf("\n");
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
if (httpd_query_key_value(_query, "delay", _delay, 10) == ESP_OK)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
printf("Delay: "); printf(_delay); printf("\n");
|
||||
ESP_LOGD(TAG, "Delay: %s", _delay);
|
||||
#endif
|
||||
delay = atoi(_delay);
|
||||
|
||||
@@ -126,7 +128,7 @@ esp_err_t handler_capture_with_ligth(httpd_req_t *req)
|
||||
Camera.GetCameraParameter(req, quality, res);
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
printf("Size: %d", res); printf(" Quality: %d\n", quality);
|
||||
ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality);
|
||||
#endif
|
||||
|
||||
Camera.SetQualitySize(quality, res);
|
||||
@@ -166,12 +168,12 @@ esp_err_t handler_capture_save_to_file(httpd_req_t *req)
|
||||
|
||||
if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
|
||||
{
|
||||
printf("Query: "); printf(_query); printf("\n");
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
if (httpd_query_key_value(_query, "filename", filename, 100) == ESP_OK)
|
||||
{
|
||||
fn.append(filename);
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
printf("Filename: "); printf(fn.c_str()); printf("\n");
|
||||
ESP_LOGD(TAG, "Filename: %s", fn.c_str());
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@@ -180,7 +182,7 @@ esp_err_t handler_capture_save_to_file(httpd_req_t *req)
|
||||
if (httpd_query_key_value(_query, "delay", _delay, 10) == ESP_OK)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
printf("Delay: "); printf(_delay); printf("\n");
|
||||
ESP_LOGD(TAG, "Delay: %s", _delay);
|
||||
#endif
|
||||
delay = atoi(_delay);
|
||||
|
||||
@@ -194,7 +196,7 @@ esp_err_t handler_capture_save_to_file(httpd_req_t *req)
|
||||
|
||||
Camera.GetCameraParameter(req, quality, res);
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
printf("Size: %d", res); printf(" Quality: %d\n", quality);
|
||||
ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality);
|
||||
#endif
|
||||
Camera.SetQualitySize(quality, res);
|
||||
|
||||
@@ -216,7 +218,7 @@ esp_err_t handler_capture_save_to_file(httpd_req_t *req)
|
||||
void register_server_camera_uri(httpd_handle_t server)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGI(TAGPARTCAMERA, "server_part_camera - Registering URI handlers");
|
||||
ESP_LOGI(TAG, "server_part_camera - Registering URI handlers");
|
||||
#endif
|
||||
|
||||
httpd_uri_t camuri = { };
|
||||
|
||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "." "../../include"
|
||||
REQUIRES tfmicro esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO)
|
||||
REQUIRES tflite-lib esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO miniz)
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,14 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
@@ -29,6 +36,8 @@
|
||||
#include "defines.h"
|
||||
#include "ClassLogFile.h"
|
||||
|
||||
#include "server_tflite.h"
|
||||
|
||||
#include "server_help.h"
|
||||
#include "interface_mqtt.h"
|
||||
#include "server_GPIO.h"
|
||||
@@ -36,17 +45,23 @@
|
||||
#include "Helper.h"
|
||||
#include "miniz.h"
|
||||
|
||||
static const char *TAG = "OTA FILE";
|
||||
|
||||
/* Max length a file path can have on storage */
|
||||
// #define FILE_PATH_MAX (ESP_VFS_PATH_MAX + CONFIG_SPIFFS_OBJ_NAME_LEN)
|
||||
#define FILE_PATH_MAX (255)
|
||||
|
||||
/* Max size of an individual file. Make sure this
|
||||
* value is same as that set in upload_script.html */
|
||||
#define MAX_FILE_SIZE (2000*1024) // 200 KB
|
||||
#define MAX_FILE_SIZE_STR "2000KB"
|
||||
#define MAX_FILE_SIZE (8000*1024) // 8 MB
|
||||
#define MAX_FILE_SIZE_STR "8MB"
|
||||
|
||||
|
||||
/* Scratch buffer size */
|
||||
#define SCRATCH_BUFSIZE 8192
|
||||
#define SCRATCH_BUFSIZE 4096
|
||||
|
||||
/* Size of partial log file to return */
|
||||
#define LOGFILE_LAST_PART_BYTES SCRATCH_BUFSIZE * 20 /* 80 kBytes */
|
||||
|
||||
struct file_server_data {
|
||||
/* Base path of file storage */
|
||||
@@ -56,17 +71,123 @@ struct file_server_data {
|
||||
char scratch[SCRATCH_BUFSIZE];
|
||||
};
|
||||
|
||||
static const char *TAG_FILESERVER = "file_server";
|
||||
|
||||
/* Handler to redirect incoming GET request for /index.html to /
|
||||
* This can be overridden by uploading file with same name */
|
||||
// static esp_err_t index_html_get_handler(httpd_req_t *req)
|
||||
// {
|
||||
// httpd_resp_set_status(req, "307 Temporary Redirect");
|
||||
// httpd_resp_set_hdr(req, "Location", "/");
|
||||
// httpd_resp_send(req, NULL, 0); // Response body can be empty
|
||||
// return ESP_OK;
|
||||
// }
|
||||
#include <iostream>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
string SUFFIX_ZW = "_0xge";
|
||||
|
||||
|
||||
static esp_err_t send_logfile(httpd_req_t *req, bool send_full_file);
|
||||
static esp_err_t send_datafile(httpd_req_t *req, bool send_full_file);
|
||||
|
||||
|
||||
esp_err_t get_numbers_file_handler(httpd_req_t *req)
|
||||
{
|
||||
std::string ret = tfliteflow.getNumbersName();
|
||||
|
||||
// ESP_LOGI(TAG, "Result get_numbers_file_handler: %s", ret.c_str());
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
httpd_resp_set_type(req, "text/plain");
|
||||
|
||||
httpd_resp_sendstr_chunk(req, ret.c_str());
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t get_data_file_handler(httpd_req_t *req)
|
||||
{
|
||||
struct dirent *entry;
|
||||
|
||||
std::string _filename, _fileext;
|
||||
size_t pos = 0;
|
||||
|
||||
const char verz_name[] = "/sdcard/log/data";
|
||||
ESP_LOGD(TAG, "Suche data files in /sdcard/log/data");
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
httpd_resp_set_type(req, "text/plain");
|
||||
|
||||
DIR *dir = opendir(verz_name);
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
_filename = std::string(entry->d_name);
|
||||
ESP_LOGD(TAG, "File: %s", _filename.c_str());
|
||||
|
||||
// ignore all files with starting dot (hidden files)
|
||||
if (_filename.rfind(".", 0) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_fileext = _filename;
|
||||
pos = _fileext.find_last_of(".");
|
||||
if (pos != std::string::npos)
|
||||
_fileext = _fileext.erase(0, pos + 1);
|
||||
|
||||
ESP_LOGD(TAG, " Extension: %s", _fileext.c_str());
|
||||
|
||||
if (_fileext == "csv")
|
||||
{
|
||||
_filename = _filename + "\t";
|
||||
httpd_resp_sendstr_chunk(req, _filename.c_str());
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t get_tflite_file_handler(httpd_req_t *req)
|
||||
{
|
||||
struct dirent *entry;
|
||||
|
||||
std::string _filename, _fileext;
|
||||
size_t pos = 0;
|
||||
|
||||
const char verz_name[] = "/sdcard/config";
|
||||
ESP_LOGD(TAG, "Suche TFLITE in /sdcard/config/");
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
httpd_resp_set_type(req, "text/plain");
|
||||
|
||||
DIR *dir = opendir(verz_name);
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
_filename = std::string(entry->d_name);
|
||||
ESP_LOGD(TAG, "File: %s", _filename.c_str());
|
||||
|
||||
// ignore all files with starting dot (hidden files)
|
||||
if (_filename.rfind(".", 0) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_fileext = _filename;
|
||||
pos = _fileext.find_last_of(".");
|
||||
if (pos != std::string::npos)
|
||||
_fileext = _fileext.erase(0, pos + 1);
|
||||
|
||||
ESP_LOGD(TAG, " Extension: %s", _fileext.c_str());
|
||||
|
||||
if ((_fileext == "tfl") || (_fileext == "tflite"))
|
||||
{
|
||||
_filename = "/config/" + _filename + "\t";
|
||||
httpd_resp_sendstr_chunk(req, _filename.c_str());
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Send HTTP response with a run-time generated html consisting of
|
||||
* a list of all files and folders under the requested path.
|
||||
@@ -91,14 +212,14 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const
|
||||
DIR *dir = opendir(dirpath_corrected);
|
||||
|
||||
const size_t dirpath_len = strlen(dirpath);
|
||||
printf("Dirpath: <%s>, Pathlength: %d\n", dirpath, dirpath_len);
|
||||
ESP_LOGD(TAG, "Dirpath: <%s>, Pathlength: %d", dirpath, dirpath_len);
|
||||
|
||||
/* Retrieve the base path of file storage to construct the full path */
|
||||
strlcpy(entrypath, dirpath, sizeof(entrypath));
|
||||
printf("entrypath: <%s>\n", entrypath);
|
||||
ESP_LOGD(TAG, "entrypath: <%s>", entrypath);
|
||||
|
||||
if (!dir) {
|
||||
ESP_LOGE(TAG_FILESERVER, "Failed to stat dir : %s", dirpath);
|
||||
ESP_LOGE(TAG, "Failed to stat dir : %s", dirpath);
|
||||
/* Respond with 404 Not Found */
|
||||
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Directory does not exist");
|
||||
return ESP_FAIL;
|
||||
@@ -114,11 +235,11 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const
|
||||
size_t chunksize;
|
||||
do {
|
||||
chunksize = fread(chunk, 1, SCRATCH_BUFSIZE, fd);
|
||||
// printf("Chunksize %d\n", chunksize);
|
||||
// ESP_LOGD(TAG, "Chunksize %d", chunksize);
|
||||
if (chunksize > 0){
|
||||
if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
|
||||
fclose(fd);
|
||||
ESP_LOGE(TAG_FILESERVER, "File sending failed!");
|
||||
ESP_LOGE(TAG, "File sending failed!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
@@ -155,13 +276,13 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const
|
||||
entrytype = (entry->d_type == DT_DIR ? "directory" : "file");
|
||||
|
||||
strlcpy(entrypath + dirpath_len, entry->d_name, sizeof(entrypath) - dirpath_len);
|
||||
printf("Entrypath: %s\n", entrypath);
|
||||
ESP_LOGD(TAG, "Entrypath: %s", entrypath);
|
||||
if (stat(entrypath, &entry_stat) == -1) {
|
||||
ESP_LOGE(TAG_FILESERVER, "Failed to stat %s : %s", entrytype, entry->d_name);
|
||||
ESP_LOGE(TAG, "Failed to stat %s : %s", entrytype, entry->d_name);
|
||||
continue;
|
||||
}
|
||||
sprintf(entrysize, "%ld", entry_stat.st_size);
|
||||
ESP_LOGI(TAG_FILESERVER, "Found %s : %s (%s bytes)", entrytype, entry->d_name, entrysize);
|
||||
ESP_LOGI(TAG, "Found %s : %s (%s bytes)", entrytype, entry->d_name, entrysize);
|
||||
|
||||
/* Send chunk of HTML file containing table entries with file name and size */
|
||||
httpd_resp_sendstr_chunk(req, "<tr><td><a href=\"");
|
||||
@@ -204,24 +325,43 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const
|
||||
(strcasecmp(&filename[strlen(filename) - sizeof(ext) + 1], ext) == 0)
|
||||
|
||||
|
||||
static esp_err_t logfileact_get_handler(httpd_req_t *req)
|
||||
static esp_err_t logfileact_get_full_handler(httpd_req_t *req) {
|
||||
return send_logfile(req, true);
|
||||
}
|
||||
|
||||
|
||||
static esp_err_t logfileact_get_last_part_handler(httpd_req_t *req) {
|
||||
return send_logfile(req, false);
|
||||
}
|
||||
|
||||
static esp_err_t datafileact_get_full_handler(httpd_req_t *req) {
|
||||
return send_datafile(req, true);
|
||||
}
|
||||
|
||||
|
||||
static esp_err_t datafileact_get_last_part_handler(httpd_req_t *req) {
|
||||
return send_datafile(req, false);
|
||||
}
|
||||
|
||||
static esp_err_t send_datafile(httpd_req_t *req, bool send_full_file)
|
||||
{
|
||||
LogFile.WriteToFile("logfileact_get_handler");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "data_get_last_part_handler");
|
||||
char filepath[FILE_PATH_MAX];
|
||||
FILE *fd = NULL;
|
||||
//struct stat file_stat;
|
||||
printf("uri: %s\n", req->uri);
|
||||
ESP_LOGD(TAG, "uri: %s", req->uri);
|
||||
|
||||
const char* filename = "log_current.txt";
|
||||
const char* filename = "";
|
||||
|
||||
printf("uri: %s, filename: %s, filepath: %s\n", req->uri, filename, filepath);
|
||||
std::string currentfilename = LogFile.GetCurrentFileNameData();
|
||||
|
||||
std::string currentfilename = LogFile.GetCurrentFileName();
|
||||
ESP_LOGD(TAG, "uri: %s, filename: %s, filepath: %s", req->uri, filename, filepath);
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
|
||||
fd = OpenFileAndWait(currentfilename.c_str(), "r");
|
||||
if (!fd) {
|
||||
ESP_LOGE(TAG_FILESERVER, "Failed to read existing file : %s", filepath);
|
||||
ESP_LOGE(TAG, "Failed to read existing file : %s", filepath);
|
||||
/* Respond with 500 Internal Server Error */
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to read existing file");
|
||||
return ESP_FAIL;
|
||||
@@ -229,9 +369,35 @@ static esp_err_t logfileact_get_handler(httpd_req_t *req)
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
|
||||
// ESP_LOGI(TAG_FILESERVER, "Sending file : %s (%ld bytes)...", &filename, file_stat.st_size);
|
||||
// ESP_LOGI(TAG, "Sending file : %s (%ld bytes)...", &filename, file_stat.st_size);
|
||||
set_content_type_from_file(req, filename);
|
||||
|
||||
if (!send_full_file) { // Send only last part of file
|
||||
ESP_LOGD(TAG, "Sending last %d bytes of the actual datafile!", LOGFILE_LAST_PART_BYTES);
|
||||
|
||||
/* Adapted from https://www.geeksforgeeks.org/implement-your-own-tail-read-last-n-lines-of-a-huge-file/ */
|
||||
if (fseek(fd, 0, SEEK_END)) {
|
||||
ESP_LOGE(TAG, "Failed to get to end of file!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
else {
|
||||
long pos = ftell(fd); // Number of bytes in the file
|
||||
ESP_LOGI(TAG, "File contains %ld bytes", pos);
|
||||
|
||||
if (fseek(fd, pos - std::min((long)LOGFILE_LAST_PART_BYTES, pos), SEEK_SET)) { // Go LOGFILE_LAST_PART_BYTES bytes back from EOF
|
||||
ESP_LOGE(TAG, "Failed to go back %ld bytes within the file!", std::min((long)LOGFILE_LAST_PART_BYTES, pos));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find end of line */
|
||||
while (1) {
|
||||
if (fgetc(fd) == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Retrieve the pointer to scratch buffer for temporary storage */
|
||||
char *chunk = ((struct file_server_data *)req->user_ctx)->scratch;
|
||||
size_t chunksize;
|
||||
@@ -242,7 +408,7 @@ static esp_err_t logfileact_get_handler(httpd_req_t *req)
|
||||
/* Send the buffer contents as HTTP response chunk */
|
||||
if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
|
||||
fclose(fd);
|
||||
ESP_LOGE(TAG_FILESERVER, "File sending failed!");
|
||||
ESP_LOGE(TAG, "File sending failed!");
|
||||
/* Abort sending file */
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
/* Respond with 500 Internal Server Error */
|
||||
@@ -255,7 +421,7 @@ static esp_err_t logfileact_get_handler(httpd_req_t *req)
|
||||
|
||||
/* Close file after sending complete */
|
||||
fclose(fd);
|
||||
ESP_LOGI(TAG_FILESERVER, "File sending complete");
|
||||
ESP_LOGI(TAG, "File sending complete");
|
||||
|
||||
/* Respond with an empty chunk to signal HTTP response completion */
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
@@ -263,31 +429,111 @@ static esp_err_t logfileact_get_handler(httpd_req_t *req)
|
||||
}
|
||||
|
||||
|
||||
static esp_err_t send_logfile(httpd_req_t *req, bool send_full_file)
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "log_get_last_part_handler");
|
||||
char filepath[FILE_PATH_MAX];
|
||||
FILE *fd = NULL;
|
||||
//struct stat file_stat;
|
||||
ESP_LOGI(TAG, "uri: %s", req->uri);
|
||||
|
||||
const char* filename = "";
|
||||
|
||||
std::string currentfilename = LogFile.GetCurrentFileName();
|
||||
|
||||
ESP_LOGD(TAG, "uri: %s, filename: %s, filepath: %s", req->uri, filename, filepath);
|
||||
|
||||
|
||||
fd = OpenFileAndWait(currentfilename.c_str(), "r");
|
||||
if (!fd) {
|
||||
ESP_LOGE(TAG, "Failed to read existing file : %s", filepath);
|
||||
/* Respond with 500 Internal Server Error */
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to read existing file");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
|
||||
// ESP_LOGI(TAG, "Sending file : %s (%ld bytes)...", &filename, file_stat.st_size);
|
||||
set_content_type_from_file(req, filename);
|
||||
|
||||
if (!send_full_file) { // Send only last part of file
|
||||
ESP_LOGD(TAG, "Sending last %d bytes of the actual logfile!", LOGFILE_LAST_PART_BYTES);
|
||||
|
||||
/* Adapted from https://www.geeksforgeeks.org/implement-your-own-tail-read-last-n-lines-of-a-huge-file/ */
|
||||
if (fseek(fd, 0, SEEK_END)) {
|
||||
ESP_LOGE(TAG, "Failed to get to end of file!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
else {
|
||||
long pos = ftell(fd); // Number of bytes in the file
|
||||
ESP_LOGI(TAG, "File contains %ld bytes", pos);
|
||||
|
||||
if (fseek(fd, pos - std::min((long)LOGFILE_LAST_PART_BYTES, pos), SEEK_SET)) { // Go LOGFILE_LAST_PART_BYTES bytes back from EOF
|
||||
ESP_LOGE(TAG, "Failed to go back %ld bytes within the file!", std::min((long)LOGFILE_LAST_PART_BYTES, pos));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find end of line */
|
||||
while (1) {
|
||||
if (fgetc(fd) == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Retrieve the pointer to scratch buffer for temporary storage */
|
||||
char *chunk = ((struct file_server_data *)req->user_ctx)->scratch;
|
||||
size_t chunksize;
|
||||
do {
|
||||
/* Read file in chunks into the scratch buffer */
|
||||
chunksize = fread(chunk, 1, SCRATCH_BUFSIZE, fd);
|
||||
|
||||
/* Send the buffer contents as HTTP response chunk */
|
||||
if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
|
||||
fclose(fd);
|
||||
ESP_LOGE(TAG, "File sending failed!");
|
||||
/* Abort sending file */
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
/* Respond with 500 Internal Server Error */
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to send file");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Keep looping till the whole file is sent */
|
||||
} while (chunksize != 0);
|
||||
|
||||
/* Close file after sending complete */
|
||||
fclose(fd);
|
||||
ESP_LOGI(TAG, "File sending complete");
|
||||
|
||||
/* Respond with an empty chunk to signal HTTP response completion */
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Handler to download a file kept on the server */
|
||||
static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
{
|
||||
LogFile.WriteToFile("download_get_handler");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "download_get_handler");
|
||||
char filepath[FILE_PATH_MAX];
|
||||
FILE *fd = NULL;
|
||||
struct stat file_stat;
|
||||
printf("uri: %s\n", req->uri);
|
||||
ESP_LOGD(TAG, "uri: %s", req->uri);
|
||||
|
||||
const char *filename = get_path_from_uri(filepath, ((struct file_server_data *)req->user_ctx)->base_path,
|
||||
req->uri + sizeof("/fileserver") - 1, sizeof(filepath));
|
||||
|
||||
printf("uri: %s, filename: %s, filepath: %s\n", req->uri, filename, filepath);
|
||||
ESP_LOGD(TAG, "uri: %s, filename: %s, filepath: %s", req->uri, filename, filepath);
|
||||
|
||||
// filename = get_path_from_uri(filepath, ((struct file_server_data *)req->user_ctx)->base_path,
|
||||
// req->uri, sizeof(filepath));
|
||||
|
||||
|
||||
if (!filename) {
|
||||
ESP_LOGE(TAG_FILESERVER, "Filename is too long");
|
||||
ESP_LOGE(TAG, "Filename is too long");
|
||||
/* Respond with 500 Internal Server Error */
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Filename too long");
|
||||
return ESP_FAIL;
|
||||
@@ -300,16 +546,17 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
if (buf_len > 1) {
|
||||
char buf[buf_len];
|
||||
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
|
||||
ESP_LOGI(TAG_FILESERVER, "Found URL query => %s", buf);
|
||||
ESP_LOGI(TAG, "Found URL query => %s", buf);
|
||||
char param[32];
|
||||
/* Get value of expected key from query string */
|
||||
if (httpd_query_key_value(buf, "readonly", param, sizeof(param)) == ESP_OK) {
|
||||
ESP_LOGI(TAG_FILESERVER, "Found URL query parameter => readonly=%s", param);
|
||||
ESP_LOGI(TAG, "Found URL query parameter => readonly=%s", param);
|
||||
readonly = param && strcmp(param,"true")==0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "uri: %s, filename: %s, filepath: %s", req->uri, filename, filepath);
|
||||
return http_resp_dir_html(req, filepath, filename, readonly);
|
||||
}
|
||||
|
||||
@@ -319,7 +566,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
|
||||
/* If file not present on SPIFFS check if URI
|
||||
* corresponds to one of the hardcoded paths */
|
||||
ESP_LOGE(TAG_FILESERVER, "Failed to stat file : %s", filepath);
|
||||
ESP_LOGE(TAG, "Failed to stat file : %s", filepath);
|
||||
/* Respond with 404 Not Found */
|
||||
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File does not exist");
|
||||
return ESP_FAIL;
|
||||
@@ -327,7 +574,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
|
||||
fd = OpenFileAndWait(filepath, "r");
|
||||
if (!fd) {
|
||||
ESP_LOGE(TAG_FILESERVER, "Failed to read existing file : %s", filepath);
|
||||
ESP_LOGE(TAG, "Failed to read existing file : %s", filepath);
|
||||
/* Respond with 500 Internal Server Error */
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to read existing file");
|
||||
return ESP_FAIL;
|
||||
@@ -335,7 +582,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
|
||||
ESP_LOGI(TAG_FILESERVER, "Sending file : %s (%ld bytes)...", filename, file_stat.st_size);
|
||||
ESP_LOGI(TAG, "Sending file : %s (%ld bytes)...", filename, file_stat.st_size);
|
||||
set_content_type_from_file(req, filename);
|
||||
|
||||
/* Retrieve the pointer to scratch buffer for temporary storage */
|
||||
@@ -348,7 +595,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
/* Send the buffer contents as HTTP response chunk */
|
||||
if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
|
||||
fclose(fd);
|
||||
ESP_LOGE(TAG_FILESERVER, "File sending failed!");
|
||||
ESP_LOGE(TAG, "File sending failed!");
|
||||
/* Abort sending file */
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
/* Respond with 500 Internal Server Error */
|
||||
@@ -361,7 +608,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
|
||||
/* Close file after sending complete */
|
||||
fclose(fd);
|
||||
ESP_LOGI(TAG_FILESERVER, "File sending complete");
|
||||
ESP_LOGI(TAG, "File successfully sent");
|
||||
|
||||
/* Respond with an empty chunk to signal HTTP response completion */
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
@@ -371,7 +618,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
/* Handler to upload a file onto the server */
|
||||
static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
{
|
||||
LogFile.WriteToFile("upload_post_handler");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "upload_post_handler");
|
||||
char filepath[FILE_PATH_MAX];
|
||||
FILE *fd = NULL;
|
||||
struct stat file_stat;
|
||||
@@ -388,13 +635,13 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
|
||||
/* Filename cannot have a trailing '/' */
|
||||
if (filename[strlen(filename) - 1] == '/') {
|
||||
ESP_LOGE(TAG_FILESERVER, "Invalid filename : %s", filename);
|
||||
ESP_LOGE(TAG, "Invalid filename : %s", filename);
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Invalid filename");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (stat(filepath, &file_stat) == 0) {
|
||||
ESP_LOGE(TAG_FILESERVER, "File already exists : %s", filepath);
|
||||
ESP_LOGE(TAG, "File already exists : %s", filepath);
|
||||
/* Respond with 400 Bad Request */
|
||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "File already exists");
|
||||
return ESP_FAIL;
|
||||
@@ -402,7 +649,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
|
||||
/* File cannot be larger than a limit */
|
||||
if (req->content_len > MAX_FILE_SIZE) {
|
||||
ESP_LOGE(TAG_FILESERVER, "File too large : %d bytes", req->content_len);
|
||||
ESP_LOGE(TAG, "File too large : %d bytes", req->content_len);
|
||||
/* Respond with 400 Bad Request */
|
||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST,
|
||||
"File size must be less than "
|
||||
@@ -414,13 +661,13 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
|
||||
fd = OpenFileAndWait(filepath, "w");
|
||||
if (!fd) {
|
||||
ESP_LOGE(TAG_FILESERVER, "Failed to create file : %s", filepath);
|
||||
ESP_LOGE(TAG, "Failed to create file : %s", filepath);
|
||||
/* Respond with 500 Internal Server Error */
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to create file");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_FILESERVER, "Receiving file : %s...", filename);
|
||||
ESP_LOGI(TAG, "Receiving file : %s...", filename);
|
||||
|
||||
/* Retrieve the pointer to scratch buffer for temporary storage */
|
||||
char *buf = ((struct file_server_data *)req->user_ctx)->scratch;
|
||||
@@ -432,7 +679,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
|
||||
while (remaining > 0) {
|
||||
|
||||
ESP_LOGI(TAG_FILESERVER, "Remaining size : %d", remaining);
|
||||
ESP_LOGI(TAG, "Remaining size : %d", remaining);
|
||||
/* Receive the file part by part into a buffer */
|
||||
if ((received = httpd_req_recv(req, buf, MIN(remaining, SCRATCH_BUFSIZE))) <= 0) {
|
||||
if (received == HTTPD_SOCK_ERR_TIMEOUT) {
|
||||
@@ -445,7 +692,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
fclose(fd);
|
||||
unlink(filepath);
|
||||
|
||||
ESP_LOGE(TAG_FILESERVER, "File reception failed!");
|
||||
ESP_LOGE(TAG, "File reception failed!");
|
||||
/* Respond with 500 Internal Server Error */
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to receive file");
|
||||
return ESP_FAIL;
|
||||
@@ -458,7 +705,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
fclose(fd);
|
||||
unlink(filepath);
|
||||
|
||||
ESP_LOGE(TAG_FILESERVER, "File write failed!");
|
||||
ESP_LOGE(TAG, "File write failed!");
|
||||
/* Respond with 500 Internal Server Error */
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to write file to storage");
|
||||
return ESP_FAIL;
|
||||
@@ -471,7 +718,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
|
||||
/* Close file upon upload completion */
|
||||
fclose(fd);
|
||||
ESP_LOGI(TAG_FILESERVER, "File reception complete");
|
||||
ESP_LOGI(TAG, "File reception complete");
|
||||
|
||||
std::string directory = std::string(filepath);
|
||||
size_t zw = directory.find("/");
|
||||
@@ -484,12 +731,10 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
}
|
||||
|
||||
int start_fn = strlen(((struct file_server_data *)req->user_ctx)->base_path);
|
||||
printf("Directory: %s, start_fn: %d, found: %d\n", directory.c_str(), start_fn, found);
|
||||
ESP_LOGD(TAG, "Directory: %s, start_fn: %d, found: %d", directory.c_str(), start_fn, found);
|
||||
directory = directory.substr(start_fn, found - start_fn + 1);
|
||||
printf("Directory danach 1: %s\n", directory.c_str());
|
||||
|
||||
directory = "/fileserver" + directory;
|
||||
printf("Directory danach 2: %s\n", directory.c_str());
|
||||
// ESP_LOGD(TAG, "Directory danach 2: %s", directory.c_str());
|
||||
|
||||
/* Redirect onto root to see the updated file list */
|
||||
httpd_resp_set_status(req, "303 See Other");
|
||||
@@ -502,7 +747,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
|
||||
/*
|
||||
if (strcmp(filepath, CONFIG_FILE) == 0) {
|
||||
printf("New config found. Reload handler.");
|
||||
ESP_LOGD(TAG, "New config found. Reload handler.");
|
||||
gpio_handler_deinit();
|
||||
MQTTdestroy();
|
||||
}
|
||||
@@ -514,7 +759,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
/* Handler to delete a file from the server */
|
||||
static esp_err_t delete_post_handler(httpd_req_t *req)
|
||||
{
|
||||
LogFile.WriteToFile("delete_post_handler");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "delete_post_handler");
|
||||
char filepath[FILE_PATH_MAX];
|
||||
struct stat file_stat;
|
||||
|
||||
@@ -529,11 +774,11 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
|
||||
|
||||
if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK)
|
||||
{
|
||||
printf("Query: "); printf(_query); printf("\n");
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
|
||||
if (httpd_query_key_value(_query, "task", _valuechar, 30) == ESP_OK)
|
||||
{
|
||||
printf("task is found: "); printf(_valuechar); printf("\n");
|
||||
ESP_LOGD(TAG, "task is found: %s", _valuechar);
|
||||
_task = std::string(_valuechar);
|
||||
}
|
||||
}
|
||||
@@ -553,12 +798,12 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
|
||||
zw = zw.substr(0, zw.length()-1);
|
||||
directory = "/fileserver" + zw + "/";
|
||||
zw = "/sdcard" + zw;
|
||||
printf("Directory to delete: %s\n", zw.c_str());
|
||||
ESP_LOGD(TAG, "Directory to delete: %s", zw.c_str());
|
||||
|
||||
delete_all_in_directory(zw);
|
||||
// directory = std::string(filepath);
|
||||
// directory = "/fileserver" + directory;
|
||||
printf("Location after delete directory content: %s\n", directory.c_str());
|
||||
ESP_LOGD(TAG, "Location after delete directory content: %s", directory.c_str());
|
||||
/* Redirect onto root to see the updated file list */
|
||||
// httpd_resp_set_status(req, "303 See Other");
|
||||
// httpd_resp_set_hdr(req, "Location", directory.c_str());
|
||||
@@ -579,19 +824,19 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
|
||||
|
||||
/* Filename cannot have a trailing '/' */
|
||||
if (filename[strlen(filename) - 1] == '/') {
|
||||
ESP_LOGE(TAG_FILESERVER, "Invalid filename : %s", filename);
|
||||
ESP_LOGE(TAG, "Invalid filename : %s", filename);
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Invalid filename");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (stat(filepath, &file_stat) == -1) {
|
||||
ESP_LOGE(TAG_FILESERVER, "File does not exist : %s", filename);
|
||||
ESP_LOGE(TAG, "File does not exist : %s", filename);
|
||||
/* Respond with 400 Bad Request */
|
||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "File does not exist");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_FILESERVER, "Deleting file : %s", filename);
|
||||
ESP_LOGI(TAG, "Deleting file : %s", filename);
|
||||
/* Delete file */
|
||||
unlink(filepath);
|
||||
|
||||
@@ -606,12 +851,10 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
|
||||
}
|
||||
|
||||
int start_fn = strlen(((struct file_server_data *)req->user_ctx)->base_path);
|
||||
printf("Directory: %s, start_fn: %d, found: %d\n", directory.c_str(), start_fn, found);
|
||||
ESP_LOGD(TAG, "Directory: %s, start_fn: %d, found: %d", directory.c_str(), start_fn, found);
|
||||
directory = directory.substr(start_fn, found - start_fn + 1);
|
||||
printf("Directory danach 3: %s\n", directory.c_str());
|
||||
|
||||
directory = "/fileserver" + directory;
|
||||
printf("Directory danach 4: %s\n", directory.c_str());
|
||||
ESP_LOGD(TAG, "Directory danach 4: %s", directory.c_str());
|
||||
}
|
||||
|
||||
|
||||
@@ -623,7 +866,7 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
|
||||
/* Redirect onto root to see the updated file list */
|
||||
httpd_resp_set_status(req, "303 See Other");
|
||||
httpd_resp_set_hdr(req, "Location", directory.c_str());
|
||||
httpd_resp_sendstr(req, "File deleted successfully");
|
||||
httpd_resp_sendstr(req, "File successfully deleted");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -635,7 +878,7 @@ void delete_all_in_directory(std::string _directory)
|
||||
std::string filename;
|
||||
|
||||
if (!dir) {
|
||||
ESP_LOGE(TAG_FILESERVER, "Failed to stat dir : %s", _directory.c_str());
|
||||
ESP_LOGE(TAG, "Failed to stat dir : %s", _directory.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -644,7 +887,7 @@ void delete_all_in_directory(std::string _directory)
|
||||
if (!(entry->d_type == DT_DIR)){
|
||||
if (strcmp("wlan.ini", entry->d_name) != 0){ // auf wlan.ini soll nicht zugegriffen werden !!!
|
||||
filename = _directory + "/" + std::string(entry->d_name);
|
||||
ESP_LOGI(TAG_FILESERVER, "Deleting file : %s", filename.c_str());
|
||||
ESP_LOGI(TAG, "Deleting file : %s", filename.c_str());
|
||||
/* Delete file */
|
||||
unlink(filename.c_str());
|
||||
}
|
||||
@@ -653,6 +896,136 @@ void delete_all_in_directory(std::string _directory)
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
std::string unzip_new(std::string _in_zip_file, std::string _target_zip, std::string _target_bin, std::string _main)
|
||||
{
|
||||
int i, sort_iter;
|
||||
mz_bool status;
|
||||
size_t uncomp_size;
|
||||
mz_zip_archive zip_archive;
|
||||
void* p;
|
||||
char archive_filename[64];
|
||||
std::string zw, ret = "";
|
||||
std::string directory = "";
|
||||
// static const char* s_Test_archive_filename = "testhtml.zip";
|
||||
|
||||
ESP_LOGD(TAG, "miniz.c version: %s", MZ_VERSION);
|
||||
ESP_LOGD(TAG, "Zipfile: %s", _in_zip_file.c_str());
|
||||
// ESP_LOGD(TAG, "Target Dir ZIP: %s", _target_zip.c_str());
|
||||
// ESP_LOGD(TAG, "Target Dir BIN: %s", _target_bin.c_str());
|
||||
// ESP_LOGD(TAG, "Target Dir main: %s", _main.c_str());
|
||||
|
||||
// Now try to open the archive.
|
||||
memset(&zip_archive, 0, sizeof(zip_archive));
|
||||
status = mz_zip_reader_init_file(&zip_archive, _in_zip_file.c_str(), 0);
|
||||
if (!status)
|
||||
{
|
||||
ESP_LOGD(TAG, "mz_zip_reader_init_file() failed!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get and print information about each file in the archive.
|
||||
int numberoffiles = (int)mz_zip_reader_get_num_files(&zip_archive);
|
||||
for (sort_iter = 0; sort_iter < 2; sort_iter++)
|
||||
{
|
||||
memset(&zip_archive, 0, sizeof(zip_archive));
|
||||
status = mz_zip_reader_init_file(&zip_archive, _in_zip_file.c_str(), sort_iter ? MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY : 0);
|
||||
if (!status)
|
||||
{
|
||||
ESP_LOGD(TAG, "mz_zip_reader_init_file() failed!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < numberoffiles; i++)
|
||||
{
|
||||
mz_zip_archive_file_stat file_stat;
|
||||
mz_zip_reader_file_stat(&zip_archive, i, &file_stat);
|
||||
sprintf(archive_filename, file_stat.m_filename);
|
||||
|
||||
if (!file_stat.m_is_directory) {
|
||||
// Try to extract all the files to the heap.
|
||||
p = mz_zip_reader_extract_file_to_heap(&zip_archive, archive_filename, &uncomp_size, 0);
|
||||
if (!p)
|
||||
{
|
||||
ESP_LOGE(TAG, "mz_zip_reader_extract_file_to_heap() failed on file %s", archive_filename);
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Save to File.
|
||||
zw = std::string(archive_filename);
|
||||
ESP_LOGD(TAG, "Rohfilename: %s", zw.c_str());
|
||||
|
||||
if (toUpper(zw) == "FIRMWARE.BIN")
|
||||
{
|
||||
zw = _target_bin + zw;
|
||||
ret = zw;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string _dir = getDirectory(zw);
|
||||
|
||||
if (_dir.length() > 0)
|
||||
{
|
||||
zw = _main + zw;
|
||||
}
|
||||
else
|
||||
{
|
||||
zw = _target_zip + zw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
string filename_zw = zw + SUFFIX_ZW;
|
||||
|
||||
ESP_LOGI(TAG, "Filename to extract: %s, Zwischenfilename: %s", zw.c_str(), filename_zw.c_str());
|
||||
|
||||
// extrahieren in zwischendatei
|
||||
DeleteFile(filename_zw);
|
||||
FILE* fpTargetFile = OpenFileAndWait(filename_zw.c_str(), "wb");
|
||||
uint writtenbytes = fwrite(p, 1, (uint)uncomp_size, fpTargetFile);
|
||||
fclose(fpTargetFile);
|
||||
|
||||
bool isokay = true;
|
||||
|
||||
if (writtenbytes == (uint)uncomp_size)
|
||||
{
|
||||
isokay = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isokay = false;
|
||||
ESP_LOGD(TAG, "ERROR in writting extracted file (function fwrite) extracted file \"%s\", size %u", archive_filename, (uint)uncomp_size);
|
||||
}
|
||||
|
||||
DeleteFile(zw);
|
||||
if (!isokay)
|
||||
ESP_LOGE(TAG, "ERROR in fwrite \"%s\", size %u", archive_filename, (uint)uncomp_size);
|
||||
isokay = isokay && RenameFile(filename_zw, zw);
|
||||
if (!isokay)
|
||||
ESP_LOGE(TAG, "ERROR in Rename \"%s\" to \"%s\"", filename_zw.c_str(), zw.c_str());
|
||||
// isokay = isokay && DeleteFile(filename_zw);
|
||||
// if (!isokay)
|
||||
// ESP_LOGE(TAG, "ERROR in Delete \"%s\"", filename_zw.c_str());
|
||||
|
||||
if (isokay)
|
||||
ESP_LOGI(TAG, "Successfully extracted file \"%s\", size %u", archive_filename, (uint)uncomp_size);
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "ERROR in extracting file \"%s\", size %u", archive_filename, (uint)uncomp_size);
|
||||
ret = "ERROR";
|
||||
}
|
||||
mz_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Close the archive, freeing any resources it was using
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Success.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void unzip(std::string _in_zip_file, std::string _target_directory){
|
||||
int i, sort_iter;
|
||||
mz_bool status;
|
||||
@@ -663,16 +1036,16 @@ void unzip(std::string _in_zip_file, std::string _target_directory){
|
||||
std::string zw;
|
||||
// static const char* s_Test_archive_filename = "testhtml.zip";
|
||||
|
||||
printf("miniz.c version: %s\n", MZ_VERSION);
|
||||
printf("Zipfile: %s\n", _in_zip_file.c_str());
|
||||
printf("Target Dir: %s\n", _target_directory.c_str());
|
||||
ESP_LOGD(TAG, "miniz.c version: %s", MZ_VERSION);
|
||||
ESP_LOGD(TAG, "Zipfile: %s", _in_zip_file.c_str());
|
||||
ESP_LOGD(TAG, "Target Dir: %s", _target_directory.c_str());
|
||||
|
||||
// Now try to open the archive.
|
||||
memset(&zip_archive, 0, sizeof(zip_archive));
|
||||
status = mz_zip_reader_init_file(&zip_archive, _in_zip_file.c_str(), 0);
|
||||
if (!status)
|
||||
{
|
||||
printf("mz_zip_reader_init_file() failed!\n");
|
||||
ESP_LOGD(TAG, "mz_zip_reader_init_file() failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -684,7 +1057,7 @@ void unzip(std::string _in_zip_file, std::string _target_directory){
|
||||
status = mz_zip_reader_init_file(&zip_archive, _in_zip_file.c_str(), sort_iter ? MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY : 0);
|
||||
if (!status)
|
||||
{
|
||||
printf("mz_zip_reader_init_file() failed!\n");
|
||||
ESP_LOGD(TAG, "mz_zip_reader_init_file() failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -698,7 +1071,7 @@ void unzip(std::string _in_zip_file, std::string _target_directory){
|
||||
p = mz_zip_reader_extract_file_to_heap(&zip_archive, archive_filename, &uncomp_size, 0);
|
||||
if (!p)
|
||||
{
|
||||
printf("mz_zip_reader_extract_file_to_heap() failed!\n");
|
||||
ESP_LOGD(TAG, "mz_zip_reader_extract_file_to_heap() failed!");
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
return;
|
||||
}
|
||||
@@ -706,13 +1079,13 @@ void unzip(std::string _in_zip_file, std::string _target_directory){
|
||||
// Save to File.
|
||||
zw = std::string(archive_filename);
|
||||
zw = _target_directory + zw;
|
||||
printf("Filename to extract: %s", zw.c_str());
|
||||
ESP_LOGD(TAG, "Filename to extract: %s", zw.c_str());
|
||||
FILE* fpTargetFile = OpenFileAndWait(zw.c_str(), "wb");
|
||||
fwrite(p, 1, (uint)uncomp_size, fpTargetFile);
|
||||
fclose(fpTargetFile);
|
||||
|
||||
printf("Successfully extracted file \"%s\", size %u\n", archive_filename, (uint)uncomp_size);
|
||||
// printf("File data: \"%s\"\n", (const char*)p);
|
||||
ESP_LOGD(TAG, "Successfully extracted file \"%s\", size %u", archive_filename, (uint)uncomp_size);
|
||||
// ESP_LOGD(TAG, "File data: \"%s\"", (const char*)p);
|
||||
|
||||
// We're done.
|
||||
mz_free(p);
|
||||
@@ -722,7 +1095,7 @@ void unzip(std::string _in_zip_file, std::string _target_directory){
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
}
|
||||
|
||||
printf("Success.\n");
|
||||
ESP_LOGD(TAG, "Success.");
|
||||
}
|
||||
|
||||
|
||||
@@ -734,19 +1107,19 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
|
||||
/* Validate file storage base path */
|
||||
if (!base_path) {
|
||||
// if (!base_path || strcmp(base_path, "/spiffs") != 0) {
|
||||
ESP_LOGE(TAG_FILESERVER, "File server base_path not set");
|
||||
ESP_LOGE(TAG, "File server base_path not set");
|
||||
// return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (server_data) {
|
||||
ESP_LOGE(TAG_FILESERVER, "File server already started");
|
||||
ESP_LOGE(TAG, "File server already started");
|
||||
// return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
/* Allocate memory for server data */
|
||||
server_data = (file_server_data *) calloc(1, sizeof(struct file_server_data));
|
||||
if (!server_data) {
|
||||
ESP_LOGE(TAG_FILESERVER, "Failed to allocate memory for server data");
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for server data");
|
||||
// return ESP_ERR_NO_MEM;
|
||||
}
|
||||
strlcpy(server_data->base_path, base_path,
|
||||
@@ -759,7 +1132,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
|
||||
// strcpy(zw, serverprefix);
|
||||
// zw[strlen(serverprefix)] = '*';
|
||||
// zw[strlen(serverprefix)+1] = '\0';
|
||||
// printf("zw: %s\n", zw);
|
||||
// ESP_LOGD(TAG, "zw: %s", zw);
|
||||
httpd_uri_t file_download = {
|
||||
.uri = "/fileserver*", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
@@ -769,16 +1142,41 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
|
||||
httpd_register_uri_handler(server, &file_download);
|
||||
|
||||
|
||||
httpd_uri_t file_datafileact = {
|
||||
.uri = "/datafileact", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = datafileact_get_full_handler,
|
||||
.user_ctx = server_data // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &file_datafileact);
|
||||
|
||||
|
||||
httpd_uri_t file_datafile_last_part_handle = {
|
||||
.uri = "/data", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = datafileact_get_last_part_handler,
|
||||
.user_ctx = server_data // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &file_datafile_last_part_handle);
|
||||
|
||||
httpd_uri_t file_logfileact = {
|
||||
.uri = "/logfileact", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = logfileact_get_handler,
|
||||
.handler = logfileact_get_full_handler,
|
||||
.user_ctx = server_data // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &file_logfileact);
|
||||
|
||||
|
||||
httpd_uri_t file_logfile_last_part_handle = {
|
||||
.uri = "/log", // Match all URIs of type /path/to/file
|
||||
.method = HTTP_GET,
|
||||
.handler = logfileact_get_last_part_handler,
|
||||
.user_ctx = server_data // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &file_logfile_last_part_handle);
|
||||
|
||||
|
||||
/* URI handler for uploading files to server */
|
||||
httpd_uri_t file_upload = {
|
||||
.uri = "/upload/*", // Match all URIs of type /upload/path/to/file
|
||||
|
||||
@@ -4,5 +4,12 @@
|
||||
void register_server_file_uri(httpd_handle_t server, const char *base_path);
|
||||
|
||||
void unzip(std::string _in_zip_file, std::string _target_directory);
|
||||
std::string unzip_new(std::string _in_zip_file, std::string _target_zip, std::string _target_bin, std::string _main = "/sdcard/");
|
||||
|
||||
|
||||
void delete_all_in_directory(std::string _directory);
|
||||
|
||||
esp_err_t get_tflite_file_handler(httpd_req_t *req);
|
||||
esp_err_t get_data_file_handler(httpd_req_t *req);
|
||||
esp_err_t get_numbers_file_handler(httpd_req_t *req);
|
||||
|
||||
void delete_all_in_directory(std::string _directory);
|
||||
@@ -5,7 +5,14 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
@@ -15,7 +22,7 @@
|
||||
#include "esp_http_server.h"
|
||||
|
||||
|
||||
static const char *TAG = "serverhelp";
|
||||
static const char *TAG = "SERVER HELP";
|
||||
|
||||
#define SCRATCH_BUFSIZE 8192
|
||||
char scratch[SCRATCH_BUFSIZE];
|
||||
@@ -36,6 +43,7 @@ esp_err_t send_file(httpd_req_t *req, std::string filename)
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Sending file : %s ...", filename.c_str());
|
||||
// httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
set_content_type_from_file(req, filename.c_str());
|
||||
|
||||
/* Retrieve the pointer to scratch buffer for temporary storage */
|
||||
@@ -113,6 +121,8 @@ esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filename)
|
||||
return httpd_resp_set_type(req, "image/x-icon");
|
||||
} else if (IS_FILE_EXT(filename, ".js")) {
|
||||
return httpd_resp_set_type(req, "text/javascript");
|
||||
} else if (IS_FILE_EXT(filename, ".css")) {
|
||||
return httpd_resp_set_type(req, "text/css");
|
||||
}
|
||||
/* This is a limited set only */
|
||||
/* For any other type always set as plain text */
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "server_file.h"
|
||||
#include "server_GPIO.h"
|
||||
|
||||
|
||||
#include "ClassLogFile.h"
|
||||
|
||||
#include "Helper.h"
|
||||
@@ -47,15 +48,79 @@ static char ota_write_data[BUFFSIZE + 1] = { 0 };
|
||||
|
||||
|
||||
#define OTA_URL_SIZE 256
|
||||
static const char *TAGPARTOTA = "server_ota";
|
||||
static const char *TAG = "OTA";
|
||||
|
||||
esp_err_t handler_reboot(httpd_req_t *req);
|
||||
|
||||
std::string _file_name_update;
|
||||
|
||||
|
||||
void task_do_Update_ZIP(void *pvParameter)
|
||||
{
|
||||
std::string filetype = toUpper(getFileType(_file_name_update));
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "File: " + _file_name_update + " Filetype: " + filetype);
|
||||
|
||||
|
||||
if (filetype == "ZIP")
|
||||
{
|
||||
std::string in, out, outbin, zw, retfirmware;
|
||||
|
||||
out = "/sdcard/html";
|
||||
outbin = "/sdcard/firmware";
|
||||
|
||||
retfirmware = unzip_new(_file_name_update, out+"/", outbin+"/");
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Files unzipped.");
|
||||
|
||||
if (retfirmware.length() > 0)
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Found firmware.bin");
|
||||
ota_update_task(retfirmware);
|
||||
}
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Trigger reboot due to firmware update.");
|
||||
doReboot();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Only ZIP-Files support for update during startup!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CheckUpdate()
|
||||
{
|
||||
FILE *pfile;
|
||||
if ((pfile = fopen("/sdcard/update.txt", "r")) == NULL)
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "No update triggered.");
|
||||
return;
|
||||
}
|
||||
|
||||
char zw[1024] = "";
|
||||
fgets(zw, 1024, pfile);
|
||||
_file_name_update = std::string(zw);
|
||||
fclose(pfile);
|
||||
DeleteFile("/sdcard/update.txt"); // Prevent Boot Loop!!!
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Update during boot triggered - Update File: " + _file_name_update);
|
||||
|
||||
|
||||
BaseType_t xReturned;
|
||||
int _i = configMINIMAL_STACK_SIZE;
|
||||
xReturned = xTaskCreate(&task_do_Update_ZIP, "task_do_Update_ZIP", configMINIMAL_STACK_SIZE * 35, NULL, tskIDLE_PRIORITY+1, NULL);
|
||||
TickType_t xDelay;
|
||||
xDelay = 2000000 / portTICK_PERIOD_MS;
|
||||
ESP_LOGD(TAG, "Wait for Update to be finished: sleep for: %ldms", (long) xDelay);
|
||||
vTaskDelay( xDelay );
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void infinite_loop(void)
|
||||
{
|
||||
int i = 0;
|
||||
ESP_LOGI(TAGPARTOTA, "When a new firmware is available on the server, press the reset button to download it");
|
||||
ESP_LOGI(TAG, "When a new firmware is available on the server, press the reset button to download it");
|
||||
while(1) {
|
||||
ESP_LOGI(TAGPARTOTA, "Waiting for a new firmware ... %d", ++i);
|
||||
ESP_LOGI(TAG, "Waiting for a new firmware... %d", ++i);
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
@@ -69,22 +134,22 @@ static bool ota_update_task(std::string fn)
|
||||
esp_ota_handle_t update_handle = 0 ;
|
||||
const esp_partition_t *update_partition = NULL;
|
||||
|
||||
ESP_LOGI(TAGPARTOTA, "Starting OTA update");
|
||||
ESP_LOGI(TAG, "Starting OTA update");
|
||||
|
||||
const esp_partition_t *configured = esp_ota_get_boot_partition();
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
|
||||
if (configured != running) {
|
||||
ESP_LOGW(TAGPARTOTA, "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x",
|
||||
ESP_LOGW(TAG, "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x",
|
||||
configured->address, running->address);
|
||||
ESP_LOGW(TAGPARTOTA, "(This can happen if either the OTA boot data or preferred boot image become corrupted somehow.)");
|
||||
ESP_LOGW(TAG, "(This can happen if either the OTA boot data or preferred boot image become somehow corrupted.)");
|
||||
}
|
||||
ESP_LOGI(TAGPARTOTA, "Running partition type %d subtype %d (offset 0x%08x)",
|
||||
ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)",
|
||||
running->type, running->subtype, running->address);
|
||||
|
||||
|
||||
update_partition = esp_ota_get_next_update_partition(NULL);
|
||||
ESP_LOGI(TAGPARTOTA, "Writing to partition subtype %d at offset 0x%x",
|
||||
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x",
|
||||
update_partition->subtype, update_partition->address);
|
||||
// assert(update_partition != NULL);
|
||||
|
||||
@@ -96,11 +161,16 @@ static bool ota_update_task(std::string fn)
|
||||
int data_read;
|
||||
|
||||
FILE* f = OpenFileAndWait(fn.c_str(), "rb"); // vorher nur "r"
|
||||
|
||||
if (f == NULL) { // File does not exist
|
||||
return false;
|
||||
}
|
||||
|
||||
data_read = fread(ota_write_data, 1, BUFFSIZE, f);
|
||||
|
||||
while (data_read > 0) {
|
||||
if (data_read < 0) {
|
||||
ESP_LOGE(TAGPARTOTA, "Error: SSL data read error");
|
||||
ESP_LOGE(TAG, "Error: SSL data read error");
|
||||
return false;
|
||||
} else if (data_read > 0) {
|
||||
if (image_header_was_checked == false) {
|
||||
@@ -108,32 +178,32 @@ static bool ota_update_task(std::string fn)
|
||||
if (data_read > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) {
|
||||
// check current version with downloading
|
||||
memcpy(&new_app_info, &ota_write_data[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t));
|
||||
ESP_LOGI(TAGPARTOTA, "New firmware version: %s", new_app_info.version);
|
||||
ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version);
|
||||
|
||||
esp_app_desc_t running_app_info;
|
||||
if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) {
|
||||
ESP_LOGI(TAGPARTOTA, "Running firmware version: %s", running_app_info.version);
|
||||
ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version);
|
||||
}
|
||||
|
||||
const esp_partition_t* last_invalid_app = esp_ota_get_last_invalid_partition();
|
||||
esp_app_desc_t invalid_app_info;
|
||||
if (esp_ota_get_partition_description(last_invalid_app, &invalid_app_info) == ESP_OK) {
|
||||
ESP_LOGI(TAGPARTOTA, "Last invalid firmware version: %s", invalid_app_info.version);
|
||||
ESP_LOGI(TAG, "Last invalid firmware version: %s", invalid_app_info.version);
|
||||
}
|
||||
|
||||
// check current version with last invalid partition
|
||||
if (last_invalid_app != NULL) {
|
||||
if (memcmp(invalid_app_info.version, new_app_info.version, sizeof(new_app_info.version)) == 0) {
|
||||
ESP_LOGW(TAGPARTOTA, "New version is the same as invalid version.");
|
||||
ESP_LOGW(TAGPARTOTA, "Previously, there was an attempt to launch the firmware with %s version, but it failed.", invalid_app_info.version);
|
||||
ESP_LOGW(TAGPARTOTA, "The firmware has been rolled back to the previous version.");
|
||||
ESP_LOGW(TAG, "New version is the same as invalid version.");
|
||||
ESP_LOGW(TAG, "Previously, there was an attempt to launch the firmware with %s version, but it failed.", invalid_app_info.version);
|
||||
ESP_LOGW(TAG, "The firmware has been rolled back to the previous version.");
|
||||
infinite_loop();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version)) == 0) {
|
||||
ESP_LOGW(TAGPARTOTA, "Current running version is the same as a new. We will not continue the update.");
|
||||
ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update.");
|
||||
infinite_loop();
|
||||
}
|
||||
*/
|
||||
@@ -141,12 +211,12 @@ static bool ota_update_task(std::string fn)
|
||||
|
||||
err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAGPARTOTA, "esp_ota_begin failed (%s)", esp_err_to_name(err));
|
||||
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
ESP_LOGI(TAGPARTOTA, "esp_ota_begin succeeded");
|
||||
ESP_LOGI(TAG, "esp_ota_begin succeeded");
|
||||
} else {
|
||||
ESP_LOGE(TAGPARTOTA, "received package is not fit len");
|
||||
ESP_LOGE(TAG, "received package is not fit len");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -155,14 +225,14 @@ static bool ota_update_task(std::string fn)
|
||||
return false;
|
||||
}
|
||||
binary_file_length += data_read;
|
||||
ESP_LOGD(TAGPARTOTA, "Written image length %d", binary_file_length);
|
||||
ESP_LOGD(TAG, "Written image length %d", binary_file_length);
|
||||
} else if (data_read == 0) {
|
||||
//
|
||||
// * As esp_http_client_read never returns negative error code, we rely on
|
||||
// * `errno` to check for underlying transport connectivity closure if any
|
||||
//
|
||||
if (errno == ECONNRESET || errno == ENOTCONN) {
|
||||
ESP_LOGE(TAGPARTOTA, "Connection closed, errno = %d", errno);
|
||||
ESP_LOGE(TAG, "Connection closed, errno = %d", errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -170,23 +240,23 @@ static bool ota_update_task(std::string fn)
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
ESP_LOGI(TAGPARTOTA, "Total Write binary data length: %d", binary_file_length);
|
||||
ESP_LOGI(TAG, "Total Write binary data length: %d", binary_file_length);
|
||||
|
||||
err = esp_ota_end(update_handle);
|
||||
if (err != ESP_OK) {
|
||||
if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
|
||||
ESP_LOGE(TAGPARTOTA, "Image validation failed, image is corrupted");
|
||||
ESP_LOGE(TAG, "Image validation failed, image is corrupted");
|
||||
}
|
||||
ESP_LOGE(TAGPARTOTA, "esp_ota_end failed (%s)!", esp_err_to_name(err));
|
||||
ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
err = esp_ota_set_boot_partition(update_partition);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAGPARTOTA, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
|
||||
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
|
||||
|
||||
}
|
||||
// ESP_LOGI(TAGPARTOTA, "Prepare to restart system!");
|
||||
// ESP_LOGI(TAG, "Prepare to restart system!");
|
||||
// esp_restart();
|
||||
|
||||
return true ;
|
||||
@@ -200,37 +270,18 @@ static void print_sha256 (const uint8_t *image_hash, const char *label)
|
||||
for (int i = 0; i < HASH_LEN; ++i) {
|
||||
sprintf(&hash_print[i * 2], "%02x", image_hash[i]);
|
||||
}
|
||||
ESP_LOGI(TAGPARTOTA, "%s: %s", label, hash_print);
|
||||
ESP_LOGI(TAG, "%s: %s", label, hash_print);
|
||||
}
|
||||
|
||||
|
||||
static bool diagnostic(void)
|
||||
{
|
||||
/*
|
||||
gpio_config_t io_conf;
|
||||
io_conf.intr_type = (gpio_int_type_t) GPIO_PIN_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << CONFIG_EXAMPLE_GPIO_DIAGNOSTIC);
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
gpio_config(&io_conf);
|
||||
|
||||
ESP_LOGI(TAGPARTOTA, "Diagnostics (5 sec)...");
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
|
||||
bool diagnostic_is_ok = gpio_get_level(CONFIG_EXAMPLE_GPIO_DIAGNOSTIC);
|
||||
|
||||
gpio_reset_pin(CONFIG_EXAMPLE_GPIO_DIAGNOSTIC);
|
||||
|
||||
return diagnostic_is_ok;
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
void CheckOTAUpdate(void)
|
||||
{
|
||||
ESP_LOGI(TAGPARTOTA, "Start CheckOTAUpdateCheck ...");
|
||||
printf("Start CheckOTAUpdateCheck ...\n");
|
||||
ESP_LOGI(TAG, "Start CheckOTAUpdateCheck...");
|
||||
|
||||
uint8_t sha_256[HASH_LEN] = { 0 };
|
||||
esp_partition_t partition;
|
||||
@@ -259,31 +310,29 @@ void CheckOTAUpdate(void)
|
||||
switch (res_stat_partition)
|
||||
{
|
||||
case ESP_OK:
|
||||
printf("CheckOTAUpdate Partition: ESP_OK\n");
|
||||
ESP_LOGD(TAG, "CheckOTAUpdate Partition: ESP_OK");
|
||||
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
|
||||
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
|
||||
// run diagnostic function ...
|
||||
bool diagnostic_is_ok = diagnostic();
|
||||
if (diagnostic_is_ok) {
|
||||
ESP_LOGI(TAGPARTOTA, "Diagnostics completed successfully! Continuing execution ...");
|
||||
printf("Diagnostics completed successfully! Continuing execution ...\n");
|
||||
ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution...");
|
||||
esp_ota_mark_app_valid_cancel_rollback();
|
||||
} else {
|
||||
ESP_LOGE(TAGPARTOTA, "Diagnostics failed! Start rollback to the previous version ...");
|
||||
printf("Diagnostics failed! Start rollback to the previous version ...\n");
|
||||
ESP_LOGE(TAG, "Diagnostics failed! Start rollback to the previous version...");
|
||||
esp_ota_mark_app_invalid_rollback_and_reboot();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ESP_ERR_INVALID_ARG:
|
||||
printf("CheckOTAUpdate Partition: ESP_ERR_INVALID_ARG\n");
|
||||
ESP_LOGD(TAG, "CheckOTAUpdate Partition: ESP_ERR_INVALID_ARG");
|
||||
break;
|
||||
case ESP_ERR_NOT_SUPPORTED:
|
||||
printf("CheckOTAUpdate Partition: ESP_ERR_NOT_SUPPORTED\n");
|
||||
ESP_LOGD(TAG, "CheckOTAUpdate Partition: ESP_ERR_NOT_SUPPORTED");
|
||||
break;
|
||||
case ESP_ERR_NOT_FOUND:
|
||||
printf("CheckOTAUpdate Partition: ESP_ERR_NOT_FOUND\n");
|
||||
ESP_LOGD(TAG, "CheckOTAUpdate Partition: ESP_ERR_NOT_FOUND");
|
||||
break;
|
||||
}
|
||||
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
|
||||
@@ -291,12 +340,10 @@ void CheckOTAUpdate(void)
|
||||
// run diagnostic function ...
|
||||
bool diagnostic_is_ok = diagnostic();
|
||||
if (diagnostic_is_ok) {
|
||||
ESP_LOGI(TAGPARTOTA, "Diagnostics completed successfully! Continuing execution ...");
|
||||
printf("Diagnostics completed successfully! Continuing execution ...\n");
|
||||
ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution...");
|
||||
esp_ota_mark_app_valid_cancel_rollback();
|
||||
} else {
|
||||
ESP_LOGE(TAGPARTOTA, "Diagnostics failed! Start rollback to the previous version ...");
|
||||
printf("Diagnostics failed! Start rollback to the previous version ...\n");
|
||||
ESP_LOGE(TAG, "Diagnostics failed! Start rollback to the previous version...");
|
||||
esp_ota_mark_app_invalid_rollback_and_reboot();
|
||||
}
|
||||
}
|
||||
@@ -311,80 +358,213 @@ esp_err_t handler_ota_update(httpd_req_t *req)
|
||||
LogFile.WriteHeapInfo("handler_ota_update - Start");
|
||||
#endif
|
||||
|
||||
LogFile.WriteToFile("handler_ota_update");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_ota_update");
|
||||
char _query[200];
|
||||
char _filename[30];
|
||||
char _filename[100];
|
||||
char _valuechar[30];
|
||||
std::string fn = "/sdcard/firmware/";
|
||||
bool _file_del = false;
|
||||
std::string _task;
|
||||
std::string _task = "";
|
||||
|
||||
if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK)
|
||||
{
|
||||
printf("Query: "); printf(_query); printf("\n");
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
|
||||
if (httpd_query_key_value(_query, "task", _valuechar, 30) == ESP_OK)
|
||||
{
|
||||
printf("task is found"); printf(_valuechar); printf("\n");
|
||||
ESP_LOGD(TAG, "task is found: %s", _valuechar);
|
||||
_task = std::string(_valuechar);
|
||||
}
|
||||
|
||||
if (httpd_query_key_value(_query, "file", _filename, 30) == ESP_OK)
|
||||
if (httpd_query_key_value(_query, "file", _filename, 100) == ESP_OK)
|
||||
{
|
||||
fn.append(_filename);
|
||||
printf("File: "); printf(fn.c_str()); printf("\n");
|
||||
ESP_LOGD(TAG, "File: %s", fn.c_str());
|
||||
}
|
||||
if (httpd_query_key_value(_query, "delete", _filename, 30) == ESP_OK)
|
||||
if (httpd_query_key_value(_query, "delete", _filename, 100) == ESP_OK)
|
||||
{
|
||||
fn.append(_filename);
|
||||
_file_del = true;
|
||||
printf("Delete Default File: "); printf(fn.c_str()); printf("\n");
|
||||
ESP_LOGD(TAG, "Delete Default File: %s", fn.c_str());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
if (_task.compare("unziphtml") == 0)
|
||||
if (_task.compare("emptyfirmwaredir") == 0)
|
||||
{
|
||||
std::string in, out, zw;
|
||||
ESP_LOGD(TAG, "Start empty directory /firmware");
|
||||
delete_all_in_directory("/sdcard/firmware");
|
||||
std::string zw = "firmware directory deleted - v2\n";
|
||||
ESP_LOGD(TAG, "%s", zw.c_str());
|
||||
printf("Ausgabe: %s\n", zw.c_str());
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
httpd_resp_send(req, zw.c_str(), strlen(zw.c_str()));
|
||||
/* Respond with an empty chunk to signal HTTP response completion */
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
|
||||
in = "/sdcard/firmware/html.zip";
|
||||
out = "/sdcard/html/";
|
||||
ESP_LOGD(TAG, "Done empty directory /firmware");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
delete_all_in_directory(out);
|
||||
if (_task.compare("update") == 0)
|
||||
{
|
||||
std::string filetype = toUpper(getFileType(fn));
|
||||
if (filetype.length() == 0)
|
||||
{
|
||||
std::string zw = "Update failed - no file specified (zip, bin, tfl, tlite)";
|
||||
httpd_resp_sendstr_chunk(req, zw.c_str());
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
unzip(in, out);
|
||||
zw = "HTML Update Successfull!<br><br>No reboot necessary";
|
||||
|
||||
if ((filetype == "TFLITE") || (filetype == "TFL"))
|
||||
{
|
||||
std::string out = "/sdcard/config/" + getFileFullFileName(fn);
|
||||
DeleteFile(out);
|
||||
CopyFile(fn, out);
|
||||
DeleteFile(fn);
|
||||
|
||||
const char* resp_str = "Neural Network File copied.";
|
||||
httpd_resp_sendstr_chunk(req, resp_str);
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
if (filetype == "ZIP")
|
||||
{
|
||||
FILE *pfile;
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Update for reboot.");
|
||||
pfile = fopen("/sdcard/update.txt", "w");
|
||||
fwrite(fn.c_str(), fn.length(), 1, pfile);
|
||||
fclose(pfile);
|
||||
|
||||
std::string zw = "reboot\n";
|
||||
httpd_resp_sendstr_chunk(req, zw.c_str());
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
ESP_LOGD(TAG, "Send reboot");
|
||||
return ESP_OK;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
std::string in, out, outbin, zw, retfirmware;
|
||||
|
||||
out = "/sdcard/html";
|
||||
outbin = "/sdcard/firmware";
|
||||
|
||||
retfirmware = unzip_new(fn, out+"/", outbin+"/");
|
||||
|
||||
if (retfirmware.length() > 0)
|
||||
{
|
||||
filetype = "BIN";
|
||||
fn = retfirmware;
|
||||
}
|
||||
else
|
||||
{
|
||||
zw = "Web Interface Update Successfull!\nNo reboot necessary.\n";
|
||||
httpd_resp_sendstr_chunk(req, zw.c_str());
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
if (filetype == "BIN")
|
||||
{
|
||||
const char* resp_str;
|
||||
|
||||
KillTFliteTasks();
|
||||
gpio_handler_deinit();
|
||||
if (ota_update_task(fn))
|
||||
{
|
||||
std::string zw = "reboot\n";
|
||||
httpd_resp_sendstr_chunk(req, zw.c_str());
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
ESP_LOGD(TAG, "Send reboot");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
resp_str = "Error during Firmware Update!!!\nPlease check output of console.";
|
||||
httpd_resp_send(req, resp_str, strlen(resp_str));
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_ota_update - Done");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
std::string zw = "Update failed - no valid file specified (zip, bin, tfl, tlite)!";
|
||||
httpd_resp_sendstr_chunk(req, zw.c_str());
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
if (_task.compare("unziphtml") == 0)
|
||||
{
|
||||
ESP_LOGD(TAG, "Task unziphtml");
|
||||
std::string in, out, zw;
|
||||
|
||||
in = "/sdcard/firmware/html.zip";
|
||||
out = "/sdcard/html";
|
||||
|
||||
delete_all_in_directory(out);
|
||||
|
||||
unzip(in, out+"/");
|
||||
zw = "Web Interface Update Successfull!\nNo reboot necessary";
|
||||
httpd_resp_send(req, zw.c_str(), strlen(zw.c_str()));
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
if (_file_del)
|
||||
{
|
||||
ESP_LOGD(TAG, "Delete !! _file_del: %s", fn.c_str());
|
||||
struct stat file_stat;
|
||||
if (stat(fn.c_str(), &file_stat) != -1) {
|
||||
printf("Deleting file : %s", fn.c_str());
|
||||
int _result = stat(fn.c_str(), &file_stat);
|
||||
ESP_LOGD(TAG, "Ergebnis %d\n", _result);
|
||||
if (_result == 0) {
|
||||
ESP_LOGD(TAG, "Deleting file : %s", fn.c_str());
|
||||
/* Delete file */
|
||||
unlink(fn.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGD(TAG, "File does not exist: %s", fn.c_str());
|
||||
}
|
||||
/* Respond with an empty chunk to signal HTTP response completion */
|
||||
std::string zw = "file deleted\n";
|
||||
ESP_LOGD(TAG, "%s", zw.c_str());
|
||||
httpd_resp_send(req, zw.c_str(), strlen(zw.c_str()));
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
string zw = "ota without parameter - should not be the case!";
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
httpd_resp_send(req, zw.c_str(), strlen(zw.c_str()));
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
|
||||
ESP_LOGE(TAG, "ota without parameter - should not be the case!");
|
||||
|
||||
/*
|
||||
const char* resp_str;
|
||||
|
||||
KillTFliteTasks();
|
||||
gpio_handler_deinit();
|
||||
if (ota_update_task(fn))
|
||||
{
|
||||
resp_str = "Firmware Update Successfull!<br><br>You can restart now.";
|
||||
resp_str = "Firmware Update Successfull! You can restart now.";
|
||||
}
|
||||
else
|
||||
{
|
||||
resp_str = "Error during Firmware Update!!!<br><br>Please check output of console.";
|
||||
resp_str = "Error during Firmware Update!!! Please check console output.";
|
||||
}
|
||||
|
||||
httpd_resp_send(req, resp_str, strlen(resp_str));
|
||||
@@ -392,6 +572,7 @@ esp_err_t handler_ota_update(httpd_req_t *req)
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_ota_update - Done");
|
||||
#endif
|
||||
*/
|
||||
|
||||
return ESP_OK;
|
||||
};
|
||||
@@ -415,8 +596,8 @@ void task_reboot(void *pvParameter)
|
||||
}
|
||||
|
||||
void doReboot(){
|
||||
ESP_LOGI(TAGPARTOTA, "Reboot in 5sec");
|
||||
LogFile.WriteToFile("Reboot in 5sec");
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Reboot triggered by Software (5s).");
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Reboot in 5sec");
|
||||
xTaskCreate(&task_reboot, "reboot", configMINIMAL_STACK_SIZE * 64, NULL, 10, NULL);
|
||||
// KillTFliteTasks(); // kills itself
|
||||
gpio_handler_destroy();
|
||||
@@ -432,9 +613,9 @@ esp_err_t handler_reboot(httpd_req_t *req)
|
||||
LogFile.WriteHeapInfo("handler_reboot - Start");
|
||||
#endif
|
||||
|
||||
LogFile.WriteToFile("handler_reboot");
|
||||
ESP_LOGI(TAGPARTOTA, "!!! System will restart within 5 sec!!!");
|
||||
const char* resp_str = "!!! System will restart within 5 sec!!!";
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_reboot");
|
||||
ESP_LOGI(TAG, "!!! System will restart within 5 sec!!!");
|
||||
const char* resp_str = "<body style='font-family: arial'> <h3 id=t></h3></body><script>var h='Rebooting!<br>The page will automatically reload in around 25..60s<br>(in case of a firmware update it can take up to 180s).<br>'; document.getElementById('t').innerHTML=h; setInterval(function (){h +='.'; document.getElementById('t').innerHTML=h; fetch(window.location.hostname,{mode: 'no-cors'}).then(r=>{parent.location.href=('/index.html');})}, 1000);</script>";
|
||||
httpd_resp_send(req, resp_str, strlen(resp_str));
|
||||
|
||||
doReboot();
|
||||
@@ -448,7 +629,7 @@ esp_err_t handler_reboot(httpd_req_t *req)
|
||||
|
||||
void register_server_ota_sdcard_uri(httpd_handle_t server)
|
||||
{
|
||||
ESP_LOGI(TAGPARTOTA, "server_ota - Registering URI handlers");
|
||||
ESP_LOGI(TAG, "Registering URI handlers");
|
||||
|
||||
httpd_uri_t camuri = { };
|
||||
camuri.method = HTTP_GET;
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
#include <esp_http_server.h>
|
||||
|
||||
//#include "ClassControllCamera.h"
|
||||
#include <string>
|
||||
|
||||
|
||||
void register_server_ota_sdcard_uri(httpd_handle_t server);
|
||||
void CheckOTAUpdate();
|
||||
void doReboot();
|
||||
void hard_restart();
|
||||
|
||||
void CheckUpdate();
|
||||
static bool ota_update_task(std::string fn);
|
||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES jomjol_tfliteclass jomjol_helper jomjol_controlcamera jomjol_mqtt jomjol_fileserver_ota jomjol_image_proc jomjol_wlan)
|
||||
REQUIRES jomjol_tfliteclass jomjol_helper jomjol_controlcamera jomjol_mqtt jomjol_influxdb jomjol_fileserver_ota jomjol_image_proc jomjol_wlan)
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "FLOW CLASS";
|
||||
|
||||
|
||||
void ClassFlow::SetInitialParameter(void)
|
||||
@@ -13,31 +15,6 @@ void ClassFlow::SetInitialParameter(void)
|
||||
disabled = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::vector<string> ClassFlow::ZerlegeZeile(std::string input, std::string delimiter)
|
||||
{
|
||||
std::vector<string> Output;
|
||||
// std::string delimiter = " =,";
|
||||
|
||||
input = trim(input, delimiter);
|
||||
size_t pos = findDelimiterPos(input, delimiter);
|
||||
std::string token;
|
||||
while (pos != std::string::npos) {
|
||||
token = input.substr(0, pos);
|
||||
token = trim(token, delimiter);
|
||||
Output.push_back(token);
|
||||
input.erase(0, pos + 1);
|
||||
input = trim(input, delimiter);
|
||||
pos = findDelimiterPos(input, delimiter);
|
||||
}
|
||||
Output.push_back(input);
|
||||
|
||||
return Output;
|
||||
|
||||
}
|
||||
|
||||
bool ClassFlow::isNewParagraph(string input)
|
||||
{
|
||||
if ((input[0] == '[') || ((input[0] == ';') && (input[1] == '[')))
|
||||
@@ -106,7 +83,7 @@ std::string ClassFlow::GetParameterName(std::string _input)
|
||||
{
|
||||
_param = _input;
|
||||
}
|
||||
// printf("Parameter: %s, Pospunkt: %d\n", _param.c_str(), _pospunkt);
|
||||
// ESP_LOGD(TAG, "Parameter: %s, Pospunkt: %d", _param.c_str(), _pospunkt);
|
||||
return _param;
|
||||
}
|
||||
|
||||
@@ -122,10 +99,10 @@ bool ClassFlow::getNextLine(FILE* pfile, string *rt)
|
||||
if (!fgets(zw, 1024, pfile))
|
||||
{
|
||||
*rt = "";
|
||||
printf("END OF FILE\n");
|
||||
ESP_LOGD(TAG, "END OF FILE");
|
||||
return false;
|
||||
}
|
||||
printf("%s", zw);
|
||||
ESP_LOGD(TAG, "%s", zw);
|
||||
*rt = zw;
|
||||
*rt = trim(*rt);
|
||||
while ((zw[0] == ';' || zw[0] == '#' || (rt->size() == 0)) && !(zw[1] == '[')) // Kommentarzeilen (; oder #) und Leerzeilen überspringen, es sei denn es ist ein neuer auskommentierter Paragraph
|
||||
@@ -133,7 +110,7 @@ bool ClassFlow::getNextLine(FILE* pfile, string *rt)
|
||||
*rt = "";
|
||||
if (!fgets(zw, 1024, pfile))
|
||||
return false;
|
||||
printf("%s", zw);
|
||||
ESP_LOGD(TAG, "%s", zw);
|
||||
*rt = zw;
|
||||
*rt = trim(*rt);
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@ struct HTMLInfo
|
||||
class ClassFlow
|
||||
{
|
||||
protected:
|
||||
// std::vector<string> ZerlegeZeile(string input);
|
||||
std::vector<string> ZerlegeZeile(string input, string delimiter = " =, \t");
|
||||
bool isNewParagraph(string input);
|
||||
bool GetNextParagraph(FILE* pfile, string& aktparamgraph);
|
||||
bool getNextLine(FILE* pfile, string* rt);
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
#include "ClassFlow.h"
|
||||
|
||||
#include "CRotateImage.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
|
||||
#include "ClassLogFile.h"
|
||||
|
||||
|
||||
static const char *TAG = "FLOW ALIGN";
|
||||
|
||||
bool AlignmentExtendedDebugging = true;
|
||||
|
||||
@@ -19,6 +21,7 @@ void ClassFlowAlignment::SetInitialParameter(void)
|
||||
initalrotate = 0;
|
||||
anz_ref = 0;
|
||||
initialmirror = false;
|
||||
use_antialiasing = false;
|
||||
initialflip = false;
|
||||
SaveAllFiles = false;
|
||||
namerawimage = "/sdcard/img_tmp/raw.jpg";
|
||||
@@ -47,7 +50,7 @@ ClassFlowAlignment::ClassFlowAlignment(std::vector<ClassFlow*>* lfc)
|
||||
|
||||
if (!ImageBasis) // die Funktion Bilder aufnehmen existiert nicht --> muss erst erzeugt werden NUR ZU TESTZWECKEN
|
||||
{
|
||||
if (AlignmentExtendedDebugging) printf("CImageBasis musste erzeugt werden\n");
|
||||
if (AlignmentExtendedDebugging) ESP_LOGD(TAG, "CImageBasis had to be created");
|
||||
ImageBasis = new CImageBasis(namerawimage);
|
||||
}
|
||||
}
|
||||
@@ -94,7 +97,12 @@ bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
if ((toUpper(zerlegt[0]) == "SEARCHFIELDY") && (zerlegt.size() > 1))
|
||||
{
|
||||
suchey = std::stod(zerlegt[1]);
|
||||
}
|
||||
}
|
||||
if ((toUpper(zerlegt[0]) == "ANTIALIASING") && (zerlegt.size() > 1))
|
||||
{
|
||||
if (toUpper(zerlegt[1]) == "TRUE")
|
||||
use_antialiasing = true;
|
||||
}
|
||||
if ((zerlegt.size() == 3) && (anz_ref < 2))
|
||||
{
|
||||
References[anz_ref].image_file = FormatFileName("/sdcard" + zerlegt[0]);
|
||||
@@ -112,7 +120,7 @@ bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
std::string zw2 = "Alignmentmodus gewählt: " + zerlegt[1];
|
||||
LogFile.WriteToFile(zw2);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw2);
|
||||
#endif
|
||||
if (toUpper(zerlegt[1]) == "HIGHACCURACY")
|
||||
alg_algo = 1;
|
||||
@@ -129,7 +137,7 @@ bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
References[i].alignment_algo = alg_algo;
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
std::string zw2 = "Alignmentmodus geschrieben: " + std::to_string(alg_algo);
|
||||
LogFile.WriteToFile(zw2);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw2);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -168,14 +176,17 @@ bool ClassFlowAlignment::doFlow(string time)
|
||||
}
|
||||
|
||||
if (initialmirror){
|
||||
printf("do mirror\n");
|
||||
ESP_LOGD(TAG, "do mirror");
|
||||
rt.Mirror();
|
||||
if (SaveAllFiles) AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/mirror.jpg"));
|
||||
}
|
||||
|
||||
if ((initalrotate != 0) || initialflip)
|
||||
{
|
||||
rt.Rotate(initalrotate);
|
||||
if (use_antialiasing)
|
||||
rt.RotateAntiAliasing(initalrotate);
|
||||
else
|
||||
rt.Rotate(initalrotate);
|
||||
if (SaveAllFiles) AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/rot.jpg"));
|
||||
}
|
||||
|
||||
@@ -270,7 +281,7 @@ bool ClassFlowAlignment::LoadReferenceAlignmentValues(void)
|
||||
// LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", "LoadReferenceAlignmentValues01");
|
||||
|
||||
fgets(zw, 1024, pFile);
|
||||
printf("%s", zw);
|
||||
ESP_LOGD(TAG, "%s", zw);
|
||||
|
||||
// zwvalue = "LoadReferenceAlignmentValues Time: " + std::string(zw);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ protected:
|
||||
float initalrotate;
|
||||
bool initialmirror;
|
||||
bool initialflip;
|
||||
bool use_antialiasing;
|
||||
RefInfo References[2];
|
||||
int anz_ref;
|
||||
string namerawimage;
|
||||
|
||||
@@ -7,50 +7,44 @@
|
||||
|
||||
#include "CTfLiteClass.h"
|
||||
#include "ClassLogFile.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char* TAG = "CNN";
|
||||
|
||||
static const char* TAG = "flow_analog";
|
||||
|
||||
bool debugdetailgeneral = false;
|
||||
|
||||
ClassFlowCNNGeneral::ClassFlowCNNGeneral(ClassFlowAlignment *_flowalign, t_CNNType _cnntype) : ClassFlowImage(NULL, TAG)
|
||||
{
|
||||
string cnnmodelfile = "";
|
||||
modelxsize = 1;
|
||||
modelysize = 1;
|
||||
CNNGoodThreshold = 0.0;
|
||||
ListFlowControll = NULL;
|
||||
previousElement = NULL;
|
||||
SaveAllFiles = false;
|
||||
disabled = false;
|
||||
// extendedResolution = false;
|
||||
isLogImageSelect = false;
|
||||
CNNType = AutoDetect;
|
||||
CNNType = _cnntype;
|
||||
flowpostalignment = _flowalign;
|
||||
logfileRetentionInDays = 5;
|
||||
}
|
||||
|
||||
/*
|
||||
int ClassFlowCNNGeneral::AnzahlROIs(int _analog = 0)
|
||||
{
|
||||
int zw = GENERAL[_analog]->ROI.size();
|
||||
if (extendedResolution && (CNNType != Digital)) zw++; // da letzte Ziffer inkl Nachhkomma, es sei denn, das Nachkomma gibt es nicht (Digital)
|
||||
return zw;
|
||||
}
|
||||
*/
|
||||
|
||||
string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution = false)
|
||||
string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution, int prev, float _vorgaengerAnalog, float analogDigitalTransitionStart)
|
||||
{
|
||||
string result = "";
|
||||
|
||||
if (GENERAL[_analog]->ROI.size() == 0)
|
||||
return result;
|
||||
|
||||
if (CNNType == Analogue)
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout _analog=" + std::to_string(_analog) + ", _extendedResolution=" + std::to_string(_extendedResolution) + ", prev=" + std::to_string(prev));
|
||||
|
||||
if (CNNType == Analogue || CNNType == Analogue100)
|
||||
{
|
||||
float zahl = GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float;
|
||||
int ergebnis_nachkomma = ((int) floor(zahl * 10) + 10) % 10;
|
||||
|
||||
int prev = -1;
|
||||
|
||||
prev = ZeigerEval(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float, prev);
|
||||
|
||||
prev = ZeigerEvalAnalogNeu(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float, prev);
|
||||
// LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(analog) zahl=" + std::to_string(zahl) + ", ergebnis_nachkomma=" + std::to_string(ergebnis_nachkomma) + ", prev=" + std::to_string(prev));
|
||||
result = std::to_string(prev);
|
||||
|
||||
if (_extendedResolution && (CNNType != Digital))
|
||||
@@ -58,7 +52,7 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
|
||||
|
||||
for (int i = GENERAL[_analog]->ROI.size() - 2; i >= 0; --i)
|
||||
{
|
||||
prev = ZeigerEval(GENERAL[_analog]->ROI[i]->result_float, prev);
|
||||
prev = ZeigerEvalAnalogNeu(GENERAL[_analog]->ROI[i]->result_float, prev);
|
||||
result = std::to_string(prev) + result;
|
||||
}
|
||||
return result;
|
||||
@@ -76,26 +70,31 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
|
||||
return result;
|
||||
}
|
||||
|
||||
if (CNNType == DigitalHyprid)
|
||||
if ((CNNType == DoubleHyprid10) || (CNNType == Digital100))
|
||||
{
|
||||
// int ergebnis_nachkomma = -1;
|
||||
int zif_akt = -1;
|
||||
|
||||
float zahl = GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float;
|
||||
if (zahl >= 0) // NaN?
|
||||
{
|
||||
if (_extendedResolution)
|
||||
if (_extendedResolution) // ist nur gesetzt, falls es die erste Ziffer ist (kein Analog vorher!)
|
||||
{
|
||||
int ergebnis_nachkomma = ((int) floor(zahl * 10)) % 10;
|
||||
int ergebnis_vorkomma = ((int) floor(zahl)) % 10;
|
||||
|
||||
result = std::to_string(ergebnis_vorkomma) + std::to_string(ergebnis_nachkomma);
|
||||
zif_akt = ergebnis_vorkomma;
|
||||
prev = ergebnis_vorkomma;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(dig100-ext) ergebnis_vorkomma=" + std::to_string(ergebnis_vorkomma) + ", ergebnis_nachkomma=" + std::to_string(ergebnis_nachkomma) + ", prev=" + std::to_string(prev));
|
||||
}
|
||||
else
|
||||
{
|
||||
zif_akt = ZeigerEvalHybrid(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float, -1, -1);
|
||||
result = std::to_string(zif_akt);
|
||||
// prev = ZeigerEval(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float, prev);
|
||||
if (_vorgaengerAnalog >= 0)
|
||||
prev = ZeigerEvalHybridNeu(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float, _vorgaengerAnalog, prev, true, analogDigitalTransitionStart);
|
||||
else
|
||||
prev = ZeigerEvalHybridNeu(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float, prev, prev);
|
||||
result = std::to_string(prev);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(dig100) prev=" + std::to_string(prev));
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -109,86 +108,190 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
|
||||
{
|
||||
if (GENERAL[_analog]->ROI[i]->result_float >= 0)
|
||||
{
|
||||
zif_akt = ZeigerEvalHybrid(GENERAL[_analog]->ROI[i]->result_float, GENERAL[_analog]->ROI[i+1]->result_float, zif_akt);
|
||||
result = std::to_string(zif_akt) + result;
|
||||
prev = ZeigerEvalHybridNeu(GENERAL[_analog]->ROI[i]->result_float, GENERAL[_analog]->ROI[i+1]->result_float, prev);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout#ZeigerEvalHybridNeu()= " + std::to_string(prev));
|
||||
result = std::to_string(prev) + result;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout#result= " + result);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
zif_akt = -1;
|
||||
prev = -1;
|
||||
result = "N" + result;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(result_float<0 /'N') result_float=" + std::to_string(GENERAL[_analog]->ROI[i]->result_float));
|
||||
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int ClassFlowCNNGeneral::ZeigerEvalHybrid(float zahl, float zahl_vorgaenger, int eval_vorgaenger)
|
||||
int ClassFlowCNNGeneral::ZeigerEvalHybridNeu(float zahl, float zahl_vorgaenger, int eval_vorgaenger, bool AnalogerVorgaenger, float digitalAnalogTransitionStart)
|
||||
{
|
||||
int result;
|
||||
int ergebnis_nachkomma = ((int) floor(zahl * 10)) % 10;
|
||||
// int ergebnis_vorkomma = ((int) floor(zahl)) % 10;
|
||||
int ergebnis_vorkomma = ((int) floor(zahl) + 10) % 10;
|
||||
|
||||
if (zahl_vorgaenger < 0) // keine Vorzahl vorhanden !!! --> Runde die Zahl
|
||||
if (eval_vorgaenger < 0)
|
||||
{
|
||||
if ((ergebnis_nachkomma <= 2) || (ergebnis_nachkomma >= 8)) // Band um die Ziffer --> Runden, da Ziffer im Rahmen Ungenauigkeit erreicht
|
||||
return ((int) round(zahl) + 10) % 10;
|
||||
if ((ergebnis_nachkomma <= DigitalUnschaerfe * 10) || (ergebnis_nachkomma >= DigitalUnschaerfe * 10)) // Band um die Ziffer --> Runden, da Ziffer im Rahmen Ungenauigkeit erreicht
|
||||
result = (int) (round(zahl) + 10) % 10;
|
||||
else
|
||||
return ((int) trunc(zahl) + 10) % 10;
|
||||
result = (int) ((int) trunc(zahl) + 10) % 10;
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "ZeigerEvalHybridNeu - kein Vorgänger - Ergebnis = " + std::to_string(result) +
|
||||
" zahl: " + std::to_string(zahl) + " zahl_vorgaenger = " + std::to_string(zahl_vorgaenger)+ " eval_vorgaenger = " + std::to_string(eval_vorgaenger) + " DigitalUnschaerfe = " + std::to_string(DigitalUnschaerfe));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (zahl_vorgaenger > 9.2) // Ziffernwechsel beginnt
|
||||
if (AnalogerVorgaenger)
|
||||
{
|
||||
if (eval_vorgaenger == 0) // Wechsel hat schon stattgefunden
|
||||
{
|
||||
return ((int) round(zahl) + 10) % 10; // Annahme, dass die neue Zahl schon in der Nähe des Ziels ist
|
||||
}
|
||||
else
|
||||
{
|
||||
if (zahl_vorgaenger <= 9.5) // Wechsel startet gerade, aber beginnt erst
|
||||
{
|
||||
if ((ergebnis_nachkomma <= 2) || (ergebnis_nachkomma >= 8)) // Band um die Ziffer --> Runden, da Ziffer im Rahmen Ungenauigkeit erreicht
|
||||
return ((int) round(zahl) + 10) % 10;
|
||||
else
|
||||
return ((int) trunc(zahl) + 10) % 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((int) trunc(zahl) + 10) % 10; // Wechsel schon weiter fortgeschritten, d.h. über 2 als Nachkomma
|
||||
}
|
||||
}
|
||||
result = ZeigerEvalAnalogToDigitNeu(zahl, zahl_vorgaenger, eval_vorgaenger, digitalAnalogTransitionStart);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "ZeigerEvalHybridNeu - Analoger Vorgänger, Bewertung über ZeigerEvalAnalogNeu = " + std::to_string(result) +
|
||||
" zahl: " + std::to_string(zahl) + " zahl_vorgaenger = " + std::to_string(zahl_vorgaenger)+ " eval_vorgaenger = " + std::to_string(eval_vorgaenger) + " DigitalUnschaerfe = " + std::to_string(DigitalUnschaerfe));
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((ergebnis_nachkomma <= 2) || (ergebnis_nachkomma >= 8)) // Band um die Ziffer --> Runden, da Ziffer im Rahmen Ungenauigkeit erreicht
|
||||
return ((int) round(zahl) + 10) % 10;
|
||||
if ((zahl_vorgaenger >= DigitalUebergangsbereichVorgaenger ) && (zahl_vorgaenger <= (10.0 - DigitalUebergangsbereichVorgaenger)))
|
||||
{
|
||||
// kein Ziffernwechsel, da Vorgänger weit genug weg ist (0+/-DigitalUebergangsbereichVorgaenger) --> zahl wird gerundet
|
||||
if ((ergebnis_nachkomma <= DigitalBand) || (ergebnis_nachkomma >= (10-DigitalBand))) // Band um die Ziffer --> Runden, da Ziffer im Rahmen Ungenauigkeit erreicht
|
||||
result = ((int) round(zahl) + 10) % 10;
|
||||
else
|
||||
result = ((int) trunc(zahl) + 10) % 10;
|
||||
|
||||
return ((int) trunc(zahl) + 10) % 10;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "ZeigerEvalHybridNeu - KEIN Analoger Vorgänger, kein Ziffernwechsel, da Vorkomma weit genug weg = " + std::to_string(result) +
|
||||
" zahl: " + std::to_string(zahl) + " zahl_vorgaenger = " + std::to_string(zahl_vorgaenger)+ " eval_vorgaenger = " + std::to_string(eval_vorgaenger) + " DigitalUnschaerfe = " + std::to_string(DigitalUnschaerfe));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (eval_vorgaenger <= 1) // Nulldurchgang beim Vorgänger hat stattgefunden (!Bewertung über Prev_value und nicht Zahl!) --> hier aufrunden (2.8 --> 3, aber auch 3.1 --> 3)
|
||||
{
|
||||
// Wir nehmen einfach an, dass das aktuelle Digit nach dem Nulldurchgang des Vorgängers
|
||||
// mindestens zur Hälfte (x.5) durchlaufen hat
|
||||
if (ergebnis_nachkomma > 5)
|
||||
// Das akt. digit hat noch keinen Nulldurchgang, aber der Vorgänger schon.
|
||||
result = (ergebnis_vorkomma + 1) % 10;
|
||||
else
|
||||
// Akt. digit und Vorgänger haben Nulldurchgang
|
||||
result = ergebnis_vorkomma;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "ZeigerEvalHybridNeu - KEIN Analoger Vorgänger, Nulldurchgang hat stattgefunden = " + std::to_string(result) +
|
||||
" zahl: " + std::to_string(zahl) + " zahl_vorgaenger = " + std::to_string(zahl_vorgaenger)+ " eval_vorgaenger = " + std::to_string(eval_vorgaenger) + " DigitalUnschaerfe = " + std::to_string(DigitalUnschaerfe));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// bleibt nur >= 9.x --> noch kein Nulldurchgang --> 2.8 --> 2,
|
||||
// und ab 9.7(DigitalUebergangsbereichVorlauf) 3.1 --> 2
|
||||
// alles >=x.4 kann als aktuelle Zahl gelten im Übergang. Bei 9.x Vorgänger kann die aktuelle
|
||||
// Zahl noch x.6 - x.7 sein.
|
||||
// Vorlauf (else - Zweig) passiert nicht bereits ab 9.
|
||||
if (DigitalUebergangsbereichVorlauf>=zahl_vorgaenger || ergebnis_nachkomma >= 4)
|
||||
// aktuelles digit hat genauso wie das Vorgängerdigit noch keinen Nulldurchgang.
|
||||
result = ergebnis_vorkomma;
|
||||
else
|
||||
// aktuelles digit läuft dem kleineren digit (9.x) vor. Also schon >=x.0 während das vorherige Digit noch
|
||||
// keinen Nulldurchgang hat. Daher wird um 1 reduziert.
|
||||
result = (ergebnis_vorkomma - 1 + 10) % 10;
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "ZeigerEvalHybridNeu - KEIN Analoger Vorgänger, >= 9.5 --> noch kein Nulldurchgang = " + std::to_string(result) +
|
||||
" zahl: " + std::to_string(zahl) + " zahl_vorgaenger = " + std::to_string(zahl_vorgaenger)+ " eval_vorgaenger = " + std::to_string(eval_vorgaenger) + " DigitalUnschaerfe = " + std::to_string(DigitalUnschaerfe) + " ergebnis_nachkomma = " + std::to_string(ergebnis_nachkomma));
|
||||
return result;
|
||||
}
|
||||
|
||||
int ClassFlowCNNGeneral::ZeigerEval(float zahl, int ziffer_vorgaenger)
|
||||
|
||||
int ClassFlowCNNGeneral::ZeigerEvalAnalogToDigitNeu(float zahl, float ziffer_vorgaenger, int eval_vorgaenger, float analogDigitalTransitionStart)
|
||||
{
|
||||
int ergebnis_nachkomma = ((int) floor(zahl * 10) + 10) % 10;
|
||||
int result;
|
||||
int ergebnis_nachkomma = ((int) floor(zahl * 10)) % 10;
|
||||
int ergebnis_vorkomma = ((int) floor(zahl) + 10) % 10;
|
||||
int ergebnis, ergebnis_rating;
|
||||
bool roundedUp = false;
|
||||
|
||||
// Innerhalb der digitalen Unschaefe
|
||||
if (ergebnis_nachkomma >= (10-DigitalUnschaerfe * 10)) { // Band um die Ziffer --> Runden, da Ziffer im Rahmen Ungenauigkeit erreicht
|
||||
result = (int) (round(zahl) + 10) % 10;
|
||||
roundedUp = true;
|
||||
// vor/nachkomma neu berechnen, da wir anhand der Unschaefe die Zahl anpassen.
|
||||
ergebnis_nachkomma = ((int) floor(result * 10)) % 10;
|
||||
ergebnis_vorkomma = ((int) floor(result) + 10) % 10;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "ZeigerEvalAnalogToDigitNeu - digitaleUnschaerfe - Ergebnis = " + std::to_string(result) +
|
||||
" zahl: " + std::to_string(zahl) + " ziffer_vorgaenger: " + std::to_string(ziffer_vorgaenger) +
|
||||
" erg_vorkomma: " + std::to_string(ergebnis_vorkomma) +
|
||||
" erg_nachkomma: " + std::to_string(ergebnis_nachkomma));
|
||||
} else {
|
||||
result = (int) ((int) trunc(zahl) + 10) % 10;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "ZeigerEvalAnalogToDigitNeu - KEINE digitaleUnschaerfe - Ergebnis = " + std::to_string(result) +
|
||||
" zahl: " + std::to_string(zahl) + " ziffer_vorgaenger = " + std::to_string(ziffer_vorgaenger));
|
||||
}
|
||||
|
||||
// Kein Nulldurchgang hat stattgefunden.
|
||||
// Nur eval_vorgaenger verwendet, da ziffer_vorgaenger hier falsch sein könnte.
|
||||
// ziffer_vorgaenger<=0.1 & eval_vorgaenger=9 entspricht analog wurde zurückgesetzt wegen vorhergehender analog, die noch nicht auf 0 sind.
|
||||
if ((eval_vorgaenger>=6 && (ziffer_vorgaenger>analogDigitalTransitionStart || ziffer_vorgaenger<=0.2) && roundedUp)
|
||||
// digit läuft dem Analog vor. Darf aber erst passieren, wenn
|
||||
// digit wirklich schnon los läuft, deshalb 9
|
||||
|| (eval_vorgaenger>9 && ziffer_vorgaenger>analogDigitalTransitionStart && ergebnis_nachkomma<=1))
|
||||
|
||||
{
|
||||
result = ((ergebnis_vorkomma+10) - 1) % 10;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "ZeigerEvalAnalogToDigitNeu - Nulldurchgang noch nicht stattgefunden = " + std::to_string(result) +
|
||||
" zahl: " + std::to_string(zahl) +
|
||||
" ziffer_vorgaenger = " + std::to_string(ziffer_vorgaenger) +
|
||||
" erg_nachkomma = " + std::to_string(ergebnis_nachkomma));
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
int ClassFlowCNNGeneral::ZeigerEvalAnalogNeu(float zahl, int ziffer_vorgaenger)
|
||||
{
|
||||
float zahl_min, zahl_max;
|
||||
int result;
|
||||
|
||||
if (ziffer_vorgaenger == -1)
|
||||
return ergebnis_vorkomma % 10;
|
||||
{
|
||||
result = (int) floor(zahl);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "ZeigerEvalAnalogNeu - kein Vorgänger - Ergebnis = " + std::to_string(result) +
|
||||
" zahl: " + std::to_string(zahl) + " ziffer_vorgaenger = " + std::to_string(ziffer_vorgaenger) + " AnalogFehler = " + std::to_string(AnalogFehler));
|
||||
return result;
|
||||
}
|
||||
|
||||
ergebnis_rating = ergebnis_nachkomma - ziffer_vorgaenger;
|
||||
if (ergebnis_nachkomma >= 5)
|
||||
ergebnis_rating-=5;
|
||||
else
|
||||
ergebnis_rating+=5;
|
||||
ergebnis = (int) round(zahl);
|
||||
if (ergebnis_rating < 0)
|
||||
ergebnis-=1;
|
||||
if (ergebnis == -1)
|
||||
ergebnis+=10;
|
||||
zahl_min = zahl - AnalogFehler / 10.0;
|
||||
zahl_max = zahl + AnalogFehler / 10.0;
|
||||
|
||||
if ((int) floor(zahl_max) - (int) floor(zahl_min) != 0)
|
||||
{
|
||||
if (ziffer_vorgaenger <= AnalogFehler)
|
||||
{
|
||||
result = ((int) floor(zahl_max) + 10) % 10;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "ZeigerEvalAnalogNeu - Zahl uneindeutig, Korrektur nach oben - Ergebnis = " + std::to_string(result) +
|
||||
" zahl: " + std::to_string(zahl) + " ziffer_vorgaenger = " + std::to_string(ziffer_vorgaenger) + " AnalogFehler = " + std::to_string(AnalogFehler));
|
||||
return result;
|
||||
}
|
||||
if (ziffer_vorgaenger >= 10 - AnalogFehler)
|
||||
{
|
||||
result = ((int) floor(zahl_min) + 10) % 10;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "ZeigerEvalAnalogNeu - Zahl uneindeutig, Korrektur nach unten - Ergebnis = " + std::to_string(result) +
|
||||
" zahl: " + std::to_string(zahl) + " ziffer_vorgaenger = " + std::to_string(ziffer_vorgaenger) + " AnalogFehler = " + std::to_string(AnalogFehler));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
result = ((int) floor(zahl) + 10) % 10;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "ZeigerEvalAnalogNeu - Zahl eindeutig, keine Korrektur notwendig - Ergebnis = " + std::to_string(result) +
|
||||
" zahl: " + std::to_string(zahl) + " ziffer_vorgaenger = " + std::to_string(ziffer_vorgaenger) + " AnalogFehler = " + std::to_string(AnalogFehler));
|
||||
|
||||
return result;
|
||||
|
||||
ergebnis = (ergebnis + 10) % 10;
|
||||
return ergebnis;
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowCNNGeneral::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
std::vector<string> zerlegt;
|
||||
@@ -206,31 +309,24 @@ bool ClassFlowCNNGeneral::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
) // Paragraph passt nicht
|
||||
return false;
|
||||
|
||||
|
||||
/*
|
||||
if ((aktparamgraph.compare("[Analog]") != 0) && (aktparamgraph.compare(";[Analog]") != 0)
|
||||
&& (aktparamgraph.compare("[Digit]") != 0) && (aktparamgraph.compare(";[Digit]"))) // Paragraph passt nicht
|
||||
return false;
|
||||
*/
|
||||
|
||||
if (aktparamgraph[0] == ';')
|
||||
{
|
||||
disabled = true;
|
||||
while (getNextLine(pfile, &aktparamgraph) && !isNewParagraph(aktparamgraph));
|
||||
printf("[Analog/Digit] is disabled !!!\n");
|
||||
ESP_LOGD(TAG, "[Analog/Digit] is disabled!");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
zerlegt = this->ZerlegeZeile(aktparamgraph);
|
||||
if ((zerlegt[0] == "LogImageLocation") && (zerlegt.size() > 1))
|
||||
zerlegt = ZerlegeZeile(aktparamgraph);
|
||||
if ((toUpper(zerlegt[0]) == "LOGIMAGELOCATION") && (zerlegt.size() > 1))
|
||||
{
|
||||
this->LogImageLocation = "/sdcard" + zerlegt[1];
|
||||
this->isLogImage = true;
|
||||
}
|
||||
if ((zerlegt[0] == "LogImageSelect") && (zerlegt.size() > 1))
|
||||
if ((toUpper(zerlegt[0]) == "LOGIMAGESELECT") && (zerlegt.size() > 1))
|
||||
{
|
||||
LogImageSelect = zerlegt[1];
|
||||
isLogImageSelect = true;
|
||||
@@ -240,20 +336,15 @@ bool ClassFlowCNNGeneral::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
this->logfileRetentionInDays = std::stoi(zerlegt[1]);
|
||||
}
|
||||
if ((toUpper(zerlegt[0]) == "MODELTYPE") && (zerlegt.size() > 1))
|
||||
{
|
||||
if (toUpper(zerlegt[1]) == "DIGITHYPRID")
|
||||
CNNType = DigitalHyprid;
|
||||
}
|
||||
|
||||
if ((zerlegt[0] == "Model") && (zerlegt.size() > 1))
|
||||
if ((toUpper(zerlegt[0]) == "MODEL") && (zerlegt.size() > 1))
|
||||
{
|
||||
this->cnnmodelfile = zerlegt[1];
|
||||
}
|
||||
if ((zerlegt[0] == "ModelInputSize") && (zerlegt.size() > 2))
|
||||
|
||||
if ((toUpper(zerlegt[0]) == "CNNGOODTHRESHOLD") && (zerlegt.size() > 1))
|
||||
{
|
||||
this->modelxsize = std::stoi(zerlegt[1]);
|
||||
this->modelysize = std::stoi(zerlegt[2]);
|
||||
CNNGoodThreshold = std::stof(zerlegt[1]);
|
||||
}
|
||||
if (zerlegt.size() >= 5)
|
||||
{
|
||||
@@ -263,6 +354,11 @@ bool ClassFlowCNNGeneral::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
neuroi->posy = std::stoi(zerlegt[2]);
|
||||
neuroi->deltax = std::stoi(zerlegt[3]);
|
||||
neuroi->deltay = std::stoi(zerlegt[4]);
|
||||
neuroi->CCW = false;
|
||||
if (zerlegt.size() >= 6)
|
||||
{
|
||||
neuroi->CCW = toUpper(zerlegt[5]) == "TRUE";
|
||||
}
|
||||
neuroi->result_float = -1;
|
||||
neuroi->image = NULL;
|
||||
neuroi->image_org = NULL;
|
||||
@@ -273,21 +369,16 @@ bool ClassFlowCNNGeneral::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
if (toUpper(zerlegt[1]) == "TRUE")
|
||||
SaveAllFiles = true;
|
||||
}
|
||||
|
||||
/*
|
||||
if ((toUpper(zerlegt[0]) == "EXTENDEDRESOLUTION") && (zerlegt.size() > 1))
|
||||
{
|
||||
if (toUpper(zerlegt[1]) == "TRUE")
|
||||
extendedResolution = true;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if (!getNetworkParameter())
|
||||
return false;
|
||||
|
||||
for (int _ana = 0; _ana < GENERAL.size(); ++_ana)
|
||||
|
||||
for (int _ana = 0; _ana < GENERAL.size(); ++_ana)
|
||||
for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i)
|
||||
{
|
||||
GENERAL[_ana]->ROI[i]->image = new CImageBasis(modelxsize, modelysize, 3);
|
||||
GENERAL[_ana]->ROI[i]->image = new CImageBasis(modelxsize, modelysize, modelchannel);
|
||||
GENERAL[_ana]->ROI[i]->image_org = new CImageBasis(GENERAL[_ana]->ROI[i]->deltax, GENERAL[_ana]->ROI[i]->deltay, 3);
|
||||
}
|
||||
|
||||
@@ -303,7 +394,6 @@ general* ClassFlowCNNGeneral::FindGENERAL(string _name_number)
|
||||
}
|
||||
|
||||
|
||||
|
||||
general* ClassFlowCNNGeneral::GetGENERAL(string _name, bool _create = true)
|
||||
{
|
||||
string _analog, _roi;
|
||||
@@ -338,9 +428,10 @@ general* ClassFlowCNNGeneral::GetGENERAL(string _name, bool _create = true)
|
||||
|
||||
roi* neuroi = new roi;
|
||||
neuroi->name = _roi;
|
||||
|
||||
_ret->ROI.push_back(neuroi);
|
||||
|
||||
printf("GetGENERAL - GENERAL %s - roi %s\n", _analog.c_str(), _roi.c_str());
|
||||
ESP_LOGD(TAG, "GetGENERAL - GENERAL %s - roi %s - CCW: %d", _analog.c_str(), _roi.c_str(), neuroi->CCW);
|
||||
|
||||
return _ret;
|
||||
}
|
||||
@@ -381,7 +472,7 @@ bool ClassFlowCNNGeneral::doFlow(string time)
|
||||
return false;
|
||||
};
|
||||
|
||||
if (debugdetailgeneral) LogFile.WriteToFile("ClassFlowCNNGeneral::doFlow nach Alignment");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "doFlow nach Alignment");
|
||||
|
||||
doNeuralNetwork(time);
|
||||
|
||||
@@ -399,7 +490,7 @@ bool ClassFlowCNNGeneral::doAlignAndCut(string time)
|
||||
for (int _ana = 0; _ana < GENERAL.size(); ++_ana)
|
||||
for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i)
|
||||
{
|
||||
printf("General %d - Align&Cut\n", i);
|
||||
ESP_LOGD(TAG, "General %d - Align&Cut", i);
|
||||
|
||||
caic->CutAndSave(GENERAL[_ana]->ROI[i]->posx, GENERAL[_ana]->ROI[i]->posy, GENERAL[_ana]->ROI[i]->deltax, GENERAL[_ana]->ROI[i]->deltay, GENERAL[_ana]->ROI[i]->image_org);
|
||||
if (SaveAllFiles)
|
||||
@@ -425,7 +516,7 @@ bool ClassFlowCNNGeneral::doAlignAndCut(string time)
|
||||
|
||||
void ClassFlowCNNGeneral::DrawROI(CImageBasis *_zw)
|
||||
{
|
||||
if (CNNType == Analogue)
|
||||
if (CNNType == Analogue || CNNType == Analogue100)
|
||||
{
|
||||
int r = 0;
|
||||
int g = 255;
|
||||
@@ -435,7 +526,7 @@ void ClassFlowCNNGeneral::DrawROI(CImageBasis *_zw)
|
||||
for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i)
|
||||
{
|
||||
_zw->drawRect(GENERAL[_ana]->ROI[i]->posx, GENERAL[_ana]->ROI[i]->posy, GENERAL[_ana]->ROI[i]->deltax, GENERAL[_ana]->ROI[i]->deltay, r, g, b, 1);
|
||||
_zw->drawCircle((int) (GENERAL[_ana]->ROI[i]->posx + GENERAL[_ana]->ROI[i]->deltax/2), (int) (GENERAL[_ana]->ROI[i]->posy + GENERAL[_ana]->ROI[i]->deltay/2), (int) (GENERAL[_ana]->ROI[i]->deltax/2), r, g, b, 2);
|
||||
_zw->drawEllipse( (int) (GENERAL[_ana]->ROI[i]->posx + GENERAL[_ana]->ROI[i]->deltax/2), (int) (GENERAL[_ana]->ROI[i]->posy + GENERAL[_ana]->ROI[i]->deltay/2), (int) (GENERAL[_ana]->ROI[i]->deltax/2), (int) (GENERAL[_ana]->ROI[i]->deltay/2), r, g, b, 2);
|
||||
_zw->drawLine((int) (GENERAL[_ana]->ROI[i]->posx + GENERAL[_ana]->ROI[i]->deltax/2), (int) GENERAL[_ana]->ROI[i]->posy, (int) (GENERAL[_ana]->ROI[i]->posx + GENERAL[_ana]->ROI[i]->deltax/2), (int) (GENERAL[_ana]->ROI[i]->posy + GENERAL[_ana]->ROI[i]->deltay), r, g, b, 2);
|
||||
_zw->drawLine((int) GENERAL[_ana]->ROI[i]->posx, (int) (GENERAL[_ana]->ROI[i]->posy + GENERAL[_ana]->ROI[i]->deltay/2), (int) GENERAL[_ana]->ROI[i]->posx + GENERAL[_ana]->ROI[i]->deltax, (int) (GENERAL[_ana]->ROI[i]->posy + GENERAL[_ana]->ROI[i]->deltay/2), r, g, b, 2);
|
||||
}
|
||||
@@ -448,6 +539,71 @@ void ClassFlowCNNGeneral::DrawROI(CImageBasis *_zw)
|
||||
}
|
||||
}
|
||||
|
||||
bool ClassFlowCNNGeneral::getNetworkParameter()
|
||||
{
|
||||
if (disabled)
|
||||
return true;
|
||||
|
||||
CTfLiteClass *tflite = new CTfLiteClass;
|
||||
string zwcnn = "/sdcard" + cnnmodelfile;
|
||||
zwcnn = FormatFileName(zwcnn);
|
||||
ESP_LOGD(TAG, "%s", zwcnn.c_str());
|
||||
if (!tflite->LoadModel(zwcnn)) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't read model file " + cnnmodelfile);
|
||||
delete tflite;
|
||||
return false;
|
||||
}
|
||||
tflite->MakeAllocate();
|
||||
|
||||
if (CNNType == AutoDetect)
|
||||
{
|
||||
tflite->GetInputDimension(false);
|
||||
modelxsize = tflite->ReadInputDimenstion(0);
|
||||
modelysize = tflite->ReadInputDimenstion(1);
|
||||
modelchannel = tflite->ReadInputDimenstion(2);
|
||||
|
||||
int _anzoutputdimensions = tflite->GetAnzOutPut();
|
||||
switch (_anzoutputdimensions)
|
||||
{
|
||||
case 2:
|
||||
CNNType = Analogue;
|
||||
ESP_LOGD(TAG, "TFlite-Type set to Analogue");
|
||||
break;
|
||||
case 10:
|
||||
CNNType = DoubleHyprid10;
|
||||
ESP_LOGD(TAG, "TFlite-Type set to DoubleHyprid10");
|
||||
break;
|
||||
case 11:
|
||||
CNNType = Digital;
|
||||
ESP_LOGD(TAG, "TFlite-Type set to Digital");
|
||||
break;
|
||||
/* case 20:
|
||||
CNNType = DigitalHyprid10;
|
||||
ESP_LOGD(TAG, "TFlite-Type set to DigitalHyprid10");
|
||||
break;
|
||||
*/
|
||||
// case 22:
|
||||
// CNNType = DigitalHyprid;
|
||||
// ESP_LOGD(TAG, "TFlite-Type set to DigitalHyprid");
|
||||
// break;
|
||||
case 100:
|
||||
if (modelxsize==32 && modelysize == 32) {
|
||||
CNNType = Analogue100;
|
||||
ESP_LOGD(TAG, "TFlite-Type set to Analogue100");
|
||||
} else {
|
||||
CNNType = Digital100;
|
||||
ESP_LOGD(TAG, "TFlite-Type set to Digital");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "tflite passt nicht zur Firmware (outout_dimension=" + std::to_string(_anzoutputdimensions) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
delete tflite;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
|
||||
{
|
||||
if (disabled)
|
||||
@@ -458,44 +614,20 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
|
||||
CTfLiteClass *tflite = new CTfLiteClass;
|
||||
string zwcnn = "/sdcard" + cnnmodelfile;
|
||||
zwcnn = FormatFileName(zwcnn);
|
||||
printf(zwcnn.c_str());printf("\n");
|
||||
ESP_LOGD(TAG, "%s", zwcnn.c_str());
|
||||
if (!tflite->LoadModel(zwcnn)) {
|
||||
printf("Can't read model file /sdcard%s\n", cnnmodelfile.c_str());
|
||||
LogFile.WriteToFile("Cannot load model");
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't read model file " + cnnmodelfile);
|
||||
|
||||
delete tflite;
|
||||
return false;
|
||||
}
|
||||
tflite->MakeAllocate();
|
||||
|
||||
if (CNNType == AutoDetect)
|
||||
{
|
||||
int _anzoutputdimensions = tflite->GetAnzOutPut();
|
||||
switch (_anzoutputdimensions)
|
||||
{
|
||||
case 2:
|
||||
CNNType = Analogue;
|
||||
printf("TFlite-Type set to Analogue\n");
|
||||
break;
|
||||
case 11:
|
||||
CNNType = Digital;
|
||||
printf("TFlite-Type set to Digital\n");
|
||||
break;
|
||||
case 22:
|
||||
CNNType = DigitalHyprid;
|
||||
printf("TFlite-Type set to DigitalHyprid\n");
|
||||
break;
|
||||
default:
|
||||
printf("ERROR ERROR ERROR - tflite passt nicht zur Firmware - ERROR ERROR ERROR\n");
|
||||
}
|
||||
// flowpostprocessing->UpdateNachkommaDecimalShift();
|
||||
}
|
||||
|
||||
for (int _ana = 0; _ana < GENERAL.size(); ++_ana)
|
||||
{
|
||||
for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i)
|
||||
{
|
||||
printf("General %d - TfLite\n", i);
|
||||
ESP_LOGD(TAG, "General %d - TfLite", i);
|
||||
|
||||
switch (CNNType) {
|
||||
case Analogue:
|
||||
@@ -505,62 +637,236 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
|
||||
|
||||
tflite->LoadInputImageBasis(GENERAL[_ana]->ROI[i]->image);
|
||||
tflite->Invoke();
|
||||
if (debugdetailgeneral) LogFile.WriteToFile("Nach Invoke");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Nach Invoke");
|
||||
|
||||
f1 = tflite->GetOutputValue(0);
|
||||
f2 = tflite->GetOutputValue(1);
|
||||
float result = fmod(atan2(f1, f2) / (M_PI * 2) + 2, 1);
|
||||
GENERAL[_ana]->ROI[i]->result_float = result * 10;
|
||||
printf("Result General(Analog)%i: %f\n", i, GENERAL[_ana]->ROI[i]->result_float);
|
||||
|
||||
if(GENERAL[_ana]->ROI[i]->CCW)
|
||||
GENERAL[_ana]->ROI[i]->result_float = 10 - (result * 10);
|
||||
else
|
||||
GENERAL[_ana]->ROI[i]->result_float = result * 10;
|
||||
|
||||
ESP_LOGD(TAG, "Result General(Analog)%i - CCW: %d - %f", i, GENERAL[_ana]->ROI[i]->CCW, GENERAL[_ana]->ROI[i]->result_float);
|
||||
if (isLogImage)
|
||||
LogImage(logPath, GENERAL[_ana]->ROI[i]->name, &GENERAL[_ana]->ROI[i]->result_float, NULL, time, GENERAL[_ana]->ROI[i]->image_org);
|
||||
} break;
|
||||
|
||||
case Digital:
|
||||
{
|
||||
GENERAL[_ana]->ROI[i]->result_klasse = 0;
|
||||
GENERAL[_ana]->ROI[i]->result_klasse = tflite->GetClassFromImageBasis(GENERAL[_ana]->ROI[i]->image);
|
||||
printf("Result General(Digit)%i: %d\n", i, GENERAL[_ana]->ROI[i]->result_klasse);
|
||||
ESP_LOGD(TAG, "Result General(Digit)%i: %d", i, GENERAL[_ana]->ROI[i]->result_klasse);
|
||||
|
||||
if (isLogImage)
|
||||
{
|
||||
string _imagename = GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name;
|
||||
if (isLogImageSelect)
|
||||
{
|
||||
if (LogImageSelect.find(GENERAL[_ana]->ROI[i]->name) != std::string::npos)
|
||||
LogImage(logPath, GENERAL[_ana]->ROI[i]->name, NULL, &GENERAL[_ana]->ROI[i]->result_klasse, time, GENERAL[_ana]->ROI[i]->image_org);
|
||||
LogImage(logPath, _imagename, NULL, &GENERAL[_ana]->ROI[i]->result_klasse, time, GENERAL[_ana]->ROI[i]->image_org);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogImage(logPath, GENERAL[_ana]->ROI[i]->name, NULL, &GENERAL[_ana]->ROI[i]->result_klasse, time, GENERAL[_ana]->ROI[i]->image_org);
|
||||
LogImage(logPath, _imagename, NULL, &GENERAL[_ana]->ROI[i]->result_klasse, time, GENERAL[_ana]->ROI[i]->image_org);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
/*
|
||||
case DigitalHyprid:
|
||||
{
|
||||
int _num, _nachkomma;
|
||||
|
||||
tflite->LoadInputImageBasis(GENERAL[_ana]->ROI[i]->image);
|
||||
tflite->Invoke();
|
||||
if (debugdetailgeneral) LogFile.WriteToFile("Nach Invoke");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Nach Invoke");
|
||||
|
||||
_num = tflite->GetOutClassification(0, 10);
|
||||
_nachkomma = tflite->GetOutClassification(11, 21);
|
||||
|
||||
|
||||
string _zwres = "Nach Invoke - Nummer: " + to_string(_num) + " Nachkomma: " + to_string(_nachkomma);
|
||||
if (debugdetailgeneral) LogFile.WriteToFile(_zwres);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, _zwres);
|
||||
|
||||
if ((_num == 10) || (_nachkomma == 10)) // NaN detektiert
|
||||
GENERAL[_ana]->ROI[i]->result_float = -1;
|
||||
else
|
||||
GENERAL[_ana]->ROI[i]->result_float = fmod((double) _num + (((double)_nachkomma)-5)/10 + (double) 10, 10);
|
||||
|
||||
printf("Result General(DigitalHyprid)%i: %f\n", i, GENERAL[_ana]->ROI[i]->result_float);
|
||||
ESP_LOGD(TAG, "Result General(DigitalHyprid)%i: %f\n", i, GENERAL[_ana]->ROI[i]->result_float);
|
||||
_zwres = "Result General(DigitalHyprid)" + to_string(i) + ": " + to_string(GENERAL[_ana]->ROI[i]->result_float);
|
||||
if (debugdetailgeneral) LogFile.WriteToFile(_zwres);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, _zwres);
|
||||
|
||||
if (isLogImage)
|
||||
LogImage(logPath, GENERAL[_ana]->ROI[i]->name, &GENERAL[_ana]->ROI[i]->result_float, NULL, time, GENERAL[_ana]->ROI[i]->image_org);
|
||||
{
|
||||
string _imagename = GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name;
|
||||
if (isLogImageSelect)
|
||||
{
|
||||
if (LogImageSelect.find(GENERAL[_ana]->ROI[i]->name) != std::string::npos)
|
||||
LogImage(logPath, _imagename, NULL, &GENERAL[_ana]->ROI[i]->result_klasse, time, GENERAL[_ana]->ROI[i]->image_org);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogImage(logPath, _imagename, NULL, &GENERAL[_ana]->ROI[i]->result_klasse, time, GENERAL[_ana]->ROI[i]->image_org);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
*/
|
||||
/*
|
||||
case DigitalHyprid10:
|
||||
{
|
||||
int _num, _nachkomma;
|
||||
|
||||
tflite->LoadInputImageBasis(GENERAL[_ana]->ROI[i]->image);
|
||||
tflite->Invoke();
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Nach Invoke");
|
||||
|
||||
_num = tflite->GetOutClassification(0, 9);
|
||||
_nachkomma = tflite->GetOutClassification(10, 19);
|
||||
|
||||
|
||||
string _zwres = "Nach Invoke - Nummer: " + to_string(_num) + " Nachkomma: " + to_string(_nachkomma);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, _zwres);
|
||||
|
||||
GENERAL[_ana]->ROI[i]->result_float = fmod((double) _num + (((double)_nachkomma)-5)/10 + (double) 10, 10);
|
||||
|
||||
ESP_LOGD(TAG, "Result General(DigitalHyprid)%i: %f\n", i, GENERAL[_ana]->ROI[i]->result_float);
|
||||
_zwres = "Result General(DigitalHyprid)" + to_string(i) + ": " + to_string(GENERAL[_ana]->ROI[i]->result_float);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, _zwres);
|
||||
|
||||
if (isLogImage)
|
||||
{
|
||||
string _imagename = GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name;
|
||||
if (isLogImageSelect)
|
||||
{
|
||||
if (LogImageSelect.find(GENERAL[_ana]->ROI[i]->name) != std::string::npos)
|
||||
LogImage(logPath, _imagename, NULL, &GENERAL[_ana]->ROI[i]->result_klasse, time, GENERAL[_ana]->ROI[i]->image_org);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogImage(logPath, _imagename, NULL, &GENERAL[_ana]->ROI[i]->result_klasse, time, GENERAL[_ana]->ROI[i]->image_org);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
*/
|
||||
|
||||
case DoubleHyprid10:
|
||||
{
|
||||
int _num, _numplus, _numminus;
|
||||
float _val, _valplus, _valminus;
|
||||
float _fit;
|
||||
float _result_save_file;
|
||||
|
||||
tflite->LoadInputImageBasis(GENERAL[_ana]->ROI[i]->image);
|
||||
tflite->Invoke();
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Nach Invoke");
|
||||
|
||||
_num = tflite->GetOutClassification(0, 9);
|
||||
_numplus = (_num + 1) % 10;
|
||||
_numminus = (_num - 1 + 10) % 10;
|
||||
|
||||
_val = tflite->GetOutputValue(_num);
|
||||
_valplus = tflite->GetOutputValue(_numplus);
|
||||
_valminus = tflite->GetOutputValue(_numminus);
|
||||
|
||||
float result = _num;
|
||||
|
||||
if (_valplus > _valminus)
|
||||
{
|
||||
result = result + _valplus / (_valplus + _val);
|
||||
_fit = _val + _valplus;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = result - _valminus / (_val + _valminus);
|
||||
_fit = _val + _valminus;
|
||||
|
||||
}
|
||||
if (result >= 10)
|
||||
result = result - 10;
|
||||
if (result < 0)
|
||||
result = result + 10;
|
||||
|
||||
string zw = "_num (p, m): " + to_string(_num) + " " + to_string(_numplus) + " " + to_string(_numminus);
|
||||
zw = zw + " _val (p, m): " + to_string(_val) + " " + to_string(_valplus) + " " + to_string(_valminus);
|
||||
zw = zw + " result: " + to_string(result) + " _fit: " + to_string(_fit);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw);
|
||||
|
||||
|
||||
_result_save_file = result;
|
||||
|
||||
if (_fit < CNNGoodThreshold)
|
||||
{
|
||||
GENERAL[_ana]->ROI[i]->isReject = true;
|
||||
result = -1;
|
||||
_result_save_file+= 100; // Für den Fall, dass fit nicht ausreichend, soll trotzdem das Ergebnis mit "-10x.y" abgespeichert werden.
|
||||
string zw = "Value Rejected due to Threshold (Fit: " + to_string(_fit) + "Threshold: " + to_string(CNNGoodThreshold) + ")";
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, zw);
|
||||
}
|
||||
else
|
||||
{
|
||||
GENERAL[_ana]->ROI[i]->isReject = false;
|
||||
}
|
||||
|
||||
|
||||
GENERAL[_ana]->ROI[i]->result_float = result;
|
||||
ESP_LOGD(TAG, "Result General(Analog)%i: %f", i, GENERAL[_ana]->ROI[i]->result_float);
|
||||
|
||||
if (isLogImage)
|
||||
{
|
||||
string _imagename = GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name;
|
||||
if (isLogImageSelect)
|
||||
{
|
||||
if (LogImageSelect.find(GENERAL[_ana]->ROI[i]->name) != std::string::npos)
|
||||
LogImage(logPath, _imagename, &_result_save_file, NULL, time, GENERAL[_ana]->ROI[i]->image_org);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogImage(logPath, _imagename, &_result_save_file, NULL, time, GENERAL[_ana]->ROI[i]->image_org);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Digital100:
|
||||
case Analogue100:
|
||||
{
|
||||
int _num;
|
||||
float _result_save_file;
|
||||
|
||||
tflite->LoadInputImageBasis(GENERAL[_ana]->ROI[i]->image);
|
||||
tflite->Invoke();
|
||||
|
||||
_num = tflite->GetOutClassification();
|
||||
|
||||
if(GENERAL[_ana]->ROI[i]->CCW)
|
||||
GENERAL[_ana]->ROI[i]->result_float = 10 - ((float)_num / 10.0);
|
||||
else
|
||||
GENERAL[_ana]->ROI[i]->result_float = (float)_num / 10.0;
|
||||
|
||||
_result_save_file = GENERAL[_ana]->ROI[i]->result_float;
|
||||
|
||||
|
||||
GENERAL[_ana]->ROI[i]->isReject = false;
|
||||
|
||||
ESP_LOGD(TAG, "Result General(Analog)%i - CCW: %d - %f", i, GENERAL[_ana]->ROI[i]->CCW, GENERAL[_ana]->ROI[i]->result_float);
|
||||
|
||||
if (isLogImage)
|
||||
{
|
||||
string _imagename = GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name;
|
||||
if (isLogImageSelect)
|
||||
{
|
||||
if (LogImageSelect.find(GENERAL[_ana]->ROI[i]->name) != std::string::npos)
|
||||
LogImage(logPath, _imagename, &_result_save_file, NULL, time, GENERAL[_ana]->ROI[i]->image_org);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogImage(logPath, _imagename, &_result_save_file, NULL, time, GENERAL[_ana]->ROI[i]->image_org);
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -574,7 +880,6 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
|
||||
|
||||
bool ClassFlowCNNGeneral::isExtendedResolution(int _number)
|
||||
{
|
||||
// if (extendedResolution && !(CNNType == Digital))
|
||||
if (!(CNNType == Digital))
|
||||
return true;
|
||||
|
||||
@@ -590,11 +895,14 @@ std::vector<HTMLInfo*> ClassFlowCNNGeneral::GetHTMLInfo()
|
||||
for (int _ana = 0; _ana < GENERAL.size(); ++_ana)
|
||||
for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i)
|
||||
{
|
||||
ESP_LOGD(TAG, "Image: %d", (int) GENERAL[_ana]->ROI[i]->image);
|
||||
if (GENERAL[_ana]->ROI[i]->image)
|
||||
{
|
||||
if (GENERAL[_ana]->name == "default")
|
||||
GENERAL[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + GENERAL[_ana]->ROI[i]->name + ".bmp"));
|
||||
else
|
||||
GENERAL[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name + ".bmp"));
|
||||
|
||||
}
|
||||
|
||||
HTMLInfo *zw = new HTMLInfo;
|
||||
if (GENERAL[_ana]->name == "default")
|
||||
@@ -615,13 +923,9 @@ std::vector<HTMLInfo*> ClassFlowCNNGeneral::GetHTMLInfo()
|
||||
zw->image = GENERAL[_ana]->ROI[i]->image;
|
||||
zw->image_org = GENERAL[_ana]->ROI[i]->image_org;
|
||||
|
||||
// printf("Push %s\n", zw->filename.c_str());
|
||||
|
||||
result.push_back(zw);
|
||||
}
|
||||
|
||||
// printf("größe: %d\n", result.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -663,3 +967,34 @@ void ClassFlowCNNGeneral::UpdateNameNumbers(std::vector<std::string> *_name_numb
|
||||
(*_name_numbers).push_back(_name);
|
||||
}
|
||||
}
|
||||
|
||||
string ClassFlowCNNGeneral::getReadoutRawString(int _analog)
|
||||
{
|
||||
string rt = "";
|
||||
|
||||
if (_analog >= GENERAL.size() || GENERAL[_analog]==NULL || GENERAL[_analog]->ROI.size() == 0)
|
||||
return rt;
|
||||
|
||||
for (int i = 0; i < GENERAL[_analog]->ROI.size(); ++i)
|
||||
{
|
||||
if (CNNType == Analogue || CNNType == Analogue100)
|
||||
{
|
||||
rt = rt + "," + RundeOutput(GENERAL[_analog]->ROI[i]->result_float, 1);
|
||||
}
|
||||
|
||||
if (CNNType == Digital)
|
||||
{
|
||||
if (GENERAL[_analog]->ROI[i]->result_klasse == 10)
|
||||
rt = rt + ",N";
|
||||
else
|
||||
rt = rt + "," + RundeOutput(GENERAL[_analog]->ROI[i]->result_klasse, 0);
|
||||
}
|
||||
|
||||
if ((CNNType == DoubleHyprid10) || (CNNType == Digital100))
|
||||
{
|
||||
rt = rt + "," + RundeOutput(GENERAL[_analog]->ROI[i]->result_float, 1);
|
||||
}
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,14 +3,16 @@
|
||||
|
||||
#include"ClassFlowDefineTypes.h"
|
||||
#include "ClassFlowAlignment.h"
|
||||
// #include "ClassFlowPostProcessing.h"
|
||||
|
||||
|
||||
enum t_CNNType {
|
||||
AutoDetect,
|
||||
Analogue,
|
||||
Analogue100,
|
||||
Digital,
|
||||
DigitalHyprid,
|
||||
DigitalHyprid10,
|
||||
DoubleHyprid10,
|
||||
Digital100,
|
||||
None
|
||||
};
|
||||
|
||||
@@ -20,23 +22,34 @@ class ClassFlowCNNGeneral :
|
||||
protected:
|
||||
t_CNNType CNNType;
|
||||
std::vector<general*> GENERAL;
|
||||
float CNNGoodThreshold;
|
||||
float AnalogFehler = 3.0;
|
||||
float AnalogToDigtalFehler = 0.8;
|
||||
float DigitalUnschaerfe = 0.2;
|
||||
int DigitalBand = 3;
|
||||
float DigitalAnalogerVorgaengerUebergangsbereich = 2;
|
||||
float DigitalUebergangsbereichVorgaenger = 0.7; // 9.3 - 0.7
|
||||
float DigitalUebergangsbereichVorlauf = 9.7; // Vorlauf-Nulldurchgang passiert erst ab ca. 9.7
|
||||
|
||||
string cnnmodelfile;
|
||||
int modelxsize, modelysize;
|
||||
int modelxsize, modelysize, modelchannel;
|
||||
bool isLogImageSelect;
|
||||
string LogImageSelect;
|
||||
ClassFlowAlignment* flowpostalignment;
|
||||
// ClassFlowPostProcessing *flowpostprocessing = NULL;
|
||||
bool SaveAllFiles;
|
||||
// bool extendedResolution;
|
||||
|
||||
int ZeigerEval(float zahl, int ziffer_vorgaenger);
|
||||
int ZeigerEvalHybrid(float zahl, float zahl_vorgaenger, int eval_vorgaenger);
|
||||
bool SaveAllFiles;
|
||||
|
||||
int ZeigerEvalAnalogNeu(float zahl, int ziffer_vorgaenger);
|
||||
int ZeigerEvalAnalogToDigitNeu(float zahl, float ziffer_vorgaenger, int eval_vorgaenger, float analogDigitalTransitionStart);
|
||||
int ZeigerEvalHybridNeu(float zahl, float zahl_vorgaenger, int eval_vorgaenger, bool AnalogerVorgaenger = false, float analogDigitalTransitionStart=9.2);
|
||||
|
||||
|
||||
|
||||
bool doNeuralNetwork(string time);
|
||||
bool doAlignAndCut(string time);
|
||||
|
||||
bool getNetworkParameter();
|
||||
|
||||
public:
|
||||
ClassFlowCNNGeneral(ClassFlowAlignment *_flowalign, t_CNNType _cnntype = AutoDetect);
|
||||
|
||||
@@ -44,13 +57,14 @@ public:
|
||||
bool doFlow(string time);
|
||||
|
||||
string getHTMLSingleStep(string host);
|
||||
string getReadout(int _analog, bool _extendedResolution);
|
||||
string getReadout(int _analog, bool _extendedResolution = false, int prev = -1, float _vorgaengerAnalog = -1, float analogDigitalTransitionStart=9.2);
|
||||
|
||||
string getReadoutRawString(int _analog);
|
||||
|
||||
void DrawROI(CImageBasis *_zw);
|
||||
|
||||
std::vector<HTMLInfo*> GetHTMLInfo();
|
||||
|
||||
// int AnzahlROIs(int _analog);
|
||||
int getAnzahlGENERAL();
|
||||
general* GetGENERAL(int _analog);
|
||||
general* GetGENERAL(string _name, bool _create);
|
||||
@@ -59,8 +73,6 @@ public:
|
||||
|
||||
bool isExtendedResolution(int _number = 0);
|
||||
|
||||
// void setPostprocessing(ClassFlowPostProcessing *_fpp){flowpostprocessing = _fpp;};
|
||||
|
||||
void UpdateNameNumbers(std::vector<std::string> *_name_numbers);
|
||||
|
||||
t_CNNType getCNNType(){return CNNType;};
|
||||
|
||||
@@ -6,7 +6,15 @@
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "ClassLogFile.h"
|
||||
#include "time_sntp.h"
|
||||
#include "Helper.h"
|
||||
@@ -19,13 +27,16 @@
|
||||
|
||||
//#define DEBUG_DETAIL_ON
|
||||
|
||||
static const char* TAG = "flow_controll";
|
||||
static const char* TAG = "FLOW CTRL";
|
||||
|
||||
|
||||
|
||||
std::string ClassFlowControll::doSingleStep(std::string _stepname, std::string _host){
|
||||
std::string _classname = "";
|
||||
std::string result = "";
|
||||
// printf("_stepname: %s\n", _stepname.c_str());
|
||||
|
||||
ESP_LOGD(TAG, "Step %s start", _stepname.c_str());
|
||||
|
||||
if ((_stepname.compare("[MakeImage]") == 0) || (_stepname.compare(";[MakeImage]") == 0)){
|
||||
_classname = "ClassFlowMakeImage";
|
||||
}
|
||||
@@ -33,8 +44,6 @@ std::string ClassFlowControll::doSingleStep(std::string _stepname, std::string _
|
||||
_classname = "ClassFlowAlignment";
|
||||
}
|
||||
if ((_stepname.compare(0, 7, "[Digits") == 0) || (_stepname.compare(0, 8, ";[Digits") == 0)) {
|
||||
// if ((_stepname.compare("[Digits]") == 0) || (_stepname.compare(";[Digits]") == 0)){
|
||||
// printf("Digits!!!\n");
|
||||
_classname = "ClassFlowCNNGeneral";
|
||||
}
|
||||
if ((_stepname.compare("[Analog]") == 0) || (_stepname.compare(";[Analog]") == 0)){
|
||||
@@ -43,6 +52,9 @@ std::string ClassFlowControll::doSingleStep(std::string _stepname, std::string _
|
||||
if ((_stepname.compare("[MQTT]") == 0) || (_stepname.compare(";[MQTT]") == 0)){
|
||||
_classname = "ClassFlowMQTT";
|
||||
}
|
||||
if ((_stepname.compare("[InfluxDB]") == 0) || (_stepname.compare(";[InfluxDB]") == 0)){
|
||||
_classname = "ClassFlowInfluxDB";
|
||||
}
|
||||
|
||||
for (int i = 0; i < FlowControll.size(); ++i)
|
||||
if (FlowControll[i]->name().compare(_classname) == 0){
|
||||
@@ -51,6 +63,8 @@ std::string ClassFlowControll::doSingleStep(std::string _stepname, std::string _
|
||||
result = FlowControll[i]->getHTMLSingleStep(_host);
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Step %s end", _stepname.c_str());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -61,14 +75,16 @@ std::string ClassFlowControll::TranslateAktstatus(std::string _input)
|
||||
return ("Take Image");
|
||||
if (_input.compare("ClassFlowAlignment") == 0)
|
||||
return ("Aligning");
|
||||
//if (_input.compare("ClassFlowAnalog") == 0)
|
||||
// return ("Analog ROIs");
|
||||
if (_input.compare("ClassFlowCNNGeneral") == 0)
|
||||
return ("Digitalization of ROIs");
|
||||
if (_input.compare("ClassFlowMQTT") == 0)
|
||||
return ("Sending MQTT");
|
||||
if (_input.compare("ClassFlowInfluxDB") == 0)
|
||||
return ("Sending InfluxDB");
|
||||
if (_input.compare("ClassFlowPostProcessing") == 0)
|
||||
return ("Processing");
|
||||
if (_input.compare("ClassFlowWriteList") == 0)
|
||||
return ("Processing");
|
||||
|
||||
return "Unkown Status";
|
||||
}
|
||||
@@ -78,7 +94,7 @@ std::vector<HTMLInfo*> ClassFlowControll::GetAllDigital()
|
||||
{
|
||||
if (flowdigit)
|
||||
{
|
||||
printf("ClassFlowControll::GetAllDigital - flowdigit != NULL\n");
|
||||
ESP_LOGD(TAG, "ClassFlowControll::GetAllDigital - flowdigit != NULL");
|
||||
return flowdigit->GetHTMLInfo();
|
||||
}
|
||||
|
||||
@@ -120,7 +136,6 @@ string ClassFlowControll::GetMQTTMainTopic()
|
||||
if (FlowControll[i]->name().compare("ClassFlowMQTT") == 0)
|
||||
return ((ClassFlowMQTT*) (FlowControll[i]))->GetMQTTMainTopic();
|
||||
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -130,14 +145,13 @@ void ClassFlowControll::SetInitialParameter(void)
|
||||
{
|
||||
AutoStart = false;
|
||||
SetupModeActive = false;
|
||||
AutoIntervall = 10;
|
||||
AutoIntervall = 10; // Minutes
|
||||
flowdigit = NULL;
|
||||
flowanalog = NULL;
|
||||
flowpostprocessing = NULL;
|
||||
disabled = false;
|
||||
aktRunNr = 0;
|
||||
aktstatus = "Booting ...";
|
||||
|
||||
}
|
||||
|
||||
bool ClassFlowControll::isAutoStart(long &_intervall)
|
||||
@@ -174,7 +188,13 @@ ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type)
|
||||
}
|
||||
if (toUpper(_type).compare("[MQTT]") == 0)
|
||||
cfc = new ClassFlowMQTT(&FlowControll);
|
||||
|
||||
if (toUpper(_type).compare("[INFLUXDB]") == 0)
|
||||
cfc = new ClassFlowInfluxDB(&FlowControll);
|
||||
|
||||
if (toUpper(_type).compare("[WRITELIST]") == 0)
|
||||
cfc = new ClassFlowWriteList(&FlowControll);
|
||||
|
||||
if (toUpper(_type).compare("[POSTPROCESSING]") == 0)
|
||||
{
|
||||
cfc = new ClassFlowPostProcessing(&FlowControll, flowanalog, flowdigit);
|
||||
@@ -187,6 +207,9 @@ ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type)
|
||||
if (toUpper(_type).compare("[AUTOTIMER]") == 0)
|
||||
cfc = this;
|
||||
|
||||
if (toUpper(_type).compare("[DATALOGGING]") == 0)
|
||||
cfc = this;
|
||||
|
||||
if (toUpper(_type).compare("[DEBUG]") == 0)
|
||||
cfc = this;
|
||||
|
||||
@@ -213,7 +236,7 @@ void ClassFlowControll::InitFlow(std::string config)
|
||||
if (pFile != NULL)
|
||||
{
|
||||
fgets(zw, 1024, pFile);
|
||||
printf("%s", zw);
|
||||
ESP_LOGD(TAG, "%s", zw);
|
||||
line = std::string(zw);
|
||||
}
|
||||
|
||||
@@ -222,7 +245,7 @@ void ClassFlowControll::InitFlow(std::string config)
|
||||
cfc = CreateClassFlow(line);
|
||||
if (cfc)
|
||||
{
|
||||
printf("Start ReadParameter (%s)\n", line.c_str());
|
||||
ESP_LOGD(TAG, "Start ReadParameter (%s)", line.c_str());
|
||||
cfc->ReadParameter(pFile, line);
|
||||
}
|
||||
else
|
||||
@@ -230,7 +253,7 @@ void ClassFlowControll::InitFlow(std::string config)
|
||||
line = "";
|
||||
if (fgets(zw, 1024, pFile) && !feof(pFile))
|
||||
{
|
||||
printf("Read: %s", zw);
|
||||
ESP_LOGD(TAG, "Read: %s", zw);
|
||||
line = std::string(zw);
|
||||
}
|
||||
}
|
||||
@@ -270,6 +293,12 @@ bool ClassFlowControll::doFlow(string time)
|
||||
LogFile.WriteHeapInfo("ClassFlowControll::doFlow - Start");
|
||||
#endif
|
||||
|
||||
/* Check if we have a valid date/time and if not restart the NTP client */
|
||||
if (! getTimeIsSet()) {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Time not set, restarting NTP Client!");
|
||||
restartNtpClient();
|
||||
}
|
||||
|
||||
for (int i = 0; i < FlowControll.size(); ++i)
|
||||
{
|
||||
zw_time = gettimestring("%H:%M:%S");
|
||||
@@ -284,11 +313,11 @@ bool ClassFlowControll::doFlow(string time)
|
||||
|
||||
if (!FlowControll[i]->doFlow(time)){
|
||||
repeat++;
|
||||
LogFile.WriteToFile("Fehler im vorheriger Schritt - wird zum " + to_string(repeat) + ". Mal wiederholt");
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Fehler im vorheriger Schritt - wird zum " + to_string(repeat) + ". Mal wiederholt");
|
||||
if (i) i -= 1; // vorheriger Schritt muss wiederholt werden (vermutlich Bilder aufnehmen)
|
||||
result = false;
|
||||
if (repeat > 5) {
|
||||
LogFile.WriteToFile("Wiederholung 5x nicht erfolgreich --> reboot");
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Wiederholung 5x nicht erfolgreich --> reboot");
|
||||
doReboot();
|
||||
// Schritt wurde 5x wiederholt --> reboot
|
||||
}
|
||||
@@ -321,7 +350,7 @@ string ClassFlowControll::getReadoutAll(int _type)
|
||||
out = out + (*numbers)[i]->name + "\t";
|
||||
switch (_type) {
|
||||
case READOUT_TYPE_VALUE:
|
||||
out = out + (*numbers)[i]->ReturnValueNoError;
|
||||
out = out + (*numbers)[i]->ReturnValue;
|
||||
break;
|
||||
case READOUT_TYPE_PREVALUE:
|
||||
if (flowpostprocessing->PreValueUse)
|
||||
@@ -344,7 +373,7 @@ string ClassFlowControll::getReadoutAll(int _type)
|
||||
if (i < (*numbers).size()-1)
|
||||
out = out + "\r\n";
|
||||
}
|
||||
// printf("OUT: %s", out.c_str());
|
||||
// ESP_LOGD(TAG, "OUT: %s", out.c_str());
|
||||
}
|
||||
|
||||
return out;
|
||||
@@ -381,7 +410,7 @@ string ClassFlowControll::GetPrevalue(std::string _number)
|
||||
return flowpostprocessing->GetPreValue(_number);
|
||||
}
|
||||
|
||||
return std::string();
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
std::string ClassFlowControll::UpdatePrevalue(std::string _newvalue, std::string _numbers, bool _extern)
|
||||
@@ -390,7 +419,7 @@ std::string ClassFlowControll::UpdatePrevalue(std::string _newvalue, std::string
|
||||
char* p;
|
||||
|
||||
_newvalue = trim(_newvalue);
|
||||
// printf("Input UpdatePreValue: %s\n", _newvalue.c_str());
|
||||
// ESP_LOGD(TAG, "Input UpdatePreValue: %s", _newvalue.c_str());
|
||||
|
||||
if (_newvalue.compare("0.0") == 0)
|
||||
{
|
||||
@@ -424,12 +453,13 @@ bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
return false;
|
||||
|
||||
|
||||
if ((toUpper(aktparamgraph).compare("[AUTOTIMER]") != 0) && (toUpper(aktparamgraph).compare("[DEBUG]") != 0) && (toUpper(aktparamgraph).compare("[SYSTEM]") != 0)) // Paragraph passt nicht zu MakeImage
|
||||
if ((toUpper(aktparamgraph).compare("[AUTOTIMER]") != 0) && (toUpper(aktparamgraph).compare("[DEBUG]") != 0) &&
|
||||
(toUpper(aktparamgraph).compare("[SYSTEM]") != 0 && (toUpper(aktparamgraph).compare("[DATALOGGING]") != 0))) // Paragraph passt nicht zu MakeImage
|
||||
return false;
|
||||
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
zerlegt = this->ZerlegeZeile(aktparamgraph, " =");
|
||||
zerlegt = ZerlegeZeile(aktparamgraph, " =");
|
||||
if ((toUpper(zerlegt[0]) == "AUTOSTART") && (zerlegt.size() > 1))
|
||||
{
|
||||
if (toUpper(zerlegt[1]) == "TRUE")
|
||||
@@ -437,25 +467,52 @@ bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
AutoStart = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((toUpper(zerlegt[0]) == "INTERVALL") && (zerlegt.size() > 1))
|
||||
{
|
||||
AutoIntervall = std::stof(zerlegt[1]);
|
||||
}
|
||||
if ((toUpper(zerlegt[0]) == "LOGFILE") && (zerlegt.size() > 1))
|
||||
|
||||
if ((toUpper(zerlegt[0]) == "DATALOGACTIVE") && (zerlegt.size() > 1))
|
||||
{
|
||||
if (toUpper(zerlegt[1]) == "TRUE")
|
||||
{
|
||||
LogFile.SwitchOnOff(true);
|
||||
LogFile.SetDataLogToSD(true);
|
||||
}
|
||||
if (toUpper(zerlegt[1]) == "FALSE")
|
||||
else {
|
||||
LogFile.SetDataLogToSD(false);
|
||||
}
|
||||
}
|
||||
|
||||
if ((toUpper(zerlegt[0]) == "DATALOGRETENTIONINDAYS") && (zerlegt.size() > 1))
|
||||
{
|
||||
LogFile.SetDataLogRetention(std::stoi(zerlegt[1]));
|
||||
}
|
||||
|
||||
if ((toUpper(zerlegt[0]) == "LOGFILE") && (zerlegt.size() > 1))
|
||||
{
|
||||
/* matches esp_log_level_t */
|
||||
if ((toUpper(zerlegt[1]) == "TRUE") || (toUpper(zerlegt[1]) == "2"))
|
||||
{
|
||||
LogFile.SwitchOnOff(false);
|
||||
LogFile.setLogLevel(ESP_LOG_WARN);
|
||||
}
|
||||
else if ((toUpper(zerlegt[1]) == "FALSE") || (toUpper(zerlegt[1]) == "0") || (toUpper(zerlegt[1]) == "1"))
|
||||
{
|
||||
LogFile.setLogLevel(ESP_LOG_ERROR);
|
||||
}
|
||||
else if (toUpper(zerlegt[1]) == "3")
|
||||
{
|
||||
LogFile.setLogLevel(ESP_LOG_INFO);
|
||||
}
|
||||
else if (toUpper(zerlegt[1]) == "4")
|
||||
{
|
||||
LogFile.setLogLevel(ESP_LOG_DEBUG);
|
||||
}
|
||||
}
|
||||
if ((toUpper(zerlegt[0]) == "LOGFILERETENTIONINDAYS") && (zerlegt.size() > 1))
|
||||
{
|
||||
LogFile.SetRetention(std::stoi(zerlegt[1]));
|
||||
}
|
||||
LogFile.SetLogFileRetention(std::stoi(zerlegt[1]));
|
||||
}
|
||||
|
||||
if ((toUpper(zerlegt[0]) == "TIMEZONE") && (zerlegt.size() > 1))
|
||||
{
|
||||
@@ -475,7 +532,7 @@ bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
// reboot notwendig damit die neue wlan.ini auch benutzt wird !!!
|
||||
fclose(pfile);
|
||||
printf("do reboot\n");
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Rebooting to activate new HOSTNAME...");
|
||||
esp_restart();
|
||||
hard_restart();
|
||||
doReboot();
|
||||
@@ -488,13 +545,14 @@ bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
SetupModeActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((toUpper(zerlegt[0]) == "LOGLEVEL") && (zerlegt.size() > 1))
|
||||
{
|
||||
LogFile.setLogLevel(stoi(zerlegt[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Start the MQTT service */
|
||||
for (int i = 0; i < FlowControll.size(); ++i)
|
||||
if (FlowControll[i]->name().compare("ClassFlowMQTT") == 0)
|
||||
return ((ClassFlowMQTT*) (FlowControll[i]))->Start(AutoIntervall);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -538,7 +596,7 @@ esp_err_t ClassFlowControll::SendRawJPG(httpd_req_t *req)
|
||||
|
||||
esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
|
||||
{
|
||||
printf("ClassFlowControll::GetJPGStream %s\n", _fn.c_str());
|
||||
ESP_LOGD(TAG, "ClassFlowControll::GetJPGStream %s", _fn.c_str());
|
||||
|
||||
CImageBasis *_send = NULL;
|
||||
esp_err_t result = ESP_FAIL;
|
||||
@@ -546,7 +604,7 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
|
||||
|
||||
if (flowalignment == NULL)
|
||||
{
|
||||
printf("Can't continue, flowalignment is NULL\n");
|
||||
ESP_LOGD(TAG, "Can't continue, flowalignment is NULL");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
@@ -569,6 +627,8 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
|
||||
{
|
||||
std::vector<HTMLInfo*> htmlinfo;
|
||||
htmlinfo = GetAllDigital();
|
||||
ESP_LOGD(TAG, "After getClassFlowControll::GetAllDigital");
|
||||
|
||||
for (int i = 0; i < htmlinfo.size(); ++i)
|
||||
{
|
||||
if (_fn == htmlinfo[i]->filename)
|
||||
@@ -624,4 +684,15 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string ClassFlowControll::getNumbersName()
|
||||
{
|
||||
return flowpostprocessing->getNumbersName();
|
||||
}
|
||||
|
||||
string ClassFlowControll::getJSON(std::string _id, std::string _mac)
|
||||
{
|
||||
return flowpostprocessing->GetJSON(_id, _mac);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
#include "ClassFlowCNNGeneral.h"
|
||||
#include "ClassFlowPostProcessing.h"
|
||||
#include "ClassFlowMQTT.h"
|
||||
#include "ClassFlowInfluxDB.h"
|
||||
#include "ClassFlowCNNGeneral.h"
|
||||
#include "ClassFlowWriteList.h"
|
||||
|
||||
|
||||
#define READOUT_TYPE_VALUE 0
|
||||
@@ -48,6 +50,8 @@ public:
|
||||
string UpdatePrevalue(std::string _newvalue, std::string _numbers, bool _extern);
|
||||
string GetPrevalue(std::string _number = "");
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
string getJSON(std::string _id = "", std::string _mac = "");
|
||||
string getNumbersName();
|
||||
|
||||
string TranslateAktstatus(std::string _input);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ struct roi {
|
||||
int posx, posy, deltax, deltay;
|
||||
float result_float;
|
||||
int result_klasse;
|
||||
bool isReject, CCW;
|
||||
string name;
|
||||
CImageBasis *image, *image_org;
|
||||
};
|
||||
@@ -16,28 +17,36 @@ struct general {
|
||||
std::vector<roi*> ROI;
|
||||
};
|
||||
|
||||
enum t_RateType {
|
||||
AbsoluteChange,
|
||||
RateChange
|
||||
};
|
||||
|
||||
|
||||
struct NumberPost {
|
||||
float MaxRateValue;
|
||||
bool useMaxRateValue;
|
||||
t_RateType RateType;
|
||||
bool ErrorMessage;
|
||||
bool PreValueOkay;
|
||||
bool AllowNegativeRates;
|
||||
bool checkDigitIncreaseConsistency;
|
||||
time_t lastvalue;
|
||||
string timeStamp;
|
||||
float FlowRateAct; // m3 / min
|
||||
float PreValue; // letzter Wert, der gut ausgelesen wurde
|
||||
float Value; // letzer ausgelesener Wert, inkl. Korrekturen
|
||||
double FlowRateAct; // m3 / min
|
||||
double PreValue; // letzter Wert, der gut ausgelesen wurde
|
||||
double Value; // letzer ausgelesener Wert, inkl. Korrekturen
|
||||
string ReturnRateValue; // RückgabewertRate
|
||||
string ReturnChangeAbsolute; // RückgabewertRate
|
||||
string ReturnRawValue; // Rohwert (mit N & führenden 0)
|
||||
string ReturnValue; // korrigierter Rückgabewert, ggf. mit Fehlermeldung
|
||||
string ReturnPreValue; // korrigierter Rückgabewert ohne Fehlermeldung
|
||||
string ReturnValueNoError;
|
||||
string ReturnPreValue; // korrigierter Rückgabewert ohne Fehlermeldung
|
||||
string ErrorMessageText; // Fehlermeldung bei Consistency Check
|
||||
int AnzahlAnalog;
|
||||
int AnzahlDigital;
|
||||
int DecimalShift;
|
||||
int DecimalShiftInitial;
|
||||
float AnalogDigitalTransitionStart; // Wann ist das digit > x.1, also wann fängt es an zu kippen
|
||||
int Nachkomma;
|
||||
|
||||
bool isExtendedResolution;
|
||||
|
||||
@@ -2,17 +2,28 @@
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "time_sntp.h"
|
||||
#include "ClassLogFile.h"
|
||||
#include "CImageBasis.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char* TAG = "FLOW IMG";
|
||||
|
||||
ClassFlowImage::ClassFlowImage(const char* logTag)
|
||||
{
|
||||
this->logTag = logTag;
|
||||
isLogImage = false;
|
||||
disabled = false;
|
||||
|
||||
this->logfileRetentionInDays = 5;
|
||||
}
|
||||
|
||||
ClassFlowImage::ClassFlowImage(std::vector<ClassFlow*> * lfc, const char* logTag) : ClassFlow(lfc)
|
||||
@@ -20,6 +31,7 @@ ClassFlowImage::ClassFlowImage(std::vector<ClassFlow*> * lfc, const char* logTag
|
||||
this->logTag = logTag;
|
||||
isLogImage = false;
|
||||
disabled = false;
|
||||
this->logfileRetentionInDays = 5;
|
||||
}
|
||||
|
||||
ClassFlowImage::ClassFlowImage(std::vector<ClassFlow*> * lfc, ClassFlow *_prev, const char* logTag) : ClassFlow(lfc, _prev)
|
||||
@@ -27,6 +39,7 @@ ClassFlowImage::ClassFlowImage(std::vector<ClassFlow*> * lfc, ClassFlow *_prev,
|
||||
this->logTag = logTag;
|
||||
isLogImage = false;
|
||||
disabled = false;
|
||||
this->logfileRetentionInDays = 5;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,8 +50,7 @@ string ClassFlowImage::CreateLogFolder(string time) {
|
||||
string logPath = LogImageLocation + "/" + time.LOGFILE_TIME_FORMAT_DATE_EXTR + "/" + time.LOGFILE_TIME_FORMAT_HOUR_EXTR;
|
||||
isLogImage = mkdir_r(logPath.c_str(), S_IRWXU) == 0;
|
||||
if (!isLogImage) {
|
||||
ESP_LOGW(logTag, "Can't create log foolder for analog images. Path %s", logPath.c_str());
|
||||
LogFile.WriteToFile("Can't create log foolder for analog images. Path " + logPath);
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't create log folder for analog images. Path " + logPath);
|
||||
}
|
||||
|
||||
return logPath;
|
||||
@@ -55,7 +67,12 @@ void ClassFlowImage::LogImage(string logPath, string name, float *resultFloat, i
|
||||
if (*resultFloat < 0)
|
||||
sprintf(buf, "N.N_");
|
||||
else
|
||||
{
|
||||
sprintf(buf, "%.1f_", *resultFloat);
|
||||
if (strcmp(buf, "10.0_") == 0)
|
||||
sprintf(buf, "0.0_");
|
||||
}
|
||||
|
||||
} else if (resultInt != NULL) {
|
||||
sprintf(buf, "%d_", *resultInt);
|
||||
} else {
|
||||
@@ -66,7 +83,7 @@ void ClassFlowImage::LogImage(string logPath, string name, float *resultFloat, i
|
||||
nm = FormatFileName(nm);
|
||||
string output = "/sdcard/img_tmp/" + name + ".jpg";
|
||||
output = FormatFileName(output);
|
||||
printf("save to file: %s\n", nm.c_str());
|
||||
ESP_LOGD(logTag, "save to file: %s", nm.c_str());
|
||||
_img->SaveToFile(nm);
|
||||
// CopyFile(output, nm);
|
||||
}
|
||||
@@ -76,7 +93,7 @@ void ClassFlowImage::RemoveOldLogs()
|
||||
if (!isLogImage)
|
||||
return;
|
||||
|
||||
ESP_LOGI(logTag, "remove old log images");
|
||||
ESP_LOGI(TAG, "remove old images");
|
||||
if (logfileRetentionInDays == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -86,16 +103,17 @@ void ClassFlowImage::RemoveOldLogs()
|
||||
char cmpfilename[30];
|
||||
|
||||
time(&rawtime);
|
||||
rawtime = addDays(rawtime, -logfileRetentionInDays);
|
||||
rawtime = addDays(rawtime, -logfileRetentionInDays + 1);
|
||||
timeinfo = localtime(&rawtime);
|
||||
//ESP_LOGD(TAG, "ImagefileRetentionInDays: %d", logfileRetentionInDays);
|
||||
|
||||
strftime(cmpfilename, 30, LOGFILE_TIME_FORMAT, timeinfo);
|
||||
//ESP_LOGE(TAG, "log file name to compare: %s", cmpfilename);
|
||||
//ESP_LOGD(TAG, "file name to compare: %s", cmpfilename);
|
||||
string folderName = string(cmpfilename).LOGFILE_TIME_FORMAT_DATE_EXTR;
|
||||
|
||||
DIR *dir = opendir(LogImageLocation.c_str());
|
||||
if (!dir) {
|
||||
ESP_LOGI(logTag, "Failed to stat dir : %s", LogImageLocation.c_str());
|
||||
ESP_LOGE(TAG, "Failed to stat dir : %s", LogImageLocation.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -105,15 +123,16 @@ void ClassFlowImage::RemoveOldLogs()
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
string folderPath = LogImageLocation + "/" + entry->d_name;
|
||||
if (entry->d_type == DT_DIR) {
|
||||
//ESP_LOGI(logTag, "Compare %s %s", entry->d_name, folderName.c_str());
|
||||
//ESP_LOGD(TAG, "Compare %s to %s", entry->d_name, folderName.c_str());
|
||||
if ((strlen(entry->d_name) == folderName.length()) && (strcmp(entry->d_name, folderName.c_str()) < 0)) {
|
||||
deleted += removeFolder(folderPath.c_str(), logTag);
|
||||
removeFolder(folderPath.c_str(), logTag);
|
||||
deleted++;
|
||||
} else {
|
||||
notDeleted ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
ESP_LOGI(logTag, "%d older log files deleted. %d current log files not deleted.", deleted, notDeleted);
|
||||
ESP_LOGI(TAG, "Image folder deleted: %d | Image folder not deleted: %d", deleted, notDeleted);
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
|
||||
164
code/components/jomjol_flowcontroll/ClassFlowInfluxDB.cpp
Normal file
164
code/components/jomjol_flowcontroll/ClassFlowInfluxDB.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
#include <sstream>
|
||||
#include "ClassFlowInfluxDB.h"
|
||||
#include "Helper.h"
|
||||
#include "connect_wlan.h"
|
||||
|
||||
#include "time_sntp.h"
|
||||
#include "interface_influxdb.h"
|
||||
#include "ClassFlowPostProcessing.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
static const char* TAG = "class_flow_influxDb";
|
||||
|
||||
void ClassFlowInfluxDB::SetInitialParameter(void)
|
||||
{
|
||||
uri = "";
|
||||
database = "";
|
||||
measurement = "";
|
||||
|
||||
OldValue = "";
|
||||
flowpostprocessing = NULL;
|
||||
user = "";
|
||||
password = "";
|
||||
previousElement = NULL;
|
||||
ListFlowControll = NULL;
|
||||
disabled = false;
|
||||
InfluxDBenable = false;
|
||||
}
|
||||
|
||||
ClassFlowInfluxDB::ClassFlowInfluxDB()
|
||||
{
|
||||
SetInitialParameter();
|
||||
}
|
||||
|
||||
ClassFlowInfluxDB::ClassFlowInfluxDB(std::vector<ClassFlow*>* lfc)
|
||||
{
|
||||
SetInitialParameter();
|
||||
|
||||
ListFlowControll = lfc;
|
||||
for (int i = 0; i < ListFlowControll->size(); ++i)
|
||||
{
|
||||
if (((*ListFlowControll)[i])->name().compare("ClassFlowPostProcessing") == 0)
|
||||
{
|
||||
flowpostprocessing = (ClassFlowPostProcessing*) (*ListFlowControll)[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClassFlowInfluxDB::ClassFlowInfluxDB(std::vector<ClassFlow*>* lfc, ClassFlow *_prev)
|
||||
{
|
||||
SetInitialParameter();
|
||||
|
||||
previousElement = _prev;
|
||||
ListFlowControll = lfc;
|
||||
|
||||
for (int i = 0; i < ListFlowControll->size(); ++i)
|
||||
{
|
||||
if (((*ListFlowControll)[i])->name().compare("ClassFlowPostProcessing") == 0)
|
||||
{
|
||||
flowpostprocessing = (ClassFlowPostProcessing*) (*ListFlowControll)[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowInfluxDB::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
std::vector<string> zerlegt;
|
||||
|
||||
aktparamgraph = trim(aktparamgraph);
|
||||
|
||||
if (aktparamgraph.size() == 0)
|
||||
if (!this->GetNextParagraph(pfile, aktparamgraph))
|
||||
return false;
|
||||
|
||||
if (toUpper(aktparamgraph).compare("[INFLUXDB]") != 0)
|
||||
return false;
|
||||
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
ESP_LOGD(TAG, "while loop reading line: %s", aktparamgraph.c_str());
|
||||
zerlegt = ZerlegeZeile(aktparamgraph);
|
||||
if ((toUpper(zerlegt[0]) == "USER") && (zerlegt.size() > 1))
|
||||
{
|
||||
this->user = zerlegt[1];
|
||||
}
|
||||
if ((toUpper(zerlegt[0]) == "PASSWORD") && (zerlegt.size() > 1))
|
||||
{
|
||||
this->password = zerlegt[1];
|
||||
}
|
||||
if ((toUpper(zerlegt[0]) == "URI") && (zerlegt.size() > 1))
|
||||
{
|
||||
this->uri = zerlegt[1];
|
||||
}
|
||||
if (((toUpper(zerlegt[0]) == "MEASUREMENT")) && (zerlegt.size() > 1))
|
||||
{
|
||||
this->measurement = zerlegt[1];
|
||||
}
|
||||
if (((toUpper(zerlegt[0]) == "DATABASE")) && (zerlegt.size() > 1))
|
||||
{
|
||||
this->database = zerlegt[1];
|
||||
}
|
||||
}
|
||||
|
||||
if ((uri.length() > 0) && (database.length() > 0) && (measurement.length() > 0))
|
||||
{
|
||||
ESP_LOGD(TAG, "Init InfluxDB with uri: %s, measurement: %s, user: %s, password: %s", uri.c_str(), measurement.c_str(), user.c_str(), password.c_str());
|
||||
InfluxDBInit(uri, database, measurement, user, password);
|
||||
InfluxDBenable = true;
|
||||
} else {
|
||||
ESP_LOGD(TAG, "InfluxDB init skipped as we are missing some parameters");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
string ClassFlowInfluxDB::GetInfluxDBMeasurement()
|
||||
{
|
||||
return measurement;
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowInfluxDB::doFlow(string zwtime)
|
||||
{
|
||||
if (!InfluxDBenable)
|
||||
return true;
|
||||
|
||||
std::string result;
|
||||
std::string resulterror = "";
|
||||
std::string resultraw = "";
|
||||
std::string resultrate = "";
|
||||
std::string resulttimestamp = "";
|
||||
string zw = "";
|
||||
string namenumber = "";
|
||||
|
||||
if (flowpostprocessing)
|
||||
{
|
||||
std::vector<NumberPost*>* NUMBERS = flowpostprocessing->GetNumbers();
|
||||
|
||||
for (int i = 0; i < (*NUMBERS).size(); ++i)
|
||||
{
|
||||
result = (*NUMBERS)[i]->ReturnValue;
|
||||
resultraw = (*NUMBERS)[i]->ReturnRawValue;
|
||||
resulterror = (*NUMBERS)[i]->ErrorMessageText;
|
||||
resultrate = (*NUMBERS)[i]->ReturnRateValue;
|
||||
resulttimestamp = (*NUMBERS)[i]->timeStamp;
|
||||
|
||||
namenumber = (*NUMBERS)[i]->name;
|
||||
if (namenumber == "default")
|
||||
namenumber = "value";
|
||||
else
|
||||
namenumber = namenumber + "/value";
|
||||
|
||||
if (result.length() > 0 && resulttimestamp.length() > 0)
|
||||
InfluxDBPublish(namenumber, result, resulttimestamp);
|
||||
}
|
||||
}
|
||||
|
||||
OldValue = result;
|
||||
|
||||
return true;
|
||||
}
|
||||
31
code/components/jomjol_flowcontroll/ClassFlowInfluxDB.h
Normal file
31
code/components/jomjol_flowcontroll/ClassFlowInfluxDB.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include "ClassFlow.h"
|
||||
|
||||
#include "ClassFlowPostProcessing.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class ClassFlowInfluxDB :
|
||||
public ClassFlow
|
||||
{
|
||||
protected:
|
||||
std::string uri, database, measurement;
|
||||
std::string OldValue;
|
||||
ClassFlowPostProcessing* flowpostprocessing;
|
||||
std::string user, password;
|
||||
bool InfluxDBenable;
|
||||
|
||||
void SetInitialParameter(void);
|
||||
|
||||
public:
|
||||
ClassFlowInfluxDB();
|
||||
ClassFlowInfluxDB(std::vector<ClassFlow*>* lfc);
|
||||
ClassFlowInfluxDB(std::vector<ClassFlow*>* lfc, ClassFlow *_prev);
|
||||
|
||||
string GetInfluxDBMeasurement();
|
||||
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
bool doFlow(string time);
|
||||
string name(){return "ClassFlowInfluxDB";};
|
||||
};
|
||||
|
||||
@@ -1,13 +1,32 @@
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include "ClassFlowMQTT.h"
|
||||
#include "Helper.h"
|
||||
#include "connect_wlan.h"
|
||||
#include "ClassLogFile.h"
|
||||
|
||||
#include "time_sntp.h"
|
||||
#include "interface_mqtt.h"
|
||||
#include "ClassFlowPostProcessing.h"
|
||||
#include "ClassFlowControll.h"
|
||||
|
||||
#include "server_mqtt.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#define __HIDE_PASSWORD
|
||||
|
||||
static const char *TAG = "FLOW MQTT";
|
||||
#define LWT_TOPIC "connection"
|
||||
#define LWT_CONNECTED "connected"
|
||||
#define LWT_DISCONNECTED "connection lost"
|
||||
|
||||
extern const char* libfive_git_version(void);
|
||||
extern const char* libfive_git_revision(void);
|
||||
extern const char* libfive_git_branch(void);
|
||||
|
||||
|
||||
void ClassFlowMQTT::SetInitialParameter(void)
|
||||
{
|
||||
uri = "";
|
||||
@@ -15,23 +34,22 @@ void ClassFlowMQTT::SetInitialParameter(void)
|
||||
topicError = "";
|
||||
topicRate = "";
|
||||
topicTimeStamp = "";
|
||||
maintopic = "";
|
||||
mainerrortopic = "";
|
||||
maintopic = hostname;
|
||||
|
||||
topicUptime = "";
|
||||
topicFreeMem = "";
|
||||
clientname = "watermeter";
|
||||
|
||||
clientname = "AIOTED-" + getMac();
|
||||
|
||||
OldValue = "";
|
||||
flowpostprocessing = NULL;
|
||||
user = "";
|
||||
password = "";
|
||||
password = "";
|
||||
SetRetainFlag = 0;
|
||||
previousElement = NULL;
|
||||
ListFlowControll = NULL;
|
||||
disabled = false;
|
||||
MQTTenable = false;
|
||||
|
||||
|
||||
|
||||
keepAlive = 25*60;
|
||||
}
|
||||
|
||||
ClassFlowMQTT::ClassFlowMQTT()
|
||||
@@ -85,7 +103,7 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
zerlegt = this->ZerlegeZeile(aktparamgraph);
|
||||
zerlegt = ZerlegeZeile(aktparamgraph);
|
||||
if ((toUpper(zerlegt[0]) == "USER") && (zerlegt.size() > 1))
|
||||
{
|
||||
this->user = zerlegt[1];
|
||||
@@ -98,6 +116,49 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
this->uri = zerlegt[1];
|
||||
}
|
||||
if ((toUpper(zerlegt[0]) == "SETRETAINFLAG") && (zerlegt.size() > 1))
|
||||
{
|
||||
if (toUpper(zerlegt[1]) == "TRUE") {
|
||||
SetRetainFlag = 1;
|
||||
setMqtt_Server_Retain(SetRetainFlag);
|
||||
}
|
||||
}
|
||||
if ((toUpper(zerlegt[0]) == "HOMEASSISTANTDISCOVERY") && (zerlegt.size() > 1))
|
||||
{
|
||||
if (toUpper(zerlegt[1]) == "TRUE")
|
||||
SetHomeassistantDiscoveryEnabled(true);
|
||||
}
|
||||
if ((toUpper(zerlegt[0]) == "METERTYPE") && (zerlegt.size() > 1)) {
|
||||
/* Use meter type for the device class
|
||||
Make sure it is a listed one on https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes */
|
||||
if (toUpper(zerlegt[1]) == "WATER_M3") {
|
||||
mqttServer_setMeterType("water", "m³", "h", "m³/h");
|
||||
}
|
||||
else if (toUpper(zerlegt[1]) == "WATER_L") {
|
||||
mqttServer_setMeterType("water", "L", "h", "L/h");
|
||||
}
|
||||
else if (toUpper(zerlegt[1]) == "WATER_FT3") {
|
||||
mqttServer_setMeterType("water", "ft³", "m", "ft³/m"); // Minutes
|
||||
}
|
||||
else if (toUpper(zerlegt[1]) == "WATER_GAL") {
|
||||
mqttServer_setMeterType("water", "gal", "h", "gal/h");
|
||||
}
|
||||
else if (toUpper(zerlegt[1]) == "GAS_M3") {
|
||||
mqttServer_setMeterType("gas", "m³", "h", "m³/h");
|
||||
}
|
||||
else if (toUpper(zerlegt[1]) == "GAS_FT3") {
|
||||
mqttServer_setMeterType("gas", "ft³", "m", "ft³/m"); // Minutes
|
||||
}
|
||||
else if (toUpper(zerlegt[1]) == "ENERGY_WH") {
|
||||
mqttServer_setMeterType("energy", "Wh", "h", "W");
|
||||
}
|
||||
else if (toUpper(zerlegt[1]) == "ENERGY_KWH") {
|
||||
mqttServer_setMeterType("energy", "kWh", "h", "kW");
|
||||
}
|
||||
else if (toUpper(zerlegt[1]) == "ENERGY_MWH") {
|
||||
mqttServer_setMeterType("energy", "MWh", "h", "MW");
|
||||
}
|
||||
}
|
||||
|
||||
if ((toUpper(zerlegt[0]) == "CLIENTID") && (zerlegt.size() > 1))
|
||||
{
|
||||
@@ -107,17 +168,15 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
if (((toUpper(zerlegt[0]) == "TOPIC") || (toUpper(zerlegt[0]) == "MAINTOPIC")) && (zerlegt.size() > 1))
|
||||
{
|
||||
maintopic = zerlegt[1];
|
||||
mqttServer_setMainTopic(maintopic);
|
||||
}
|
||||
}
|
||||
|
||||
if (!MQTTisConnected() && (uri.length() > 0) && (maintopic.length() > 0))
|
||||
{
|
||||
mainerrortopic = maintopic + "/connection";
|
||||
MQTTInit(uri, clientname, user, password, mainerrortopic, 60);
|
||||
MQTTPublish(mainerrortopic, "connected");
|
||||
MQTTenable = true;
|
||||
}
|
||||
|
||||
/* Note:
|
||||
* Originally, we started the MQTT client here.
|
||||
* How ever we need the interval parameter from the ClassFlowControll, but that only gets started later.
|
||||
* To work around this, we delay the start and trigger it from ClassFlowControll::ReadParameter() */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -128,39 +187,58 @@ string ClassFlowMQTT::GetMQTTMainTopic()
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowMQTT::Start(float AutoIntervall) {
|
||||
|
||||
roundInterval = AutoIntervall; // Minutes
|
||||
keepAlive = roundInterval * 60 * 2.5; // Seconds, make sure it is greater thatn 2 rounds!
|
||||
|
||||
std::stringstream stream;
|
||||
stream << std::fixed << std::setprecision(1) << "Digitizer interval is " << roundInterval <<
|
||||
" minutes => setting MQTT LWT timeout to " << ((float)keepAlive/60) << " minutes.";
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, stream.str());
|
||||
|
||||
mqttServer_setParameter(flowpostprocessing->GetNumbers(), keepAlive, roundInterval);
|
||||
|
||||
MQTT_Configure(uri, clientname, user, password, maintopic, LWT_TOPIC, LWT_CONNECTED, LWT_DISCONNECTED,
|
||||
keepAlive, SetRetainFlag, (void *)&GotConnected);
|
||||
|
||||
if (!MQTT_Init()) {
|
||||
if (!MQTT_Init()) { // Retry
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowMQTT::doFlow(string zwtime)
|
||||
{
|
||||
if (!MQTTenable)
|
||||
return true;
|
||||
|
||||
std::string result;
|
||||
std::string resulterror = "";
|
||||
std::string resultrate = "";
|
||||
std::string resultraw = "";
|
||||
std::string resultrate = ""; // Always Unit / Minute
|
||||
std::string resultRatePerTimeUnit = ""; // According to selection
|
||||
std::string resulttimestamp = "";
|
||||
std::string resultchangabs = "";
|
||||
string zw = "";
|
||||
string namenumber = "";
|
||||
|
||||
MQTTPublish(mainerrortopic, "connected");
|
||||
|
||||
zw = maintopic + "/" + "uptime";
|
||||
char uptimeStr[11];
|
||||
sprintf(uptimeStr, "%ld", (long)getUpTime());
|
||||
MQTTPublish(zw, uptimeStr);
|
||||
|
||||
zw = maintopic + "/" + "freeMem";
|
||||
char freeheapmem[11];
|
||||
sprintf(freeheapmem, "%zu", esp_get_free_heap_size());
|
||||
MQTTPublish(zw, freeheapmem);
|
||||
publishSystemData();
|
||||
|
||||
if (flowpostprocessing)
|
||||
{
|
||||
std::vector<NumberPost*>* NUMBERS = flowpostprocessing->GetNumbers();
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Publishing MQTT topics...");
|
||||
|
||||
for (int i = 0; i < (*NUMBERS).size(); ++i)
|
||||
{
|
||||
result = (*NUMBERS)[i]->ReturnValueNoError;
|
||||
result = (*NUMBERS)[i]->ReturnValue;
|
||||
resultraw = (*NUMBERS)[i]->ReturnRawValue;
|
||||
resulterror = (*NUMBERS)[i]->ErrorMessageText;
|
||||
resultrate = std::to_string((*NUMBERS)[i]->FlowRateAct);
|
||||
resultrate = (*NUMBERS)[i]->ReturnRateValue; // Unit per minutes
|
||||
resultchangabs = (*NUMBERS)[i]->ReturnChangeAbsolute; // Units per round
|
||||
resulttimestamp = (*NUMBERS)[i]->timeStamp;
|
||||
|
||||
namenumber = (*NUMBERS)[i]->name;
|
||||
@@ -169,26 +247,55 @@ bool ClassFlowMQTT::doFlow(string zwtime)
|
||||
else
|
||||
namenumber = maintopic + "/" + namenumber + "/";
|
||||
|
||||
zw = namenumber + "value";
|
||||
MQTTPublish(zw, result);
|
||||
|
||||
zw = namenumber + "error";
|
||||
MQTTPublish(zw, resulterror, 1);
|
||||
if (result.length() > 0)
|
||||
MQTTPublish(namenumber + "value", result, SetRetainFlag);
|
||||
|
||||
zw = namenumber + "rate";
|
||||
MQTTPublish(zw, resultrate);
|
||||
if (resulterror.length() > 0)
|
||||
MQTTPublish(namenumber + "error", resulterror, SetRetainFlag);
|
||||
|
||||
zw = namenumber + "timestamp";
|
||||
MQTTPublish(zw, resulttimestamp);
|
||||
if (resultrate.length() > 0) {
|
||||
MQTTPublish(namenumber + "rate", resultrate, SetRetainFlag);
|
||||
|
||||
std::string resultRatePerTimeUnit;
|
||||
if (getTimeUnit() == "h") { // Need conversion to be per hour
|
||||
resultRatePerTimeUnit = resultRatePerTimeUnit = to_string((*NUMBERS)[i]->FlowRateAct * 60); // per minutes => per hour
|
||||
}
|
||||
else { // Keep per minute
|
||||
resultRatePerTimeUnit = resultrate;
|
||||
}
|
||||
MQTTPublish(namenumber + "rate_per_time_unit", resultRatePerTimeUnit, SetRetainFlag);
|
||||
}
|
||||
|
||||
if (resultchangabs.length() > 0) {
|
||||
MQTTPublish(namenumber + "changeabsolut", resultchangabs, SetRetainFlag); // Legacy API
|
||||
MQTTPublish(namenumber + "rate_per_digitalization_round", resultchangabs, SetRetainFlag);
|
||||
}
|
||||
|
||||
if (resultraw.length() > 0)
|
||||
MQTTPublish(namenumber + "raw", resultraw, SetRetainFlag);
|
||||
|
||||
if (resulttimestamp.length() > 0)
|
||||
MQTTPublish(namenumber + "timestamp", resulttimestamp, SetRetainFlag);
|
||||
|
||||
std::string json = "";
|
||||
|
||||
if (result.length() > 0)
|
||||
json += "{\"value\":"+result;
|
||||
else
|
||||
json += "{\"value\":\"\"";
|
||||
|
||||
json += ",\"raw\":\""+resultraw;
|
||||
json += "\",\"error\":\""+resulterror;
|
||||
|
||||
if (resultrate.length() > 0)
|
||||
json += "\",\"rate\":"+resultrate;
|
||||
else
|
||||
json += "\",\"rate\":\"\"";
|
||||
|
||||
std::string json="{\"value\":"+result;
|
||||
json += ",\"error\":\""+resulterror;
|
||||
json += "\",\"rate\":"+resultrate;
|
||||
json += ",\"timestamp\":\""+resulttimestamp+"\"}";
|
||||
|
||||
zw = namenumber + "json";
|
||||
MQTTPublish(zw, json);
|
||||
MQTTPublish(namenumber + "json", json, SetRetainFlag);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -204,7 +311,7 @@ bool ClassFlowMQTT::doFlow(string zwtime)
|
||||
result = result + "\t" + zw;
|
||||
}
|
||||
}
|
||||
MQTTPublish(topic, result);
|
||||
MQTTPublish(topic, result, SetRetainFlag);
|
||||
}
|
||||
|
||||
OldValue = result;
|
||||
|
||||
@@ -13,9 +13,11 @@ protected:
|
||||
std::string OldValue;
|
||||
ClassFlowPostProcessing* flowpostprocessing;
|
||||
std::string user, password;
|
||||
bool MQTTenable;
|
||||
int SetRetainFlag;
|
||||
int keepAlive; // Seconds
|
||||
float roundInterval; // Minutes
|
||||
|
||||
std::string maintopic, mainerrortopic;
|
||||
std::string maintopic;
|
||||
void SetInitialParameter(void);
|
||||
|
||||
public:
|
||||
@@ -24,6 +26,7 @@ public:
|
||||
ClassFlowMQTT(std::vector<ClassFlow*>* lfc, ClassFlow *_prev);
|
||||
|
||||
string GetMQTTMainTopic();
|
||||
bool Start(float AutoIntervall);
|
||||
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
bool doFlow(string time);
|
||||
|
||||
@@ -5,10 +5,15 @@
|
||||
#include "CImageBasis.h"
|
||||
#include "ClassControllCamera.h"
|
||||
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
// #define DEBUG_DETAIL_ON
|
||||
|
||||
// #define WIFITURNOFF
|
||||
|
||||
static const char* TAG = "flow_make_image";
|
||||
|
||||
esp_err_t ClassFlowMakeImage::camera_capture(){
|
||||
@@ -26,7 +31,7 @@ void ClassFlowMakeImage::takePictureWithFlash(int flashdauer)
|
||||
rawImage->width = image_width;
|
||||
rawImage->height = image_height;
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
printf("Flashdauer: %d\n", flashdauer);
|
||||
ESP_LOGD(TAG, "Flashdauer: %d", flashdauer);
|
||||
Camera.CaptureToBasisImage(rawImage, flashdauer);
|
||||
time(&TimeImageTaken);
|
||||
localtime(&TimeImageTaken);
|
||||
@@ -52,6 +57,8 @@ void ClassFlowMakeImage::SetInitialParameter(void)
|
||||
|
||||
ClassFlowMakeImage::ClassFlowMakeImage(std::vector<ClassFlow*>* lfc) : ClassFlowImage(lfc, TAG)
|
||||
{
|
||||
LogImageLocation = "/log/source";
|
||||
logfileRetentionInDays = 5;
|
||||
SetInitialParameter();
|
||||
}
|
||||
|
||||
@@ -73,7 +80,7 @@ bool ClassFlowMakeImage::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
zerlegt = this->ZerlegeZeile(aktparamgraph);
|
||||
zerlegt = ZerlegeZeile(aktparamgraph);
|
||||
if ((zerlegt[0] == "LogImageLocation") && (zerlegt.size() > 1))
|
||||
{
|
||||
LogImageLocation = "/sdcard" + zerlegt[1];
|
||||
@@ -99,6 +106,10 @@ bool ClassFlowMakeImage::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
waitbeforepicture = stoi(zerlegt[1]);
|
||||
}
|
||||
|
||||
if ((toUpper(zerlegt[0]) == "LOGFILERETENTIONINDAYS") && (zerlegt.size() > 1))
|
||||
{
|
||||
this->logfileRetentionInDays = std::stoi(zerlegt[1]);
|
||||
}
|
||||
|
||||
if ((toUpper(zerlegt[0]) == "BRIGHTNESS") && (zerlegt.size() > 1))
|
||||
{
|
||||
@@ -118,7 +129,15 @@ bool ClassFlowMakeImage::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
if ((toUpper(zerlegt[0]) == "FIXEDEXPOSURE") && (zerlegt.size() > 1))
|
||||
{
|
||||
if (toUpper(zerlegt[1]) == "TRUE")
|
||||
FixedExposure = true;
|
||||
FixedExposure = true;
|
||||
}
|
||||
|
||||
if ((toUpper(zerlegt[0]) == "LEDINTENSITY") && (zerlegt.size() > 1))
|
||||
{
|
||||
float ledintensity = stof(zerlegt[1]);
|
||||
ledintensity = min((float) 100, ledintensity);
|
||||
ledintensity = max((float) 0, ledintensity);
|
||||
Camera.SetLEDIntensity(ledintensity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +152,7 @@ bool ClassFlowMakeImage::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
waitbeforepicture_store = waitbeforepicture;
|
||||
if (FixedExposure && (waitbeforepicture > 0))
|
||||
{
|
||||
// printf("Fixed Exposure enabled!\n");
|
||||
// ESP_LOGD(TAG, "Fixed Exposure enabled!");
|
||||
int flashdauer = (int) (waitbeforepicture * 1000);
|
||||
Camera.EnableAutoExposure(flashdauer);
|
||||
waitbeforepicture = 0.2;
|
||||
@@ -162,8 +181,18 @@ bool ClassFlowMakeImage::doFlow(string zwtime)
|
||||
LogFile.WriteHeapInfo("ClassFlowMakeImage::doFlow - Before takePictureWithFlash");
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef WIFITURNOFF
|
||||
esp_wifi_stop(); // to save power usage and
|
||||
#endif
|
||||
|
||||
takePictureWithFlash(flashdauer);
|
||||
|
||||
#ifdef WIFITURNOFF
|
||||
esp_wifi_start();
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("ClassFlowMakeImage::doFlow - After takePictureWithFlash");
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user