├── .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 | --------------------------------------------------------------------------------