├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── Makefile
├── README.md
├── components
├── esp32-camera
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── Kconfig
│ ├── LICENSE
│ ├── README.md
│ ├── component.mk
│ ├── conversions
│ │ ├── esp_jpg_decode.c
│ │ ├── include
│ │ │ ├── esp_jpg_decode.h
│ │ │ └── img_converters.h
│ │ ├── jpge.cpp
│ │ ├── private_include
│ │ │ ├── jpge.h
│ │ │ └── yuv.h
│ │ ├── to_bmp.c
│ │ ├── to_jpg.cpp
│ │ └── yuv.c
│ ├── driver
│ │ ├── camera.c
│ │ ├── include
│ │ │ ├── esp_camera.h
│ │ │ └── sensor.h
│ │ ├── private_include
│ │ │ ├── camera_common.h
│ │ │ ├── sccb.h
│ │ │ ├── twi.h
│ │ │ └── xclk.h
│ │ ├── sccb.c
│ │ ├── sensor.c
│ │ ├── twi.c
│ │ └── xclk.c
│ └── sensors
│ │ ├── ov2640.c
│ │ ├── ov3660.c
│ │ ├── ov7725.c
│ │ └── private_include
│ │ ├── ov2640.h
│ │ ├── ov2640_regs.h
│ │ ├── ov2640_settings.h
│ │ ├── ov3660.h
│ │ ├── ov3660_regs.h
│ │ ├── ov3660_settings.h
│ │ ├── ov7725.h
│ │ └── ov7725_regs.h
├── nabtotunnel
│ ├── CMakeLists.txt
│ ├── component.mk
│ ├── esp32tcp
│ │ ├── unabto_tcp.c
│ │ └── unabto_tcp_esp32.h
│ ├── unabto_tunnel.c
│ ├── unabto_tunnel.h
│ ├── unabto_tunnel_common.c
│ ├── unabto_tunnel_common.h
│ ├── unabto_tunnel_select.c
│ ├── unabto_tunnel_select.h
│ ├── unabto_tunnel_tcp.c
│ └── unabto_tunnel_tcp.h
├── unabto-esp-fingerprint
│ ├── CMakeLists.txt
│ └── component.mk
└── unabto-esp-idf
│ ├── CMakeLists.txt
│ ├── README.md
│ ├── component.mk
│ ├── crypto
│ ├── unabto_aes.c
│ ├── unabto_aes.h
│ ├── unabto_aes_cbc.c
│ ├── unabto_hmac_sha256.c
│ ├── unabto_sha256.c
│ └── unabto_sha256.h
│ ├── dns_adapter.c
│ ├── network_adapter.c
│ ├── random_adapter.c
│ ├── time_adapter.c
│ ├── unabto_aes_cbc_test.c
│ ├── unabto_aes_cbc_test.h
│ ├── unabto_basename.c
│ ├── unabto_basename.h
│ ├── unabto_config.h
│ ├── unabto_log_header_unix.c
│ ├── unabto_platform.h
│ └── unabto_platform_types.h
├── docs
├── ESP-EYE-browser.png
├── esp32cam-discover.png
├── esp32cam-overview.png
├── esp32cam-overviewpaired.png
└── esp32cam-viewcamera.png
├── main
├── CMakeLists.txt
├── Kconfig.projbuild
├── component.mk
├── demo_application.h
├── fp_acl_esp32_nvs.c
├── fp_acl_esp32_nvs.h
├── main.c
└── unabto_application.c
├── partitions.csv
└── sdkconfig.defaults
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | sdkconfig.*
3 | sdkconfig
4 | *~
5 | log
6 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "components/unabto"]
2 | path = unabto
3 | url = https://github.com/nabto/unabto.git
4 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # The following lines of boilerplate have to be in your project's CMakeLists
2 | # in this exact order for cmake to work correctly
3 | cmake_minimum_required(VERSION 3.5)
4 |
5 | set(UNABTO_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/unabto)
6 | include(./unabto/build/cmake/unabto_files.cmake)
7 |
8 | set(ENV{EXTRA_CFLAGS} -Wno-maybe-uninitialized)
9 |
10 | include($ENV{IDF_PATH}/tools/cmake/project.cmake)
11 | project(esp32_nabto)
12 |
13 | set(COMPONENTS esp32-camera nabtotunnel unabto-esp-fingerprint unabto-esp-idf)
14 |
15 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a
3 | # project subdirectory.
4 | #
5 |
6 | PROJECT_NAME := esp32_nabto
7 |
8 | EXTRA_CFLAGS := -Wno-maybe-uninitialized
9 |
10 | include $(IDF_PATH)/make/project.mk
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > **Warning**
2 | > Deprecation notice: This project is based on the now deprecated uNabto platform, hence this project is no longer actively maintained. The Nabto 4/Micro (uNabto) platform has been superseded by Nabto 5/Edge (see our [comparsion of the two platforms](https://docs.nabto.com/developer/guides/overview/edge-vs-micro.html)). An officially supported SDK for ESP32 is [available in github](https://github.com/nabto/edge-esp32). Also, see our [guide to using Nabto Edge with ESP32](https://docs.nabto.com/developer/platforms/embedded/esp32.html).
3 | >
4 | > We have not yet ported the ESP32 cam application from uNabto to Nabto Edge, it is expected to be available no later than Q4 2023. In the meantime, you can use a combination: Use the ESP32 uNabto demo as inspiration for the application and use the [already available ESP32 integration](https://github.com/nabto/edge-esp32) (with no camera support yet).
5 |
6 | # uNabto ESP32 cam demo
7 |
8 | This project turns the ESP32-CAM into a remote P2P accesible surveillance camera.
9 | It uses the esp-idf FreeRTOS based core (vs. some other demos which uses the arduino core).
10 | Also it uses the espressif esp32-cam library with slight modification (we could not get the reset to work).
11 |
12 | The video is MJPEG and the module can cope to remotely stream (encode to mjpeg and encrypt and integrity check) a VGA feed at around 10 frames per second.
13 |
14 | You should also read the related blog article:
15 | https://www.nabto.com/esp32/
16 |
17 | # The structure
18 |
19 | The structure of the project is as follows
20 |
21 |
22 | +
23 | +-->+-------------+
24 | | | Main | This folder contains the initial setup
25 | | +-------------+ and the application_event() function defining
26 | | the application
27 | +-->+-------------+
28 | | Components |
29 | +-------------+
30 | |
31 | +------->+----------------+
32 | | | unabto | Don't edit here (link to other github rep)
33 | | +----------------+
34 | |
35 | +------->+----------------+
36 | | | unabto-esp-idf | The platform integration
37 | | +----------------+
38 | |
39 | +------->+----------------+
40 | | | nabtotunnel | Nabto tunnel application
41 | | +----------------+
42 | |
43 | +------->+----------------+
44 | | | unabto-esp- | Client fingerprint database
45 | | | fingerprint | storage in NVS
46 | | +----------------+
47 | |
48 | +------->+----------------+
49 | | esp32-camera | From the espressif github (not a link, since we adjusted)
50 | +----------------+
51 |
52 |
53 |
54 | ESP-IDF project has a speciel structure. You can read more about that here:
55 | https://esp-idf.readthedocs.io/en/v1.0/build_system.html
56 | The unabto source and the integration code is done as components and therefore resides in the IDF component folder.
57 | The unabto sdk is a submodule link to the unabto generic source.
58 |
59 | The initial setup/commisioning and the application is located in the main folder.
60 | unabto_application.c contains the application (inside the application_event function), the main.c contains the setup and configuration of the WiFi module.
61 |
62 |
63 | # How to set it up
64 |
65 | ## Step 1: Setup the ESP-IDF build environment
66 |
67 | Follow the setup of the ESP-IDF toolchain setup
68 |
69 | http://esp-idf.readthedocs.io/en/stable/get-started/index.html
70 | (WARNING!!! It is important to use the "stable" release not latests.. Issues with fcntl has been detected as of late june 2019)
71 |
72 | ## Step 2: Clone the repository
73 |
74 |
75 | ```
76 | git clone --recursive https://github.com/nabto/nabto-esp32cam.git
77 | ```
78 |
79 | ## Step 3: Make menuconfig
80 |
81 | Enter into menu "Camera configuration"
82 |
83 | Edit/adjust the following menu items:
84 |
85 |
86 | * WIFI access point name (SSID) : The wifi access point you want the module to attach to
87 | * WIFI password : The password used by the access point
88 | * Nabto ID : The Nabto device id you get from your AppMyProduct account
89 | * Nabto key - 32 hex chars : The key for the specific device id you entered in the before mentioned item
90 |
91 | Camera wiring! If you have an ESP-EYE board nothing else needs to be set up if you have an “ESP32 Cam” from Ai Tinker you need to configure this too (also in the “Camera configuration” menu).
92 |
93 |
94 | ## Step 3: Build the project
95 |
96 | ```
97 | make
98 | ```
99 |
100 | ## Step 4: Flash the Image
101 |
102 | Possible you need to adjust the serial deivce to use for flashing which is setup in the menuconfig part, but mostly the standard setup will match your platform.
103 |
104 | ```
105 | make flash
106 | ```
107 |
108 |
109 | # How to test the application
110 |
111 |
112 | ## Monitor the output from the board
113 |
114 | Using the monitor command you should see a printout similar to the following every time the ESP32-EVB starts up:
115 |
116 | Look for the "connected!" telling that the device knows how to connect to your WIFI. Also look for the Nabto state change to "ATTACHED" meaning that the device succesfully attached to Nabto infrastructure (registered and is online, waiting for connect requests from clients). The cloud service (controller) address can be varying dependent on geographic region (we have 4 datacenters) and availabillity.
117 |
118 | ```
119 | 00:00:01:457 main.c(382) connected!
120 | 00:00:01:460 main.c(388) IP Address: 192.168.2.147
121 | 00:00:01:465 main.c(389) Subnet mask: 255.255.255.0
122 | 00:00:01:470 main.c(390) Gateway: 192.168.2.1
123 | 00:00:01:475 unabto_application.c(59) In demo_init
124 | 00:00:01:479 unabto_application.c(78) Before fp_mem_init
125 | 00:00:01:495 unabto_application.c(81) Before acl_ae_init
126 | 00:00:01:495 unabto_common_main.c(110) Device id: 'jicnkjqs.ev9dbf.appmyproduct.com'
127 | 00:00:01:498 unabto_common_main.c(111) Program Release 4.4.0-alpha.0
128 | 00:00:01:505 network_adapter.c(140) Socket opened: port=5570
129 | 00:00:01:510 network_adapter.c(140) Socket opened: port=49153
130 | 00:00:01:515 unabto_stream_event.c(235) sizeof(stream__)=328
131 | 00:00:01:521 unabto_context.c(55) SECURE ATTACH: 1, DATA: 1
132 | 00:00:01:526 unabto_context.c(63) NONCE_SIZE: 32, CLEAR_TEXT: 0
133 | 00:00:01:532 unabto_common_main.c(183) Nabto was successfully initialized
134 | 00:00:01:539 unabto_context.c(55) SECURE ATTACH: 1, DATA: 1
135 | 00:00:01:543 unabto_context.c(63) NONCE_SIZE: 32, CLEAR_TEXT: 0
136 | 00:00:01:550 network_adapter.c(140) Socket opened: port=49154
137 | 00:00:01:555 unabto_attach.c(770) State change from IDLE to WAIT_DNS
138 | 00:00:01:561 unabto_attach.c(771) Resolving DNS for jicnkjqs.ev9dbf.appmyproduct.com
139 | 00:00:01:675 unabto_attach.c(790) Resolved DNS for jicnkjqs.ev9dbf.appmyproduct.com to:
140 | 00:00:01:675 unabto_attach.c(796) Controller ip: 34.232.129.33
141 | 00:00:01:678 unabto_attach.c(802) State change from WAIT_DNS to WAIT_BS
142 | 00:00:01:887 unabto_attach.c(480) State change from WAIT_BS to WAIT_GSP
143 | 00:00:01:888 unabto_attach.c(481) GSP address: 34.194.195.231:5565
144 | 00:00:01:895 unabto_attach.c(270) ######## U_INVITE with LARGE nonce sent, version: - URL: -
145 | 00:00:02:089 unabto_attach.c(563) State change from WAIT_GSP to ATTACHED
146 | ```
147 |
148 | To test the camera you can try to access:
149 | http://:8081/
150 |
151 | Which will show something like this:
152 |
153 |
154 |
155 |
156 |
157 |
158 | ## Download the AMP video app
159 |
160 | Download the Android or iPhone app from app store
161 | * https://play.google.com/store/apps/details?id=com.appmyproduct.video
162 | * https://itunes.apple.com/lc/app/appmyproduct-video-client/id1276975254
163 |
164 | ## Pair the video app with the wifi module
165 |
166 | Setup your phone to be connected to the same WIFI network as the device. This is ultra important since the app and the device will do a broadcast discovery to find eachother. The app will create an anonomous PKI cert and send the fingerprint of the key (like SSH) to the device on the local network which is considered "safe" (ie. don't pair on public network). The device add this fingerprint to the access control list and after this the device will now accept that the app can remotely connect. Read more about [Nabto access control lists and pairing here](https://www.nabto.com/pairing-and-access-control-part-1-intro-and-device/).
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 | ## Connect and view video
175 |
176 | Now you should be able to connect to the camera when you click on the camera logo.
177 |
178 |
179 |
180 |
181 |
182 |
--------------------------------------------------------------------------------
/components/esp32-camera/.gitignore:
--------------------------------------------------------------------------------
1 | *.DS_Store
2 |
--------------------------------------------------------------------------------
/components/esp32-camera/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(COMPONENT_SRCS
2 | driver/camera.c
3 | driver/sccb.c
4 | driver/sensor.c
5 | driver/twi.c
6 | driver/xclk.c
7 | sensors/ov2640.c
8 | sensors/ov3660.c
9 | sensors/ov7725.c
10 | conversions/yuv.c
11 | conversions/to_jpg.cpp
12 | conversions/to_bmp.c
13 | conversions/jpge.cpp
14 | conversions/esp_jpg_decode.c
15 | )
16 |
17 | set(COMPONENT_ADD_INCLUDEDIRS
18 | driver/include
19 | conversions/include
20 | )
21 |
22 | set(COMPONENT_PRIV_INCLUDEDIRS
23 | driver/private_include
24 | sensors/private_include
25 | conversions/private_include
26 | )
27 |
28 | set(COMPONENT_REQUIRES driver)
29 | set(COMPONENT_PRIV_REQUIRES freertos)
30 |
31 | register_component()
32 |
--------------------------------------------------------------------------------
/components/esp32-camera/Kconfig:
--------------------------------------------------------------------------------
1 | menu "Camera configuration"
2 |
3 | config OV2640_SUPPORT
4 | bool "OV2640 Support"
5 | default y
6 | help
7 | Enable this option if you want to use the OV2640.
8 | Disable this option to safe memory.
9 |
10 | config OV7725_SUPPORT
11 | bool "OV7725 Support"
12 | default n
13 | help
14 | Enable this option if you want to use the OV7725.
15 | Disable this option to safe memory.
16 |
17 | config OV3660_SUPPORT
18 | bool "OV3660 Support"
19 | default y
20 | help
21 | Enable this option if you want to use the OV3360.
22 | Disable this option to safe memory.
23 |
24 | config SCCB_HARDWARE_I2C
25 | bool "Use hardware I2C1 for SCCB"
26 | default y
27 | help
28 | Enable this option if you want to use hardware I2C to control the camera.
29 | Disable this option to use software I2C.
30 |
31 | choice CAMERA_TASK_PINNED_TO_CORE
32 | bool "Camera task pinned to core"
33 | default CAMERA_CORE0
34 | help
35 | Pin the camera handle task to a certain core(0/1). It can also be done automatically choosing NO_AFFINITY.
36 |
37 | config CAMERA_CORE0
38 | bool "CORE0"
39 | config CAMERA_CORE1
40 | bool "CORE1"
41 | config CAMERA_NO_AFFINITY
42 | bool "NO_AFFINITY"
43 |
44 | endchoice
45 |
46 | endmenu
47 |
--------------------------------------------------------------------------------
/components/esp32-camera/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/components/esp32-camera/README.md:
--------------------------------------------------------------------------------
1 | # ESP32 Camera Driver
2 |
3 | ## General Information
4 |
5 | This repository hosts ESP32 compatible driver for OV2640 and OV3660 image sensors. Additionally it provides a few tools, which allow converting the captured frame data to the more common BMP and JPEG formats.
6 |
7 | ## Important to Remember
8 |
9 | - Except when using CIF or lower resolution with JPEG, the driver requires PSRAM to be installed and activated.
10 | - 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`.
11 | - 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.
12 | - 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.
13 |
14 | ## Installation Instructions
15 |
16 | - Clone or download and extract the repository to the components folder of your ESP-IDF project
17 | - Enable PSRAM in `menuconfig`
18 | - Include `esp_camera.h` in your code
19 |
20 | ## Examples
21 |
22 | ### Initialization
23 |
24 | ```c
25 | #include "esp_camera.h"
26 |
27 | //WROVER-KIT PIN Map
28 | #define CAM_PIN_PWDN -1 //power down is not used
29 | #define CAM_PIN_RESET -1 //software reset will be performed
30 | #define CAM_PIN_XCLK 21
31 | #define CAM_PIN_SIOD 26
32 | #define CAM_PIN_SIOC 27
33 |
34 | #define CAM_PIN_D7 35
35 | #define CAM_PIN_D6 34
36 | #define CAM_PIN_D5 39
37 | #define CAM_PIN_D4 36
38 | #define CAM_PIN_D3 19
39 | #define CAM_PIN_D2 18
40 | #define CAM_PIN_D1 5
41 | #define CAM_PIN_D0 4
42 | #define CAM_PIN_VSYNC 25
43 | #define CAM_PIN_HREF 23
44 | #define CAM_PIN_PCLK 22
45 |
46 | static camera_config_t camera_config = {
47 | .pin_pwdn = CAM_PIN_PWDN,
48 | .pin_reset = CAM_PIN_RESET,
49 | .pin_xclk = CAM_PIN_XCLK,
50 | .pin_sscb_sda = CAM_PIN_SIOD,
51 | .pin_sscb_scl = CAM_PIN_SIOC,
52 |
53 | .pin_d7 = CAM_PIN_D7,
54 | .pin_d6 = CAM_PIN_D6,
55 | .pin_d5 = CAM_PIN_D5,
56 | .pin_d4 = CAM_PIN_D4,
57 | .pin_d3 = CAM_PIN_D3,
58 | .pin_d2 = CAM_PIN_D2,
59 | .pin_d1 = CAM_PIN_D1,
60 | .pin_d0 = CAM_PIN_D0,
61 | .pin_vsync = CAM_PIN_VSYNC,
62 | .pin_href = CAM_PIN_HREF,
63 | .pin_pclk = CAM_PIN_PCLK,
64 |
65 | //XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental)
66 | .xclk_freq_hz = 20000000,
67 | .ledc_timer = LEDC_TIMER_0,
68 | .ledc_channel = LEDC_CHANNEL_0,
69 |
70 | .pixel_format = PIXFORMAT_JPEG,//YUV422,GRAYSCALE,RGB565,JPEG
71 | .frame_size = FRAMESIZE_UXGA,//QQVGA-QXGA Do not use sizes above QVGA when not JPEG
72 |
73 | .jpeg_quality = 12, //0-63 lower number means higher quality
74 | .fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG
75 | };
76 |
77 | esp_err_t camera_init(){
78 | //power up the camera if PWDN pin is defined
79 | if(CAM_PIN_PWDN != -1){
80 | pinMode(CAM_PIN_PWDN, OUTPUT);
81 | digitalWrite(CAM_PIN_PWDN, LOW);
82 | }
83 |
84 | //initialize the camera
85 | esp_err_t err = esp_camera_init(&camera_config);
86 | if (err != ESP_OK) {
87 | ESP_LOGE(TAG, "Camera Init Failed");
88 | return err;
89 | }
90 |
91 | return ESP_OK;
92 | }
93 |
94 | esp_err_t camera_capture(){
95 | //acquire a frame
96 | camera_fb_t * fb = esp_camera_fb_get();
97 | if (!fb) {
98 | ESP_LOGE(TAG, "Camera Capture Failed");
99 | return ESP_FAIL;
100 | }
101 | //replace this with your own function
102 | process_image(fb->width, fb->height, fb->format, fb->buf, fb->len);
103 |
104 | //return the frame buffer back to the driver for reuse
105 | esp_camera_fb_return(fb);
106 | return ESP_OK;
107 | }
108 | ```
109 |
110 | ### JPEG HTTP Capture
111 |
112 | ```c
113 | #include "esp_camera.h"
114 | #include "esp_http_server.h"
115 | #include "esp_timer.h"
116 |
117 | typedef struct {
118 | httpd_req_t *req;
119 | size_t len;
120 | } jpg_chunking_t;
121 |
122 | static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){
123 | jpg_chunking_t *j = (jpg_chunking_t *)arg;
124 | if(!index){
125 | j->len = 0;
126 | }
127 | if(httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK){
128 | return 0;
129 | }
130 | j->len += len;
131 | return len;
132 | }
133 |
134 | esp_err_t jpg_httpd_handler(httpd_req_t *req){
135 | camera_fb_t * fb = NULL;
136 | esp_err_t res = ESP_OK;
137 | size_t fb_len = 0;
138 | int64_t fr_start = esp_timer_get_time();
139 |
140 | fb = esp_camera_fb_get();
141 | if (!fb) {
142 | ESP_LOGE(TAG, "Camera capture failed");
143 | httpd_resp_send_500(req);
144 | return ESP_FAIL;
145 | }
146 | res = httpd_resp_set_type(req, "image/jpeg");
147 | if(res == ESP_OK){
148 | res = httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg");
149 | }
150 |
151 | if(res == ESP_OK){
152 | if(fb->format == PIXFORMAT_JPEG){
153 | fb_len = fb->len;
154 | res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
155 | } else {
156 | jpg_chunking_t jchunk = {req, 0};
157 | res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL;
158 | httpd_resp_send_chunk(req, NULL, 0);
159 | fb_len = jchunk.len;
160 | }
161 | }
162 | esp_camera_fb_return(fb);
163 | int64_t fr_end = esp_timer_get_time();
164 | ESP_LOGI(TAG, "JPG: %uKB %ums", (uint32_t)(fb_len/1024), (uint32_t)((fr_end - fr_start)/1000));
165 | return res;
166 | }
167 | ```
168 |
169 | ### JPEG HTTP Stream
170 |
171 | ```c
172 | #include "esp_camera.h"
173 | #include "esp_http_server.h"
174 | #include "esp_timer.h"
175 |
176 | #define PART_BOUNDARY "123456789000000000000987654321"
177 | static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
178 | static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
179 | static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
180 |
181 | esp_err_t jpg_stream_httpd_handler(httpd_req_t *req){
182 | camera_fb_t * fb = NULL;
183 | esp_err_t res = ESP_OK;
184 | size_t _jpg_buf_len;
185 | uint8_t * _jpg_buf;
186 | char * part_buf[64];
187 | static int64_t last_frame = 0;
188 | if(!last_frame) {
189 | last_frame = esp_timer_get_time();
190 | }
191 |
192 | res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
193 | if(res != ESP_OK){
194 | return res;
195 | }
196 |
197 | while(true){
198 | fb = esp_camera_fb_get();
199 | if (!fb) {
200 | ESP_LOGE(TAG, "Camera capture failed");
201 | res = ESP_FAIL;
202 | } else {
203 | if(fb->format != PIXFORMAT_JPEG){
204 | bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
205 | if(!jpeg_converted){
206 | ESP_LOGE(TAG, "JPEG compression failed");
207 | esp_camera_fb_return(fb);
208 | res = ESP_FAIL;
209 | }
210 | } else {
211 | _jpg_buf_len = fb->len;
212 | _jpg_buf = fb->buf;
213 | }
214 | }
215 | if(res == ESP_OK){
216 | size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
217 |
218 | res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
219 | }
220 | if(res == ESP_OK){
221 | res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
222 | }
223 | if(res == ESP_OK){
224 | res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
225 | }
226 | if(fb->format != PIXFORMAT_JPEG){
227 | free(_jpg_buf);
228 | }
229 | esp_camera_fb_return(fb);
230 | if(res != ESP_OK){
231 | break;
232 | }
233 | int64_t fr_end = esp_timer_get_time();
234 | int64_t frame_time = fr_end - last_frame;
235 | last_frame = fr_end;
236 | frame_time /= 1000;
237 | ESP_LOGI(TAG, "MJPG: %uKB %ums (%.1ffps)",
238 | (uint32_t)(_jpg_buf_len/1024),
239 | (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time);
240 | }
241 |
242 | last_frame = 0;
243 | return res;
244 | }
245 | ```
246 |
247 | ### BMP HTTP Capture
248 |
249 | ```c
250 | #include "esp_camera.h"
251 | #include "esp_http_server.h"
252 | #include "esp_timer.h"
253 |
254 | esp_err_t bmp_httpd_handler(httpd_req_t *req){
255 | camera_fb_t * fb = NULL;
256 | esp_err_t res = ESP_OK;
257 | int64_t fr_start = esp_timer_get_time();
258 |
259 | fb = esp_camera_fb_get();
260 | if (!fb) {
261 | ESP_LOGE(TAG, "Camera capture failed");
262 | httpd_resp_send_500(req);
263 | return ESP_FAIL;
264 | }
265 |
266 | uint8_t * buf = NULL;
267 | size_t buf_len = 0;
268 | bool converted = frame2bmp(fb, &buf, &buf_len);
269 | esp_camera_fb_return(fb);
270 | if(!converted){
271 | ESP_LOGE(TAG, "BMP conversion failed");
272 | httpd_resp_send_500(req);
273 | return ESP_FAIL;
274 | }
275 |
276 | res = httpd_resp_set_type(req, "image/x-windows-bmp")
277 | || httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.bmp")
278 | || httpd_resp_send(req, (const char *)buf, buf_len);
279 | free(buf);
280 | int64_t fr_end = esp_timer_get_time();
281 | ESP_LOGI(TAG, "BMP: %uKB %ums", (uint32_t)(buf_len/1024), (uint32_t)((fr_end - fr_start)/1000));
282 | return res;
283 | }
284 | ```
285 |
--------------------------------------------------------------------------------
/components/esp32-camera/component.mk:
--------------------------------------------------------------------------------
1 | COMPONENT_ADD_INCLUDEDIRS := driver/include conversions/include
2 | COMPONENT_PRIV_INCLUDEDIRS := driver/private_include conversions/private_include sensors/private_include
3 | COMPONENT_SRCDIRS := driver conversions sensors
4 | CXXFLAGS += -fno-rtti
5 |
--------------------------------------------------------------------------------
/components/esp32-camera/conversions/esp_jpg_decode.c:
--------------------------------------------------------------------------------
1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | #include "esp_jpg_decode.h"
15 | #include "rom/tjpgd.h"
16 |
17 | #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
18 | #include "esp32-hal-log.h"
19 | #define TAG ""
20 | #else
21 | #include "esp_log.h"
22 | static const char* TAG = "esp_jpg_decode";
23 | #endif
24 |
25 | typedef struct {
26 | jpg_scale_t scale;
27 | jpg_reader_cb reader;
28 | jpg_writer_cb writer;
29 | void * arg;
30 | size_t len;
31 | size_t index;
32 | } esp_jpg_decoder_t;
33 |
34 | static const char * jd_errors[] = {
35 | "Succeeded",
36 | "Interrupted by output function",
37 | "Device error or wrong termination of input stream",
38 | "Insufficient memory pool for the image",
39 | "Insufficient stream input buffer",
40 | "Parameter error",
41 | "Data format error",
42 | "Right format but not supported",
43 | "Not supported JPEG standard"
44 | };
45 |
46 | static uint32_t _jpg_write(JDEC *decoder, void *bitmap, JRECT *rect)
47 | {
48 | uint16_t x = rect->left;
49 | uint16_t y = rect->top;
50 | uint16_t w = rect->right + 1 - x;
51 | uint16_t h = rect->bottom + 1 - y;
52 | uint8_t *data = (uint8_t *)bitmap;
53 |
54 | esp_jpg_decoder_t * jpeg = (esp_jpg_decoder_t *)decoder->device;
55 |
56 | if (jpeg->writer) {
57 | return jpeg->writer(jpeg->arg, x, y, w, h, data);
58 | }
59 | return 0;
60 | }
61 |
62 | static uint32_t _jpg_read(JDEC *decoder, uint8_t *buf, uint32_t len)
63 | {
64 | esp_jpg_decoder_t * jpeg = (esp_jpg_decoder_t *)decoder->device;
65 | if (jpeg->len && len > (jpeg->len - jpeg->index)) {
66 | len = jpeg->len - jpeg->index;
67 | }
68 | if (len) {
69 | len = jpeg->reader(jpeg->arg, jpeg->index, buf, len);
70 | if (!len) {
71 | ESP_LOGE(TAG, "Read Fail at %u/%u", jpeg->index, jpeg->len);
72 | }
73 | jpeg->index += len;
74 | }
75 | return len;
76 | }
77 |
78 | esp_err_t esp_jpg_decode(size_t len, jpg_scale_t scale, jpg_reader_cb reader, jpg_writer_cb writer, void * arg)
79 | {
80 | static uint8_t work[3100];
81 | JDEC decoder;
82 | esp_jpg_decoder_t jpeg;
83 |
84 | jpeg.len = len;
85 | jpeg.reader = reader;
86 | jpeg.writer = writer;
87 | jpeg.arg = arg;
88 | jpeg.scale = scale;
89 | jpeg.index = 0;
90 |
91 | JRESULT jres = jd_prepare(&decoder, _jpg_read, work, 3100, &jpeg);
92 | if(jres != JDR_OK){
93 | ESP_LOGE(TAG, "JPG Header Parse Failed! %s", jd_errors[jres]);
94 | return ESP_FAIL;
95 | }
96 |
97 | uint16_t output_width = decoder.width / (1 << (uint8_t)(jpeg.scale));
98 | uint16_t output_height = decoder.height / (1 << (uint8_t)(jpeg.scale));
99 |
100 | //output start
101 | writer(arg, 0, 0, output_width, output_height, NULL);
102 | //output write
103 | jres = jd_decomp(&decoder, _jpg_write, (uint8_t)jpeg.scale);
104 | //output end
105 | writer(arg, output_width, output_height, output_width, output_height, NULL);
106 |
107 | if (jres != JDR_OK) {
108 | ESP_LOGE(TAG, "JPG Decompression Failed! %s", jd_errors[jres]);
109 | return ESP_FAIL;
110 | }
111 | //check if all data has been consumed.
112 | if (len && jpeg.index < len) {
113 | _jpg_read(&decoder, NULL, len - jpeg.index);
114 | }
115 |
116 | return ESP_OK;
117 | }
118 |
119 |
--------------------------------------------------------------------------------
/components/esp32-camera/conversions/include/esp_jpg_decode.h:
--------------------------------------------------------------------------------
1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | #ifndef _ESP_JPG_DECODE_H_
15 | #define _ESP_JPG_DECODE_H_
16 |
17 | #ifdef __cplusplus
18 | extern "C" {
19 | #endif
20 |
21 | #include
22 | #include
23 | #include
24 | #include "esp_err.h"
25 |
26 | typedef enum {
27 | JPG_SCALE_NONE,
28 | JPG_SCALE_2X,
29 | JPG_SCALE_4X,
30 | JPG_SCALE_8X,
31 | JPG_SCALE_MAX = JPG_SCALE_8X
32 | } jpg_scale_t;
33 |
34 | typedef size_t (* jpg_reader_cb)(void * arg, size_t index, uint8_t *buf, size_t len);
35 | typedef bool (* jpg_writer_cb)(void * arg, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t *data);
36 |
37 | esp_err_t esp_jpg_decode(size_t len, jpg_scale_t scale, jpg_reader_cb reader, jpg_writer_cb writer, void * arg);
38 |
39 | #ifdef __cplusplus
40 | }
41 | #endif
42 |
43 | #endif /* _ESP_JPG_DECODE_H_ */
44 |
--------------------------------------------------------------------------------
/components/esp32-camera/conversions/include/img_converters.h:
--------------------------------------------------------------------------------
1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | #ifndef _IMG_CONVERTERS_H_
15 | #define _IMG_CONVERTERS_H_
16 |
17 | #ifdef __cplusplus
18 | extern "C" {
19 | #endif
20 |
21 | #include
22 | #include
23 | #include
24 | #include "esp_camera.h"
25 |
26 | typedef size_t (* jpg_out_cb)(void * arg, size_t index, const void* data, size_t len);
27 |
28 | /**
29 | * @brief Convert image buffer to JPEG
30 | *
31 | * @param src Source buffer in RGB565, RGB888, YUYV or GRAYSCALE format
32 | * @param src_len Length in bytes of the source buffer
33 | * @param width Width in pixels of the source image
34 | * @param height Height in pixels of the source image
35 | * @param format Format of the source image
36 | * @param quality JPEG quality of the resulting image
37 | * @param cp Callback to be called to write the bytes of the output JPEG
38 | * @param arg Pointer to be passed to the callback
39 | *
40 | * @return true on success
41 | */
42 | 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);
43 |
44 | /**
45 | * @brief Convert camera frame buffer to JPEG
46 | *
47 | * @param fb Source camera frame buffer
48 | * @param quality JPEG quality of the resulting image
49 | * @param cp Callback to be called to write the bytes of the output JPEG
50 | * @param arg Pointer to be passed to the callback
51 | *
52 | * @return true on success
53 | */
54 | bool frame2jpg_cb(camera_fb_t * fb, uint8_t quality, jpg_out_cb cb, void * arg);
55 |
56 | /**
57 | * @brief Convert image buffer to JPEG buffer
58 | *
59 | * @param src Source buffer in RGB565, RGB888, YUYV or GRAYSCALE format
60 | * @param src_len Length in bytes of the source buffer
61 | * @param width Width in pixels of the source image
62 | * @param height Height in pixels of the source image
63 | * @param format Format of the source image
64 | * @param quality JPEG quality of the resulting image
65 | * @param out Pointer to be populated with the address of the resulting buffer
66 | * @param out_len Pointer to be populated with the length of the output buffer
67 | *
68 | * @return true on success
69 | */
70 | 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);
71 |
72 | /**
73 | * @brief Convert camera frame buffer to JPEG buffer
74 | *
75 | * @param fb Source camera frame buffer
76 | * @param quality JPEG quality of the resulting image
77 | * @param out Pointer to be populated with the address of the resulting buffer
78 | * @param out_len Pointer to be populated with the length of the output buffer
79 | *
80 | * @return true on success
81 | */
82 | bool frame2jpg(camera_fb_t * fb, uint8_t quality, uint8_t ** out, size_t * out_len);
83 |
84 | /**
85 | * @brief Convert image buffer to BMP buffer
86 | *
87 | * @param src Source buffer in JPEG, RGB565, RGB888, YUYV or GRAYSCALE format
88 | * @param src_len Length in bytes of the source buffer
89 | * @param width Width in pixels of the source image
90 | * @param height Height in pixels of the source image
91 | * @param format Format of the source image
92 | * @param out Pointer to be populated with the address of the resulting buffer
93 | * @param out_len Pointer to be populated with the length of the output buffer
94 | *
95 | * @return true on success
96 | */
97 | 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);
98 |
99 | /**
100 | * @brief Convert camera frame buffer to BMP buffer
101 | *
102 | * @param fb Source camera frame buffer
103 | * @param out Pointer to be populated with the address of the resulting buffer
104 | * @param out_len Pointer to be populated with the length of the output buffer
105 | *
106 | * @return true on success
107 | */
108 | bool frame2bmp(camera_fb_t * fb, uint8_t ** out, size_t * out_len);
109 |
110 | /**
111 | * @brief Convert image buffer to RGB888 buffer (used for face detection)
112 | *
113 | * @param src Source buffer in JPEG, RGB565, RGB888, YUYV or GRAYSCALE format
114 | * @param src_len Length in bytes of the source buffer
115 | * @param format Format of the source image
116 | * @param rgb_buf Pointer to the output buffer (width * height * 3)
117 | *
118 | * @return true on success
119 | */
120 | bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint8_t * rgb_buf);
121 |
122 | #ifdef __cplusplus
123 | }
124 | #endif
125 |
126 | #endif /* _IMG_CONVERTERS_H_ */
127 |
--------------------------------------------------------------------------------
/components/esp32-camera/conversions/private_include/jpge.h:
--------------------------------------------------------------------------------
1 | // jpge.h - C++ class for JPEG compression.
2 | // Public domain, Rich Geldreich
3 | // Alex Evans: Added RGBA support, linear memory allocator.
4 | #ifndef JPEG_ENCODER_H
5 | #define JPEG_ENCODER_H
6 |
7 | namespace jpge
8 | {
9 | typedef unsigned char uint8;
10 | typedef signed short int16;
11 | typedef signed int int32;
12 | typedef unsigned short uint16;
13 | typedef unsigned int uint32;
14 | typedef unsigned int uint;
15 |
16 | // JPEG chroma subsampling factors. Y_ONLY (grayscale images) and H2V2 (color images) are the most common.
17 | enum subsampling_t { Y_ONLY = 0, H1V1 = 1, H2V1 = 2, H2V2 = 3 };
18 |
19 | // JPEG compression parameters structure.
20 | struct params {
21 | inline params() : m_quality(85), m_subsampling(H2V2) { }
22 |
23 | inline bool check() const {
24 | if ((m_quality < 1) || (m_quality > 100)) {
25 | return false;
26 | }
27 | if ((uint)m_subsampling > (uint)H2V2) {
28 | return false;
29 | }
30 | return true;
31 | }
32 |
33 | // Quality: 1-100, higher is better. Typical values are around 50-95.
34 | int m_quality;
35 |
36 | // m_subsampling:
37 | // 0 = Y (grayscale) only
38 | // 1 = H1V1 subsampling (YCbCr 1x1x1, 3 blocks per MCU)
39 | // 2 = H2V1 subsampling (YCbCr 2x1x1, 4 blocks per MCU)
40 | // 3 = H2V2 subsampling (YCbCr 4x1x1, 6 blocks per MCU-- very common)
41 | subsampling_t m_subsampling;
42 | };
43 |
44 | // Output stream abstract class - used by the jpeg_encoder class to write to the output stream.
45 | // put_buf() is generally called with len==JPGE_OUT_BUF_SIZE bytes, but for headers it'll be called with smaller amounts.
46 | class output_stream {
47 | public:
48 | virtual ~output_stream() { };
49 | virtual bool put_buf(const void* Pbuf, int len) = 0;
50 | virtual uint get_size() const = 0;
51 | };
52 |
53 | // Lower level jpeg_encoder class - useful if more control is needed than the above helper functions.
54 | class jpeg_encoder {
55 | public:
56 | jpeg_encoder();
57 | ~jpeg_encoder();
58 |
59 | // Initializes the compressor.
60 | // pStream: The stream object to use for writing compressed data.
61 | // params - Compression parameters structure, defined above.
62 | // width, height - Image dimensions.
63 | // channels - May be 1, or 3. 1 indicates grayscale, 3 indicates RGB source data.
64 | // Returns false on out of memory or if a stream write fails.
65 | bool init(output_stream *pStream, int width, int height, int src_channels, const params &comp_params = params());
66 |
67 | // Call this method with each source scanline.
68 | // width * src_channels bytes per scanline is expected (RGB or Y format).
69 | // You must call with NULL after all scanlines are processed to finish compression.
70 | // Returns false on out of memory or if a stream write fails.
71 | bool process_scanline(const void* pScanline);
72 |
73 | // Deinitializes the compressor, freeing any allocated memory. May be called at any time.
74 | void deinit();
75 |
76 | private:
77 | jpeg_encoder(const jpeg_encoder &);
78 | jpeg_encoder &operator =(const jpeg_encoder &);
79 |
80 | typedef int32 sample_array_t;
81 | enum { JPGE_OUT_BUF_SIZE = 512 };
82 |
83 | output_stream *m_pStream;
84 | params m_params;
85 | uint8 m_num_components;
86 | uint8 m_comp_h_samp[3], m_comp_v_samp[3];
87 | int m_image_x, m_image_y, m_image_bpp, m_image_bpl;
88 | int m_image_x_mcu, m_image_y_mcu;
89 | int m_image_bpl_xlt, m_image_bpl_mcu;
90 | int m_mcus_per_row;
91 | int m_mcu_x, m_mcu_y;
92 | uint8 *m_mcu_lines[16];
93 | uint8 m_mcu_y_ofs;
94 | sample_array_t m_sample_array[64];
95 | int16 m_coefficient_array[64];
96 |
97 | int m_last_dc_val[3];
98 | uint8 m_out_buf[JPGE_OUT_BUF_SIZE];
99 | uint8 *m_pOut_buf;
100 | uint m_out_buf_left;
101 | uint32 m_bit_buffer;
102 | uint m_bits_in;
103 | uint8 m_pass_num;
104 | bool m_all_stream_writes_succeeded;
105 |
106 | bool jpg_open(int p_x_res, int p_y_res, int src_channels);
107 |
108 | void flush_output_buffer();
109 | void put_bits(uint bits, uint len);
110 |
111 | void emit_byte(uint8 i);
112 | void emit_word(uint i);
113 | void emit_marker(int marker);
114 |
115 | void emit_jfif_app0();
116 | void emit_dqt();
117 | void emit_sof();
118 | void emit_dht(uint8 *bits, uint8 *val, int index, bool ac_flag);
119 | void emit_dhts();
120 | void emit_sos();
121 |
122 | void compute_quant_table(int32 *dst, const int16 *src);
123 | void load_quantized_coefficients(int component_num);
124 |
125 | void load_block_8_8_grey(int x);
126 | void load_block_8_8(int x, int y, int c);
127 | void load_block_16_8(int x, int c);
128 | void load_block_16_8_8(int x, int c);
129 |
130 | void code_coefficients_pass_two(int component_num);
131 | void code_block(int component_num);
132 |
133 | void process_mcu_row();
134 | bool process_end_of_image();
135 | void load_mcu(const void* src);
136 | void clear();
137 | void init();
138 | };
139 |
140 | } // namespace jpge
141 |
142 | #endif // JPEG_ENCODER
143 |
--------------------------------------------------------------------------------
/components/esp32-camera/conversions/private_include/yuv.h:
--------------------------------------------------------------------------------
1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | #ifndef _CONVERSIONS_YUV_H_
15 | #define _CONVERSIONS_YUV_H_
16 |
17 | #ifdef __cplusplus
18 | extern "C" {
19 | #endif
20 |
21 | #include
22 |
23 | void yuv2rgb(uint8_t y, uint8_t u, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b);
24 |
25 | #ifdef __cplusplus
26 | }
27 | #endif
28 |
29 | #endif /* _CONVERSIONS_YUV_H_ */
30 |
--------------------------------------------------------------------------------
/components/esp32-camera/conversions/to_bmp.c:
--------------------------------------------------------------------------------
1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | #include
15 | #include
16 | #include "img_converters.h"
17 | #include "esp_spiram.h"
18 | #include "soc/efuse_reg.h"
19 | #include "esp_heap_caps.h"
20 | #include "yuv.h"
21 | #include "sdkconfig.h"
22 | #include "esp_jpg_decode.h"
23 |
24 | #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
25 | #include "esp32-hal-log.h"
26 | #define TAG ""
27 | #else
28 | #include "esp_log.h"
29 | static const char* TAG = "to_bmp";
30 | #endif
31 |
32 | static const int BMP_HEADER_LEN = 54;
33 |
34 | typedef struct {
35 | uint32_t filesize;
36 | uint32_t reserved;
37 | uint32_t fileoffset_to_pixelarray;
38 | uint32_t dibheadersize;
39 | int32_t width;
40 | int32_t height;
41 | uint16_t planes;
42 | uint16_t bitsperpixel;
43 | uint32_t compression;
44 | uint32_t imagesize;
45 | uint32_t ypixelpermeter;
46 | uint32_t xpixelpermeter;
47 | uint32_t numcolorspallette;
48 | uint32_t mostimpcolor;
49 | } bmp_header_t;
50 |
51 | typedef struct {
52 | uint16_t width;
53 | uint16_t height;
54 | uint16_t data_offset;
55 | const uint8_t *input;
56 | uint8_t *output;
57 | } rgb_jpg_decoder;
58 |
59 | static void *_malloc(size_t size)
60 | {
61 | return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
62 | }
63 |
64 | //output buffer and image width
65 | static bool _rgb_write(void * arg, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t *data)
66 | {
67 | rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg;
68 | if(!data){
69 | if(x == 0 && y == 0){
70 | //write start
71 | jpeg->width = w;
72 | jpeg->height = h;
73 | //if output is null, this is BMP
74 | if(!jpeg->output){
75 | jpeg->output = (uint8_t *)_malloc((w*h*3)+jpeg->data_offset);
76 | if(!jpeg->output){
77 | return false;
78 | }
79 | }
80 | } else {
81 | //write end
82 | }
83 | return true;
84 | }
85 |
86 | size_t jw = jpeg->width*3;
87 | size_t t = y * jw;
88 | size_t b = t + (h * jw);
89 | size_t l = x * 3;
90 | uint8_t *out = jpeg->output+jpeg->data_offset;
91 | uint8_t *o = out;
92 | size_t iy, ix;
93 |
94 | w = w * 3;
95 |
96 | for(iy=t; iyinput + index, len);
114 | }
115 | return len;
116 | }
117 |
118 | static bool jpg2rgb888(const uint8_t *src, size_t src_len, uint8_t * out, jpg_scale_t scale)
119 | {
120 | rgb_jpg_decoder jpeg;
121 | jpeg.width = 0;
122 | jpeg.height = 0;
123 | jpeg.input = src;
124 | jpeg.output = out;
125 | jpeg.data_offset = 0;
126 |
127 | if(esp_jpg_decode(src_len, scale, _jpg_read, _rgb_write, (void*)&jpeg) != ESP_OK){
128 | return false;
129 | }
130 | return true;
131 | }
132 |
133 | bool jpg2bmp(const uint8_t *src, size_t src_len, uint8_t ** out, size_t * out_len)
134 | {
135 |
136 | rgb_jpg_decoder jpeg;
137 | jpeg.width = 0;
138 | jpeg.height = 0;
139 | jpeg.input = src;
140 | jpeg.output = NULL;
141 | jpeg.data_offset = BMP_HEADER_LEN;
142 |
143 | if(esp_jpg_decode(src_len, JPG_SCALE_NONE, _jpg_read, _rgb_write, (void*)&jpeg) != ESP_OK){
144 | return false;
145 | }
146 |
147 | size_t output_size = jpeg.width*jpeg.height*3;
148 |
149 | jpeg.output[0] = 'B';
150 | jpeg.output[1] = 'M';
151 | bmp_header_t * bitmap = (bmp_header_t*)&jpeg.output[2];
152 | bitmap->reserved = 0;
153 | bitmap->filesize = output_size+BMP_HEADER_LEN;
154 | bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN;
155 | bitmap->dibheadersize = 40;
156 | bitmap->width = jpeg.width;
157 | bitmap->height = -jpeg.height;//set negative for top to bottom
158 | bitmap->planes = 1;
159 | bitmap->bitsperpixel = 24;
160 | bitmap->compression = 0;
161 | bitmap->imagesize = output_size;
162 | bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI
163 | bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI
164 | bitmap->numcolorspallette = 0;
165 | bitmap->mostimpcolor = 0;
166 |
167 | *out = jpeg.output;
168 | *out_len = output_size+BMP_HEADER_LEN;
169 |
170 | return true;
171 | }
172 |
173 | bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint8_t * rgb_buf)
174 | {
175 | int pix_count = 0;
176 | if(format == PIXFORMAT_JPEG) {
177 | return jpg2rgb888(src_buf, src_len, rgb_buf, JPG_SCALE_NONE);
178 | } else if(format == PIXFORMAT_RGB888) {
179 | memcpy(rgb_buf, src_buf, src_len);
180 | } else if(format == PIXFORMAT_RGB565) {
181 | int i;
182 | uint8_t hb, lb;
183 | pix_count = src_len / 2;
184 | for(i=0; i> 3;
189 | *rgb_buf++ = hb & 0xF8;
190 | }
191 | } else if(format == PIXFORMAT_GRAYSCALE) {
192 | int i;
193 | uint8_t b;
194 | pix_count = src_len;
195 | for(i=0; ireserved = 0;
247 | bitmap->filesize = out_size;
248 | bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN;
249 | bitmap->dibheadersize = 40;
250 | bitmap->width = width;
251 | bitmap->height = -height;//set negative for top to bottom
252 | bitmap->planes = 1;
253 | bitmap->bitsperpixel = 24;
254 | bitmap->compression = 0;
255 | bitmap->imagesize = pix_count * 3;
256 | bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI
257 | bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI
258 | bitmap->numcolorspallette = 0;
259 | bitmap->mostimpcolor = 0;
260 |
261 | uint8_t * rgb_buf = out_buf + BMP_HEADER_LEN;
262 | uint8_t * src_buf = src;
263 |
264 |
265 | //convert data to RGB888
266 | if(format == PIXFORMAT_RGB888) {
267 | memcpy(rgb_buf, src_buf, pix_count*3);
268 | } else if(format == PIXFORMAT_RGB565) {
269 | int i;
270 | uint8_t hb, lb;
271 | for(i=0; i> 3;
276 | *rgb_buf++ = hb & 0xF8;
277 | }
278 | } else if(format == PIXFORMAT_GRAYSCALE) {
279 | int i;
280 | uint8_t b;
281 | for(i=0; ibuf, fb->len, fb->width, fb->height, fb->format, out, out_len);
316 | }
317 |
--------------------------------------------------------------------------------
/components/esp32-camera/conversions/to_jpg.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | #include
15 | #include
16 | #include "esp_spiram.h"
17 | #include "esp_attr.h"
18 | #include "soc/efuse_reg.h"
19 | #include "esp_heap_caps.h"
20 | #include "esp_camera.h"
21 | #include "img_converters.h"
22 | #include "jpge.h"
23 | #include "yuv.h"
24 |
25 | #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
26 | #include "esp32-hal-log.h"
27 | #define TAG ""
28 | #else
29 | #include "esp_log.h"
30 | static const char* TAG = "to_bmp";
31 | #endif
32 |
33 | static void *_malloc(size_t size)
34 | {
35 | void * res = malloc(size);
36 | if(res) {
37 | return res;
38 | }
39 | return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
40 | }
41 |
42 | 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)
43 | {
44 | int i=0, o=0, l=0;
45 | if(format == PIXFORMAT_GRAYSCALE) {
46 | memcpy(dst, src + line * width, width);
47 | } else if(format == PIXFORMAT_RGB888) {
48 | l = width * 3;
49 | src += l * line;
50 | for(i=0; i> 3;
61 | dst[o++] = (src[i+1] & 0x1F) << 3;
62 | }
63 | } else if(format == PIXFORMAT_YUV422) {
64 | uint8_t y0, y1, u, v;
65 | uint8_t r, g, b;
66 | l = width * 2;
67 | src += l * line;
68 | for(i=0; i 100) {
100 | quality = 100;
101 | }
102 |
103 | jpge::params comp_params = jpge::params();
104 | comp_params.m_subsampling = subsampling;
105 | comp_params.m_quality = quality;
106 |
107 | jpge::jpeg_encoder dst_image;
108 |
109 | if (!dst_image.init(dst_stream, width, height, num_channels, comp_params)) {
110 | ESP_LOGE(TAG, "JPG encoder init failed");
111 | return false;
112 | }
113 |
114 | uint8_t* line = (uint8_t*)_malloc(width * num_channels);
115 | if(!line) {
116 | ESP_LOGE(TAG, "Scan line malloc failed");
117 | return false;
118 | }
119 |
120 | for (int i = 0; i < height; i++) {
121 | convert_line_format(src, format, line, width, num_channels, i);
122 | if (!dst_image.process_scanline(line)) {
123 | ESP_LOGE(TAG, "JPG process line %u failed", i);
124 | free(line);
125 | return false;
126 | }
127 | }
128 | free(line);
129 |
130 | if (!dst_image.process_scanline(NULL)) {
131 | ESP_LOGE(TAG, "JPG image finish failed");
132 | return false;
133 | }
134 | dst_image.deinit();
135 | return true;
136 | }
137 |
138 | class callback_stream : public jpge::output_stream {
139 | protected:
140 | jpg_out_cb ocb;
141 | void * oarg;
142 | size_t index;
143 |
144 | public:
145 | callback_stream(jpg_out_cb cb, void * arg) : ocb(cb), oarg(arg), index(0) { }
146 | virtual ~callback_stream() { }
147 | virtual bool put_buf(const void* data, int len)
148 | {
149 | index += ocb(oarg, index, data, len);
150 | return true;
151 | }
152 | virtual size_t get_size() const
153 | {
154 | return index;
155 | }
156 | };
157 |
158 | 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)
159 | {
160 | callback_stream dst_stream(cb, arg);
161 | return convert_image(src, width, height, format, quality, &dst_stream);
162 | }
163 |
164 | bool frame2jpg_cb(camera_fb_t * fb, uint8_t quality, jpg_out_cb cb, void * arg)
165 | {
166 | return fmt2jpg_cb(fb->buf, fb->len, fb->width, fb->height, fb->format, quality, cb, arg);
167 | }
168 |
169 |
170 |
171 | class memory_stream : public jpge::output_stream {
172 | protected:
173 | uint8_t *out_buf;
174 | size_t max_len, index;
175 |
176 | public:
177 | memory_stream(void *pBuf, uint buf_size) : out_buf(static_cast(pBuf)), max_len(buf_size), index(0) { }
178 |
179 | virtual ~memory_stream() { }
180 |
181 | virtual bool put_buf(const void* pBuf, int len)
182 | {
183 | if (!pBuf) {
184 | //end of image
185 | return true;
186 | }
187 | if ((size_t)len > (max_len - index)) {
188 | ESP_LOGW(TAG, "JPG output overflow: %d bytes", len - (max_len - index));
189 | len = max_len - index;
190 | }
191 | if (len) {
192 | memcpy(out_buf + index, pBuf, len);
193 | index += len;
194 | }
195 | return true;
196 | }
197 |
198 | virtual size_t get_size() const
199 | {
200 | return index;
201 | }
202 | };
203 |
204 | 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)
205 | {
206 | //todo: allocate proper buffer for holding JPEG data
207 | //this should be enough for CIF frame size
208 | int jpg_buf_len = 64*1024;
209 |
210 |
211 | uint8_t * jpg_buf = (uint8_t *)_malloc(jpg_buf_len);
212 | if(jpg_buf == NULL) {
213 | ESP_LOGE(TAG, "JPG buffer malloc failed");
214 | return false;
215 | }
216 | memory_stream dst_stream(jpg_buf, jpg_buf_len);
217 |
218 | if(!convert_image(src, width, height, format, quality, &dst_stream)) {
219 | free(jpg_buf);
220 | return false;
221 | }
222 |
223 | *out = jpg_buf;
224 | *out_len = dst_stream.get_size();
225 | return true;
226 | }
227 |
228 | bool frame2jpg(camera_fb_t * fb, uint8_t quality, uint8_t ** out, size_t * out_len)
229 | {
230 | return fmt2jpg(fb->buf, fb->len, fb->width, fb->height, fb->format, quality, out, out_len);
231 | }
232 |
--------------------------------------------------------------------------------
/components/esp32-camera/driver/include/esp_camera.h:
--------------------------------------------------------------------------------
1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | /*
15 | * Example Use
16 | *
17 | static camera_config_t camera_example_config = {
18 | .pin_pwdn = PIN_PWDN,
19 | .pin_reset = PIN_RESET,
20 | .pin_xclk = PIN_XCLK,
21 | .pin_sscb_sda = PIN_SIOD,
22 | .pin_sscb_scl = PIN_SIOC,
23 | .pin_d7 = PIN_D7,
24 | .pin_d6 = PIN_D6,
25 | .pin_d5 = PIN_D5,
26 | .pin_d4 = PIN_D4,
27 | .pin_d3 = PIN_D3,
28 | .pin_d2 = PIN_D2,
29 | .pin_d1 = PIN_D1,
30 | .pin_d0 = PIN_D0,
31 | .pin_vsync = PIN_VSYNC,
32 | .pin_href = PIN_HREF,
33 | .pin_pclk = PIN_PCLK,
34 |
35 | .xclk_freq_hz = 20000000,
36 | .ledc_timer = LEDC_TIMER_0,
37 | .ledc_channel = LEDC_CHANNEL_0,
38 | .pixel_format = PIXFORMAT_JPEG,
39 | .frame_size = FRAMESIZE_SVGA,
40 | .jpeg_quality = 10,
41 | .fb_count = 2
42 | };
43 |
44 | esp_err_t camera_example_init(){
45 | return esp_camera_init(&camera_example_config);
46 | }
47 |
48 | esp_err_t camera_example_capture(){
49 | //capture a frame
50 | camera_fb_t * fb = esp_camera_fb_get();
51 | if (!fb) {
52 | ESP_LOGE(TAG, "Frame buffer could not be acquired");
53 | return ESP_FAIL;
54 | }
55 |
56 | //replace this with your own function
57 | display_image(fb->width, fb->height, fb->pixformat, fb->buf, fb->len);
58 |
59 | //return the frame buffer back to be reused
60 | esp_camera_fb_return(fb);
61 |
62 | return ESP_OK;
63 | }
64 | */
65 |
66 | #pragma once
67 |
68 | #include "esp_err.h"
69 | #include "driver/ledc.h"
70 | #include "sensor.h"
71 |
72 | #ifdef __cplusplus
73 | extern "C" {
74 | #endif
75 |
76 | /**
77 | * @brief Configuration structure for camera initialization
78 | */
79 | typedef struct {
80 | int pin_pwdn; /*!< GPIO pin for camera power down line */
81 | int pin_reset; /*!< GPIO pin for camera reset line */
82 | int pin_xclk; /*!< GPIO pin for camera XCLK line */
83 | int pin_sscb_sda; /*!< GPIO pin for camera SDA line */
84 | int pin_sscb_scl; /*!< GPIO pin for camera SCL line */
85 | int pin_d7; /*!< GPIO pin for camera D7 line */
86 | int pin_d6; /*!< GPIO pin for camera D6 line */
87 | int pin_d5; /*!< GPIO pin for camera D5 line */
88 | int pin_d4; /*!< GPIO pin for camera D4 line */
89 | int pin_d3; /*!< GPIO pin for camera D3 line */
90 | int pin_d2; /*!< GPIO pin for camera D2 line */
91 | int pin_d1; /*!< GPIO pin for camera D1 line */
92 | int pin_d0; /*!< GPIO pin for camera D0 line */
93 | int pin_vsync; /*!< GPIO pin for camera VSYNC line */
94 | int pin_href; /*!< GPIO pin for camera HREF line */
95 | int pin_pclk; /*!< GPIO pin for camera PCLK line */
96 |
97 | int xclk_freq_hz; /*!< Frequency of XCLK signal, in Hz. Either 20KHz or 10KHz for OV2640 double FPS (Experimental) */
98 |
99 | ledc_timer_t ledc_timer; /*!< LEDC timer to be used for generating XCLK */
100 | ledc_channel_t ledc_channel; /*!< LEDC channel to be used for generating XCLK */
101 |
102 | pixformat_t pixel_format; /*!< Format of the pixel data: PIXFORMAT_ + YUV422|GRAYSCALE|RGB565|JPEG */
103 | framesize_t frame_size; /*!< Size of the output image: FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA */
104 |
105 | int jpeg_quality; /*!< Quality of JPEG output. 0-63 lower means higher quality */
106 | size_t fb_count; /*!< Number of frame buffers to be allocated. If more than one, then each frame will be acquired (double speed) */
107 | } camera_config_t;
108 |
109 | /**
110 | * @brief Data structure of camera frame buffer
111 | */
112 | typedef struct {
113 | uint8_t * buf; /*!< Pointer to the pixel data */
114 | size_t len; /*!< Length of the buffer in bytes */
115 | size_t width; /*!< Width of the buffer in pixels */
116 | size_t height; /*!< Height of the buffer in pixels */
117 | pixformat_t format; /*!< Format of the pixel data */
118 | } camera_fb_t;
119 |
120 | #define ESP_ERR_CAMERA_BASE 0x20000
121 | #define ESP_ERR_CAMERA_NOT_DETECTED (ESP_ERR_CAMERA_BASE + 1)
122 | #define ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE (ESP_ERR_CAMERA_BASE + 2)
123 | #define ESP_ERR_CAMERA_FAILED_TO_SET_OUT_FORMAT (ESP_ERR_CAMERA_BASE + 3)
124 | #define ESP_ERR_CAMERA_NOT_SUPPORTED (ESP_ERR_CAMERA_BASE + 4)
125 |
126 | /**
127 | * @brief Initialize the camera driver
128 | *
129 | * @note call camera_probe before calling this function
130 | *
131 | * This function detects and configures camera over I2C interface,
132 | * allocates framebuffer and DMA buffers,
133 | * initializes parallel I2S input, and sets up DMA descriptors.
134 | *
135 | * Currently this function can only be called once and there is
136 | * no way to de-initialize this module.
137 | *
138 | * @param config Camera configuration parameters
139 | *
140 | * @return ESP_OK on success
141 | */
142 | esp_err_t esp_camera_init(const camera_config_t* config);
143 |
144 | /**
145 | * @brief Deinitialize the camera driver
146 | *
147 | * @return
148 | * - ESP_OK on success
149 | * - ESP_ERR_INVALID_STATE if the driver hasn't been initialized yet
150 | */
151 | esp_err_t esp_camera_deinit();
152 |
153 | /**
154 | * @brief Obtain pointer to a frame buffer.
155 | *
156 | * @return pointer to the frame buffer
157 | */
158 | camera_fb_t* esp_camera_fb_get();
159 |
160 | /**
161 | * @brief Return the frame buffer to be reused again.
162 | *
163 | * @param fb Pointer to the frame buffer
164 | */
165 | void esp_camera_fb_return(camera_fb_t * fb);
166 |
167 | /**
168 | * @brief Get a pointer to the image sensor control structure
169 | *
170 | * @return pointer to the sensor
171 | */
172 | sensor_t * esp_camera_sensor_get();
173 |
174 |
175 | #ifdef __cplusplus
176 | }
177 | #endif
178 |
179 | #include "img_converters.h"
180 |
181 |
--------------------------------------------------------------------------------
/components/esp32-camera/driver/include/sensor.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the OpenMV project.
3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader
4 | * This work is licensed under the MIT license, see the file LICENSE for details.
5 | *
6 | * Sensor abstraction layer.
7 | *
8 | */
9 | #ifndef __SENSOR_H__
10 | #define __SENSOR_H__
11 | #include
12 |
13 | #define OV9650_PID (0x96)
14 | #define OV2640_PID (0x26)
15 | #define OV7725_PID (0x77)
16 | #define OV3660_PID (0x36)
17 |
18 | typedef enum {
19 | PIXFORMAT_RGB565, // 2BPP/RGB565
20 | PIXFORMAT_YUV422, // 2BPP/YUV422
21 | PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE
22 | PIXFORMAT_JPEG, // JPEG/COMPRESSED
23 | PIXFORMAT_RGB888, // 3BPP/RGB888
24 | PIXFORMAT_RAW, // RAW
25 | PIXFORMAT_RGB444, // 3BP2P/RGB444
26 | PIXFORMAT_RGB555, // 3BP2P/RGB555
27 | } pixformat_t;
28 |
29 | typedef enum {
30 | FRAMESIZE_QQVGA, // 160x120
31 | FRAMESIZE_QQVGA2, // 128x160
32 | FRAMESIZE_QCIF, // 176x144
33 | FRAMESIZE_HQVGA, // 240x176
34 | FRAMESIZE_QVGA, // 320x240
35 | FRAMESIZE_CIF, // 400x296
36 | FRAMESIZE_VGA, // 640x480
37 | FRAMESIZE_SVGA, // 800x600
38 | FRAMESIZE_XGA, // 1024x768
39 | FRAMESIZE_SXGA, // 1280x1024
40 | FRAMESIZE_UXGA, // 1600x1200
41 | FRAMESIZE_QXGA, // 2048*1536
42 | FRAMESIZE_INVALID
43 | } framesize_t;
44 |
45 | typedef enum {
46 | GAINCEILING_2X,
47 | GAINCEILING_4X,
48 | GAINCEILING_8X,
49 | GAINCEILING_16X,
50 | GAINCEILING_32X,
51 | GAINCEILING_64X,
52 | GAINCEILING_128X,
53 | } gainceiling_t;
54 |
55 | typedef struct {
56 | uint8_t MIDH;
57 | uint8_t MIDL;
58 | uint8_t PID;
59 | uint8_t VER;
60 | } sensor_id_t;
61 |
62 | typedef struct {
63 | framesize_t framesize;//0 - 10
64 | uint8_t quality;//0 - 63
65 | int8_t brightness;//-2 - 2
66 | int8_t contrast;//-2 - 2
67 | int8_t saturation;//-2 - 2
68 | int8_t sharpness;//-2 - 2
69 | uint8_t denoise;
70 | uint8_t special_effect;//0 - 6
71 | uint8_t wb_mode;//0 - 4
72 | uint8_t awb;
73 | uint8_t awb_gain;
74 | uint8_t aec;
75 | uint8_t aec2;
76 | int8_t ae_level;//-2 - 2
77 | uint16_t aec_value;//0 - 1200
78 | uint8_t agc;
79 | uint8_t agc_gain;//0 - 30
80 | uint8_t gainceiling;//0 - 6
81 | uint8_t bpc;
82 | uint8_t wpc;
83 | uint8_t raw_gma;
84 | uint8_t lenc;
85 | uint8_t hmirror;
86 | uint8_t vflip;
87 | uint8_t dcw;
88 | uint8_t colorbar;
89 | } camera_status_t;
90 |
91 | typedef struct _sensor sensor_t;
92 | typedef struct _sensor {
93 | sensor_id_t id; // Sensor ID.
94 | uint8_t slv_addr; // Sensor I2C slave address.
95 | pixformat_t pixformat;
96 | camera_status_t status;
97 | int xclk_freq_hz;
98 |
99 | // Sensor function pointers
100 | int (*init_status) (sensor_t *sensor);
101 | int (*reset) (sensor_t *sensor);
102 | int (*set_pixformat) (sensor_t *sensor, pixformat_t pixformat);
103 | int (*set_framesize) (sensor_t *sensor, framesize_t framesize);
104 | int (*set_contrast) (sensor_t *sensor, int level);
105 | int (*set_brightness) (sensor_t *sensor, int level);
106 | int (*set_saturation) (sensor_t *sensor, int level);
107 | int (*set_sharpness) (sensor_t *sensor, int level);
108 | int (*set_denoise) (sensor_t *sensor, int level);
109 | int (*set_gainceiling) (sensor_t *sensor, gainceiling_t gainceiling);
110 | int (*set_quality) (sensor_t *sensor, int quality);
111 | int (*set_colorbar) (sensor_t *sensor, int enable);
112 | int (*set_whitebal) (sensor_t *sensor, int enable);
113 | int (*set_gain_ctrl) (sensor_t *sensor, int enable);
114 | int (*set_exposure_ctrl) (sensor_t *sensor, int enable);
115 | int (*set_hmirror) (sensor_t *sensor, int enable);
116 | int (*set_vflip) (sensor_t *sensor, int enable);
117 |
118 | int (*set_aec2) (sensor_t *sensor, int enable);
119 | int (*set_awb_gain) (sensor_t *sensor, int enable);
120 | int (*set_agc_gain) (sensor_t *sensor, int gain);
121 | int (*set_aec_value) (sensor_t *sensor, int gain);
122 |
123 | int (*set_special_effect) (sensor_t *sensor, int effect);
124 | int (*set_wb_mode) (sensor_t *sensor, int mode);
125 | int (*set_ae_level) (sensor_t *sensor, int level);
126 |
127 | int (*set_dcw) (sensor_t *sensor, int enable);
128 | int (*set_bpc) (sensor_t *sensor, int enable);
129 | int (*set_wpc) (sensor_t *sensor, int enable);
130 |
131 | int (*set_raw_gma) (sensor_t *sensor, int enable);
132 | int (*set_lenc) (sensor_t *sensor, int enable);
133 | } sensor_t;
134 |
135 | // Resolution table (in camera.c)
136 | extern const int resolution[][2];
137 |
138 | #endif /* __SENSOR_H__ */
139 |
--------------------------------------------------------------------------------
/components/esp32-camera/driver/private_include/camera_common.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include "rom/lldesc.h"
7 | #include "esp_err.h"
8 | #include "esp_intr_alloc.h"
9 | #include "freertos/FreeRTOS.h"
10 | #include "freertos/semphr.h"
11 | #include "freertos/task.h"
12 | #include "esp_camera.h"
13 | #include "sensor.h"
14 |
15 | typedef union {
16 | struct {
17 | uint8_t sample2;
18 | uint8_t unused2;
19 | uint8_t sample1;
20 | uint8_t unused1;
21 | };
22 | uint32_t val;
23 | } dma_elem_t;
24 |
25 | typedef enum {
26 | /* camera sends byte sequence: s1, s2, s3, s4, ...
27 | * fifo receives: 00 s1 00 s2, 00 s2 00 s3, 00 s3 00 s4, ...
28 | */
29 | SM_0A0B_0B0C = 0,
30 | /* camera sends byte sequence: s1, s2, s3, s4, ...
31 | * fifo receives: 00 s1 00 s2, 00 s3 00 s4, ...
32 | */
33 | SM_0A0B_0C0D = 1,
34 | /* camera sends byte sequence: s1, s2, s3, s4, ...
35 | * fifo receives: 00 s1 00 00, 00 s2 00 00, 00 s3 00 00, ...
36 | */
37 | SM_0A00_0B00 = 3,
38 | } i2s_sampling_mode_t;
39 |
40 |
--------------------------------------------------------------------------------
/components/esp32-camera/driver/private_include/sccb.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the OpenMV project.
3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader
4 | * This work is licensed under the MIT license, see the file LICENSE for details.
5 | *
6 | * SCCB (I2C like) driver.
7 | *
8 | */
9 | #ifndef __SCCB_H__
10 | #define __SCCB_H__
11 | #include
12 | int SCCB_Init(int pin_sda, int pin_scl);
13 | uint8_t SCCB_Probe();
14 | uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg);
15 | uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data);
16 | uint8_t SCCB_Read16(uint8_t slv_addr, uint16_t reg);
17 | uint8_t SCCB_Write16(uint8_t slv_addr, uint16_t reg, uint8_t data);
18 | #endif // __SCCB_H__
19 |
--------------------------------------------------------------------------------
/components/esp32-camera/driver/private_include/twi.h:
--------------------------------------------------------------------------------
1 | /*
2 | twi.h - Software I2C library for ESP31B
3 |
4 | Copyright (c) 2015 Hristo Gochkov. All rights reserved.
5 | This file is part of the ESP31B core for Arduino environment.
6 |
7 | This library is free software; you can redistribute it and/or
8 | modify it under the terms of the GNU Lesser General Public
9 | License as published by the Free Software Foundation; either
10 | version 2.1 of the License, or (at your option) any later version.
11 |
12 | This library is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | Lesser General Public License for more details.
16 |
17 | You should have received a copy of the GNU Lesser General Public
18 | License along with this library; if not, write to the Free Software
19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 | */
21 | #ifndef SI2C_h
22 | #define SI2C_h
23 |
24 | #ifdef __cplusplus
25 | extern "C" {
26 | #endif
27 |
28 | void twi_init(unsigned char sda, unsigned char scl);
29 | void twi_stop(void);
30 | void twi_setClock(unsigned int freq);
31 | uint8_t twi_writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop);
32 | uint8_t twi_readFrom(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop);
33 |
34 | #ifdef __cplusplus
35 | }
36 | #endif
37 |
38 | #endif
--------------------------------------------------------------------------------
/components/esp32-camera/driver/private_include/xclk.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "camera_common.h"
4 |
5 | esp_err_t camera_enable_out_clock();
6 |
7 | void camera_disable_out_clock();
8 |
--------------------------------------------------------------------------------
/components/esp32-camera/driver/sccb.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the OpenMV project.
3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader
4 | * This work is licensed under the MIT license, see the file LICENSE for details.
5 | *
6 | * SCCB (I2C like) driver.
7 | *
8 | */
9 | #include
10 | #include
11 | #include
12 | #include "sccb.h"
13 | #include
14 | #include "sdkconfig.h"
15 | #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
16 | #include "esp32-hal-log.h"
17 | #else
18 | #include "esp_log.h"
19 | static const char* TAG = "sccb";
20 | #endif
21 |
22 | #define LITTLETOBIG(x) ((x<<8)|(x>>8))
23 |
24 | #ifdef CONFIG_SCCB_HARDWARE_I2C
25 | #include "driver/i2c.h"
26 |
27 | #define SCCB_FREQ 200000 /*!< I2C master frequency*/
28 | #define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
29 | #define READ_BIT I2C_MASTER_READ /*!< I2C master read */
30 | #define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
31 | #define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
32 | #define ACK_VAL 0x0 /*!< I2C ack value */
33 | #define NACK_VAL 0x1 /*!< I2C nack value */
34 | const int SCCB_I2C_PORT = 1;
35 | static uint8_t ESP_SLAVE_ADDR = 0x3c;
36 | #else
37 | #include "twi.h"
38 | #endif
39 |
40 | int SCCB_Init(int pin_sda, int pin_scl)
41 | {
42 | ESP_LOGI(TAG, "pin_sda %d pin_scl %d\n", pin_sda, pin_scl);
43 | #ifdef CONFIG_SCCB_HARDWARE_I2C
44 | //log_i("SCCB_Init start");
45 | i2c_config_t conf;
46 | conf.mode = I2C_MODE_MASTER;
47 | conf.sda_io_num = pin_sda;
48 | conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
49 | conf.scl_io_num = pin_scl;
50 | conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
51 | conf.master.clk_speed = SCCB_FREQ;
52 |
53 | i2c_param_config(SCCB_I2C_PORT, &conf);
54 | i2c_driver_install(SCCB_I2C_PORT, conf.mode, 0, 0, 0);
55 | #else
56 | twi_init(pin_sda, pin_scl);
57 | #endif
58 | return 0;
59 | }
60 |
61 | uint8_t SCCB_Probe()
62 | {
63 | #ifdef CONFIG_SCCB_HARDWARE_I2C
64 | uint8_t slave_addr = 0x0;
65 | while(slave_addr < 0x7f) {
66 | i2c_cmd_handle_t cmd = i2c_cmd_link_create();
67 | i2c_master_start(cmd);
68 | i2c_master_write_byte(cmd, ( slave_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
69 | i2c_master_stop(cmd);
70 | esp_err_t ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
71 | i2c_cmd_link_delete(cmd);
72 | if( ret == ESP_OK) {
73 | ESP_SLAVE_ADDR = slave_addr;
74 | return ESP_SLAVE_ADDR;
75 | }
76 | slave_addr++;
77 | }
78 | return ESP_SLAVE_ADDR;
79 | #else
80 | uint8_t reg = 0x00;
81 | uint8_t slv_addr = 0x00;
82 |
83 | ESP_LOGI(TAG, "SCCB_Probe start");
84 | for (uint8_t i = 0; i < 127; i++) {
85 | if (twi_writeTo(i, ®, 1, true) == 0) {
86 | slv_addr = i;
87 | break;
88 | }
89 |
90 | if (i!=126) {
91 | vTaskDelay(10 / portTICK_PERIOD_MS); // Necessary for OV7725 camera (not for OV2640).
92 | }
93 | }
94 | return slv_addr;
95 | #endif
96 | }
97 |
98 | uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg)
99 | {
100 | #ifdef CONFIG_SCCB_HARDWARE_I2C
101 | uint8_t data=0;
102 | esp_err_t ret = ESP_FAIL;
103 | i2c_cmd_handle_t cmd = i2c_cmd_link_create();
104 | i2c_master_start(cmd);
105 | i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN);
106 | i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
107 | i2c_master_stop(cmd);
108 | ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
109 | i2c_cmd_link_delete(cmd);
110 | if(ret != ESP_OK) return -1;
111 | cmd = i2c_cmd_link_create();
112 | i2c_master_start(cmd);
113 | i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN);
114 | i2c_master_read_byte(cmd, &data, NACK_VAL);
115 | i2c_master_stop(cmd);
116 | ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
117 | i2c_cmd_link_delete(cmd);
118 | if(ret != ESP_OK) {
119 | ESP_LOGE(TAG, "SCCB_Read Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", ESP_SLAVE_ADDR, reg, data, ret);
120 | }
121 | return data;
122 | #else
123 | uint8_t data=0;
124 |
125 | int rc = twi_writeTo(slv_addr, ®, 1, true);
126 | if (rc != 0) {
127 | data = 0xff;
128 | } else {
129 | rc = twi_readFrom(slv_addr, &data, 1, true);
130 | if (rc != 0) {
131 | data=0xFF;
132 | }
133 | }
134 | if (rc != 0) {
135 | ESP_LOGE(TAG, "SCCB_Read [%02x] failed rc=%d\n", reg, rc);
136 | }
137 | return data;
138 | #endif
139 | }
140 |
141 | uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data)
142 | {
143 | #ifdef CONFIG_SCCB_HARDWARE_I2C
144 | esp_err_t ret = ESP_FAIL;
145 | i2c_cmd_handle_t cmd = i2c_cmd_link_create();
146 | i2c_master_start(cmd);
147 | i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN);
148 | i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
149 | i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
150 | i2c_master_stop(cmd);
151 | ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
152 | i2c_cmd_link_delete(cmd);
153 | if(ret != ESP_OK) {
154 | ESP_LOGE(TAG, "SCCB_Write Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", ESP_SLAVE_ADDR, reg, data, ret);
155 | }
156 | return ret == ESP_OK ? 0 : -1;
157 | #else
158 | uint8_t ret=0;
159 | uint8_t buf[] = {reg, data};
160 |
161 | if(twi_writeTo(slv_addr, buf, 2, true) != 0) {
162 | ret=0xFF;
163 | }
164 | if (ret != 0) {
165 | ESP_LOGE(TAG, "SCCB_Write [%02x]=%02x failed\n", reg, data);
166 | }
167 | return ret;
168 | #endif
169 | }
170 |
171 | uint8_t SCCB_Read16(uint8_t slv_addr, uint16_t reg)
172 | {
173 | #ifdef CONFIG_SCCB_HARDWARE_I2C
174 | uint8_t data=0;
175 | esp_err_t ret = ESP_FAIL;
176 | uint16_t reg_htons = LITTLETOBIG(reg);
177 | uint8_t *reg_u8 = (uint8_t *)®_htons;
178 | i2c_cmd_handle_t cmd = i2c_cmd_link_create();
179 | i2c_master_start(cmd);
180 | i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN);
181 | i2c_master_write_byte(cmd, reg_u8[0], ACK_CHECK_EN);
182 | i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN);
183 | i2c_master_stop(cmd);
184 | ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
185 | i2c_cmd_link_delete(cmd);
186 | if(ret != ESP_OK) return -1;
187 | cmd = i2c_cmd_link_create();
188 | i2c_master_start(cmd);
189 | i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN);
190 | i2c_master_read_byte(cmd, &data, NACK_VAL);
191 | i2c_master_stop(cmd);
192 | ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
193 | i2c_cmd_link_delete(cmd);
194 | if(ret != ESP_OK) {
195 | ESP_LOGE(TAG, "W [%04x]=%02x fail\n", reg, data);
196 | }
197 | return data;
198 | #else
199 | uint8_t data=0;
200 | uint16_t reg_htons = LITTLETOBIG(reg);
201 | uint8_t *reg_u8 = (uint8_t *)®_htons;
202 | uint8_t buf[] = {reg_u8[0], reg_u8[1]};
203 |
204 | int rc = twi_writeTo(slv_addr, buf, 2, true);
205 | if (rc != 0) {
206 | data = 0xff;
207 | } else {
208 | rc = twi_readFrom(slv_addr, &data, 1, true);
209 | if (rc != 0) {
210 | data=0xFF;
211 | }
212 | }
213 | if (rc != 0) {
214 | ESP_LOGE(TAG, "R [%04x] fail rc=%d\n", reg, rc);
215 | }
216 | return data;
217 | #endif
218 | }
219 |
220 | uint8_t SCCB_Write16(uint8_t slv_addr, uint16_t reg, uint8_t data)
221 | {
222 | static uint16_t i = 0;
223 | #ifdef CONFIG_SCCB_HARDWARE_I2C
224 | esp_err_t ret = ESP_FAIL;
225 | uint16_t reg_htons = LITTLETOBIG(reg);
226 | uint8_t *reg_u8 = (uint8_t *)®_htons;
227 | i2c_cmd_handle_t cmd = i2c_cmd_link_create();
228 | i2c_master_start(cmd);
229 | i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN);
230 | i2c_master_write_byte(cmd, reg_u8[0], ACK_CHECK_EN);
231 | i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN);
232 | i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
233 | i2c_master_stop(cmd);
234 | ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
235 | i2c_cmd_link_delete(cmd);
236 | if(ret != ESP_OK) {
237 | ESP_LOGE(TAG, "W [%04x]=%02x %d fail\n", reg, data, i++);
238 | }
239 | return ret == ESP_OK ? 0 : -1;
240 | #else
241 | uint8_t ret=0;
242 | uint16_t reg_htons = LITTLETOBIG(reg);
243 | uint8_t *reg_u8 = (uint8_t *)®_htons;
244 | uint8_t buf[] = {reg_u8[0], reg_u8[1], data};
245 |
246 | if(twi_writeTo(slv_addr, buf, 3, true) != 0) {
247 | ret = 0xFF;
248 | }
249 | if (ret != 0) {
250 | ESP_LOGE(TAG, "W [%04x]=%02x %d fail\n", reg, data, i++);
251 | }
252 | return ret;
253 | #endif
254 | }
255 |
--------------------------------------------------------------------------------
/components/esp32-camera/driver/sensor.c:
--------------------------------------------------------------------------------
1 |
2 | const int resolution[][2] = {
3 | { 160, 120 }, /* QQVGA */
4 | { 128, 160 }, /* QQVGA2*/
5 | { 176, 144 }, /* QCIF */
6 | { 240, 176 }, /* HQVGA */
7 | { 320, 240 }, /* QVGA */
8 | { 400, 296 }, /* CIF */
9 | { 640, 480 }, /* VGA */
10 | { 800, 600 }, /* SVGA */
11 | { 1024, 768 }, /* XGA */
12 | { 1280, 1024 }, /* SXGA */
13 | { 1600, 1200 }, /* UXGA */
14 | { 2048, 1536 }, /* QXGA */
15 | };
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/components/esp32-camera/driver/xclk.c:
--------------------------------------------------------------------------------
1 | #include "driver/gpio.h"
2 | #include "driver/ledc.h"
3 | #include "esp_err.h"
4 | #include "esp_log.h"
5 | #include "xclk.h"
6 |
7 | #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
8 | #include "esp32-hal-log.h"
9 | #else
10 | #include "esp_log.h"
11 | static const char* TAG = "camera_xclk";
12 | #endif
13 |
14 | esp_err_t camera_enable_out_clock(camera_config_t* config)
15 | {
16 | periph_module_enable(PERIPH_LEDC_MODULE);
17 |
18 | ledc_timer_config_t timer_conf;
19 | timer_conf.duty_resolution = 2;
20 | timer_conf.freq_hz = config->xclk_freq_hz;
21 | timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
22 | timer_conf.timer_num = config->ledc_timer;
23 | timer_conf.clk_cfg = LEDC_USE_APB_CLK;
24 | esp_err_t err = ledc_timer_config(&timer_conf);
25 | if (err != ESP_OK) {
26 | ESP_LOGE(TAG, "ledc_timer_config failed, rc=%x", err);
27 | return err;
28 | }
29 |
30 | ledc_channel_config_t ch_conf;
31 | ch_conf.gpio_num = config->pin_xclk;
32 | ch_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
33 | ch_conf.channel = config->ledc_channel;
34 | ch_conf.intr_type = LEDC_INTR_DISABLE;
35 | ch_conf.timer_sel = config->ledc_timer;
36 | ch_conf.duty = 2;
37 | ch_conf.hpoint = 0;
38 | err = ledc_channel_config(&ch_conf);
39 | if (err != ESP_OK) {
40 | ESP_LOGE(TAG, "ledc_channel_config failed, rc=%x", err);
41 | return err;
42 | }
43 | return ESP_OK;
44 | }
45 |
46 | void camera_disable_out_clock()
47 | {
48 | periph_module_disable(PERIPH_LEDC_MODULE);
49 | }
50 |
--------------------------------------------------------------------------------
/components/esp32-camera/sensors/ov7725.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the OpenMV project.
3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader
4 | * This work is licensed under the MIT license, see the file LICENSE for details.
5 | *
6 | * OV7725 driver.
7 | *
8 | */
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include "sccb.h"
14 | #include "ov7725.h"
15 | #include "ov7725_regs.h"
16 | #include "freertos/FreeRTOS.h"
17 | #include "freertos/task.h"
18 |
19 | #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
20 | #include "esp32-hal-log.h"
21 | #else
22 | #include "esp_log.h"
23 | static const char* TAG = "ov7725";
24 | #endif
25 |
26 |
27 | static const uint8_t default_regs[][2] = {
28 | {COM3, COM3_SWAP_YUV},
29 | {COM7, COM7_RES_QVGA | COM7_FMT_YUV},
30 |
31 | {COM4, 0x01}, /* bypass PLL */
32 | {CLKRC, 0xC0}, /* Res/Bypass pre-scalar */
33 |
34 | // QVGA Window Size
35 | {HSTART, 0x3F},
36 | {HSIZE, 0x50},
37 | {VSTART, 0x03},
38 | {VSIZE, 0x78},
39 | {HREF, 0x00},
40 |
41 | // Scale down to QVGA Resolution
42 | {HOUTSIZE, 0x50},
43 | {VOUTSIZE, 0x78},
44 |
45 | {COM12, 0x03},
46 | {EXHCH, 0x00},
47 | {TGT_B, 0x7F},
48 | {FIXGAIN, 0x09},
49 | {AWB_CTRL0, 0xE0},
50 | {DSP_CTRL1, 0xFF},
51 |
52 | {DSP_CTRL2, DSP_CTRL2_VDCW_EN | DSP_CTRL2_HDCW_EN | DSP_CTRL2_HZOOM_EN | DSP_CTRL2_VZOOM_EN},
53 |
54 | {DSP_CTRL3, 0x00},
55 | {DSP_CTRL4, 0x00},
56 | {DSPAUTO, 0xFF},
57 |
58 | {COM8, 0xF0},
59 | {COM6, 0xC5},
60 | {COM9, 0x11},
61 | {COM10, COM10_VSYNC_NEG | COM10_PCLK_MASK}, //Invert VSYNC and MASK PCLK
62 | {BDBASE, 0x7F},
63 | {DBSTEP, 0x03},
64 | {AEW, 0x96},
65 | {AEB, 0x64},
66 | {VPT, 0xA1},
67 | {EXHCL, 0x00},
68 | {AWB_CTRL3, 0xAA},
69 | {COM8, 0xFF},
70 |
71 | //Gamma
72 | {GAM1, 0x0C},
73 | {GAM2, 0x16},
74 | {GAM3, 0x2A},
75 | {GAM4, 0x4E},
76 | {GAM5, 0x61},
77 | {GAM6, 0x6F},
78 | {GAM7, 0x7B},
79 | {GAM8, 0x86},
80 | {GAM9, 0x8E},
81 | {GAM10, 0x97},
82 | {GAM11, 0xA4},
83 | {GAM12, 0xAF},
84 | {GAM13, 0xC5},
85 | {GAM14, 0xD7},
86 | {GAM15, 0xE8},
87 |
88 | {SLOP, 0x20},
89 | {EDGE1, 0x05},
90 | {EDGE2, 0x03},
91 | {EDGE3, 0x00},
92 | {DNSOFF, 0x01},
93 |
94 | {MTX1, 0xB0},
95 | {MTX2, 0x9D},
96 | {MTX3, 0x13},
97 | {MTX4, 0x16},
98 | {MTX5, 0x7B},
99 | {MTX6, 0x91},
100 | {MTX_CTRL, 0x1E},
101 |
102 | {BRIGHTNESS, 0x08},
103 | {CONTRAST, 0x30},
104 | {UVADJ0, 0x81},
105 | {SDE, (SDE_CONT_BRIGHT_EN | SDE_SATURATION_EN)},
106 |
107 | // For 30 fps/60Hz
108 | {DM_LNL, 0x00},
109 | {DM_LNH, 0x00},
110 | {BDBASE, 0x7F},
111 | {DBSTEP, 0x03},
112 |
113 | // Lens Correction, should be tuned with real camera module
114 | {LC_RADI, 0x10},
115 | {LC_COEF, 0x10},
116 | {LC_COEFB, 0x14},
117 | {LC_COEFR, 0x17},
118 | {LC_CTR, 0x05},
119 | {COM5, 0xF5}, //0x65
120 |
121 | {0x00, 0x00},
122 | };
123 |
124 |
125 | static int reset(sensor_t *sensor)
126 | {
127 | int i=0;
128 | const uint8_t (*regs)[2];
129 |
130 | // Reset all registers
131 | SCCB_Write(sensor->slv_addr, COM7, COM7_RESET);
132 |
133 | // Delay 10 ms
134 | vTaskDelay(10 / portTICK_PERIOD_MS);
135 |
136 | // Write default regsiters
137 | for (i=0, regs = default_regs; regs[i][0]; i++) {
138 | SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]);
139 | }
140 |
141 | // Delay
142 | vTaskDelay(30 / portTICK_PERIOD_MS);
143 |
144 | return 0;
145 | }
146 |
147 |
148 | static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
149 | {
150 | int ret=0;
151 | // Read register COM7
152 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM7);
153 |
154 | switch (pixformat) {
155 | case PIXFORMAT_RGB565:
156 | reg = COM7_SET_RGB(reg, COM7_FMT_RGB565);
157 | break;
158 | case PIXFORMAT_YUV422:
159 | case PIXFORMAT_GRAYSCALE:
160 | reg = COM7_SET_FMT(reg, COM7_FMT_YUV);
161 | break;
162 | default:
163 | return -1;
164 | }
165 |
166 | // Write back register COM7
167 | ret = SCCB_Write(sensor->slv_addr, COM7, reg);
168 |
169 | // Delay
170 | vTaskDelay(30 / portTICK_PERIOD_MS);
171 |
172 | return ret;
173 | }
174 |
175 | static int set_framesize(sensor_t *sensor, framesize_t framesize)
176 | {
177 | int ret=0;
178 | uint16_t w = resolution[framesize][0];
179 | uint16_t h = resolution[framesize][1];
180 |
181 | // Write MSBs
182 | ret |= SCCB_Write(sensor->slv_addr, HOUTSIZE, w>>2);
183 | ret |= SCCB_Write(sensor->slv_addr, VOUTSIZE, h>>1);
184 |
185 | // Write LSBs
186 | ret |= SCCB_Write(sensor->slv_addr, EXHCH, ((w&0x3) | ((h&0x1) << 2)));
187 |
188 | if (framesize < FRAMESIZE_VGA) {
189 | // Enable auto-scaling/zooming factors
190 | ret |= SCCB_Write(sensor->slv_addr, DSPAUTO, 0xFF);
191 | } else {
192 | // Disable auto-scaling/zooming factors
193 | ret |= SCCB_Write(sensor->slv_addr, DSPAUTO, 0xF3);
194 |
195 | // Clear auto-scaling/zooming factors
196 | ret |= SCCB_Write(sensor->slv_addr, SCAL0, 0x00);
197 | ret |= SCCB_Write(sensor->slv_addr, SCAL1, 0x00);
198 | ret |= SCCB_Write(sensor->slv_addr, SCAL2, 0x00);
199 | }
200 |
201 | // Delay
202 | vTaskDelay(30 / portTICK_PERIOD_MS);
203 |
204 | return ret;
205 | }
206 |
207 | static int set_colorbar(sensor_t *sensor, int enable)
208 | {
209 | int ret=0;
210 | uint8_t reg;
211 |
212 | // Read reg COM3
213 | reg = SCCB_Read(sensor->slv_addr, COM3);
214 | // Enable colorbar test pattern output
215 | reg = COM3_SET_CBAR(reg, enable);
216 | // Write back COM3
217 | ret |= SCCB_Write(sensor->slv_addr, COM3, reg);
218 |
219 | // Read reg DSP_CTRL3
220 | reg = SCCB_Read(sensor->slv_addr, DSP_CTRL3);
221 | // Enable DSP colorbar output
222 | reg = DSP_CTRL3_SET_CBAR(reg, enable);
223 | // Write back DSP_CTRL3
224 | ret |= SCCB_Write(sensor->slv_addr, DSP_CTRL3, reg);
225 |
226 | return ret;
227 | }
228 |
229 | static int set_whitebal(sensor_t *sensor, int enable)
230 | {
231 | // Read register COM8
232 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM8);
233 |
234 | // Set white bal on/off
235 | reg = COM8_SET_AWB(reg, enable);
236 |
237 | // Write back register COM8
238 | return SCCB_Write(sensor->slv_addr, COM8, reg);
239 | }
240 |
241 | static int set_gain_ctrl(sensor_t *sensor, int enable)
242 | {
243 | // Read register COM8
244 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM8);
245 |
246 | // Set white bal on/off
247 | reg = COM8_SET_AGC(reg, enable);
248 |
249 | // Write back register COM8
250 | return SCCB_Write(sensor->slv_addr, COM8, reg);
251 | }
252 |
253 | static int set_exposure_ctrl(sensor_t *sensor, int enable)
254 | {
255 | // Read register COM8
256 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM8);
257 |
258 | // Set white bal on/off
259 | reg = COM8_SET_AEC(reg, enable);
260 |
261 | // Write back register COM8
262 | return SCCB_Write(sensor->slv_addr, COM8, reg);
263 | }
264 |
265 | static int set_hmirror(sensor_t *sensor, int enable)
266 | {
267 | // Read register COM3
268 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM3);
269 |
270 | // Set mirror on/off
271 | reg = COM3_SET_MIRROR(reg, enable);
272 |
273 | // Write back register COM3
274 | return SCCB_Write(sensor->slv_addr, COM3, reg);
275 | }
276 |
277 | static int set_vflip(sensor_t *sensor, int enable)
278 | {
279 | // Read register COM3
280 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM3);
281 |
282 | // Set mirror on/off
283 | reg = COM3_SET_FLIP(reg, enable);
284 |
285 | // Write back register COM3
286 | return SCCB_Write(sensor->slv_addr, COM3, reg);
287 | }
288 |
289 | int ov7725_init(sensor_t *sensor)
290 | {
291 | // Set function pointers
292 | sensor->reset = reset;
293 | sensor->set_pixformat = set_pixformat;
294 | sensor->set_framesize = set_framesize;
295 | sensor->set_colorbar = set_colorbar;
296 | sensor->set_whitebal = set_whitebal;
297 | sensor->set_gain_ctrl = set_gain_ctrl;
298 | sensor->set_exposure_ctrl = set_exposure_ctrl;
299 | sensor->set_hmirror = set_hmirror;
300 | sensor->set_vflip = set_vflip;
301 |
302 | // Retrieve sensor's signature
303 | sensor->id.MIDH = SCCB_Read(sensor->slv_addr, REG_MIDH);
304 | sensor->id.MIDL = SCCB_Read(sensor->slv_addr, REG_MIDL);
305 | sensor->id.PID = SCCB_Read(sensor->slv_addr, REG_PID);
306 | sensor->id.VER = SCCB_Read(sensor->slv_addr, REG_VER);
307 |
308 | ESP_LOGD(TAG, "OV7725 Attached");
309 |
310 | return 0;
311 | }
312 |
--------------------------------------------------------------------------------
/components/esp32-camera/sensors/private_include/ov2640.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the OpenMV project.
3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader
4 | * This work is licensed under the MIT license, see the file LICENSE for details.
5 | *
6 | * OV2640 driver.
7 | *
8 | */
9 | #ifndef __OV2640_H__
10 | #define __OV2640_H__
11 | #include "sensor.h"
12 | int ov2640_init(sensor_t *sensor);
13 | #endif // __OV2640_H__
14 |
--------------------------------------------------------------------------------
/components/esp32-camera/sensors/private_include/ov2640_regs.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the OpenMV project.
3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader
4 | * This work is licensed under the MIT license, see the file LICENSE for details.
5 | *
6 | * OV2640 register definitions.
7 | */
8 | #ifndef __REG_REGS_H__
9 | #define __REG_REGS_H__
10 | /* DSP register bank FF=0x00*/
11 | #define R_BYPASS 0x05
12 | #define QS 0x44
13 | #define CTRLI 0x50
14 | #define HSIZE 0x51
15 | #define VSIZE 0x52
16 | #define XOFFL 0x53
17 | #define YOFFL 0x54
18 | #define VHYX 0x55
19 | #define DPRP 0x56
20 | #define TEST 0x57
21 | #define ZMOW 0x5A
22 | #define ZMOH 0x5B
23 | #define ZMHH 0x5C
24 | #define BPADDR 0x7C
25 | #define BPDATA 0x7D
26 | #define CTRL2 0x86
27 | #define CTRL3 0x87
28 | #define SIZEL 0x8C
29 | #define HSIZE8 0xC0
30 | #define VSIZE8 0xC1
31 | #define CTRL0 0xC2
32 | #define CTRL1 0xC3
33 | #define R_DVP_SP 0xD3
34 | #define IMAGE_MODE 0xDA
35 | #define RESET 0xE0
36 | #define MS_SP 0xF0
37 | #define SS_ID 0xF7
38 | #define SS_CTRL 0xF7
39 | #define MC_BIST 0xF9
40 | #define MC_AL 0xFA
41 | #define MC_AH 0xFB
42 | #define MC_D 0xFC
43 | #define P_CMD 0xFD
44 | #define P_STATUS 0xFE
45 | #define BANK_SEL 0xFF
46 |
47 | #define CTRLI_LP_DP 0x80
48 | #define CTRLI_ROUND 0x40
49 |
50 | #define CTRL0_AEC_EN 0x80
51 | #define CTRL0_AEC_SEL 0x40
52 | #define CTRL0_STAT_SEL 0x20
53 | #define CTRL0_VFIRST 0x10
54 | #define CTRL0_YUV422 0x08
55 | #define CTRL0_YUV_EN 0x04
56 | #define CTRL0_RGB_EN 0x02
57 | #define CTRL0_RAW_EN 0x01
58 |
59 | #define CTRL2_DCW_EN 0x20
60 | #define CTRL2_SDE_EN 0x10
61 | #define CTRL2_UV_ADJ_EN 0x08
62 | #define CTRL2_UV_AVG_EN 0x04
63 | #define CTRL2_CMX_EN 0x01
64 |
65 | #define CTRL3_BPC_EN 0x80
66 | #define CTRL3_WPC_EN 0x40
67 |
68 | #define R_DVP_SP_AUTO_MODE 0x80
69 |
70 | #define R_BYPASS_DSP_EN 0x00
71 | #define R_BYPASS_DSP_BYPAS 0x01
72 |
73 | #define IMAGE_MODE_Y8_DVP_EN 0x40
74 | #define IMAGE_MODE_JPEG_EN 0x10
75 | #define IMAGE_MODE_YUV422 0x00
76 | #define IMAGE_MODE_RAW10 0x04
77 | #define IMAGE_MODE_RGB565 0x08
78 | #define IMAGE_MODE_HREF_VSYNC 0x02
79 | #define IMAGE_MODE_LBYTE_FIRST 0x01
80 |
81 | #define RESET_MICROC 0x40
82 | #define RESET_SCCB 0x20
83 | #define RESET_JPEG 0x10
84 | #define RESET_DVP 0x04
85 | #define RESET_IPU 0x02
86 | #define RESET_CIF 0x01
87 |
88 | #define MC_BIST_RESET 0x80
89 | #define MC_BIST_BOOT_ROM_SEL 0x40
90 | #define MC_BIST_12KB_SEL 0x20
91 | #define MC_BIST_12KB_MASK 0x30
92 | #define MC_BIST_512KB_SEL 0x08
93 | #define MC_BIST_512KB_MASK 0x0C
94 | #define MC_BIST_BUSY_BIT_R 0x02
95 | #define MC_BIST_MC_RES_ONE_SH_W 0x02
96 | #define MC_BIST_LAUNCH 0x01
97 |
98 |
99 | typedef enum {
100 | BANK_DSP, BANK_SENSOR, BANK_MAX
101 | } ov2640_bank_t;
102 |
103 | /* Sensor register bank FF=0x01*/
104 | #define GAIN 0x00
105 | #define COM1 0x03
106 | #define REG04 0x04
107 | #define REG08 0x08
108 | #define COM2 0x09
109 | #define REG_PID 0x0A
110 | #define REG_VER 0x0B
111 | #define COM3 0x0C
112 | #define COM4 0x0D
113 | #define AEC 0x10
114 | #define CLKRC 0x11
115 | #define COM7 0x12
116 | #define COM8 0x13
117 | #define COM9 0x14 /* AGC gain ceiling */
118 | #define COM10 0x15
119 | #define HSTART 0x17
120 | #define HSTOP 0x18
121 | #define VSTART 0x19
122 | #define VSTOP 0x1A
123 | #define MIDH 0x1C
124 | #define MIDL 0x1D
125 | #define AEW 0x24
126 | #define AEB 0x25
127 | #define VV 0x26
128 | #define REG2A 0x2A
129 | #define FRARL 0x2B
130 | #define ADDVSL 0x2D
131 | #define ADDVSH 0x2E
132 | #define YAVG 0x2F
133 | #define HSDY 0x30
134 | #define HEDY 0x31
135 | #define REG32 0x32
136 | #define ARCOM2 0x34
137 | #define REG45 0x45
138 | #define FLL 0x46
139 | #define FLH 0x47
140 | #define COM19 0x48
141 | #define ZOOMS 0x49
142 | #define COM22 0x4B
143 | #define COM25 0x4E
144 | #define BD50 0x4F
145 | #define BD60 0x50
146 | #define REG5D 0x5D
147 | #define REG5E 0x5E
148 | #define REG5F 0x5F
149 | #define REG60 0x60
150 | #define HISTO_LOW 0x61
151 | #define HISTO_HIGH 0x62
152 |
153 | #define REG04_DEFAULT 0x28
154 | #define REG04_HFLIP_IMG 0x80
155 | #define REG04_VFLIP_IMG 0x40
156 | #define REG04_VREF_EN 0x10
157 | #define REG04_HREF_EN 0x08
158 | #define REG04_SET(x) (REG04_DEFAULT|x)
159 |
160 | #define COM2_STDBY 0x10
161 | #define COM2_OUT_DRIVE_1x 0x00
162 | #define COM2_OUT_DRIVE_2x 0x01
163 | #define COM2_OUT_DRIVE_3x 0x02
164 | #define COM2_OUT_DRIVE_4x 0x03
165 |
166 | #define COM3_DEFAULT 0x38
167 | #define COM3_BAND_50Hz 0x04
168 | #define COM3_BAND_60Hz 0x00
169 | #define COM3_BAND_AUTO 0x02
170 | #define COM3_BAND_SET(x) (COM3_DEFAULT|x)
171 |
172 | #define COM7_SRST 0x80
173 | #define COM7_RES_UXGA 0x00 /* UXGA */
174 | #define COM7_RES_SVGA 0x40 /* SVGA */
175 | #define COM7_RES_CIF 0x20 /* CIF */
176 | #define COM7_ZOOM_EN 0x04 /* Enable Zoom */
177 | #define COM7_COLOR_BAR 0x02 /* Enable Color Bar Test */
178 |
179 | #define COM8_DEFAULT 0xC0
180 | #define COM8_BNDF_EN 0x20 /* Enable Banding filter */
181 | #define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */
182 | #define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */
183 | #define COM8_SET(x) (COM8_DEFAULT|x)
184 |
185 | #define COM9_DEFAULT 0x08
186 | #define COM9_AGC_GAIN_2x 0x00 /* AGC: 2x */
187 | #define COM9_AGC_GAIN_4x 0x01 /* AGC: 4x */
188 | #define COM9_AGC_GAIN_8x 0x02 /* AGC: 8x */
189 | #define COM9_AGC_GAIN_16x 0x03 /* AGC: 16x */
190 | #define COM9_AGC_GAIN_32x 0x04 /* AGC: 32x */
191 | #define COM9_AGC_GAIN_64x 0x05 /* AGC: 64x */
192 | #define COM9_AGC_GAIN_128x 0x06 /* AGC: 128x */
193 | #define COM9_AGC_SET(x) (COM9_DEFAULT|(x<<5))
194 |
195 | #define COM10_HREF_EN 0x80 /* HSYNC changes to HREF */
196 | #define COM10_HSYNC_EN 0x40 /* HREF changes to HSYNC */
197 | #define COM10_PCLK_FREE 0x20 /* PCLK output option: free running PCLK */
198 | #define COM10_PCLK_EDGE 0x10 /* Data is updated at the rising edge of PCLK */
199 | #define COM10_HREF_NEG 0x08 /* HREF negative */
200 | #define COM10_VSYNC_NEG 0x02 /* VSYNC negative */
201 | #define COM10_HSYNC_NEG 0x01 /* HSYNC negative */
202 |
203 | #define CTRL1_AWB 0x08 /* Enable AWB */
204 |
205 | #define VV_AGC_TH_SET(h,l) ((h<<4)|(l&0x0F))
206 |
207 | #define REG32_UXGA 0x36
208 | #define REG32_SVGA 0x09
209 | #define REG32_CIF 0x89
210 |
211 | #define CLKRC_2X 0x80
212 | #define CLKRC_2X_UXGA (0x01 | CLKRC_2X)
213 | #define CLKRC_2X_SVGA CLKRC_2X
214 | #define CLKRC_2X_CIF CLKRC_2X
215 |
216 | #endif //__REG_REGS_H__
217 |
--------------------------------------------------------------------------------
/components/esp32-camera/sensors/private_include/ov2640_settings.h:
--------------------------------------------------------------------------------
1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | #ifndef _OV2640_SETTINGS_H_
15 | #define _OV2640_SETTINGS_H_
16 |
17 | #include
18 | #include
19 | #include "esp_attr.h"
20 | #include "ov2640_regs.h"
21 |
22 | // 30fps@24MHz
23 | const DRAM_ATTR uint8_t ov2640_settings_cif[][2] = {
24 | {BANK_SEL, BANK_DSP},
25 | {0x2c, 0xff},
26 | {0x2e, 0xdf},
27 | {BANK_SEL, BANK_SENSOR},
28 | {0x3c, 0x32},
29 | {CLKRC, 0x01},
30 | {COM2, COM2_OUT_DRIVE_3x},
31 | {REG04, REG04_DEFAULT},
32 | {COM8, COM8_DEFAULT | COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN},
33 | {COM9, COM9_AGC_SET(COM9_AGC_GAIN_8x)},
34 | {0x2c, 0x0c},
35 | {0x33, 0x78},
36 | {0x3a, 0x33},
37 | {0x3b, 0xfB},
38 | {0x3e, 0x00},
39 | {0x43, 0x11},
40 | {0x16, 0x10},
41 | {0x39, 0x92},
42 | {0x35, 0xda},
43 | {0x22, 0x1a},
44 | {0x37, 0xc3},
45 | {0x23, 0x00},
46 | {ARCOM2, 0xc0},
47 | {0x06, 0x88},
48 | {0x07, 0xc0},
49 | {COM4, 0x87},
50 | {0x0e, 0x41},
51 | {0x4c, 0x00},
52 | {0x4a, 0x81},
53 | {0x21, 0x99},
54 | {AEW, 0x40},
55 | {AEB, 0x38},
56 | {VV, VV_AGC_TH_SET(8,2)},
57 | {0x5c, 0x00},
58 | {0x63, 0x00},
59 | {HISTO_LOW, 0x70},
60 | {HISTO_HIGH, 0x80},
61 | {0x7c, 0x05},
62 | {0x20, 0x80},
63 | {0x28, 0x30},
64 | {0x6c, 0x00},
65 | {0x6d, 0x80},
66 | {0x6e, 0x00},
67 | {0x70, 0x02},
68 | {0x71, 0x94},
69 | {0x73, 0xc1},
70 | {0x3d, 0x34},
71 | {0x5a, 0x57},
72 | {BD50, 0xbb},
73 | {BD60, 0x9c},
74 | {COM7, COM7_RES_CIF},
75 | {HSTART, 0x11},
76 | {HSTOP, 0x43},
77 | {VSTART, 0x00},
78 | {VSTOP, 0x25},
79 | {REG32, 0x89},
80 | {0x37, 0xc0},
81 | {BD50, 0xca},
82 | {BD60, 0xa8},
83 | {0x6d, 0x00},
84 | {0x3d, 0x38},
85 | {BANK_SEL, BANK_DSP},
86 | {0xe5, 0x7f},
87 | {MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL},
88 | {0x41, 0x24},
89 | {RESET, RESET_JPEG | RESET_DVP},
90 | {0x76, 0xff},
91 | {0x33, 0xa0},
92 | {0x42, 0x20},
93 | {0x43, 0x18},
94 | {0x4c, 0x00},
95 | {CTRL3, CTRL3_WPC_EN | 0x10 },
96 | {0x88, 0x3f},
97 | {0xd7, 0x03},
98 | {0xd9, 0x10},
99 | {R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x02},
100 | {0xc8, 0x08},
101 | {0xc9, 0x80},
102 | {BPADDR, 0x00},
103 | {BPDATA, 0x00},
104 | {BPADDR, 0x03},
105 | {BPDATA, 0x48},
106 | {BPDATA, 0x48},
107 | {BPADDR, 0x08},
108 | {BPDATA, 0x20},
109 | {BPDATA, 0x10},
110 | {BPDATA, 0x0e},
111 | {0x90, 0x00},
112 | {0x91, 0x0e},
113 | {0x91, 0x1a},
114 | {0x91, 0x31},
115 | {0x91, 0x5a},
116 | {0x91, 0x69},
117 | {0x91, 0x75},
118 | {0x91, 0x7e},
119 | {0x91, 0x88},
120 | {0x91, 0x8f},
121 | {0x91, 0x96},
122 | {0x91, 0xa3},
123 | {0x91, 0xaf},
124 | {0x91, 0xc4},
125 | {0x91, 0xd7},
126 | {0x91, 0xe8},
127 | {0x91, 0x20},
128 | {0x92, 0x00},
129 | {0x93, 0x06},
130 | {0x93, 0xe3},
131 | {0x93, 0x05},
132 | {0x93, 0x05},
133 | {0x93, 0x00},
134 | {0x93, 0x04},
135 | {0x93, 0x00},
136 | {0x93, 0x00},
137 | {0x93, 0x00},
138 | {0x93, 0x00},
139 | {0x93, 0x00},
140 | {0x93, 0x00},
141 | {0x93, 0x00},
142 | {0x96, 0x00},
143 | {0x97, 0x08},
144 | {0x97, 0x19},
145 | {0x97, 0x02},
146 | {0x97, 0x0c},
147 | {0x97, 0x24},
148 | {0x97, 0x30},
149 | {0x97, 0x28},
150 | {0x97, 0x26},
151 | {0x97, 0x02},
152 | {0x97, 0x98},
153 | {0x97, 0x80},
154 | {0x97, 0x00},
155 | {0x97, 0x00},
156 | {0xa4, 0x00},
157 | {0xa8, 0x00},
158 | {0xc5, 0x11},
159 | {0xc6, 0x51},
160 | {0xbf, 0x80},
161 | {0xc7, 0x10},
162 | {0xb6, 0x66},
163 | {0xb8, 0xA5},
164 | {0xb7, 0x64},
165 | {0xb9, 0x7C},
166 | {0xb3, 0xaf},
167 | {0xb4, 0x97},
168 | {0xb5, 0xFF},
169 | {0xb0, 0xC5},
170 | {0xb1, 0x94},
171 | {0xb2, 0x0f},
172 | {0xc4, 0x5c},
173 | {CTRL1, 0xfd},
174 | {0x7f, 0x00},
175 | {0xe5, 0x1f},
176 | {0xe1, 0x67},
177 | {0xdd, 0x7f},
178 | {IMAGE_MODE, 0x00},
179 | {RESET, 0x00},
180 | {R_BYPASS, R_BYPASS_DSP_EN},
181 | {0, 0}
182 | };
183 |
184 | const DRAM_ATTR uint8_t ov2640_settings_to_cif[][2] = {
185 | {BANK_SEL, BANK_SENSOR},
186 | {COM7, COM7_RES_CIF},
187 |
188 | //Set the sensor output window
189 | {COM1, 0x0A},
190 | {REG32, REG32_CIF},
191 | {HSTART, 0x11},
192 | {HSTOP, 0x43},
193 | {VSTART, 0x00},
194 | {VSTOP, 0x25},
195 |
196 | {CLKRC, 0x01},
197 | {BD50, 0xca},
198 | {BD60, 0xa8},
199 | {0x5a, 0x23},
200 | {0x6d, 0x00},
201 | {0x3d, 0x38},
202 | {0x39, 0x92},
203 | {0x35, 0xda},
204 | {0x22, 0x1a},
205 | {0x37, 0xc3},
206 | {0x23, 0x00},
207 | {ARCOM2, 0xc0},
208 | {0x06, 0x88},
209 | {0x07, 0xc0},
210 | {COM4, 0x87},
211 | {0x0e, 0x41},
212 | {0x4c, 0x00},
213 | {BANK_SEL, BANK_DSP},
214 | {RESET, RESET_DVP},
215 |
216 | //Set the sensor resolution (UXGA, SVGA, CIF)
217 | {HSIZE8, 0x32},
218 | {VSIZE8, 0x25},
219 | {SIZEL, 0x00},
220 |
221 | //Set the image window size >= output size
222 | {HSIZE, 0x64},
223 | {VSIZE, 0x4a},
224 | {XOFFL, 0x00},
225 | {YOFFL, 0x00},
226 | {VHYX, 0x00},
227 | {TEST, 0x00},
228 |
229 | {CTRL2, CTRL2_DCW_EN | 0x1D},
230 | {CTRLI, CTRLI_LP_DP | 0x00},
231 | {R_DVP_SP, 0x82},
232 | {0, 0}
233 | };
234 |
235 | const DRAM_ATTR uint8_t ov2640_settings_to_svga[][2] = {
236 | {BANK_SEL, BANK_SENSOR},
237 | {COM7, COM7_RES_SVGA},
238 |
239 | //Set the sensor output window
240 | {COM1, 0x0A},
241 | {REG32, REG32_SVGA},
242 | {HSTART, 0x11},
243 | {HSTOP, 0x43},
244 | {VSTART, 0x00},
245 | {VSTOP, 0x4b},
246 |
247 | {CLKRC, 0x01},
248 | {0x37, 0xc0},
249 | {BD50, 0xca},
250 | {BD60, 0xa8},
251 | {0x5a, 0x23},
252 | {0x6d, 0x00},
253 | {0x3d, 0x38},
254 | {0x39, 0x92},
255 | {0x35, 0xda},
256 | {0x22, 0x1a},
257 | {0x37, 0xc3},
258 | {0x23, 0x00},
259 | {ARCOM2, 0xc0},
260 | {0x06, 0x88},
261 | {0x07, 0xc0},
262 | {COM4, 0x87},
263 | {0x0e, 0x41},
264 | {0x42, 0x03},
265 | {0x4c, 0x00},
266 | {BANK_SEL, BANK_DSP},
267 | {RESET, RESET_DVP},
268 |
269 | //Set the sensor resolution (UXGA, SVGA, CIF)
270 | {HSIZE8, 0x64},
271 | {VSIZE8, 0x4B},
272 | {SIZEL, 0x00},
273 |
274 | //Set the image window size >= output size
275 | {HSIZE, 0xC8},
276 | {VSIZE, 0x96},
277 | {XOFFL, 0x00},
278 | {YOFFL, 0x00},
279 | {VHYX, 0x00},
280 | {TEST, 0x00},
281 |
282 | {CTRL2, CTRL2_DCW_EN | 0x1D},
283 | {CTRLI, CTRLI_LP_DP | 0x00},
284 | {R_DVP_SP, 0x80},
285 | {0, 0}
286 | };
287 |
288 | const DRAM_ATTR uint8_t ov2640_settings_to_uxga[][2] = {
289 | {BANK_SEL, BANK_SENSOR},
290 | {COM7, COM7_RES_UXGA},
291 |
292 | //Set the sensor output window
293 | {COM1, 0x0F},
294 | {REG32, REG32_UXGA},
295 | {HSTART, 0x11},
296 | {HSTOP, 0x75},
297 | {VSTART, 0x01},
298 | {VSTOP, 0x97},
299 |
300 | {CLKRC, 0x01},
301 | {0x3d, 0x34},
302 | {BD50, 0xbb},
303 | {BD60, 0x9c},
304 | {0x5a, 0x57},
305 | {0x6d, 0x80},
306 | {0x39, 0x82},
307 | {0x23, 0x00},
308 | {0x07, 0xc0},
309 | {0x4c, 0x00},
310 | {0x35, 0x88},
311 | {0x22, 0x0a},
312 | {0x37, 0x40},
313 | {ARCOM2, 0xa0},
314 | {0x06, 0x02},
315 | {COM4, 0xb7},
316 | {0x0e, 0x01},
317 | {0x42, 0x83},
318 | {BANK_SEL, BANK_DSP},
319 | {RESET, RESET_DVP},
320 |
321 | //Set the sensor resolution (UXGA, SVGA, CIF)
322 | {HSIZE8, 0xc8},
323 | {VSIZE8, 0x96},
324 | {SIZEL, 0x00},
325 |
326 | //Set the image window size >= output size
327 | {HSIZE, 0x90},
328 | {VSIZE, 0x2c},
329 | {XOFFL, 0x00},
330 | {YOFFL, 0x00},
331 | {VHYX, 0x88},
332 | {TEST, 0x00},
333 |
334 | {CTRL2, CTRL2_DCW_EN | 0x1d},
335 | {CTRLI, 0x00},
336 | {R_DVP_SP, 0x82},
337 | {0, 0}
338 | };
339 |
340 | const DRAM_ATTR uint8_t ov2640_settings_jpeg3[][2] = {
341 | {BANK_SEL, BANK_DSP},
342 | {RESET, RESET_JPEG | RESET_DVP},
343 | {IMAGE_MODE, IMAGE_MODE_JPEG_EN | IMAGE_MODE_HREF_VSYNC},
344 | {0xD7, 0x03},
345 | {0xE1, 0x77},
346 | {0xE5, 0x1F},
347 | {0xD9, 0x10},
348 | {0xDF, 0x80},
349 | {0x33, 0x80},
350 | {0x3C, 0x10},
351 | {R_DVP_SP, 0x04},
352 | {0xEB, 0x30},
353 | {0xDD, 0x7F},
354 | {RESET, 0x00},
355 | {0, 0}
356 | };
357 |
358 | static const uint8_t ov2640_settings_yuv422[][2] = {
359 | {BANK_SEL, BANK_DSP},
360 | {RESET, RESET_DVP},
361 | {IMAGE_MODE, IMAGE_MODE_YUV422},
362 | {0xD7, 0x01},
363 | {0xE1, 0x67},
364 | {RESET, 0x00},
365 | {0, 0},
366 | };
367 |
368 | static const uint8_t ov2640_settings_rgb565[][2] = {
369 | {BANK_SEL, BANK_DSP},
370 | {RESET, RESET_DVP},
371 | {IMAGE_MODE, IMAGE_MODE_RGB565},
372 | {0xD7, 0x03},
373 | {0xE1, 0x77},
374 | {RESET, 0x00},
375 | {0, 0},
376 | };
377 |
378 | #define NUM_BRIGHTNESS_LEVELS (5)
379 | static const uint8_t brightness_regs[NUM_BRIGHTNESS_LEVELS + 1][5] = {
380 | {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA },
381 | {0x00, 0x04, 0x09, 0x00, 0x00 }, /* -2 */
382 | {0x00, 0x04, 0x09, 0x10, 0x00 }, /* -1 */
383 | {0x00, 0x04, 0x09, 0x20, 0x00 }, /* 0 */
384 | {0x00, 0x04, 0x09, 0x30, 0x00 }, /* +1 */
385 | {0x00, 0x04, 0x09, 0x40, 0x00 }, /* +2 */
386 | };
387 |
388 | #define NUM_CONTRAST_LEVELS (5)
389 | static const uint8_t contrast_regs[NUM_CONTRAST_LEVELS + 1][7] = {
390 | {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA, BPDATA, BPDATA },
391 | {0x00, 0x04, 0x07, 0x20, 0x18, 0x34, 0x06 }, /* -2 */
392 | {0x00, 0x04, 0x07, 0x20, 0x1c, 0x2a, 0x06 }, /* -1 */
393 | {0x00, 0x04, 0x07, 0x20, 0x20, 0x20, 0x06 }, /* 0 */
394 | {0x00, 0x04, 0x07, 0x20, 0x24, 0x16, 0x06 }, /* +1 */
395 | {0x00, 0x04, 0x07, 0x20, 0x28, 0x0c, 0x06 }, /* +2 */
396 | };
397 |
398 | #define NUM_SATURATION_LEVELS (5)
399 | static const uint8_t saturation_regs[NUM_SATURATION_LEVELS + 1][5] = {
400 | {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA },
401 | {0x00, 0x02, 0x03, 0x28, 0x28 }, /* -2 */
402 | {0x00, 0x02, 0x03, 0x38, 0x38 }, /* -1 */
403 | {0x00, 0x02, 0x03, 0x48, 0x48 }, /* 0 */
404 | {0x00, 0x02, 0x03, 0x58, 0x58 }, /* +1 */
405 | {0x00, 0x02, 0x03, 0x68, 0x68 }, /* +2 */
406 | };
407 |
408 | #define NUM_SPECIAL_EFFECTS (7)
409 | static const uint8_t special_effects_regs[NUM_SPECIAL_EFFECTS + 1][5] = {
410 | {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA },
411 | {0x00, 0X00, 0x05, 0X80, 0X80 }, /* no effect */
412 | {0x00, 0X40, 0x05, 0X80, 0X80 }, /* negative */
413 | {0x00, 0X18, 0x05, 0X80, 0X80 }, /* black and white */
414 | {0x00, 0X18, 0x05, 0X40, 0XC0 }, /* reddish */
415 | {0x00, 0X18, 0x05, 0X40, 0X40 }, /* greenish */
416 | {0x00, 0X18, 0x05, 0XA0, 0X40 }, /* blue */
417 | {0x00, 0X18, 0x05, 0X40, 0XA6 }, /* retro */
418 | };
419 |
420 | #define NUM_WB_MODES (4)
421 | static const uint8_t wb_modes_regs[NUM_WB_MODES + 1][3] = {
422 | {0XCC, 0XCD, 0XCE },
423 | {0x5E, 0X41, 0x54 }, /* sunny */
424 | {0x65, 0X41, 0x4F }, /* cloudy */
425 | {0x52, 0X41, 0x66 }, /* office */
426 | {0x42, 0X3F, 0x71 }, /* home */
427 | };
428 |
429 | #define NUM_AE_LEVELS (5)
430 | static const uint8_t ae_levels_regs[NUM_AE_LEVELS + 1][3] = {
431 | { AEW, AEB, VV },
432 | {0x20, 0X18, 0x60 },
433 | {0x34, 0X1C, 0x00 },
434 | {0x3E, 0X38, 0x81 },
435 | {0x48, 0X40, 0x81 },
436 | {0x58, 0X50, 0x92 },
437 | };
438 |
439 | const uint8_t agc_gain_tbl[31] = {
440 | 0x00, 0x10, 0x18, 0x30, 0x34, 0x38, 0x3C, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7A, 0x7C, 0x7E, 0xF0,
441 | 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
442 | };
443 |
444 | #endif /* _OV2640_SETTINGS_H_ */
445 |
--------------------------------------------------------------------------------
/components/esp32-camera/sensors/private_include/ov3660.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the OpenMV project.
3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader
4 | * This work is licensed under the MIT license, see the file LICENSE for details.
5 | *
6 | * OV3660 driver.
7 | *
8 | */
9 | #ifndef __OV3660_H__
10 | #define __OV3660_H__
11 |
12 | #include "sensor.h"
13 |
14 | int ov3660_init(sensor_t *sensor);
15 |
16 | #endif // __OV3660_H__
17 |
--------------------------------------------------------------------------------
/components/esp32-camera/sensors/private_include/ov3660_regs.h:
--------------------------------------------------------------------------------
1 | /*
2 | * OV3660 register definitions.
3 | */
4 | #ifndef __OV3660_REG_REGS_H__
5 | #define __OV3660_REG_REGS_H__
6 |
7 | /* system control registers */
8 | #define SYSTEM_CTROL0 0x3008 // Bit[7]: Software reset
9 | // Bit[6]: Software power down
10 | // Bit[5]: Reserved
11 | // Bit[4]: SRB clock SYNC enable
12 | // Bit[3]: Isolation suspend select
13 | // Bit[2:0]: Not used
14 |
15 | /* output format control registers */
16 | #define FORMAT_CTRL 0x501F // Format select
17 | // Bit[2:0]:
18 | // 000: YUV422
19 | // 001: RGB
20 | // 010: Dither
21 | // 011: RAW after DPC
22 | // 101: RAW after CIP
23 |
24 | /* format control registers */
25 | #define FORMAT_CTRL00 0x4300
26 |
27 | /* frame control registers */
28 | #define FRAME_CTRL01 0x4201 // Control Passed Frame Number When both ON and OFF number set to 0x00,frame control is in bypass mode
29 | // Bit[7:4]: Not used
30 | // Bit[3:0]: Frame ON number
31 | #define FRAME_CTRL02 0x4202 // Control Masked Frame Number When both ON and OFF number set to 0x00,frame control is in bypass mode
32 | // Bit[7:4]: Not used
33 | // BIT[3:0]: Frame OFF number
34 |
35 | /* ISP top control registers */
36 | #define PRE_ISP_TEST_SETTING_1 0x503D // Bit[7]: Test enable
37 | // 0: Test disable
38 | // 1: Color bar enable
39 | // Bit[6]: Rolling
40 | // Bit[5]: Transparent
41 | // Bit[4]: Square black and white
42 | // Bit[3:2]: Color bar style
43 | // 00: Standard 8 color bar
44 | // 01: Gradual change at vertical mode 1
45 | // 10: Gradual change at horizontal
46 | // 11: Gradual change at vertical mode 2
47 | // Bit[1:0]: Test select
48 | // 00: Color bar
49 | // 01: Random data
50 | // 10: Square data
51 | // 11: Black image
52 |
53 | //exposure = {0x3500[3:0], 0x3501[7:0], 0x3502[7:0]} / 16 × tROW
54 |
55 | /* AEC/AGC control functions */
56 | #define AEC_PK_MANUAL 0x3503 // AEC Manual Mode Control
57 | // Bit[7:6]: Reserved
58 | // Bit[5]: Gain delay option
59 | // Valid when 0x3503[4]=1’b0
60 | // 0: Delay one frame latch
61 | // 1: One frame latch
62 | // Bit[4:2]: Reserved
63 | // Bit[1]: AGC manual
64 | // 0: Auto enable
65 | // 1: Manual enable
66 | // Bit[0]: AEC manual
67 | // 0: Auto enable
68 | // 1: Manual enable
69 |
70 | //gain = {0x350A[1:0], 0x350B[7:0]} / 16
71 |
72 | /* mirror and flip registers */
73 | #define TIMING_TC_REG20 0x3820 // Timing Control Register
74 | // Bit[2:1]: Vertical flip enable
75 | // 00: Normal
76 | // 11: Vertical flip
77 | // Bit[0]: Vertical binning enable
78 | #define TIMING_TC_REG21 0x3821 // Timing Control Register
79 | // Bit[5]: Compression Enable
80 | // Bit[2:1]: Horizontal mirror enable
81 | // 00: Normal
82 | // 11: Horizontal mirror
83 | // Bit[0]: Horizontal binning enable
84 |
85 | #define CLOCK_POL_CONTROL 0x4740// Bit[5]: PCLK polarity 0: active low
86 | // 1: active high
87 | // Bit[3]: Gate PCLK under VSYNC
88 | // Bit[2]: Gate PCLK under HREF
89 | // Bit[1]: HREF polarity
90 | // 0: active low
91 | // 1: active high
92 | // Bit[0] VSYNC polarity
93 | // 0: active low
94 | // 1: active high
95 | #define DRIVE_CAPABILITY 0x302c // Bit[7:6]:
96 | // 00: 1x
97 | // 01: 2x
98 | // 10: 3x
99 | // 11: 4x
100 |
101 |
102 | #define X_ADDR_ST_H 0x3800 //Bit[3:0]: X address start[11:8]
103 | #define X_ADDR_ST_L 0x3801 //Bit[7:0]: X address start[7:0]
104 | #define Y_ADDR_ST_H 0x3802 //Bit[2:0]: Y address start[10:8]
105 | #define Y_ADDR_ST_L 0x3803 //Bit[7:0]: Y address start[7:0]
106 | #define X_ADDR_END_H 0x3804 //Bit[3:0]: X address end[11:8]
107 | #define X_ADDR_END_L 0x3805 //Bit[7:0]:
108 | #define Y_ADDR_END_H 0x3806 //Bit[2:0]: Y address end[10:8]
109 | #define Y_ADDR_END_L 0x3807 //Bit[7:0]:
110 | // Size after scaling
111 | #define X_OUTPUT_SIZE_H 0x3808 //Bit[3:0]: DVP output horizontal width[11:8]
112 | #define X_OUTPUT_SIZE_L 0x3809 //Bit[7:0]:
113 | #define Y_OUTPUT_SIZE_H 0x380a //Bit[2:0]: DVP output vertical height[10:8]
114 | #define Y_OUTPUT_SIZE_L 0x380b //Bit[7:0]:
115 | #define X_TOTAL_SIZE_H 0x380c //Bit[3:0]: Total horizontal size[11:8]
116 | #define X_TOTAL_SIZE_L 0x380d //Bit[7:0]:
117 | #define Y_TOTAL_SIZE_H 0x380e //Bit[7:0]: Total vertical size[15:8]
118 | #define Y_TOTAL_SIZE_L 0x380f //Bit[7:0]:
119 | #define X_OFFSET_H 0x3810 //Bit[3:0]: ISP horizontal offset[11:8]
120 | #define X_OFFSET_L 0x3811 //Bit[7:0]:
121 | #define Y_OFFSET_H 0x3812 //Bit[2:0]: ISP vertical offset[10:8]
122 | #define Y_OFFSET_L 0x3813 //Bit[7:0]:
123 | #define X_INCREMENT 0x3814 //Bit[7:4]: Horizontal odd subsample increment
124 | //Bit[3:0]: Horizontal even subsample increment
125 | #define Y_INCREMENT 0x3815 //Bit[7:4]: Vertical odd subsample increment
126 | //Bit[3:0]: Vertical even subsample increment
127 | // Size before scaling
128 | //#define X_INPUT_SIZE (X_ADDR_END - X_ADDR_ST + 1 - (2 * X_OFFSET))
129 | //#define Y_INPUT_SIZE (Y_ADDR_END - Y_ADDR_ST + 1 - (2 * Y_OFFSET))
130 |
131 | #define ISP_CONTROL_01 0x5001 // Bit[5]: Scale enable
132 | // 0: Disable
133 | // 1: Enable
134 |
135 | #define SCALE_CTRL_1 0x5601 // Bit[6:4]: HDIV RW
136 | // DCW scale times
137 | // 000: DCW 1 time
138 | // 001: DCW 2 times
139 | // 010: DCW 4 times
140 | // 100: DCW 8 times
141 | // 101: DCW 16 times
142 | // Others: DCW 16 times
143 | // Bit[2:0]: VDIV RW
144 | // DCW scale times
145 | // 000: DCW 1 time
146 | // 001: DCW 2 times
147 | // 010: DCW 4 times
148 | // 100: DCW 8 times
149 | // 101: DCW 16 times
150 | // Others: DCW 16 times
151 |
152 | #define SCALE_CTRL_2 0x5602 // X_SCALE High Bits
153 | #define SCALE_CTRL_3 0x5603 // X_SCALE Low Bits
154 | #define SCALE_CTRL_4 0x5604 // Y_SCALE High Bits
155 | #define SCALE_CTRL_5 0x5605 // Y_SCALE Low Bits
156 | #define SCALE_CTRL_6 0x5606 // Bit[3:0]: V Offset
157 |
158 | #define PCLK_RATIO 0x3824 // Bit[4:0]: PCLK ratio manual
159 | #define VFIFO_CTRL0C 0x460C // Bit[1]: PCLK manual enable
160 | // 0: Auto
161 | // 1: Manual by PCLK_RATIO
162 |
163 | #define VFIFO_X_SIZE_H 0x4602
164 | #define VFIFO_X_SIZE_L 0x4603
165 | #define VFIFO_Y_SIZE_H 0x4604
166 | #define VFIFO_Y_SIZE_L 0x4605
167 |
168 | #define SC_PLLS_CTRL0 0x303a // Bit[7]: PLLS bypass
169 | #define SC_PLLS_CTRL1 0x303b // Bit[4:0]: PLLS multiplier
170 | #define SC_PLLS_CTRL2 0x303c // Bit[6:4]: PLLS charge pump control
171 | // Bit[3:0]: PLLS system divider
172 | #define SC_PLLS_CTRL3 0x303d // Bit[5:4]: PLLS pre-divider
173 | // 00: 1
174 | // 01: 1.5
175 | // 10: 2
176 | // 11: 3
177 | // Bit[2]: PLLS root-divider - 1
178 | // Bit[1:0]: PLLS seld5
179 | // 00: 1
180 | // 01: 1
181 | // 10: 2
182 | // 11: 2.5
183 |
184 | #define COMPRESSION_CTRL00 0x4400 //
185 | #define COMPRESSION_CTRL01 0x4401 //
186 | #define COMPRESSION_CTRL02 0x4402 //
187 | #define COMPRESSION_CTRL03 0x4403 //
188 | #define COMPRESSION_CTRL04 0x4404 //
189 | #define COMPRESSION_CTRL05 0x4405 //
190 | #define COMPRESSION_CTRL06 0x4406 //
191 | #define COMPRESSION_CTRL07 0x4407 // Bit[5:0]: QS
192 | #define COMPRESSION_ISI_CTRL 0x4408 //
193 | #define COMPRESSION_CTRL09 0x4409 //
194 | #define COMPRESSION_CTRL0a 0x440a //
195 | #define COMPRESSION_CTRL0b 0x440b //
196 | #define COMPRESSION_CTRL0c 0x440c //
197 | #define COMPRESSION_CTRL0d 0x440d //
198 | #define COMPRESSION_CTRL0E 0x440e //
199 |
200 | /**
201 | * @brief register value
202 | */
203 | #define TEST_COLOR_BAR 0xC0 /* Enable Color Bar roling Test */
204 |
205 | #define AEC_PK_MANUAL_AGC_MANUALEN 0x02 /* Enable AGC Manual enable */
206 | #define AEC_PK_MANUAL_AEC_MANUALEN 0x01 /* Enable AEC Manual enable */
207 |
208 | #define TIMING_TC_REG20_VFLIP 0x06 /* Vertical flip enable */
209 | #define TIMING_TC_REG21_HMIRROR 0x06 /* Horizontal mirror enable */
210 |
211 | #endif // __OV3660_REG_REGS_H__
212 |
--------------------------------------------------------------------------------
/components/esp32-camera/sensors/private_include/ov3660_settings.h:
--------------------------------------------------------------------------------
1 | #ifndef _OV3660_SETTINGS_H_
2 | #define _OV3660_SETTINGS_H_
3 |
4 | #include
5 | #include
6 | #include "esp_attr.h"
7 | #include "ov3660_regs.h"
8 |
9 | #define REG_DLY 0xffff
10 | #define REGLIST_TAIL 0x0000
11 |
12 | const DRAM_ATTR uint16_t sensor_default_regs[][2] = {
13 | {SYSTEM_CTROL0, 0x82}, // software reset
14 | {REG_DLY, 10}, // delay 10ms
15 |
16 | {0x3103, 0x13},
17 | {SYSTEM_CTROL0, 0x42},
18 | {0x3017, 0xff},
19 | {0x3018, 0xff},
20 | {DRIVE_CAPABILITY, 0xc3},
21 | {CLOCK_POL_CONTROL, 0x21},
22 |
23 | {0x3611, 0x01},
24 | {0x3612, 0x2d},
25 |
26 | {0x3032, 0x00},
27 | {0x3614, 0x80},
28 | {0x3618, 0x00},
29 | {0x3619, 0x75},
30 | {0x3622, 0x80},
31 | {0x3623, 0x00},
32 | {0x3624, 0x03},
33 | {0x3630, 0x52},
34 | {0x3632, 0x07},
35 | {0x3633, 0xd2},
36 | {0x3704, 0x80},
37 | {0x3708, 0x66},
38 | {0x3709, 0x12},
39 | {0x370b, 0x12},
40 | {0x3717, 0x00},
41 | {0x371b, 0x60},
42 | {0x371c, 0x00},
43 | {0x3901, 0x13},
44 |
45 | {0x3600, 0x08},
46 | {0x3620, 0x43},
47 | {0x3702, 0x20},
48 | {0x3739, 0x48},
49 | {0x3730, 0x20},
50 | {0x370c, 0x0c},
51 |
52 | {0x3a18, 0x00},
53 | {0x3a19, 0xf8},
54 |
55 | {0x3000, 0x10},
56 | {0x3004, 0xef},
57 |
58 | {0x6700, 0x05},
59 | {0x6701, 0x19},
60 | {0x6702, 0xfd},
61 | {0x6703, 0xd1},
62 | {0x6704, 0xff},
63 | {0x6705, 0xff},
64 |
65 | {0x3c01, 0x80},
66 | {0x3c00, 0x04},
67 | {0x3a08, 0x00}, {0x3a09, 0x62}, //50Hz Band Width Step (10bit)
68 | {0x3a0e, 0x08}, //50Hz Max Bands in One Frame (6 bit)
69 | {0x3a0a, 0x00}, {0x3a0b, 0x52}, //60Hz Band Width Step (10bit)
70 | {0x3a0d, 0x09}, //60Hz Max Bands in One Frame (6 bit)
71 |
72 | {0x3a00, 0x3a},//night mode off
73 | {0x3a14, 0x09},
74 | {0x3a15, 0x30},
75 | {0x3a02, 0x09},
76 | {0x3a03, 0x30},
77 |
78 | {COMPRESSION_CTRL0E, 0x08},
79 | {0x4520, 0x0b},
80 | {0x460b, 0x37},
81 | {0x4713, 0x02},
82 | {0x471c, 0xd0},
83 | {0x5086, 0x00},
84 |
85 | {0x5002, 0x00},
86 | {0x501f, 0x00},
87 |
88 | {SYSTEM_CTROL0, 0x02},
89 |
90 | {0x5180, 0xff},
91 | {0x5181, 0xf2},
92 | {0x5182, 0x00},
93 | {0x5183, 0x14},
94 | {0x5184, 0x25},
95 | {0x5185, 0x24},
96 | {0x5186, 0x16},
97 | {0x5187, 0x16},
98 | {0x5188, 0x16},
99 | {0x5189, 0x68},
100 | {0x518a, 0x60},
101 | {0x518b, 0xe0},
102 | {0x518c, 0xb2},
103 | {0x518d, 0x42},
104 | {0x518e, 0x35},
105 | {0x518f, 0x56},
106 | {0x5190, 0x56},
107 | {0x5191, 0xf8},
108 | {0x5192, 0x04},
109 | {0x5193, 0x70},
110 | {0x5194, 0xf0},
111 | {0x5195, 0xf0},
112 | {0x5196, 0x03},
113 | {0x5197, 0x01},
114 | {0x5198, 0x04},
115 | {0x5199, 0x12},
116 | {0x519a, 0x04},
117 | {0x519b, 0x00},
118 | {0x519c, 0x06},
119 | {0x519d, 0x82},
120 | {0x519e, 0x38},
121 |
122 | {0x5381, 0x1d},
123 | {0x5382, 0x60},
124 | {0x5383, 0x03},
125 | {0x5384, 0x0c},
126 | {0x5385, 0x78},
127 | {0x5386, 0x84},
128 | {0x5387, 0x7d},
129 | {0x5388, 0x6b},
130 | {0x5389, 0x12},
131 | {0x538a, 0x01},
132 | {0x538b, 0x98},
133 |
134 | {0x5481, 0x05},
135 | {0x5482, 0x09},
136 | {0x5483, 0x10},
137 | {0x5484, 0x3a},
138 | {0x5485, 0x4c},
139 | {0x5486, 0x5a},
140 | {0x5487, 0x68},
141 | {0x5488, 0x74},
142 | {0x5489, 0x80},
143 | {0x548a, 0x8e},
144 | {0x548b, 0xa4},
145 | {0x548c, 0xb4},
146 | {0x548d, 0xc8},
147 | {0x548e, 0xde},
148 | {0x548f, 0xf0},
149 | {0x5490, 0x15},
150 |
151 | {0x5000, 0xa7},
152 | {0x5800, 0x0C},
153 | {0x5801, 0x09},
154 | {0x5802, 0x0C},
155 | {0x5803, 0x0C},
156 | {0x5804, 0x0D},
157 | {0x5805, 0x17},
158 | {0x5806, 0x06},
159 | {0x5807, 0x05},
160 | {0x5808, 0x04},
161 | {0x5809, 0x06},
162 | {0x580a, 0x09},
163 | {0x580b, 0x0E},
164 | {0x580c, 0x05},
165 | {0x580d, 0x01},
166 | {0x580e, 0x01},
167 | {0x580f, 0x01},
168 | {0x5810, 0x05},
169 | {0x5811, 0x0D},
170 | {0x5812, 0x05},
171 | {0x5813, 0x01},
172 | {0x5814, 0x01},
173 | {0x5815, 0x01},
174 | {0x5816, 0x05},
175 | {0x5817, 0x0D},
176 | {0x5818, 0x08},
177 | {0x5819, 0x06},
178 | {0x581a, 0x05},
179 | {0x581b, 0x07},
180 | {0x581c, 0x0B},
181 | {0x581d, 0x0D},
182 | {0x581e, 0x12},
183 | {0x581f, 0x0D},
184 | {0x5820, 0x0E},
185 | {0x5821, 0x10},
186 | {0x5822, 0x10},
187 | {0x5823, 0x1E},
188 | {0x5824, 0x53},
189 | {0x5825, 0x15},
190 | {0x5826, 0x05},
191 | {0x5827, 0x14},
192 | {0x5828, 0x54},
193 | {0x5829, 0x25},
194 | {0x582a, 0x33},
195 | {0x582b, 0x33},
196 | {0x582c, 0x34},
197 | {0x582d, 0x16},
198 | {0x582e, 0x24},
199 | {0x582f, 0x41},
200 | {0x5830, 0x50},
201 | {0x5831, 0x42},
202 | {0x5832, 0x15},
203 | {0x5833, 0x25},
204 | {0x5834, 0x34},
205 | {0x5835, 0x33},
206 | {0x5836, 0x24},
207 | {0x5837, 0x26},
208 | {0x5838, 0x54},
209 | {0x5839, 0x25},
210 | {0x583a, 0x15},
211 | {0x583b, 0x25},
212 | {0x583c, 0x53},
213 | {0x583d, 0xCF},
214 |
215 | {0x3a0f, 0x30},
216 | {0x3a10, 0x28},
217 | {0x3a1b, 0x30},
218 | {0x3a1e, 0x28},
219 | {0x3a11, 0x60},
220 | {0x3a1f, 0x14},
221 |
222 | {0x5302, 0x28},
223 | {0x5303, 0x20},
224 |
225 | {0x5306, 0x1c}, //de-noise offset 1
226 | {0x5307, 0x28}, //de-noise offset 2
227 |
228 | {0x4002, 0xc5},
229 | {0x4003, 0x81},
230 | {0x4005, 0x12},
231 |
232 | {0x5688, 0x11},
233 | {0x5689, 0x11},
234 | {0x568a, 0x11},
235 | {0x568b, 0x11},
236 | {0x568c, 0x11},
237 | {0x568d, 0x11},
238 | {0x568e, 0x11},
239 | {0x568f, 0x11},
240 |
241 | {0x5580, 0x06},
242 | {0x5588, 0x00},
243 | {0x5583, 0x40},
244 | {0x5584, 0x2c},
245 |
246 | {ISP_CONTROL_01, 0x83}, // turn color matrix, awb and SDE
247 | {REGLIST_TAIL, 0x00}, // tail
248 | };
249 |
250 | const DRAM_ATTR uint16_t sensor_fmt_jpeg[][2] = {
251 | {FORMAT_CTRL, 0x00}, // YUV422
252 | {FORMAT_CTRL00, 0x30}, // YUYV
253 | {0x3002, 0x00},//0x1c to 0x00 !!!
254 | {0x3006, 0xff},//0xc3 to 0xff !!!
255 | {0x471c, 0x50},//0xd0 to 0x50 !!!
256 | {REGLIST_TAIL, 0x00}, // tail
257 | };
258 |
259 | const DRAM_ATTR uint16_t sensor_fmt_raw[][2] = {
260 | {FORMAT_CTRL00, 0x00}, // RAW
261 | {REGLIST_TAIL, 0x00}
262 | };
263 |
264 | const DRAM_ATTR uint16_t sensor_fmt_grayscale[][2] = {
265 | {FORMAT_CTRL, 0x00}, // YUV422
266 | {FORMAT_CTRL00, 0x10}, // Y8
267 | {REGLIST_TAIL, 0x00}
268 | };
269 |
270 | const DRAM_ATTR uint16_t sensor_fmt_yuv422[][2] = {
271 | {FORMAT_CTRL, 0x00}, // YUV422
272 | {FORMAT_CTRL00, 0x30}, // YUYV
273 | {REGLIST_TAIL, 0x00}
274 | };
275 |
276 | const DRAM_ATTR uint16_t sensor_fmt_rgb565[][2] = {
277 | {FORMAT_CTRL, 0x01}, // RGB
278 | {FORMAT_CTRL00, 0x61}, // RGB565 (BGR)
279 | {REGLIST_TAIL, 0x00}
280 | };
281 |
282 | const DRAM_ATTR uint8_t sensor_saturation_levels[9][11] = {
283 | {0x1d, 0x60, 0x03, 0x07, 0x48, 0x4f, 0x4b, 0x40, 0x0b, 0x01, 0x98},//-4
284 | {0x1d, 0x60, 0x03, 0x08, 0x54, 0x5c, 0x58, 0x4b, 0x0d, 0x01, 0x98},//-3
285 | {0x1d, 0x60, 0x03, 0x0a, 0x60, 0x6a, 0x64, 0x56, 0x0e, 0x01, 0x98},//-2
286 | {0x1d, 0x60, 0x03, 0x0b, 0x6c, 0x77, 0x70, 0x60, 0x10, 0x01, 0x98},//-1
287 | {0x1d, 0x60, 0x03, 0x0c, 0x78, 0x84, 0x7d, 0x6b, 0x12, 0x01, 0x98},//0
288 | {0x1d, 0x60, 0x03, 0x0d, 0x84, 0x91, 0x8a, 0x76, 0x14, 0x01, 0x98},//+1
289 | {0x1d, 0x60, 0x03, 0x0e, 0x90, 0x9e, 0x96, 0x80, 0x16, 0x01, 0x98},//+2
290 | {0x1d, 0x60, 0x03, 0x10, 0x9c, 0xac, 0xa2, 0x8b, 0x17, 0x01, 0x98},//+3
291 | {0x1d, 0x60, 0x03, 0x11, 0xa8, 0xb9, 0xaf, 0x96, 0x19, 0x01, 0x98},//+4
292 | };
293 |
294 | const DRAM_ATTR uint8_t sensor_special_effects[7][4] = {
295 | {0x06, 0x40, 0x2c, 0x08},//Normal
296 | {0x46, 0x40, 0x28, 0x08},//Negative
297 | {0x1e, 0x80, 0x80, 0x08},//Grayscale
298 | {0x1e, 0x80, 0xc0, 0x08},//Red Tint
299 | {0x1e, 0x60, 0x60, 0x08},//Green Tint
300 | {0x1e, 0xa0, 0x40, 0x08},//Blue Tint
301 | {0x1e, 0x40, 0xa0, 0x08},//Sepia
302 | };
303 |
304 | #endif
305 |
--------------------------------------------------------------------------------
/components/esp32-camera/sensors/private_include/ov7725.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the OpenMV project.
3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader
4 | * This work is licensed under the MIT license, see the file LICENSE for details.
5 | *
6 | * OV7725 driver.
7 | *
8 | */
9 | #ifndef __OV7725_H__
10 | #define __OV7725_H__
11 | #include "sensor.h"
12 |
13 | int ov7725_init(sensor_t *sensor);
14 | #endif // __OV7725_H__
15 |
--------------------------------------------------------------------------------
/components/nabtotunnel/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | idf_component_register(SRCS ./unabto_tunnel.c ./unabto_tunnel_common.c ./unabto_tunnel_select.c ./unabto_tunnel_tcp.c ./esp32tcp/unabto_tcp.c
2 | INCLUDE_DIRS . ../unabto-esp-idf ../../unabto/src ../../unabto/src/modules/network/tcp/
3 | REQUIRES )
4 |
5 |
--------------------------------------------------------------------------------
/components/nabtotunnel/component.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Component Makefile
3 | #
4 |
5 | COMPONENT_ADD_INCLUDEDIRS := . ../../unabto/src ../../unabto/src/modules/network/tcp/
6 | COMPONENT_SRCDIRS := . ./esp32tcp
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/components/nabtotunnel/esp32tcp/unabto_tcp.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #ifndef MSG_NOSIGNAL
11 | #define MSG_NOSIGNAL 0
12 | #endif
13 |
14 | unabto_tcp_status unabto_tcp_read(struct unabto_tcp_socket* sock, void* buf, const size_t len, size_t* read) {
15 | int status;
16 | int err;
17 |
18 | status = recv(sock->socket, buf, len, 0);
19 | err = errno;
20 | if (status < 0) {
21 | if ((err == EAGAIN) || err == EWOULDBLOCK) {
22 | return UTS_WOULD_BLOCK;
23 | } else {
24 | NABTO_LOG_ERROR(("unabto_tcp_read failed error: %s, socket: %i", strerror(err), sock->socket));
25 | return UTS_FAILED;
26 | }
27 | } else if (status == 0) {
28 | NABTO_LOG_TRACE(("TCP connection closed by peer"));
29 | return UTS_EOF;
30 | } else {
31 | *read = status;
32 | return UTS_OK;
33 | }
34 | }
35 |
36 | unabto_tcp_status unabto_tcp_write(struct unabto_tcp_socket* sock, const void* buf, const size_t len, size_t* written){
37 | int status;
38 | NABTO_LOG_TRACE(("Writing %i bytes to tcp socket", len));
39 | status = send(sock->socket, buf, len, MSG_NOSIGNAL);
40 | NABTO_LOG_TRACE(("tcp send status: %i", status));
41 | if (status < 0) {
42 | int err = errno;
43 | if ((err == EAGAIN) || err == EWOULDBLOCK) {
44 | return UTS_WOULD_BLOCK;
45 | } else {
46 | NABTO_LOG_ERROR(("Send of tcp packet failed error: %s, socket: %i", strerror(err), sock->socket));
47 | return UTS_FAILED;
48 | }
49 | }
50 | *written = status;
51 | return UTS_OK;
52 | }
53 |
54 | unabto_tcp_status unabto_tcp_close(struct unabto_tcp_socket* sock){
55 | if (sock->socket == INVALID_SOCKET) {
56 | NABTO_LOG_ERROR(("trying to close invalid socket"));
57 | } else {
58 | close(sock->socket);
59 | sock->socket = INVALID_SOCKET;
60 | }
61 | return UTS_OK;
62 | }
63 |
64 | unabto_tcp_status unabto_tcp_shutdown(struct unabto_tcp_socket* sock){
65 | shutdown(sock->socket, SHUT_WR);
66 | return UTS_OK;
67 | }
68 |
69 | unabto_tcp_status unabto_tcp_open(struct unabto_tcp_socket* sock, enum nabto_ip_address_type addressType, void* epollDataPtr){
70 | if (addressType == NABTO_IP_V4) {
71 | sock->socket = socket(AF_INET, SOCK_STREAM, 0);
72 | } else if (addressType == NABTO_IP_V6) {
73 | sock->socket = socket(AF_INET6, SOCK_STREAM, 0);
74 | } else {
75 | NABTO_LOG_ERROR(("invalid address type"));
76 | return UTS_FAILED;
77 | }
78 | if (sock->socket < 0) {
79 | NABTO_LOG_ERROR(("Could not create socket for TCP"));
80 | return UTS_FAILED;
81 | }
82 |
83 | {
84 | int flags = 1;
85 | if (setsockopt(sock->socket, IPPROTO_TCP, TCP_NODELAY, (char *) &flags, sizeof(int)) != 0) {
86 | NABTO_LOG_ERROR(("Could not set socket option TCP_NODELAY"));
87 | }
88 | flags = fcntl(sock->socket, F_GETFL, 0);
89 | if (flags < 0) {
90 | NABTO_LOG_ERROR(("fcntl failed in F_GETFL"));
91 | unabto_tcp_close(sock);
92 | return UTS_FAILED;
93 | }
94 | if (fcntl(sock->socket, F_SETFL, flags | O_NONBLOCK) < 0) {
95 | NABTO_LOG_ERROR(("fcntl failed in F_SETFL"));
96 | unabto_tcp_close(sock);
97 | return UTS_FAILED;
98 | }
99 |
100 | flags = 1;
101 | if(setsockopt(sock->socket, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags)) < 0) {
102 | NABTO_LOG_ERROR(("could not enable KEEPALIVE"));
103 | }
104 |
105 |
106 | return UTS_OK;
107 | }
108 | }
109 |
110 |
111 | unabto_tcp_status unabto_tcp_connect(struct unabto_tcp_socket* sock, nabto_endpoint* ep){
112 | int status;
113 | if (ep->addr.type == NABTO_IP_V4) {
114 | struct sockaddr_in host;
115 |
116 | memset(&host,0,sizeof(struct sockaddr_in));
117 | host.sin_family = AF_INET;
118 | host.sin_addr.s_addr = htonl(ep->addr.addr.ipv4);
119 | host.sin_port = htons(ep->port);
120 | NABTO_LOG_TRACE(("Connecting to " PRIep, MAKE_EP_PRINTABLE(*ep)));
121 |
122 | status = connect(sock->socket, (struct sockaddr*)&host, sizeof(struct sockaddr_in));
123 | } else if (ep->addr.type == NABTO_IP_V6) {
124 | struct sockaddr_in6 host;
125 |
126 | memset(&host,0,sizeof(struct sockaddr_in6));
127 | host.sin6_family = AF_INET6;
128 | memcpy(host.sin6_addr.s6_addr, ep->addr.addr.ipv6, 16);
129 | host.sin6_port = htons(ep->port);
130 | NABTO_LOG_TRACE(("Connecting to " PRIep, MAKE_EP_PRINTABLE(*ep)));
131 |
132 | status = connect(sock->socket, (struct sockaddr*)&host, sizeof(struct sockaddr_in6));
133 |
134 | } else {
135 | return UTS_FAILED;
136 | }
137 |
138 | if (status == 0) {
139 | return UTS_OK;
140 | } else {
141 | int err = errno;
142 | if (err == EINPROGRESS) {
143 | return UTS_CONNECTING;
144 | } else {
145 | NABTO_LOG_ERROR(("Could not connect to tcp endpoint. %s", strerror(errno)));
146 | return UTS_FAILED;
147 | }
148 | }
149 | }
150 |
151 |
152 | /* Polls if socket has been connected
153 | */
154 | unabto_tcp_status unabto_tcp_connect_poll(struct unabto_tcp_socket* sock){
155 | int err;
156 | socklen_t len;
157 | len = sizeof(err);
158 | if (getsockopt(sock->socket, SOL_SOCKET, SO_ERROR, &err, &len) != 0) {
159 | return UTS_FAILED;
160 | } else {
161 | if (err == 0) {
162 | return UTS_OK;
163 | } else if ( err == EINPROGRESS) {
164 | return UTS_CONNECTING;
165 | } else {
166 | NABTO_LOG_ERROR(("Socket not open %d", err));
167 | return UTS_FAILED;
168 | }
169 | }
170 | return UTS_OK;
171 | }
172 |
173 |
--------------------------------------------------------------------------------
/components/nabtotunnel/esp32tcp/unabto_tcp_esp32.h:
--------------------------------------------------------------------------------
1 | #ifndef _UNABTO_TCP_ESP32_H_
2 | #define _UNABTO_TCP_ESP32_H_
3 | #include
4 |
5 | #define INVALID_SOCKET (-1)
6 |
7 | struct unabto_tcp_socket {
8 | int socket;
9 | };
10 |
11 | #endif //_UNABTO_TCP_ESP32_H_
12 |
--------------------------------------------------------------------------------
/components/nabtotunnel/unabto_tunnel.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "unabto_tunnel.h"
3 |
4 | bool init_tunnel_module()
5 | {
6 | return unabto_tunnel_init_tunnels();
7 | }
8 |
9 | void deinit_tunnel_module()
10 | {
11 | unabto_tunnel_deinit_tunnels();
12 | }
13 |
14 | void unabto_stream_accept(unabto_stream* stream) {
15 | unabto_tunnel_stream_accept(stream);
16 | }
17 |
18 | void unabto_stream_event(unabto_stream* stream, unabto_stream_event_type event) {
19 | tunnel* t = unabto_tunnel_get_tunnel(stream);
20 | NABTO_LOG_TRACE(("Stream %i, %i", unabto_stream_index(stream), event));
21 | unabto_tunnel_event(t, TUNNEL_EVENT_SOURCE_UNABTO);
22 | }
23 |
24 |
25 |
26 | /*
27 | bool allow_client_access(nabto_connect* connection) {
28 | return true;
29 | }
30 | */
31 |
32 | bool tunnel_allow_connection(const char* host, int port) {
33 |
34 | int c = strncmp(host, "127.0.0.1", 10);
35 |
36 | if( c==0 && port == 8081) {
37 | NABTO_LOG_INFO(("Allow connection host:%s port:%i", host, port));
38 | return true;
39 | }
40 |
41 | NABTO_LOG_INFO(("Not allowing connection host:%s port:%i", host, port));
42 | return false;
43 | }
44 |
45 |
46 |
47 | bool unabto_tunnel_allow_client_access(nabto_connect* connection) {
48 | return true;
49 | }
50 |
51 | #if NABTO_ENABLE_TUNNEL_STATUS_CALLBACKS
52 | void unabto_tunnel_status_callback(tunnel_status_event event, tunnel* tunnel) {
53 | tunnel_status_tcp_details info;
54 | unabto_tunnel_status_get_tcp_info(tunnel, &info);
55 | NABTO_LOG_INFO(("Tunnel event [%d] on tunnel [%d] to host [%s] on port [%d], bytes sent: [%d]", event, tunnel->tunnelId,
56 | info.host, info.port, info.sentBytes));
57 | }
58 | #endif
59 |
60 |
--------------------------------------------------------------------------------
/components/nabtotunnel/unabto_tunnel.h:
--------------------------------------------------------------------------------
1 | #ifndef _TUNNEL_H_
2 | #define _TUNNEL_H_
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #if defined(WIN32) || defined(WINCE)
12 | // use winsock
13 | #define WINSOCK 1
14 | #endif
15 |
16 | bool init_tunnel_module();
17 | void deinit_tunnel_module();
18 |
19 | void tunnel_event(tunnel* state, tunnel_event_source event_source);
20 |
21 | #endif // _TUNNEL_H_
22 |
--------------------------------------------------------------------------------
/components/nabtotunnel/unabto_tunnel_common.h:
--------------------------------------------------------------------------------
1 | #ifndef _UNABTO_TUNNEL_COMMON_H_
2 | #define _UNABTO_TUNNEL_COMMON_H_
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #if NABTO_ENABLE_EPOLL
10 | #include
11 | #endif
12 |
13 |
14 | #define MAX_COMMAND_LENGTH 512
15 | #define MAX_DEVICE_NAME_LENGTH 128
16 | #define MAX_HOST_LENGTH 128
17 |
18 | typedef enum {
19 | TS_IDLE,
20 | TS_READ_COMMAND,
21 | TS_PARSE_COMMAND,
22 | TS_FAILED_COMMAND, // failed to read/parse command, close connect attempt.
23 | TS_OPEN_SOCKET,
24 | TS_OPENING_SOCKET,
25 | TS_FORWARD,
26 | TS_CLOSING
27 | } tunnelStates;
28 |
29 | typedef enum {
30 | FS_READ,
31 | FS_WRITE,
32 | FS_CLOSING
33 | } forwardState;
34 |
35 | typedef enum {
36 | TUNNEL_EVENT_SOURCE_UART_WRITE,
37 | TUNNEL_EVENT_SOURCE_UART_READ,
38 | TUNNEL_EVENT_SOURCE_TCP_WRITE,
39 | TUNNEL_EVENT_SOURCE_TCP_READ,
40 | TUNNEL_EVENT_SOURCE_UNABTO
41 | } tunnel_event_source;
42 |
43 | typedef enum {
44 | TUNNEL_TYPE_NONE,
45 | TUNNEL_TYPE_TCP,
46 | TUNNEL_TYPE_UART,
47 | TUNNEL_TYPE_ECHO
48 | } tunnel_type;
49 |
50 | typedef struct uart_tunnel_static_memory {
51 | char deviceName[MAX_DEVICE_NAME_LENGTH];
52 | } uart_tunnel_static_memory;
53 |
54 | typedef struct tcp_tunnel_static_memory {
55 | char host[MAX_HOST_LENGTH];
56 | //~ uint8_t tcpReadBuffer[NABTO_MEMORY_STREAM_SEGMENT_SIZE];
57 | } tcp_tunnel_static_memory;
58 |
59 | union tunnel_static_memory_union{
60 | struct tcp_tunnel_static_memory tcp_sm;
61 | struct uart_tunnel_static_memory uart_sm;
62 | };
63 |
64 | typedef struct tunnel_static_memory{
65 | uint8_t command[MAX_COMMAND_LENGTH];
66 | union tunnel_static_memory_union stmu;
67 | } tunnel_static_memory;
68 |
69 | typedef struct uart_vars{
70 | int fd;
71 | } uart_vars;
72 |
73 | typedef struct tcp_vars{
74 | int port;
75 | struct unabto_tcp_socket sock;
76 | } tcp_vars;
77 |
78 |
79 |
80 | typedef struct tunnel {
81 | #if NABTO_ENABLE_EPOLL
82 | // it's important that this is the first member
83 | int epollEventType;
84 | #endif
85 | unabto_stream* stream;
86 | tunnelStates state;
87 | int commandLength;
88 | forwardState extReadState;
89 | forwardState unabtoReadState;
90 | int tunnelId;
91 | tunnel_static_memory* staticMemory;
92 |
93 | tunnel_type tunnelType;
94 | union {
95 | uart_vars uart;
96 | tcp_vars tcp;
97 | } tunnel_type_vars;
98 | } tunnel;
99 |
100 | void unabto_tunnel_reset_tunnel_struct(tunnel* t);
101 | bool unabto_tunnel_init_tunnels();
102 | void unabto_tunnel_deinit_tunnels();
103 | void unabto_tunnel_stream_accept(unabto_stream* stream);
104 | tunnel* unabto_tunnel_get_tunnel(unabto_stream* stream);
105 |
106 | void unabto_tunnel_event(tunnel* tunnel, tunnel_event_source event_source);
107 | void unabto_tunnel_idle(tunnel* tunnel, tunnel_event_source tunnel_event);
108 | void unabto_tunnel_read_command(tunnel* tunnel, tunnel_event_source tunnel_event);
109 | void unabto_tunnel_parse_command(tunnel* tunnel, tunnel_event_source tunnel_event);
110 | void unabto_tunnel_closing(tunnel* tunnel, tunnel_event_source tunnel_event);
111 |
112 | void unabto_tunnel_event_dispatch(tunnel* tunnel, tunnel_event_source event_source);
113 |
114 | void unabto_tunnel_select_add_to_fd_set(fd_set* readFds, int* maxReadFd, fd_set* writeFds, int* maxWriteFd);
115 | void unabto_tunnel_select_handle(fd_set* readFds, fd_set* writeFds);
116 | bool tunnel_send_init_message(tunnel* tunnel, const char* msg);
117 |
118 | bool unabto_tunnel_has_uart();
119 |
120 | #if NABTO_ENABLE_EPOLL
121 | void unabto_tunnel_epoll_event(struct epoll_event* event);
122 | #endif
123 |
124 | /**
125 | * Query at tunnel open request whether a client is allowed access (check ACL, optional functionality).
126 | * @param connection the connection being established
127 | * @return true if access to the devices is allowed
128 | */
129 | bool unabto_tunnel_allow_client_access(nabto_connect* connection);
130 |
131 | #if NABTO_ENABLE_TUNNEL_STATUS_CALLBACKS
132 |
133 | typedef enum {
134 | NABTO_TCP_TUNNEL_OPENED,
135 | NABTO_TCP_TUNNEL_CLOSED
136 | } tunnel_status_event;
137 |
138 | /**
139 | * Inform the application of a tunnel event
140 | */
141 | void unabto_tunnel_status_callback(tunnel_status_event event, tunnel* tunnel);
142 |
143 | typedef struct tunnel_status_tcp_details {
144 | char* host;
145 | int port;
146 | unsigned sentBytes;
147 | unsigned receivedBytes;
148 | } tunnel_status_tcp_details;
149 |
150 | /**
151 | * Access tcp tunnel information
152 | */
153 | void unabto_tunnel_status_get_tcp_info(tunnel* tunnel, tunnel_status_tcp_details* info);
154 |
155 |
156 | #endif
157 |
158 |
159 |
160 | #endif // _UNABTO_TUNNEL_COMMON_H_
161 |
--------------------------------------------------------------------------------
/components/nabtotunnel/unabto_tunnel_select.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "unabto_tunnel_select.h"
11 | #include "unabto_tunnel.h"
12 |
13 | #if defined(WIN32) || defined(WINCE)
14 | // use winsock
15 | #define WINSOCK 1
16 | #include
17 | #else
18 | // use a bsd api
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #endif
25 |
26 | #include
27 |
28 | void tunnel_loop_select() {
29 | if (!unabto_init()) {
30 | NABTO_LOG_FATAL(("Failed to initialize unabto"));
31 | }
32 |
33 | if (!init_tunnel_module()) {
34 | NABTO_LOG_FATAL(("Cannot initialize tunnel module"));
35 | return;
36 | }
37 |
38 | unabto_time_auto_update(false);
39 | // time is updated here and after the select since that's the only blocking point.
40 | unabto_time_update_stamp();
41 | while(true) {
42 | nabto_stamp_t nextEvent;
43 | nabto_stamp_t now;
44 | int timeout;
45 | fd_set read_fds;
46 | fd_set write_fds;
47 | int max_read_fd = 0;
48 | int max_write_fd = 0;
49 | struct timeval timeout_val;
50 | int nfds;
51 |
52 | unabto_next_event(&nextEvent);
53 | now = nabtoGetStamp();
54 | timeout = nabtoStampDiff2ms(nabtoStampDiff(&nextEvent, &now));
55 |
56 | if (timeout < 0) {
57 | timeout = 1;
58 | }
59 |
60 | FD_ZERO(&read_fds);
61 | FD_ZERO(&write_fds);
62 | unabto_network_select_add_to_read_fd_set(&read_fds, &max_read_fd);
63 |
64 | #if NABTO_ENABLE_TCP_FALLBACK
65 | unabto_tcp_fallback_select_add_to_read_fd_set(&read_fds, &max_read_fd);
66 | unabto_tcp_fallback_select_add_to_write_fd_set(&write_fds, &max_write_fd);
67 | #endif
68 |
69 | unabto_tunnel_select_add_to_fd_set(&read_fds, &max_read_fd, &write_fds, &max_write_fd);
70 |
71 | timeout_val.tv_sec = (timeout/1000);
72 | timeout_val.tv_usec = ((timeout)%1000)*1000;
73 |
74 | fflush(stdout);
75 | //NABTO_LOG_TRACE(("MAX(max_read_fd+1, max_write_fd+1)=%i",MAX(max_read_fd+1, max_write_fd+1)));
76 |
77 | nfds = select(MAX(max_read_fd+1, max_write_fd+1), &read_fds, &write_fds, NULL, &timeout_val);
78 |
79 | if (nfds < 0) {
80 |
81 | int err = errno;
82 | if (err == EINTR) {
83 | // ok
84 | } else {
85 | NABTO_LOG_ERROR(("Select returned error %s, %i", strerror(err), err));
86 | return;
87 | }
88 |
89 | }
90 |
91 | unabto_time_update_stamp();
92 |
93 | if (nfds > 0) {
94 | #if NABTO_ENABLE_TCP_FALLBACK
95 | unabto_tcp_fallback_select_write_sockets(&write_fds);
96 | unabto_tcp_fallback_select_read_sockets(&read_fds);
97 | #endif
98 | unabto_network_select_read_sockets(&read_fds);
99 |
100 | unabto_tunnel_select_handle(&read_fds, &write_fds);
101 | }
102 | unabto_time_event();
103 | }
104 | deinit_tunnel_module();
105 | unabto_close();
106 | }
107 |
108 |
--------------------------------------------------------------------------------
/components/nabtotunnel/unabto_tunnel_select.h:
--------------------------------------------------------------------------------
1 | #ifndef _TUNNEL_SELECT_H_
2 | #define _TUNNEL_SELECT_H_
3 |
4 | void tunnel_loop_select(void);
5 |
6 | #endif
7 |
--------------------------------------------------------------------------------
/components/nabtotunnel/unabto_tunnel_tcp.h:
--------------------------------------------------------------------------------
1 | #ifndef _TUNNEL_TCP_H_
2 | #define _TUNNEL_TCP_H_
3 | #include
4 |
5 | /**
6 | * return false to disallow connections to the specified host:port
7 | */
8 | bool tunnel_allow_connection(const char* host, int port);
9 |
10 | void tcp_forward(tunnel* tunnel);
11 | void unabto_forward_tcp(tunnel* tunnel);
12 | bool opening_socket(tunnel* tunnel);
13 | bool open_socket(tunnel* tunnel);
14 |
15 | void unabto_tunnel_tcp_init(tunnel* tunnel);
16 |
17 | void unabto_tunnel_tcp_parse_command(tunnel* tunnel, tunnel_event_source event_source);
18 |
19 | void unabto_tunnel_tcp_event(tunnel* tunnel, tunnel_event_source event_source);
20 |
21 | void unabto_tunnel_tcp_set_default_host(const char* host);
22 | void unabto_tunnel_tcp_set_default_port(uint16_t port);
23 |
24 | const char* unabto_tunnel_tcp_get_default_host();
25 | uint16_t unabto_tunnel_tcp_get_default_port();
26 |
27 | #ifndef UNABTO_TUNNEL_TCP_DEFAULT_PORT
28 | #define UNABTO_TUNNEL_TCP_DEFAULT_PORT 22
29 | #endif
30 |
31 | #ifndef UNABTO_TUNNEL_TCP_DEFAULT_HOST
32 | #define UNABTO_TUNNEL_TCP_DEFAULT_HOST "127.0.0.1"
33 | #endif
34 |
35 | #endif // _TUNNEL_TCP_H_
36 |
--------------------------------------------------------------------------------
/components/unabto-esp-fingerprint/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | idf_component_register(SRCS ../../unabto/src/modules/fingerprint_acl/fp_acl.c ../../unabto/src/modules/fingerprint_acl/fp_acl_ae.c ../../unabto/src/modules/fingerprint_acl/fp_acl_memory.c
3 | INCLUDE_DIRS . ../unabto-esp-idf ../../unabto/src ../../unabto/src/modules/network/tcp/
4 | REQUIRES )
5 |
6 |
--------------------------------------------------------------------------------
/components/unabto-esp-fingerprint/component.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Component Makefile
3 | #
4 |
5 | COMPONENT_ADD_INCLUDEDIRS := . ../../unabto/src ../unabto-esp-idf
6 | COMPONENT_SRCDIRS := ../../unabto/src/modules/fingerprint_acl
7 |
8 | COMPONENT_OBJS := ../../unabto/src/modules/fingerprint_acl/fp_acl.o \
9 | ../../unabto/src/modules/fingerprint_acl/fp_acl_ae.o \
10 | ../../unabto/src/modules/fingerprint_acl/fp_acl_memory.o
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | set(esp-idf-nabto-src "./dns_adapter.c"
3 | "./network_adapter.c"
4 | "./random_adapter.c"
5 | "./time_adapter.c"
6 | "./unabto_aes_cbc_test.c"
7 | "./unabto_basename.c"
8 | "./unabto_log_header_unix.c"
9 | "./crypto/unabto_aes.c"
10 | "./crypto/unabto_aes_cbc.c"
11 | "./crypto/unabto_hmac_sha256.c"
12 | "./crypto/unabto_sha256.c")
13 |
14 | idf_component_register(SRCS ${esp-idf-nabto-src} ${unabto_core_src}
15 | INCLUDE_DIRS "." "../../unabto/src"
16 | REQUIRES mbedtls)
17 |
18 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/README.md:
--------------------------------------------------------------------------------
1 |
2 | This directory contains the glue for ESP-IDF integration with Nabto
3 | Also, the component ensures to include the right uNabto directories with sourcefiles for the firmware
4 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/component.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Component Makefile
3 | #
4 |
5 | COMPONENT_ADD_INCLUDEDIRS := . ./utunnel/ ../../unabto/src
6 | COMPONENT_SRCDIRS := . ./crypto ./utunnel/ ../../unabto/src/unabto ../../unabto/src/modules/log
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/crypto/unabto_aes.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Nabto - All Rights Reserved.
3 | */
4 | #ifndef _UNABTO_AES_H_
5 | #define _UNABTO_AES_H_
6 |
7 | #include "unabto/unabto_env_base.h"
8 |
9 | #ifdef __cplusplus
10 | extern "C" {
11 | #endif
12 |
13 | #define AES_MAXROUNDS 14
14 | #define AES_IV_SIZE 16
15 | #define AES_BLOCKSIZE 16
16 |
17 | typedef struct aes_key_st
18 | {
19 | uint16_t rounds;
20 | uint16_t key_size;
21 | uint32_t ks[(AES_MAXROUNDS+1)*8];
22 | uint8_t iv[AES_IV_SIZE];
23 | } AES_CTX;
24 |
25 | typedef enum
26 | {
27 | AES_MODE_128,
28 | AES_MODE_256
29 | } AES_MODE;
30 |
31 | void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
32 | void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
33 |
34 | void AES_set_key(AES_CTX *ctx, const uint8_t* key,
35 | const uint8_t *iv, AES_MODE mode);
36 |
37 | void AES_convert_key(AES_CTX *ctx);
38 |
39 | void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length);
40 |
41 | void AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length);
42 |
43 |
44 | #ifdef __cplusplus
45 | } //extern "C"
46 | #endif
47 |
48 | #endif
49 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/crypto/unabto_aes_cbc.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Nabto - All Rights Reserved.
3 | */
4 | #include "unabto/unabto_env_base.h"
5 |
6 | #if NABTO_ENABLE_UCRYPTO
7 |
8 | #include "unabto/unabto_aes_cbc.h"
9 | #include "modules/crypto/generic/unabto_aes.h"
10 | #include "mbedtls/aes.h"
11 |
12 |
13 |
14 | bool unabto_aes128_cbc_encrypt(const uint8_t* key, uint8_t* input, uint16_t input_len) {
15 |
16 | int ret=0;
17 |
18 | uint8_t cbc[16];
19 |
20 |
21 | mbedtls_aes_context aes;
22 | if ((input_len < 16) || (input_len % 16 != 0)) {
23 | return false;
24 | }
25 |
26 | //mbedtls_aes_init( &aes );
27 |
28 | ret = mbedtls_aes_setkey_enc( &aes, key, 128 );
29 | if(ret < 0) {
30 | mbedtls_aes_free(&aes );
31 | NABTO_LOG_ERROR(("AES error in encrypt - could not setkey_dec ret:%d", ret));
32 | return false;
33 | }
34 |
35 | // Crypto alters the IV.. so we need to copy it first
36 | memcpy(cbc, input, 16);
37 | ret = mbedtls_aes_crypt_cbc( &aes, MBEDTLS_AES_ENCRYPT, input_len-16, cbc, input+16, input+16);
38 |
39 | if(ret != 0) {
40 | NABTO_LOG_ERROR(("AES error in encrypt %d", ret));
41 | }
42 | //mbedtls_aes_free(&aes);
43 | return ret==0;
44 | }
45 |
46 | /**
47 | * we are running the algoritm backwards to eliminate the need to remember too much state.
48 | */
49 | bool unabto_aes128_cbc_decrypt(const uint8_t* key, uint8_t* input, uint16_t input_len) {
50 |
51 | int ret = 0;
52 |
53 | mbedtls_aes_context aes;
54 | if ((input_len < 16) || (input_len % 16 != 0)) {
55 | return false;
56 | }
57 |
58 | mbedtls_aes_init( &aes );
59 |
60 | ret = mbedtls_aes_setkey_dec( &aes, key, 128 );
61 |
62 | if(ret < 0) {
63 | mbedtls_aes_free(&aes );
64 | NABTO_LOG_ERROR(("AES error in decrypt - could not setkey_dec ret:%d", ret));
65 | return false;
66 | }
67 |
68 | ret = mbedtls_aes_crypt_cbc( &aes, MBEDTLS_AES_DECRYPT, input_len-16, input, input+16, input+16);
69 |
70 | if(ret != 0) {
71 | NABTO_LOG_ERROR(("AES error in encrypt ret:%d", ret));
72 | }
73 | mbedtls_aes_free(&aes);
74 | return ret==0;
75 | }
76 |
77 | #endif /*NABTO_ENABLE_UCRYPTO*/
78 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/crypto/unabto_hmac_sha256.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Nabto - All Rights Reserved.
3 | */
4 | #define NABTO_LOG_MODULE_CURRENT NABTO_LOG_MODULE_ENCRYPTION
5 |
6 | #include
7 |
8 | #if NABTO_ENABLE_UCRYPTO
9 |
10 |
11 | #include "mbedtls/md.h"
12 | #include
13 | #include "unabto_sha256.h"
14 |
15 | #include
16 |
17 | /* HMAC-SHA-256 functions */
18 |
19 | //static sha256_ctx sha_ctx;
20 | //static uint8_t block_pad[SHA256_BLOCK_LENGTH];
21 |
22 | //void print_sha256_ctx(sha256_ctx* ctx);
23 |
24 | void unabto_hmac_sha256_buffers(const unabto_buffer keys[], uint8_t keys_size,
25 | const unabto_buffer messages[], uint8_t messages_size,
26 | uint8_t *mac, uint16_t mac_size)
27 | {
28 |
29 | uint16_t keySize = 0;
30 | uint16_t i;
31 |
32 | uint8_t key[UNABTO_SHA256_BLOCK_LENGTH];
33 | uint8_t* ptr;
34 | int res;
35 |
36 | uint8_t hmacResult[32];
37 |
38 |
39 | for (i = 0; i < keys_size; i++) {
40 | keySize += keys[i].size;
41 | }
42 |
43 | UNABTO_ASSERT(keySize <= UNABTO_SHA256_BLOCK_LENGTH);
44 |
45 | ptr = key;
46 | for(i = 0; i < keys_size; i++) {
47 | memcpy(ptr, (const void*) keys[i].data, keys[i].size);
48 | ptr += keys[i].size;
49 | }
50 |
51 |
52 |
53 | mbedtls_md_context_t ctx;
54 | mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
55 |
56 |
57 | mbedtls_md_init(&ctx);
58 | mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1);
59 | mbedtls_md_hmac_starts(&ctx, (const unsigned char *) key, keySize);
60 |
61 | for (i = 0; i < messages_size; i++) {
62 | if (messages[i].size > 0) {
63 | res = mbedtls_md_hmac_update(&ctx, (const unsigned char *) messages[i].data, messages[i].size);
64 | if (res != 0) {
65 | NABTO_LOG_ERROR(("mbedtls_md_hmac_update error"));
66 | }
67 | }
68 | }
69 |
70 |
71 | mbedtls_md_hmac_finish(&ctx, hmacResult);
72 | mbedtls_md_free(&ctx);
73 |
74 | memcpy(mac, hmacResult, mac_size);
75 |
76 |
77 | }
78 |
79 | #endif /* NABTO_ENABLE_UCRYPTO */
80 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/crypto/unabto_sha256.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Nabto - All Rights Reserved.
3 | */
4 | /*
5 | * FILE: sha2.h
6 | * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/
7 | *
8 | * Copyright (c) 2000-2001, Aaron D. Gifford
9 | * All rights reserved.
10 | *
11 | * Redistribution and use in source and binary forms, with or without
12 | * modification, are permitted provided that the following conditions
13 | * are met:
14 | * 1. Redistributions of source code must retain the above copyright
15 | * notice, this list of conditions and the following disclaimer.
16 | * 2. Redistributions in binary form must reproduce the above copyright
17 | * notice, this list of conditions and the following disclaimer in the
18 | * documentation and/or other materials provided with the distribution.
19 | * 3. Neither the name of the copyright holder nor the names of contributors
20 | * may be used to endorse or promote products derived from this software
21 | * without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 | * SUCH DAMAGE.
34 | *
35 | * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $
36 | */
37 |
38 | #ifndef _SHA256_H_
39 | #define _SHA256_H_
40 |
41 | #if NABTO_SLIM
42 | #include
43 | #else
44 | #include
45 | #endif
46 |
47 | #ifdef __cplusplus
48 | extern "C" {
49 | #endif
50 |
51 | enum {
52 | SHA256_BLOCK_LENGTH = 64,
53 | #ifndef SHA256_DIGEST_LENGTH // Defined in openssl hence we need to avoid collision.
54 | SHA256_DIGEST_LENGTH = 32,
55 | #endif
56 | SHA256_BLOCK_SIZE = SHA256_BLOCK_LENGTH, // deprecated
57 | SHA256_DIGEST_SIZE = SHA256_DIGEST_LENGTH // deprecated
58 | };
59 |
60 |
61 | /*** SHA-256/384/512 Various Length Definitions ***********************/
62 |
63 | typedef struct {
64 | uint32_t state[8];
65 | uint8_t buffer[SHA256_BLOCK_LENGTH];
66 | uint16_t byteCount;
67 | } sha256_ctx;
68 |
69 |
70 | /**
71 | * Initialize the sha256 context
72 | * @param sha256_ctx context to be initialized
73 | */
74 | void unabto_sha256_init(sha256_ctx *context);
75 |
76 | /**
77 | * Update the sha256 context with the given data
78 | */
79 | void unabto_sha256_update(sha256_ctx* context, const uint8_t* data, uint16_t length);
80 |
81 | void unabto_sha256_final(sha256_ctx* context, uint8_t* digest);
82 |
83 |
84 | #ifdef __cplusplus
85 | } //extern "C"
86 | #endif
87 |
88 | #endif
89 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/dns_adapter.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "lwip/dns.h"
4 | #include "lwip/inet.h"
5 | #include "lwip/ip_addr.h"
6 | #include "lwip/ip4_addr.h"
7 | #include "lwip/dns.h"
8 |
9 |
10 | static uint32_t basestationIPV4 = 0;
11 |
12 | static void dns_callback(const char *name, const ip_addr_t *ipAddr, void *dummy)
13 | {
14 | (void)dummy;
15 | if (ipAddr) {
16 | basestationIPV4 = ntohl(ip_addr_get_ip4_u32(ipAddr));
17 | }
18 | }
19 |
20 |
21 |
22 | void nabto_dns_resolve(const char* id)
23 | {
24 |
25 | basestationIPV4 = 0;
26 | ip_addr_t resolvedIp;
27 | ip_addr_t* dummy = &resolvedIp; // To get past some stupid warnings treated as errors
28 | switch(dns_gethostbyname(id, dummy, dns_callback, NULL))
29 | {
30 | case ERR_OK:
31 | basestationIPV4 = ntohl(ip_addr_get_ip4_u32(dummy));
32 | break;
33 | case ERR_INPROGRESS:
34 | basestationIPV4 = 0;
35 | break;
36 | default:
37 | NABTO_LOG_ERROR(("DNS call failed"));
38 | basestationIPV4 = -1;
39 | }
40 | }
41 |
42 | //TBC
43 | nabto_dns_status_t nabto_dns_is_resolved(const char* id, struct nabto_ip_address* v4addr)
44 | {
45 | switch(basestationIPV4)
46 | {
47 | case 0:
48 | return NABTO_DNS_NOT_FINISHED;
49 | case -1:
50 | return NABTO_DNS_ERROR;
51 | default:
52 | v4addr->addr.ipv4 = basestationIPV4;
53 | v4addr->type = NABTO_IP_V4;
54 | return NABTO_DNS_OK;
55 | }
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/network_adapter.c:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | #include
14 | #include
15 |
16 | #include
17 |
18 | #include
19 | #include
20 |
21 | #define MAX(a,b) (((a)>(b))?(a):(b))
22 |
23 |
24 | #include "unabto_platform.h"
25 |
26 |
27 | typedef struct socketListElement {
28 | nabto_socket_t socket;
29 | struct socketListElement *prev;
30 | struct socketListElement *next;
31 | } socketListElement;
32 |
33 | static NABTO_THREAD_LOCAL_STORAGE struct socketListElement* socketList = 0;
34 |
35 |
36 |
37 |
38 | void nabto_socket_set_invalid(nabto_socket_t* s) {
39 | s->sock = -1;
40 | }
41 |
42 | bool nabto_socket_is_equal(const nabto_socket_t* s1, const nabto_socket_t* s2) {
43 | return s1->sock == s2->sock;
44 | }
45 |
46 | void nabto_resolve_ipv4(uint32_t ipv4, struct nabto_ip_address* ip) {
47 | ip->type = NABTO_IP_V4;
48 | ip->addr.ipv4 = ipv4;
49 | }
50 |
51 |
52 | /**
53 | * Close a socket.
54 | * Close can be called on already closed sockets. And should tolerate this behavior.
55 | *
56 | * @param socket the socket to be closed
57 | */
58 | void nabto_socket_close(nabto_socket_t* sock)
59 | {
60 |
61 | if (sock && sock->sock != NABTO_INVALID_SOCKET) {
62 | socketListElement* se;
63 | socketListElement* found = 0;
64 | DL_FOREACH(socketList,se) {
65 | if (se->socket.sock == sock->sock) {
66 | found = se;
67 | break;
68 | }
69 | }
70 | if (!found) {
71 | NABTO_LOG_ERROR(("Socket %i Not found in socket list", sock->sock));
72 | } else {
73 | DL_DELETE(socketList, se);
74 | free(se);
75 | }
76 |
77 | close(sock->sock);
78 | sock->sock = NABTO_INVALID_SOCKET;
79 |
80 | }
81 |
82 | }
83 |
84 |
85 | bool nabto_socket_init(uint16_t* localPort, nabto_socket_t* sock) {
86 |
87 | socketListElement* se;
88 | int sd;
89 |
90 | NABTO_LOG_TRACE(("Open socket: port=%u", (int)*localPort));
91 |
92 | sd = socket(AF_INET, SOCK_DGRAM, 0);
93 |
94 | NABTO_LOG_TRACE(("Created socket: %u", (int)sd));
95 |
96 | if (sd == -1) {
97 | NABTO_LOG_ERROR(("Unable to create socket: (%i) '%s'.", errno, strerror(errno)));
98 | return false;
99 | }
100 |
101 | {
102 | struct sockaddr_in sa;
103 | int status;
104 | memset(&sa, 0, sizeof(sa));
105 | sa.sin_family = AF_INET;
106 | sa.sin_addr.s_addr = INADDR_ANY;
107 | sa.sin_port = htons(*localPort);
108 |
109 | status = bind(sd, (struct sockaddr*)&sa, sizeof(sa));
110 |
111 | if (status < 0) {
112 | NABTO_LOG_ERROR(("Unable to bind socket: (%i) '%s'.", errno, strerror(errno)));
113 | close(sd);
114 | return false;
115 | }
116 | int flags = fcntl(sd, F_GETFL, 0);
117 | if (flags == -1) flags = 0;
118 | fcntl(sd, F_SETFL, flags | O_NONBLOCK);
119 |
120 | se = (socketListElement*)malloc(sizeof(socketListElement));
121 | if (!se) {
122 | NABTO_LOG_FATAL(("Malloc of a single small list element should not fail!"));
123 | close(sd);
124 | return false;
125 | }
126 | se->socket.sock = sd;
127 | DL_APPEND(socketList, se);
128 | sock->sock = sd;
129 | }
130 | {
131 | struct sockaddr_in sao;
132 | socklen_t len = sizeof(sao);
133 | if ( getsockname(sd, (struct sockaddr*)&sao, &len) != -1) {
134 | *localPort = htons(sao.sin_port);
135 | } else {
136 | NABTO_LOG_ERROR(("Unable to get local port of socket: (%i) '%s'.", errno, strerror(errno)));
137 | }
138 | }
139 |
140 | NABTO_LOG_INFO(("Socket opened: port=%u", (int)*localPort));
141 |
142 | return true;
143 | }
144 |
145 | void nabto_close_socket(nabto_socket_t* s) {
146 | if (s && s->sock != NABTO_INVALID_SOCKET) {
147 | close(s->sock);
148 | s->sock = NABTO_INVALID_SOCKET;
149 | }
150 | }
151 |
152 | ssize_t nabto_read(nabto_socket_t s,
153 | uint8_t* buf,
154 | size_t len,
155 | struct nabto_ip_address* addr,
156 | uint16_t* port)
157 | {
158 | int res;
159 | struct sockaddr_in sa;
160 | size_t salen = sizeof(sa);
161 | memset(&sa, 0, sizeof(sa));
162 | sa.sin_family = AF_INET;
163 | res = recvfrom(s.sock, (char*) buf, (int)len, 0, (struct sockaddr*)&sa, &salen);
164 |
165 | if (res >= 0) {
166 | addr->type = NABTO_IP_V4;
167 | addr->addr.ipv4 = ntohl(sa.sin_addr.s_addr);
168 | *port = ntohs(sa.sin_port);
169 | NABTO_LOG_TRACE(("Socket read: ip=" PRIip ", port=%u", MAKE_IP_PRINTABLE(addr->addr.ipv4), (int)*port));
170 | }
171 | return res;
172 | }
173 |
174 | ssize_t nabto_write(nabto_socket_t s,
175 | const uint8_t* buf,
176 | size_t len,
177 | const struct nabto_ip_address* addr,
178 | uint16_t port)
179 | {
180 | int res;
181 | struct sockaddr_in sa;
182 | memset(&sa, 0, sizeof(sa));
183 | sa.sin_family = AF_INET;
184 | sa.sin_addr.s_addr = htonl((*addr).addr.ipv4);
185 | sa.sin_port = htons(port);
186 | res = sendto(s.sock, buf, (int)len, 0, (struct sockaddr*)&sa, sizeof(sa));
187 | NABTO_LOG_TRACE(("Socket write: ip=" PRIip ", port=%u socket:%i", MAKE_IP_PRINTABLE(addr->addr.ipv4), (int)port, s.sock));
188 | if (res < 0) {
189 | NABTO_LOG_ERROR(("ERROR: %i in nabto_write() '%s'", (int) errno,strerror(errno)));
190 | }
191 | return res;
192 | }
193 |
194 |
195 | void unabto_network_select_add_to_read_fd_set(fd_set* readFds, int* maxReadFd) {
196 | socketListElement* se;
197 | DL_FOREACH(socketList, se) {
198 | //NABTO_LOG_TRACE(("Adding Socket:%i to read_fd_set", se->socket.sock));
199 | FD_SET(se->socket.sock, readFds);
200 | *maxReadFd = MAX(*maxReadFd, se->socket.sock);
201 | }
202 | }
203 |
204 | void unabto_network_select_read_sockets(fd_set* readFds) {
205 | socketListElement* se;
206 | DL_FOREACH(socketList, se) {
207 | if (FD_ISSET(se->socket.sock, readFds)) {
208 | unabto_read_socket(se->socket);
209 | }
210 | }
211 | }
212 |
213 |
214 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/random_adapter.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "esp_system.h"
3 | #include
4 |
5 |
6 | #define MIN(a,b) (((a)<(b))?(a):(b))
7 |
8 |
9 | /**
10 | * Note: esp_random can first be called after wifi has been initialized...
11 | * So don't use this implementation on on pure ethernet systems
12 | */
13 | void nabto_random(uint8_t* buf, size_t len) {
14 | if(buf == NULL)
15 | return;
16 |
17 | uint32_t random;
18 | for(int i=0; i MAX_STAMP_DIFF;
17 | }
18 |
19 | nabto_stamp_diff_t nabtoStampDiff(nabto_stamp_t * newest, nabto_stamp_t * oldest) {
20 | return (*newest - *oldest);
21 | }
22 |
23 | int nabtoStampDiff2ms(nabto_stamp_diff_t diff) {
24 | return (int) diff*portTICK_PERIOD_MS;
25 | }
26 |
27 | void unabto_time_auto_update(bool enabled) {
28 | }
29 |
30 | void unabto_time_update_stamp() {
31 | }
32 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/unabto_aes_cbc_test.c:
--------------------------------------------------------------------------------
1 |
2 | #include
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | /**
9 | Case #4: Encrypting 64 bytes (4 blocks) using AES-CBC with 128-bit key
10 | Key : 0x56e47a38c5598974bc46903dba290349
11 | IV : 0x8ce82eefbea0da3c44699ed7db51b7d9
12 | Plaintext : 0xa0a1a2a3a4a5a6a7a8a9aaabacadaeaf
13 | b0b1b2b3b4b5b6b7b8b9babbbcbdbebf
14 | c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
15 | d0d1d2d3d4d5d6d7d8d9dadbdcdddedf
16 | Ciphertext: 0xc30e32ffedc0774e6aff6af0869f71aa
17 | 0f3af07a9a31a9c684db207eb0ef8e4e
18 | 35907aa632c3ffdf868bb7b29d3d46ad
19 | 83ce9f9a102ee99d49a53e87f4c3da55
20 | */
21 |
22 |
23 | static uint8_t plaintext[80];
24 |
25 |
26 | static const uint8_t key[16] = {0x56, 0xe4, 0x7a, 0x38, 0xc5, 0x59, 0x89, 0x74,
27 | 0xbc, 0x46, 0x90, 0x3d, 0xba, 0x29, 0x03, 0x49};
28 |
29 | static const uint8_t iv[16] = {0x8c, 0xe8, 0x2e, 0xef, 0xbe, 0xa0, 0xda, 0x3c, 0x44, 0x69, 0x9e, 0xd7, 0xdb, 0x51, 0xb7, 0xd9};
30 |
31 | // with iv
32 | static uint8_t ciphertext[80] = {0x8c, 0xe8, 0x2e, 0xef, 0xbe, 0xa0, 0xda, 0x3c, 0x44, 0x69, 0x9e, 0xd7, 0xdb, 0x51, 0xb7, 0xd9,
33 | 0xc3, 0x0e, 0x32, 0xff, 0xed, 0xc0, 0x77, 0x4e, 0x6a, 0xff, 0x6a, 0xf0, 0x86, 0x9f, 0x71, 0xaa,
34 | 0x0f, 0x3a, 0xf0, 0x7a, 0x9a, 0x31, 0xa9, 0xc6, 0x84, 0xdb, 0x20, 0x7e, 0xb0, 0xef, 0x8e, 0x4e,
35 | 0x35, 0x90, 0x7a, 0xa6, 0x32, 0xc3, 0xff, 0xdf, 0x86, 0x8b, 0xb7, 0xb2, 0x9d, 0x3d, 0x46, 0xad,
36 | 0x83, 0xce, 0x9f, 0x9a, 0x10, 0x2e, 0xe9, 0x9d, 0x49, 0xa5, 0x3e, 0x87, 0xf4, 0xc3, 0xda, 0x55};
37 |
38 | bool aes_cbc_test(void)
39 | {
40 | bool ret = true;
41 | bool r;
42 | int i;
43 |
44 | memcpy(plaintext, iv, 16);
45 | for(i = 0; i < 64; i++)
46 | {
47 | plaintext[16 + i] = 160 + i;
48 | }
49 |
50 | if(!unabto_aes128_cbc_encrypt(key, plaintext, sizeof (plaintext)))
51 | {
52 | NABTO_LOG_TRACE(("aes_cbc_encrypt failed"));
53 | }
54 | r = (memcmp((void*) plaintext, (void*) ciphertext, sizeof (ciphertext)) == 0);
55 | ret &= r;
56 | if(!r)
57 | {
58 | NABTO_LOG_INFO(("Aes cbc encryption failed"));
59 | }
60 |
61 | if(!unabto_aes128_cbc_decrypt(key, ciphertext, sizeof (ciphertext)))
62 | {
63 | NABTO_LOG_TRACE(("aes_cbc decrypt failed"));
64 | }
65 | r = true;
66 | for(i = 0; i < 64; i++)
67 | {
68 | if(ciphertext[16 + i] != 160 + i)
69 | {
70 | r = false;
71 | }
72 | }
73 |
74 | ret &= r;
75 | if(!r)
76 | {
77 | NABTO_LOG_INFO(("Aes_cbc decryption failed"));
78 | }
79 |
80 | NABTO_LOG_INFO(("Aes_cbc decryption succeeded"));
81 |
82 | return ret;
83 | }
84 |
85 | int aes_cbc_timing_test(void)
86 | {
87 | nabto_stamp_t future;
88 | int i = 0;
89 |
90 | nabtoSetFutureStamp(&future, 1000);
91 |
92 | while(!nabtoIsStampPassed(&future))
93 | {
94 | unabto_aes128_cbc_encrypt(key, plaintext, sizeof (plaintext));
95 | unabto_aes128_cbc_decrypt(key, plaintext, sizeof (plaintext));
96 | i++;
97 | }
98 |
99 | return i;
100 | }
101 |
102 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/unabto_aes_cbc_test.h:
--------------------------------------------------------------------------------
1 | #ifndef _AES_CBC_TEST_H_
2 | #define _AES_CBC_TEST_H_
3 |
4 | #include
5 |
6 | bool aes_cbc_test(void);
7 | int aes_cbc_timing_test(void);
8 |
9 | #endif
10 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/unabto_basename.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2008-2013 Nabto - All Rights Reserved.
3 | */
4 | #if defined(_MSC_VER)
5 | #ifndef _CRT_SECURE_NO_WARNINGS
6 | #define _CRT_SECURE_NO_WARNINGS
7 | #endif
8 | #endif
9 |
10 | #include
11 | #include
12 |
13 |
14 | #include
15 |
16 | /** @return the filename part (without preceeding path) of a file pathname.
17 | * @param path pathname to a file. */
18 | const char* unabto_basename(const char* path)
19 | {
20 | const char *p;
21 | char ch;
22 |
23 | p = path + strlen(path);
24 | while (p > path) {
25 | ch = *(p - 1);
26 | if (ch == '/' || ch == '\\' || ch == ':')
27 | break;
28 | --p;
29 | }
30 | return p;
31 | }
32 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/unabto_basename.h:
--------------------------------------------------------------------------------
1 | #ifndef _UNABTO_BASENAME_H_
2 | #define _UNABTO_BASENAME_H_
3 | const char* unabto_basename(const char* path);
4 | #endif
5 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/unabto_config.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #define UNABTO_PLATFORM_CUSTOM 1
4 | #define NABTO_SET_TIME_FROM_ALIVE 0
5 | #define NABTO_ENABLE_REMOTE_CONNECTION 1
6 |
7 |
8 | // From tunnel config
9 |
10 | #define NABTO_ENABLE_CONNECTION_ESTABLISHMENT_ACL_CHECK 1
11 | #define NABTO_ENABLE_TUNNEL_OPEN_ACL_CHECK 1
12 |
13 | #define NABTO_ENABLE_STREAM 1
14 | #define NABTO_STREAM_MAX_STREAMS 1
15 |
16 | //#define NABTO_STREAM_RECEIVE_WINDOW_SIZE 2
17 | #define NABTO_STREAM_RECEIVE_WINDOW_SIZE 10
18 | //#define NABTO_STREAM_SEND_WINDOW_SIZE 8
19 | #define NABTO_STREAM_SEND_WINDOW_SIZE 60
20 |
21 |
22 | #define NABTO_APPLICATION_EVENT_MODEL_ASYNC 1
23 | #define NABTO_ENABLE_EXTENDED_RENDEZVOUS_MULTIPLE_SOCKETS 0
24 |
25 | #define NABTO_CONNECTIONS_SIZE 3
26 | #define NABTO_APPREQ_QUEUE_SIZE NABTO_CONNECTIONS_SIZE
27 |
28 | //#define NABTO_ENABLE_DEBUG_PACKETS 1
29 | //#define NABTO_ENABLE_DEBUG_SYSLOG_CONFIG 1
30 | //#define NABTO_ENABLE_GET_LOCAL_IP 1
31 |
32 | #define NABTO_ENABLE_DYNAMIC_MEMORY 1
33 |
34 | //#define NABTO_ENABLE_TCP_FALLBACK 1
35 |
36 | #define NABTO_ENABLE_TUNNEL_TCP 1
37 | #define NABTO_ENABLE_TUNNEL_STATUS_CALLBACKS 1
38 |
39 | #define NABTO_ENABLE_LOCAL_PSK_CONNECTION 0
40 |
41 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/unabto_log_header_unix.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | int unabto_log_header(const char* file, unsigned int line)
12 | {
13 | time_t sec;
14 | unsigned int ms;
15 | struct timeval tv;
16 | struct tm tm;
17 | gettimeofday(&tv, NULL);
18 | sec = tv.tv_sec;
19 | ms = tv.tv_usec/1000;
20 |
21 | localtime_r(&sec, &tm);
22 |
23 | return printf("%02u:%02u:%02u:%03u %s(%u) ",
24 | tm.tm_hour, tm.tm_min, tm.tm_sec, ms,
25 | unabto_basename(file), (line));
26 | }
27 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/unabto_platform.h:
--------------------------------------------------------------------------------
1 | #include "unabto_platform_types.h"
2 |
3 | #include
4 | #include
5 | #include
6 |
7 |
8 |
9 | #define NABTO_INVALID_SOCKET -1
10 |
11 |
12 | //#ifndef NABTO_LOG_SEVERITY_FILTER
13 | //#define NABTO_LOG_SEVERITY_FILTER NABTO_LOG_SEVERITY_LEVEL_TRACE
14 | //#endif
15 |
16 |
17 | //#define NABTO_LOG_BASIC_PRINT(severity, message)
18 |
19 | #ifndef NABTO_LOG_BASIC_PRINT
20 | /** Print debugging info.
21 | * @param loglevel logging level
22 | * @param cmsg the message
23 | */
24 | #define NABTO_LOG_BASIC_PRINT(loglevel, cmsg) do { \
25 | unabto_log_header(__FILE__, __LINE__); \
26 | printf cmsg; \
27 | printf("\n"); \
28 | fflush(stdout); \
29 | } while(0)
30 | #endif
31 |
32 |
--------------------------------------------------------------------------------
/components/unabto-esp-idf/unabto_platform_types.h:
--------------------------------------------------------------------------------
1 | #ifndef _UNABTO_PLATFORM_TYPES_H_
2 | #define _UNABTO_PLATFORM_TYPES_H_
3 |
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include "freertos/FreeRTOS.h"
10 | #include
11 |
12 |
13 |
14 | /** The timestamp definition */
15 | typedef portTickType nabto_stamp_t;
16 | typedef nabto_stamp_t nabto_stamp_diff_t;
17 |
18 | #define nabtoMsec2Stamp(msec) (msec / portTICK_PERIOD_MS)
19 |
20 |
21 | //typedef int nabto_socket_t;
22 |
23 |
24 | typedef struct nabto_socket_t nabto_socket_t;
25 |
26 |
27 | //typedef int nabto_socket_t;
28 | struct nabto_socket_t {
29 | int sock;
30 | };
31 |
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/docs/ESP-EYE-browser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nabto/nabto-esp32cam/fb1d79a8ef65e475a00627f847f6c605ed3bcea1/docs/ESP-EYE-browser.png
--------------------------------------------------------------------------------
/docs/esp32cam-discover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nabto/nabto-esp32cam/fb1d79a8ef65e475a00627f847f6c605ed3bcea1/docs/esp32cam-discover.png
--------------------------------------------------------------------------------
/docs/esp32cam-overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nabto/nabto-esp32cam/fb1d79a8ef65e475a00627f847f6c605ed3bcea1/docs/esp32cam-overview.png
--------------------------------------------------------------------------------
/docs/esp32cam-overviewpaired.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nabto/nabto-esp32cam/fb1d79a8ef65e475a00627f847f6c605ed3bcea1/docs/esp32cam-overviewpaired.png
--------------------------------------------------------------------------------
/docs/esp32cam-viewcamera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nabto/nabto-esp32cam/fb1d79a8ef65e475a00627f847f6c605ed3bcea1/docs/esp32cam-viewcamera.png
--------------------------------------------------------------------------------
/main/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | idf_component_register(SRCS ./fp_acl_esp32_nvs.c ./main.c ./unabto_application.c
2 | INCLUDE_DIRS "." "../unabto/src" "../components/unabto-esp-idf" "../components/nabtotunnel" "../unabto/src/modules/log"
3 | REQUIRES )
4 |
5 |
--------------------------------------------------------------------------------
/main/Kconfig.projbuild:
--------------------------------------------------------------------------------
1 | menu "Camera configuration"
2 |
3 | config SSID
4 | string "WIFI access point name (SSID)"
5 | default "myaccesspoint"
6 | help
7 | Enter the name of the WIFI access point
8 |
9 | config SSID_PASSWORD
10 | string "WIFI password"
11 | default "12345678"
12 | help
13 | Enter ssid password
14 |
15 |
16 | config NABTO_ID
17 | string "Nabto ID"
18 | default "xxxxxxxx.yyyyy.appmyproduct.com"
19 | help
20 | Enter the Nabto id - you can get one from appmyproduct.com
21 |
22 | config NABTO_KEY
23 | string "Nabto key - 32 hex chars"
24 | default "01234567890123456789012345678912"
25 | help
26 | Enter the 32 char hex key that is for the device id
27 |
28 | choice CAMERA_WIRING
29 | prompt "Setup correct wiring of camera"
30 | default ESP-EYE
31 | help
32 | The different ESP32 camera modules uses different wiring for the camera.
33 | Please supply the correct one, or adjust the camera_config in main.c
34 | config ESP_EYE
35 | bool "ESP-EYE"
36 | config ESP_TINKER
37 | bool "Seedstudios/AI.Tinker"
38 | config M5CAMERA_A
39 | bool "M5Stack Camera A"
40 | endchoice
41 |
42 |
43 | endmenu
44 |
--------------------------------------------------------------------------------
/main/component.mk:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/main/demo_application.h:
--------------------------------------------------------------------------------
1 | #ifndef _DEMO_APPLICATION_H
2 | #define _DEMO_APPLICATION_H
3 |
4 | void demo_application_set_device_id(const char* id);
5 | void demo_application_set_device_name(const char* name);
6 | void demo_application_set_device_product(const char* product);
7 | void demo_application_set_device_icon_(const char* icon);
8 | void demo_application_tick();
9 | void demo_init();
10 |
11 | #endif
12 |
--------------------------------------------------------------------------------
/main/fp_acl_esp32_nvs.c:
--------------------------------------------------------------------------------
1 | /*
2 | @file fp_acl_esp32_nvs.c
3 | @brief Handles persistent storage of Nabto ACL into ESP32 NVS.
4 |
5 | Copyright (c) 2019 Connictro GmbH / Michael Paar
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11 | of the Software, and to permit persons to whom the Software is furnished to do
12 | so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
18 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
19 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21 | OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 | */
24 |
25 | /* Includes */
26 |
27 | //#include "app_common_defs.h"
28 | //#include "nabto_cred_config.h"
29 | //#include "esp_http_client.h"
30 | #include "nvs.h"
31 | #include "nvs_flash.h"
32 | #include "fp_acl_esp32_nvs.h"
33 |
34 | /* Macros */
35 |
36 | /* Static variables */
37 | static const char *NVS_NABTOPERSIST_TAG = "nabtopersist";
38 | static const char *NABTO_PERSIST_WHATSTR = "Nabto persistence store";
39 | #define NVS_STORAGE_NAMESPACE "nabtocreds"
40 |
41 |
42 |
43 | /* Implementation */
44 |
45 |
46 | /* Implementation */
47 |
48 | // Retrieve specific config string (key or modbus cfg) from NVS.
49 | esp_err_t _read_blob_from_nvs(char *blob, const char *nvstag, size_t sz, const char *what)
50 | {
51 | esp_err_t status = ESP_OK;
52 | nvs_handle nabto_nvs_handle;
53 |
54 | NABTO_LOG_TRACE(("open NVS storage"));
55 | status = nvs_open(NVS_STORAGE_NAMESPACE, NVS_READONLY, &nabto_nvs_handle);
56 | if (status != ESP_OK)
57 | return status;
58 |
59 | NABTO_LOG_TRACE(("namespace exists, trying to read %s from NVS", what));
60 | status = nvs_get_blob(nabto_nvs_handle, nvstag, blob, &sz);
61 |
62 | if (status != ESP_OK)
63 | {
64 | NABTO_LOG_ERROR(("No valid %s in NVS", what));
65 | status = ESP_ERR_NOT_FOUND;
66 | } else {
67 | NABTO_LOG_TRACE(("%s: %s read from NVS", what, blob));
68 | }
69 | nvs_close(nabto_nvs_handle);
70 |
71 | return status;
72 | }
73 |
74 | // write specific config string (key or modbus cfg) to NVS.
75 | esp_err_t _write_blob_to_nvs(char *blob, const char *nvstag, size_t sz, const char *what)
76 | {
77 | esp_err_t status = ESP_OK;
78 | nvs_handle nabto_nvs_handle;
79 |
80 | NABTO_LOG_INFO(("open NVS storage for write"));
81 | status = nvs_open(NVS_STORAGE_NAMESPACE, NVS_READWRITE, &nabto_nvs_handle);
82 | if (status != ESP_OK)
83 | return status;
84 |
85 | NABTO_LOG_INFO(("Writing %s to NVS", what));
86 |
87 | status = nvs_set_blob(nabto_nvs_handle, nvstag, blob, sz);
88 | if (status != ESP_OK)
89 | {
90 | nvs_close(nabto_nvs_handle);
91 | return status;
92 | }
93 |
94 | status = nvs_commit(nabto_nvs_handle);
95 | nvs_close(nabto_nvs_handle);
96 | NABTO_LOG_INFO(("End of write status:%i", status));
97 |
98 | return status;
99 | }
100 |
101 | esp_err_t _erase_tag_from_nvs(const char *nvstag, const char *what)
102 | {
103 | esp_err_t status = ESP_OK;
104 | nvs_handle nabto_nvs_handle;
105 |
106 | NABTO_LOG_INFO(("open NVS storage for erase"));
107 | status = nvs_open(NVS_STORAGE_NAMESPACE, NVS_READWRITE, &nabto_nvs_handle);
108 | if (status != ESP_OK)
109 | return status;
110 |
111 | NABTO_LOG_INFO(("Erasing %s from NVS", what));
112 | status = nvs_erase_key(nabto_nvs_handle, nvstag);
113 | nvs_close(nabto_nvs_handle);
114 | return status;
115 | }
116 |
117 |
118 | fp_acl_db_status fp_acl_nvs_load(struct fp_mem_state* acl)
119 | {
120 | esp_err_t status = _read_blob_from_nvs((void *)acl, NVS_NABTOPERSIST_TAG, sizeof(struct fp_mem_state), NABTO_PERSIST_WHATSTR);
121 |
122 | // The status is OK even if the NVS tag did not exist - bootstrap scenario (acl comes initialized with default values already).
123 | return (status == ESP_OK || status == ESP_ERR_NVS_NOT_FOUND) ? FP_ACL_DB_OK : FP_ACL_DB_LOAD_FAILED;
124 | }
125 |
126 | fp_acl_db_status fp_acl_nvs_save(struct fp_mem_state* acl)
127 | {
128 | esp_err_t status = _write_blob_to_nvs((void *)acl, NVS_NABTOPERSIST_TAG, sizeof(struct fp_mem_state), NABTO_PERSIST_WHATSTR);
129 |
130 | return (status == ESP_OK) ? FP_ACL_DB_OK : FP_ACL_DB_SAVE_FAILED;
131 | }
132 |
133 | fp_acl_db_status fp_acl_nvs_reset()
134 | {
135 | esp_err_t status = _erase_tag_from_nvs(NVS_NABTOPERSIST_TAG, NABTO_PERSIST_WHATSTR);
136 |
137 | return (status == ESP_OK) ? FP_ACL_DB_OK : FP_ACL_DB_SAVE_FAILED;
138 | }
139 |
140 | fp_acl_db_status fp_acl_nvs_init(struct fp_mem_persistence* per)
141 | {
142 | per->load = &fp_acl_nvs_load;
143 | per->save = &fp_acl_nvs_save;
144 | return FP_ACL_DB_OK;
145 | }
146 |
147 |
148 |
--------------------------------------------------------------------------------
/main/fp_acl_esp32_nvs.h:
--------------------------------------------------------------------------------
1 | /*
2 | @file fp_acl_esp32_nvs.h
3 | @brief Handles persistent storage of Nabto ACL into ESP32 NVS.
4 |
5 | Copyright (c) 2019 Connictro GmbH / Michael Paar
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11 | of the Software, and to permit persons to whom the Software is furnished to do
12 | so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
18 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
19 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21 | OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 | */
24 |
25 | /* Includes */
26 |
27 | #ifndef _FP_ACL_ESP32_NVS_H_
28 | #define _FP_ACL_ESP32_NVS_H_
29 |
30 | //#include "app_common_defs.h"
31 | //#include "nabto_cred_config.h"
32 | #include "nvs.h"
33 | #include "nvs_flash.h"
34 | #include
35 | #include
36 |
37 | /* Save / Load Nabto persistency information to/from NVS. */
38 | esp_err_t nabto_set_persistency_file(void *persist_str, size_t sz);
39 | esp_err_t nabto_get_persistency_file(void *persist_str, size_t sz);
40 |
41 | fp_acl_db_status fp_acl_nvs_save(struct fp_mem_state* acl);
42 | fp_acl_db_status fp_acl_nvs_load(struct fp_mem_state* acl);
43 | fp_acl_db_status fp_acl_nvs_reset();
44 | fp_acl_db_status fp_acl_nvs_init(struct fp_mem_persistence* per);
45 |
46 |
47 | #endif /* _FP_ACL_ESP32_NVS_H_ */
48 |
--------------------------------------------------------------------------------
/main/unabto_application.c:
--------------------------------------------------------------------------------
1 | /**
2 | * uNabto application logic implementation
3 | */
4 | #include "demo_application.h"
5 | #include
6 | #include "unabto/unabto_app.h"
7 | #include
8 | #include
9 | #include "fp_acl_esp32_nvs.h"
10 |
11 | typedef enum { HPM_COOL = 0,
12 | HPM_HEAT = 1,
13 | HPM_CIRCULATE = 2,
14 | HPM_DEHUMIDIFY = 3} heatpump_mode_t;
15 |
16 | #define AMP_DEVICE_NAME_DEFAULT "Tunnel"
17 | #define MAX_DEVICE_NAME_LENGTH 50
18 | static char device_name[MAX_DEVICE_NAME_LENGTH];
19 | static const char* device_product = "uNabto Video";
20 | static const char* device_icon = "video.png";
21 | static const char* device_interface_id_ = "8eee78e7-8f22-4019-8cee-4dcbc1c8186c";
22 | static uint16_t device_interface_version_major_ = 1;
23 | static uint16_t device_interface_version_minor_ = 0;
24 |
25 |
26 | static struct fp_acl_db db_;
27 | struct fp_mem_persistence fp_file_;
28 |
29 | #define REQUIRES_GUEST FP_ACL_PERMISSION_NONE
30 | #define REQUIRES_OWNER FP_ACL_PERMISSION_ADMIN
31 |
32 |
33 |
34 |
35 | void debug_dump_acl() {
36 | void* it = db_.first();
37 | NABTO_LOG_INFO(("Access control list dump:"));
38 | while (it != NULL) {
39 | struct fp_acl_user user;
40 | fp_acl_db_status res = db_.load(it, &user);
41 | if (res != FP_ACL_DB_OK) {
42 | NABTO_LOG_WARN(("ACL error %d\n", res));
43 | return;
44 | }
45 | NABTO_LOG_INFO(("%s [%02x:%02x:%02x:%02x:...]: %04x",
46 | user.name,
47 | user.fp.value.data[0],
48 | user.fp.value.data[1],
49 | user.fp.value.data[2],
50 | user.fp.value.data[3],
51 | user.permissions));
52 | it = db_.next(it);
53 | }
54 | }
55 |
56 | void demo_init() {
57 |
58 |
59 | NABTO_LOG_INFO(("In demo_init"));
60 |
61 | struct fp_acl_settings default_settings;
62 |
63 | default_settings.systemPermissions =
64 | FP_ACL_SYSTEM_PERMISSION_PAIRING |
65 | FP_ACL_SYSTEM_PERMISSION_LOCAL_ACCESS |
66 | FP_ACL_PERMISSION_REMOTE_ACCESS;
67 | default_settings.defaultUserPermissions =
68 | FP_ACL_PERMISSION_LOCAL_ACCESS|
69 | FP_ACL_PERMISSION_REMOTE_ACCESS;
70 | default_settings.firstUserPermissions =
71 | FP_ACL_PERMISSION_ADMIN |
72 | FP_ACL_PERMISSION_LOCAL_ACCESS |
73 | FP_ACL_PERMISSION_REMOTE_ACCESS;
74 |
75 |
76 | (void)fp_acl_nvs_init(&fp_file_); // persistence via ESP32 Non Volatile Store (NVS)
77 |
78 | NABTO_LOG_INFO(("Before fp_mem_init"));
79 | fp_mem_init(&db_, &default_settings, &fp_file_);
80 |
81 | NABTO_LOG_INFO(("Before acl_ae_init"));
82 | fp_acl_ae_init(&db_);
83 |
84 | //snprintf(device_name_, sizeof(device_name_), DEVICE_NAME_DEFAULT);
85 | //updateLed();
86 | }
87 |
88 |
89 | void demo_application_tick() {
90 |
91 | }
92 |
93 | int copy_buffer(unabto_query_request* read_buffer, uint8_t* dest, uint16_t bufSize, uint16_t* len) {
94 | uint8_t* buffer;
95 | if (!(unabto_query_read_uint8_list(read_buffer, &buffer, len))) {
96 | return AER_REQ_TOO_SMALL;
97 | }
98 | if (*len > bufSize) {
99 | return AER_REQ_TOO_LARGE;
100 | }
101 | memcpy(dest, buffer, *len);
102 | return AER_REQ_RESPONSE_READY;
103 | }
104 |
105 | int copy_string(unabto_query_request* read_buffer, char* dest, uint16_t destSize) {
106 | uint16_t len;
107 | int res = copy_buffer(read_buffer, (uint8_t*)dest, destSize-1, &len);
108 | if (res != AER_REQ_RESPONSE_READY) {
109 | return res;
110 | }
111 | dest[len] = 0;
112 | return AER_REQ_RESPONSE_READY;
113 | }
114 |
115 | int write_string(unabto_query_response* write_buffer, const char* string) {
116 | return unabto_query_write_uint8_list(write_buffer, (uint8_t *)string, strlen(string));
117 | }
118 |
119 | bool allow_client_access(nabto_connect* connection) {
120 | return true;
121 | bool local = connection->isLocal;
122 | bool allow = fp_acl_is_connection_allowed(connection) || local;
123 | NABTO_LOG_INFO(("Allowing %s connect request: %s", (local ? "local" : "remote"), (allow ? "yes" : "no")));
124 | debug_dump_acl();
125 | return allow;
126 | }
127 |
128 | application_event_result application_event(application_request* request,
129 | unabto_query_request* query_request,
130 | unabto_query_response* query_response) {
131 |
132 | NABTO_LOG_TRACE(("Nabto application_event: %u", request->queryId));
133 | debug_dump_acl();
134 |
135 | // handle requests as defined in interface definition shared with
136 | // client - for the default demo, see
137 | // https://github.com/nabto/ionic-starter-nabto/blob/master/www/nabto/unabto_queries.xml
138 |
139 | //application_event_result res;
140 |
141 | NABTO_LOG_INFO(("Nabto application_event: %u", request->queryId));
142 |
143 | if (request->queryId == 0) {
144 | // AMP get_interface_info.json
145 | if (!write_string(query_response, device_interface_id_)) return AER_REQ_RSP_TOO_LARGE;
146 | if (!unabto_query_write_uint16(query_response, device_interface_version_major_)) return AER_REQ_RSP_TOO_LARGE;
147 | if (!unabto_query_write_uint16(query_response, device_interface_version_minor_)) return AER_REQ_RSP_TOO_LARGE;
148 | return AER_REQ_RESPONSE_READY;
149 |
150 | } else if (request->queryId == 10000) {
151 | // AMP get_public_device_info.json
152 | if (!write_string(query_response, device_name)) return AER_REQ_RSP_TOO_LARGE;
153 | if (!write_string(query_response, device_product)) return AER_REQ_RSP_TOO_LARGE;
154 | if (!write_string(query_response, device_icon)) return AER_REQ_RSP_TOO_LARGE;
155 | if (!unabto_query_write_uint8(query_response, fp_acl_is_pair_allowed(request))) return AER_REQ_RSP_TOO_LARGE;
156 | if (!unabto_query_write_uint8(query_response, fp_acl_is_user_paired(request))) return AER_REQ_RSP_TOO_LARGE;
157 | if (!unabto_query_write_uint8(query_response, fp_acl_is_user_owner(request))) return AER_REQ_RSP_TOO_LARGE;
158 | return AER_REQ_RESPONSE_READY;
159 |
160 | } else if (request->queryId == 10010) {
161 | int res;
162 | // AMP set_device_info.json
163 | if (!fp_acl_is_request_allowed(request, REQUIRES_OWNER)) return AER_REQ_NO_ACCESS;
164 | res = copy_string(query_request, device_name, sizeof(device_name));
165 | if (res != AER_REQ_RESPONSE_READY) return res;
166 | if (!write_string(query_response, device_name)) return AER_REQ_RSP_TOO_LARGE;
167 | return AER_REQ_RESPONSE_READY;
168 |
169 | } else if (request->queryId >= 11000 && request->queryId < 12000) {
170 | // PPKA access control
171 | return fp_acl_ae_dispatch(11000, request, query_request, query_response);
172 |
173 | } else {
174 | NABTO_LOG_WARN(("Unhandled query id: %u", request->queryId));
175 | return AER_REQ_INV_QUERY_ID;
176 | }
177 |
178 | }
179 |
180 |
181 |
182 | bool application_poll_query(application_request** applicationRequest) {
183 | return false;
184 | }
185 |
186 | application_event_result application_poll(application_request* applicationRequest, unabto_query_response* writeBuffer) {
187 | return AER_REQ_SYSTEM_ERROR;
188 | }
189 |
190 | void application_poll_drop(application_request* applicationRequest) {
191 | }
192 |
--------------------------------------------------------------------------------
/partitions.csv:
--------------------------------------------------------------------------------
1 | # Espressif ESP32 Partition Table
2 | # Name, Type, SubType, Offset, Size
3 | factory, app, factory, 0x010000, 3M
4 | nvs, data, nvs, 0x310000, 16K
5 |
--------------------------------------------------------------------------------
/sdkconfig.defaults:
--------------------------------------------------------------------------------
1 |
2 |
3 | CONFIG_ESP32_SPIRAM_SUPPORT=y
4 | CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
5 |
6 |
7 |
--------------------------------------------------------------------------------