├── .gitignore ├── LICENSE ├── README.md ├── air_firmware ├── .gitignore ├── .vscode │ └── settings.json ├── CMakeLists.txt ├── components │ └── esp32-camera │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ ├── Kconfig │ │ ├── LICENSE │ │ ├── README.md │ │ ├── component.mk │ │ ├── conversions │ │ ├── include │ │ │ ├── esp_jpg_decode.h │ │ │ └── img_converters.h │ │ └── private_include │ │ │ ├── jpge.h │ │ │ └── yuv.h │ │ ├── driver │ │ ├── camera.c │ │ ├── include │ │ │ ├── esp_camera.h │ │ │ └── sensor.h │ │ ├── private_include │ │ │ ├── camera_common.h │ │ │ ├── sccb.h │ │ │ └── xclk.h │ │ ├── sccb.c │ │ ├── sensor.c │ │ └── xclk.c │ │ ├── examples │ │ └── take_picture.c │ │ ├── library.json │ │ └── sensors │ │ ├── nt99141.c │ │ ├── ov2640.c │ │ ├── ov3660.c │ │ ├── ov5640.c │ │ ├── ov7670.c │ │ ├── ov7725.c │ │ └── private_include │ │ ├── nt99141.h │ │ ├── nt99141_regs.h │ │ ├── nt99141_settings.h │ │ ├── ov2640.h │ │ ├── ov2640_regs.h │ │ ├── ov2640_settings.h │ │ ├── ov3660.h │ │ ├── ov3660_regs.h │ │ ├── ov3660_settings.h │ │ ├── ov5640.h │ │ ├── ov5640_regs.h │ │ ├── ov5640_settings.h │ │ ├── ov7670.h │ │ ├── ov7670_regs.h │ │ ├── ov7725.h │ │ └── ov7725_regs.h ├── main │ ├── CMakeLists.txt │ ├── component.mk │ ├── main.cpp │ ├── main.h │ ├── queue.cpp │ └── queue.h └── sdkconfig ├── components └── common │ ├── CMakeLists.txt │ ├── circular_buffer.h │ ├── component.mk │ ├── crc.cpp │ ├── crc.h │ ├── fec.cpp │ ├── fec.h │ ├── fec_codec.cpp │ ├── fec_codec.h │ ├── packets.h │ ├── safe_printf.cpp │ ├── safe_printf.h │ ├── structures.cpp │ └── structures.h └── gs ├── .vscode └── settings.json ├── Makefile └── src ├── Clock.h ├── Comms.cpp ├── Comms.h ├── HUD.cpp ├── HUD.h ├── IHAL.h ├── Log.h ├── PI_HAL.cpp ├── PI_HAL.h ├── Video_Decoder.cpp ├── Video_Decoder.h ├── droid_sans_font.cpp ├── fmt ├── args.h ├── chrono.h ├── color.h ├── compile.h ├── core.h ├── format-inl.h ├── format.cc ├── format.h ├── locale.h ├── os.cc ├── os.h ├── ostream.h ├── posix.h ├── printf.h └── ranges.h ├── imgui ├── imconfig.h ├── imgui.cpp ├── imgui.h ├── imgui_demo.cpp ├── imgui_draw.cpp ├── imgui_impl_sdl.cpp ├── imgui_impl_sdl.h ├── imgui_internal.h ├── misc │ └── freetype │ │ ├── imgui_freetype.cpp │ │ └── imgui_freetype.h ├── stb_rect_pack.h ├── stb_textedit.h └── stb_truetype.h ├── imgui_impl_opengl3.cpp ├── imgui_impl_opengl3.h ├── main.cpp ├── main.h └── utils ├── Pool.h └── radiotap ├── ieee80211_radiotap.h ├── radiotap.cpp └── radiotap.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | tasks.json 35 | build.sh 36 | deploy.sh 37 | .DS_Store 38 | sdkconfig.old 39 | air_firmware/build -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 jeanleflambeur 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # esp32-cam-fpv 2 | esp32 cam digital, low latency FPV 3 | 4 | This project uses a modified esp-camera component running on an AI Thinker board to send low-latency mjpeg video to a Raspberry PI base station with 1-2 wifi cards using packet injection and monitor mode. 5 | 6 | It uses FEC encoding (4/7 currently configured) with 1400 byte packets and it achieves quite good performance: 7 | * Up to 12Mbps video rate. 8 | * More than 90 FPS at 400x296 or lower with 20-50 ms latency. 9 | * 34-44 FPS at 800x600 or 640x480 with 50-80 ms latency. 10 | * 12 FPS at 1024x768 with >100 ms latency. 11 | * Air unit weighs in at 18g with camera, antenna and a 3D printed case. 12 | 13 | It's based on an Ai Thinker board with an OV2640 camera board and the esp-camera component. 14 | 15 | The data is received from the camera module as JPEG ar 20MHz I2S clock and passed directly to the wifi module and written to the SD card if the DVR is enabled. 16 | The ESP camera component was modified to send the data as it's received from the DMA instead of frame-by-frame basis. This decreases latency quite significantly (10-20 ms) and reduces the need to allocate full frames in PSRAM. 17 | 18 | The wifi data is send using packet injection with configurable rate - from 2 MB CCK to 72MB MCS7 - and power. 19 | 20 | The air unit can also record the video straight from the camera to a sd card. The format is a rudimentary MJPEG without any header so when playing back the FPS will be whatever your player will decide.\ 21 | There is significant buffering when writing to SD (3MB at the moment) to work around the very regular slowdowns of sd cards. 22 | 23 | 24 | 25 | The receiver is a Raspberry PI 4 with 2 wifi adapters in monitor mode (TL-WN722N). The adapters work as diversity receivers and the data is reconstructed from the FEC packets. 26 | 27 | The JPEG decoding is done with turbojpeg to lower latency and - based on the resolution - can take between 1 and 7 milliseconds.\ 28 | It's then uploaded to 3 separate textures as YUV and converted to RGB in a shader. 29 | 30 | The link is bi-directional so the ground station can send data to the air unit. At the moment it sends camera and wifi configuration data but I plan to have a full bi-directional serial port for telemetry coming soon.\ 31 | The back link uses 64byte packets with a 2/6 FEC encoding (so quite solid) at a low wifi rate (I think 1Mb). 32 | 33 | This is very WIP at the moment, but it proves that the ESP32 can definitely stream video with very low latency. \ 34 | I plan to use this is a long range micro quad. 35 | 36 | Here is a video shot at 30 FPS at 800x600 (video converted from the source mjpeg): 37 | 38 | https://user-images.githubusercontent.com/10252034/116135308-43c08c00-a6d1-11eb-99b9-9dbb106b6489.mp4 39 | 40 | ## Building 41 | ### esp32 firmware: 42 | - Uses esp-idf-v4.3-beta1, can probably work with newer idf versions. It needs to be properly installed (follow the instructions in the IDF documentation) 43 | - Only the Ai Thinker esp cam board tested 44 | - In the air_firmware, execute this: `idf.py -p /dev/tty.usbserial1 flash monitor`. Replace `tty.usbserial1` with your serial port. 45 | - Make sure you place the board in flashing mode bu connecting IO0 to GND and resetting the board. 46 | - After compiling and resetting, you should get some stats per second, smth like this in the console:\ 47 | `WLAN S: 695196, R: 350, E: 0, D: 0, % : 0 || FPS: 64, D: 401268 || D: 0, E: 0`\ 48 | `WLAN S: 761616, R: 420, E: 0, D: 0, % : 0 || FPS: 69, D: 443679 || D: 0, E: 0`\ 49 | `WLAN S: 763092, R: 420, E: 0, D: 0, % : 0 || FPS: 69, D: 449410 || D: 0, E: 0`\ 50 | `WLAN S: 764568, R: 420, E: 0, D: 0, % : 0 || FPS: 69, D: 450996 || D: 0, E: 0`\ 51 | `WLAN S: 761616, R: 350, E: 0, D: 0, % : 0 || FPS: 69, D: 449347 || D: 0, E: 0` 52 | 53 | ### Raspberry Pi ground station: 54 | - I use a Raspberry Pi 4 in a RasPad3 enclosure, but any HDMI display should work. Raspberry Pi 3 should work as well. 55 | - You need to use 2 TL-WN722N adapters connected to USB. Check the EZ-wifibroadcast wiki for more info about the hardware revision of these adapters and alternative adapters. Make sure you get the 2.4GHz ones, of course. NOTE: the adapters are critical, not all work in monitor mode! 56 | - If you only have one adapter or they are not called `wlan1` & `wlan2`, check the `main.cpp` file and change the names and number there:\ 57 | `rx_descriptor.interfaces = {"wlan1", "wlan2"};`\ 58 | `tx_descriptor.interface = "wlan1";`\ 59 | Eventually this should be command line driven. 60 | - The UI uses ImGui and is touch driven - but mouse should work as well 61 | - Dependencies: 62 | `sudo apt install libdrm-dev libgbm-dev libgles2-mesa-dev libpcap-dev libturbojpeg0-dev libts-dev libsdl2-dev libfreetype6-dev ` 63 | - In the gs folder, execute `make -j4` 64 | - Run `sudo -E DISPLAY=:0 ./gs` 65 | 66 | The GS can run both with X11 and without. However, to run it without GS you need to compile SDL2 yourself to add support for kmsdrm: 67 | `git clone https://github.com/libsdl-org/SDL.git`\ 68 | `cd SDL`\ 69 | `mkdir build`\ 70 | `cd build`\ 71 | `../configure --disable-video-rpi --enable-video-kmsdrm --enable-video-x11 --disable-video-opengl`\ 72 | `make -j5`\ 73 | `sudo make install` 74 | 75 | To run without X11 using the just compiled SDL2, do this:\ 76 | `sudo -E LD_LIBRARY_PATH=/usr/local/lib DISPLAY=:0 ./gs` 77 | 78 | Some other things that should improve latency: 79 | - Disable the compositor from raspi-config. This should increase FPS 80 | - Change from fake kms to real kms in config.txt: dtoverlay=vc4-fkms-v3d to dtoverlay=vc4-kms-v3d 81 | 82 | VSync is disabled and on a PI4 you should get > 200FPS if everything went ok and you have configured the PI correctly. 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /air_firmware/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .pioenvs 3 | .piolibdeps 4 | .vscode/.browse.c_cpp.db* 5 | .vscode/c_cpp_properties.json 6 | .vscode/launch.json 7 | -------------------------------------------------------------------------------- /air_firmware/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "__bit_reference": "cpp", 4 | "__config": "cpp", 5 | "__debug": "cpp", 6 | "__errc": "cpp", 7 | "__functional_base": "cpp", 8 | "__hash_table": "cpp", 9 | "__locale": "cpp", 10 | "__mutex_base": "cpp", 11 | "__node_handle": "cpp", 12 | "__nullptr": "cpp", 13 | "__split_buffer": "cpp", 14 | "__string": "cpp", 15 | "__threading_support": "cpp", 16 | "__tuple": "cpp", 17 | "algorithm": "cpp", 18 | "array": "cpp", 19 | "atomic": "cpp", 20 | "bit": "cpp", 21 | "bitset": "cpp", 22 | "cctype": "cpp", 23 | "chrono": "cpp", 24 | "cmath": "cpp", 25 | "complex": "cpp", 26 | "cstdarg": "cpp", 27 | "cstddef": "cpp", 28 | "cstdint": "cpp", 29 | "cstdio": "cpp", 30 | "cstdlib": "cpp", 31 | "cstring": "cpp", 32 | "ctime": "cpp", 33 | "cwchar": "cpp", 34 | "cwctype": "cpp", 35 | "deque": "cpp", 36 | "exception": "cpp", 37 | "functional": "cpp", 38 | "initializer_list": "cpp", 39 | "ios": "cpp", 40 | "iosfwd": "cpp", 41 | "istream": "cpp", 42 | "iterator": "cpp", 43 | "limits": "cpp", 44 | "locale": "cpp", 45 | "memory": "cpp", 46 | "mutex": "cpp", 47 | "new": "cpp", 48 | "optional": "cpp", 49 | "ostream": "cpp", 50 | "ratio": "cpp", 51 | "sstream": "cpp", 52 | "stdexcept": "cpp", 53 | "streambuf": "cpp", 54 | "string": "cpp", 55 | "string_view": "cpp", 56 | "system_error": "cpp", 57 | "thread": "cpp", 58 | "tuple": "cpp", 59 | "type_traits": "cpp", 60 | "typeinfo": "cpp", 61 | "unordered_map": "cpp", 62 | "utility": "cpp", 63 | "vector": "cpp" 64 | }, 65 | "idf.adapterTargetName": "esp32", 66 | "idf.portWin": "COM5", 67 | "idf.openOcdConfigs": [ 68 | "board/esp32-wrover-kit-3.3v.cfg" 69 | ], 70 | "idf.flashType": "UART" 71 | } -------------------------------------------------------------------------------- /air_firmware/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | set(EXTRA_COMPONENT_DIRS "../components") 4 | set(COMPONENT_REQUIRES "common") 5 | 6 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 7 | project(air_firmware) 8 | -------------------------------------------------------------------------------- /air_firmware/components/esp32-camera/.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | -------------------------------------------------------------------------------- /air_firmware/components/esp32-camera/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(COMPONENT_SRCS 2 | driver/camera.c 3 | driver/sccb.c 4 | driver/sensor.c 5 | driver/xclk.c 6 | sensors/ov2640.c 7 | sensors/ov3660.c 8 | sensors/ov5640.c 9 | sensors/ov7725.c 10 | ) 11 | 12 | set(COMPONENT_ADD_INCLUDEDIRS 13 | driver/include 14 | conversions/include 15 | ) 16 | 17 | set(COMPONENT_PRIV_INCLUDEDIRS 18 | driver/private_include 19 | sensors/private_include 20 | conversions/private_include 21 | ) 22 | 23 | set(COMPONENT_REQUIRES driver) 24 | set(COMPONENT_PRIV_REQUIRES freertos nvs_flash) 25 | 26 | register_component() 27 | -------------------------------------------------------------------------------- /air_firmware/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 save 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 save 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 save memory. 23 | 24 | config OV5640_SUPPORT 25 | bool "OV5640 Support" 26 | default y 27 | help 28 | Enable this option if you want to use the OV5640. 29 | Disable this option to save memory. 30 | 31 | config SCCB_HARDWARE_I2C 32 | bool "Use hardware I2C for SCCB" 33 | default y 34 | help 35 | Enable this option if you want to use hardware I2C to control the camera. 36 | Disable this option to use software I2C. 37 | 38 | choice SCCB_HARDWARE_I2C_PORT 39 | bool "I2C peripheral to use for SCCB" 40 | depends on SCCB_HARDWARE_I2C 41 | default SCCB_HARDWARE_I2C_PORT1 42 | 43 | config SCCB_HARDWARE_I2C_PORT0 44 | bool "I2C0" 45 | config SCCB_HARDWARE_I2C_PORT1 46 | bool "I2C1" 47 | 48 | endchoice 49 | 50 | choice CAMERA_TASK_PINNED_TO_CORE 51 | bool "Camera task pinned to core" 52 | default CAMERA_CORE0 53 | help 54 | Pin the camera handle task to a certain core(0/1). It can also be done automatically choosing NO_AFFINITY. 55 | 56 | config CAMERA_CORE0 57 | bool "CORE0" 58 | config CAMERA_CORE1 59 | bool "CORE1" 60 | config CAMERA_NO_AFFINITY 61 | bool "NO_AFFINITY" 62 | 63 | endchoice 64 | 65 | endmenu 66 | -------------------------------------------------------------------------------- /air_firmware/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 | -------------------------------------------------------------------------------- /air_firmware/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 | -------------------------------------------------------------------------------- /air_firmware/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 | * You MUST free the pointer once you are done with it. 67 | * @param out_len Pointer to be populated with the length of the output buffer 68 | * 69 | * @return true on success 70 | */ 71 | 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); 72 | 73 | /** 74 | * @brief Convert camera frame buffer to JPEG buffer 75 | * 76 | * @param fb Source camera frame buffer 77 | * @param quality JPEG quality of the resulting image 78 | * @param out Pointer to be populated with the address of the resulting buffer 79 | * @param out_len Pointer to be populated with the length of the output buffer 80 | * 81 | * @return true on success 82 | */ 83 | bool frame2jpg(camera_fb_t * fb, uint8_t quality, uint8_t ** out, size_t * out_len); 84 | 85 | /** 86 | * @brief Convert image buffer to BMP buffer 87 | * 88 | * @param src Source buffer in JPEG, RGB565, RGB888, YUYV or GRAYSCALE format 89 | * @param src_len Length in bytes of the source buffer 90 | * @param width Width in pixels of the source image 91 | * @param height Height in pixels of the source image 92 | * @param format Format of the source image 93 | * @param out Pointer to be populated with the address of the resulting buffer 94 | * @param out_len Pointer to be populated with the length of the output buffer 95 | * 96 | * @return true on success 97 | */ 98 | 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); 99 | 100 | /** 101 | * @brief Convert camera frame buffer to BMP buffer 102 | * 103 | * @param fb Source camera frame buffer 104 | * @param out Pointer to be populated with the address of the resulting buffer 105 | * @param out_len Pointer to be populated with the length of the output buffer 106 | * 107 | * @return true on success 108 | */ 109 | bool frame2bmp(camera_fb_t * fb, uint8_t ** out, size_t * out_len); 110 | 111 | /** 112 | * @brief Convert image buffer to RGB888 buffer (used for face detection) 113 | * 114 | * @param src Source buffer in JPEG, RGB565, RGB888, YUYV or GRAYSCALE format 115 | * @param src_len Length in bytes of the source buffer 116 | * @param format Format of the source image 117 | * @param rgb_buf Pointer to the output buffer (width * height * 3) 118 | * 119 | * @return true on success 120 | */ 121 | bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint8_t * rgb_buf); 122 | 123 | #ifdef __cplusplus 124 | } 125 | #endif 126 | 127 | #endif /* _IMG_CONVERTERS_H_ */ 128 | -------------------------------------------------------------------------------- /air_firmware/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 | -------------------------------------------------------------------------------- /air_firmware/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 | -------------------------------------------------------------------------------- /air_firmware/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 | #include "sys/time.h" 72 | 73 | #ifdef __cplusplus 74 | extern "C" { 75 | #endif 76 | 77 | /** 78 | * @brief Configuration structure for camera initialization 79 | */ 80 | typedef struct { 81 | int pin_pwdn; /*!< GPIO pin for camera power down line */ 82 | int pin_reset; /*!< GPIO pin for camera reset line */ 83 | int pin_xclk; /*!< GPIO pin for camera XCLK line */ 84 | int pin_sscb_sda; /*!< GPIO pin for camera SDA line */ 85 | int pin_sscb_scl; /*!< GPIO pin for camera SCL line */ 86 | int pin_d7; /*!< GPIO pin for camera D7 line */ 87 | int pin_d6; /*!< GPIO pin for camera D6 line */ 88 | int pin_d5; /*!< GPIO pin for camera D5 line */ 89 | int pin_d4; /*!< GPIO pin for camera D4 line */ 90 | int pin_d3; /*!< GPIO pin for camera D3 line */ 91 | int pin_d2; /*!< GPIO pin for camera D2 line */ 92 | int pin_d1; /*!< GPIO pin for camera D1 line */ 93 | int pin_d0; /*!< GPIO pin for camera D0 line */ 94 | int pin_vsync; /*!< GPIO pin for camera VSYNC line */ 95 | int pin_href; /*!< GPIO pin for camera HREF line */ 96 | int pin_pclk; /*!< GPIO pin for camera PCLK line */ 97 | 98 | int xclk_freq_hz; /*!< Frequency of XCLK signal, in Hz. Either 20KHz or 10KHz for OV2640 double FPS (Experimental) */ 99 | 100 | ledc_timer_t ledc_timer; /*!< LEDC timer to be used for generating XCLK */ 101 | ledc_channel_t ledc_channel; /*!< LEDC channel to be used for generating XCLK */ 102 | 103 | pixformat_t pixel_format; /*!< Format of the pixel data: PIXFORMAT_ + YUV422|GRAYSCALE|RGB565|JPEG */ 104 | framesize_t frame_size; /*!< Size of the output image: FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA */ 105 | 106 | int jpeg_quality; /*!< Quality of JPEG output. 0-63 lower means higher quality */ 107 | size_t fb_count; /*!< Number of frame buffers to be allocated. If more than one, then each frame will be acquired (double speed) */ 108 | } camera_config_t; 109 | 110 | /** 111 | * @brief Data structure of camera frame buffer 112 | */ 113 | typedef struct { 114 | // uint8_t * buf; /*!< Pointer to the pixel data */ 115 | size_t len; /*!< Length of the buffer in bytes */ 116 | size_t width; /*!< Width of the buffer in pixels */ 117 | size_t height; /*!< Height of the buffer in pixels */ 118 | pixformat_t format; /*!< Format of the pixel data */ 119 | //struct timeval timestamp; /*!< Timestamp since boot of the first DMA buffer of the frame */ 120 | } camera_fb_t; 121 | 122 | typedef void (*camera_fb_data_cb_t)(const void* data, size_t stride, size_t count, bool last); 123 | 124 | #define ESP_ERR_CAMERA_BASE 0x20000 125 | #define ESP_ERR_CAMERA_NOT_DETECTED (ESP_ERR_CAMERA_BASE + 1) 126 | #define ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE (ESP_ERR_CAMERA_BASE + 2) 127 | #define ESP_ERR_CAMERA_FAILED_TO_SET_OUT_FORMAT (ESP_ERR_CAMERA_BASE + 3) 128 | #define ESP_ERR_CAMERA_NOT_SUPPORTED (ESP_ERR_CAMERA_BASE + 4) 129 | 130 | /** 131 | * @brief Initialize the camera driver 132 | * 133 | * @note call camera_probe before calling this function 134 | * 135 | * This function detects and configures camera over I2C interface, 136 | * allocates framebuffer and DMA buffers, 137 | * initializes parallel I2S input, and sets up DMA descriptors. 138 | * 139 | * Currently this function can only be called once and there is 140 | * no way to de-initialize this module. 141 | * 142 | * @param config Camera configuration parameters 143 | * 144 | * @return ESP_OK on success 145 | */ 146 | esp_err_t esp_camera_init(const camera_config_t* config, camera_fb_data_cb_t cb); 147 | 148 | /** 149 | * @brief Deinitialize the camera driver 150 | * 151 | * @return 152 | * - ESP_OK on success 153 | * - ESP_ERR_INVALID_STATE if the driver hasn't been initialized yet 154 | */ 155 | esp_err_t esp_camera_deinit(); 156 | 157 | /** 158 | * @brief Obtain pointer to a frame buffer. 159 | * 160 | * @return pointer to the frame buffer 161 | */ 162 | camera_fb_t* esp_camera_fb_get(); 163 | 164 | /** 165 | * @brief Return the frame buffer to be reused again. 166 | * 167 | * @param fb Pointer to the frame buffer 168 | */ 169 | void esp_camera_fb_return(camera_fb_t * fb); 170 | 171 | /** 172 | * @brief Get a pointer to the image sensor control structure 173 | * 174 | * @return pointer to the sensor 175 | */ 176 | sensor_t * esp_camera_sensor_get(); 177 | 178 | /** 179 | * @brief Save camera settings to non-volatile-storage (NVS) 180 | * 181 | * @param key A unique nvs key name for the camera settings 182 | */ 183 | esp_err_t esp_camera_save_to_nvs(const char *key); 184 | 185 | /** 186 | * @brief Load camera settings from non-volatile-storage (NVS) 187 | * 188 | * @param key A unique nvs key name for the camera settings 189 | */ 190 | esp_err_t esp_camera_load_from_nvs(const char *key); 191 | 192 | #ifdef __cplusplus 193 | } 194 | #endif 195 | 196 | #include "img_converters.h" 197 | 198 | -------------------------------------------------------------------------------- /air_firmware/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 | #include 13 | 14 | #define NT99141_PID (0x14) 15 | #define OV9650_PID (0x96) 16 | #define OV7725_PID (0x77) 17 | #define OV2640_PID (0x26) 18 | #define OV3660_PID (0x36) 19 | #define OV5640_PID (0x56) 20 | #define OV7670_PID (0x76) 21 | 22 | typedef enum { 23 | PIXFORMAT_RGB565, // 2BPP/RGB565 24 | PIXFORMAT_YUV422, // 2BPP/YUV422 25 | PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE 26 | PIXFORMAT_JPEG, // JPEG/COMPRESSED 27 | PIXFORMAT_RGB888, // 3BPP/RGB888 28 | PIXFORMAT_RAW, // RAW 29 | PIXFORMAT_RGB444, // 3BP2P/RGB444 30 | PIXFORMAT_RGB555, // 3BP2P/RGB555 31 | } pixformat_t; 32 | 33 | typedef enum { 34 | FRAMESIZE_96X96, // 96x96 35 | FRAMESIZE_QQVGA, // 160x120 36 | FRAMESIZE_QCIF, // 176x144 37 | FRAMESIZE_HQVGA, // 240x176 38 | FRAMESIZE_240X240, // 240x240 39 | FRAMESIZE_QVGA, // 320x240 40 | FRAMESIZE_CIF, // 400x296 41 | FRAMESIZE_HVGA, // 480x320 42 | FRAMESIZE_VGA, // 640x480 43 | FRAMESIZE_SVGA, // 800x600 44 | FRAMESIZE_XGA, // 1024x768 45 | FRAMESIZE_HD, // 1280x720 46 | FRAMESIZE_SXGA, // 1280x1024 47 | FRAMESIZE_UXGA, // 1600x1200 48 | // 3MP Sensors 49 | FRAMESIZE_FHD, // 1920x1080 50 | FRAMESIZE_P_HD, // 720x1280 51 | FRAMESIZE_P_3MP, // 864x1536 52 | FRAMESIZE_QXGA, // 2048x1536 53 | // 5MP Sensors 54 | FRAMESIZE_QHD, // 2560x1440 55 | FRAMESIZE_WQXGA, // 2560x1600 56 | FRAMESIZE_P_FHD, // 1080x1920 57 | FRAMESIZE_QSXGA, // 2560x1920 58 | FRAMESIZE_INVALID 59 | } framesize_t; 60 | 61 | typedef enum { 62 | ASPECT_RATIO_4X3, 63 | ASPECT_RATIO_3X2, 64 | ASPECT_RATIO_16X10, 65 | ASPECT_RATIO_5X3, 66 | ASPECT_RATIO_16X9, 67 | ASPECT_RATIO_21X9, 68 | ASPECT_RATIO_5X4, 69 | ASPECT_RATIO_1X1, 70 | ASPECT_RATIO_9X16 71 | } aspect_ratio_t; 72 | 73 | typedef enum { 74 | GAINCEILING_2X, 75 | GAINCEILING_4X, 76 | GAINCEILING_8X, 77 | GAINCEILING_16X, 78 | GAINCEILING_32X, 79 | GAINCEILING_64X, 80 | GAINCEILING_128X, 81 | } gainceiling_t; 82 | 83 | typedef struct { 84 | uint16_t max_width; 85 | uint16_t max_height; 86 | uint16_t start_x; 87 | uint16_t start_y; 88 | uint16_t end_x; 89 | uint16_t end_y; 90 | uint16_t offset_x; 91 | uint16_t offset_y; 92 | uint16_t total_x; 93 | uint16_t total_y; 94 | } ratio_settings_t; 95 | 96 | typedef struct { 97 | const uint16_t width; 98 | const uint16_t height; 99 | const aspect_ratio_t aspect_ratio; 100 | } resolution_info_t; 101 | 102 | // Resolution table (in sensor.c) 103 | extern const resolution_info_t resolution[]; 104 | 105 | typedef struct { 106 | uint8_t MIDH; 107 | uint8_t MIDL; 108 | uint8_t PID; 109 | uint8_t VER; 110 | } sensor_id_t; 111 | 112 | typedef struct { 113 | framesize_t framesize;//0 - 10 114 | bool scale; 115 | bool binning; 116 | uint8_t quality;//0 - 63 117 | int8_t brightness;//-2 - 2 118 | int8_t contrast;//-2 - 2 119 | int8_t saturation;//-2 - 2 120 | int8_t sharpness;//-2 - 2 121 | uint8_t denoise; 122 | uint8_t special_effect;//0 - 6 123 | uint8_t wb_mode;//0 - 4 124 | uint8_t awb; 125 | uint8_t awb_gain; 126 | uint8_t aec; 127 | uint8_t aec2; 128 | int8_t ae_level;//-2 - 2 129 | uint16_t aec_value;//0 - 1200 130 | uint8_t agc; 131 | uint8_t agc_gain;//0 - 30 132 | uint8_t gainceiling;//0 - 6 133 | uint8_t bpc; 134 | uint8_t wpc; 135 | uint8_t raw_gma; 136 | uint8_t lenc; 137 | uint8_t hmirror; 138 | uint8_t vflip; 139 | uint8_t dcw; 140 | uint8_t colorbar; 141 | } camera_status_t; 142 | 143 | typedef struct _sensor sensor_t; 144 | typedef struct _sensor { 145 | sensor_id_t id; // Sensor ID. 146 | uint8_t slv_addr; // Sensor I2C slave address. 147 | pixformat_t pixformat; 148 | camera_status_t status; 149 | int xclk_freq_hz; 150 | 151 | // Sensor function pointers 152 | int (*init_status) (sensor_t *sensor); 153 | int (*reset) (sensor_t *sensor); 154 | int (*set_pixformat) (sensor_t *sensor, pixformat_t pixformat); 155 | int (*set_framesize) (sensor_t *sensor, framesize_t framesize); 156 | int (*set_contrast) (sensor_t *sensor, int level); 157 | int (*set_brightness) (sensor_t *sensor, int level); 158 | int (*set_saturation) (sensor_t *sensor, int level); 159 | int (*set_sharpness) (sensor_t *sensor, int level); 160 | int (*set_denoise) (sensor_t *sensor, int level); 161 | int (*set_gainceiling) (sensor_t *sensor, gainceiling_t gainceiling); 162 | int (*set_quality) (sensor_t *sensor, int quality); 163 | int (*set_colorbar) (sensor_t *sensor, int enable); 164 | int (*set_whitebal) (sensor_t *sensor, int enable); 165 | int (*set_gain_ctrl) (sensor_t *sensor, int enable); 166 | int (*set_exposure_ctrl) (sensor_t *sensor, int enable); 167 | int (*set_hmirror) (sensor_t *sensor, int enable); 168 | int (*set_vflip) (sensor_t *sensor, int enable); 169 | 170 | int (*set_aec2) (sensor_t *sensor, int enable); 171 | int (*set_awb_gain) (sensor_t *sensor, int enable); 172 | int (*set_agc_gain) (sensor_t *sensor, int gain); 173 | int (*set_aec_value) (sensor_t *sensor, int gain); 174 | 175 | int (*set_special_effect) (sensor_t *sensor, int effect); 176 | int (*set_wb_mode) (sensor_t *sensor, int mode); 177 | int (*set_ae_level) (sensor_t *sensor, int level); 178 | 179 | int (*set_dcw) (sensor_t *sensor, int enable); 180 | int (*set_bpc) (sensor_t *sensor, int enable); 181 | int (*set_wpc) (sensor_t *sensor, int enable); 182 | 183 | int (*set_raw_gma) (sensor_t *sensor, int enable); 184 | int (*set_lenc) (sensor_t *sensor, int enable); 185 | 186 | int (*get_reg) (sensor_t *sensor, int reg, int mask); 187 | int (*set_reg) (sensor_t *sensor, int reg, int mask, int value); 188 | int (*set_res_raw) (sensor_t *sensor, int startX, int startY, int endX, int endY, int offsetX, int offsetY, int totalX, int totalY, int outputX, int outputY, bool scale, bool binning); 189 | int (*set_pll) (sensor_t *sensor, int bypass, int mul, int sys, int root, int pre, int seld5, int pclken, int pclk); 190 | int (*set_xclk) (sensor_t *sensor, int timer, int xclk); 191 | } sensor_t; 192 | 193 | #endif /* __SENSOR_H__ */ 194 | -------------------------------------------------------------------------------- /air_firmware/components/esp32-camera/driver/private_include/camera_common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "esp_err.h" 7 | #include "esp_intr_alloc.h" 8 | #include "freertos/FreeRTOS.h" 9 | #include "freertos/semphr.h" 10 | #include "freertos/task.h" 11 | #include "esp_camera.h" 12 | #include "sensor.h" 13 | 14 | #include "esp_system.h" 15 | #if ESP_IDF_VERSION_MAJOR >= 4 // IDF 4+ 16 | #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 17 | #include "esp32/rom/lldesc.h" 18 | #else 19 | #error Target CONFIG_IDF_TARGET is not supported 20 | #endif 21 | #else // ESP32 Before IDF 4.0 22 | #include "rom/lldesc.h" 23 | #endif 24 | 25 | typedef union { 26 | struct { 27 | uint8_t sample2; 28 | uint8_t unused2; 29 | uint8_t sample1; 30 | uint8_t unused1; 31 | }; 32 | uint32_t val; 33 | } dma_elem_t; 34 | 35 | typedef enum { 36 | /* camera sends byte sequence: s1, s2, s3, s4, ... 37 | * fifo receives: 00 s1 00 s2, 00 s2 00 s3, 00 s3 00 s4, ... 38 | */ 39 | SM_0A0B_0B0C = 0, 40 | /* camera sends byte sequence: s1, s2, s3, s4, ... 41 | * fifo receives: 00 s1 00 s2, 00 s3 00 s4, ... 42 | */ 43 | SM_0A0B_0C0D = 1, 44 | /* camera sends byte sequence: s1, s2, s3, s4, ... 45 | * fifo receives: 00 s1 00 00, 00 s2 00 00, 00 s3 00 00, ... 46 | */ 47 | SM_0A00_0B00 = 3, 48 | } i2s_sampling_mode_t; 49 | 50 | -------------------------------------------------------------------------------- /air_firmware/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 | -------------------------------------------------------------------------------- /air_firmware/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 | -------------------------------------------------------------------------------- /air_firmware/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 13 | #include "sccb.h" 14 | #include 15 | #include "sdkconfig.h" 16 | #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) 17 | #include "esp32-hal-log.h" 18 | #else 19 | #include "esp_log.h" 20 | static const char* TAG = "sccb"; 21 | #endif 22 | 23 | #define LITTLETOBIG(x) ((x<<8)|(x>>8)) 24 | 25 | #include "driver/i2c.h" 26 | 27 | #define SCCB_FREQ 100000 /*!< 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 | #if CONFIG_SCCB_HARDWARE_I2C_PORT1 35 | const int SCCB_I2C_PORT = 1; 36 | #else 37 | const int SCCB_I2C_PORT = 0; 38 | #endif 39 | static uint8_t ESP_SLAVE_ADDR = 0x3c; 40 | 41 | int SCCB_Init(int pin_sda, int pin_scl) 42 | { 43 | ESP_LOGI(TAG, "pin_sda %d pin_scl %d\n", pin_sda, pin_scl); 44 | //log_i("SCCB_Init start"); 45 | i2c_config_t conf; 46 | memset(&conf, 0, sizeof(i2c_config_t)); 47 | conf.mode = I2C_MODE_MASTER; 48 | conf.sda_io_num = pin_sda; 49 | conf.sda_pullup_en = GPIO_PULLUP_ENABLE; 50 | conf.scl_io_num = pin_scl; 51 | conf.scl_pullup_en = GPIO_PULLUP_ENABLE; 52 | conf.master.clk_speed = SCCB_FREQ; 53 | 54 | i2c_param_config(SCCB_I2C_PORT, &conf); 55 | i2c_driver_install(SCCB_I2C_PORT, conf.mode, 0, 0, 0); 56 | return 0; 57 | } 58 | 59 | uint8_t SCCB_Probe() 60 | { 61 | uint8_t slave_addr = 0x0; 62 | while(slave_addr < 0x7f) { 63 | i2c_cmd_handle_t cmd = i2c_cmd_link_create(); 64 | i2c_master_start(cmd); 65 | i2c_master_write_byte(cmd, ( slave_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN); 66 | i2c_master_stop(cmd); 67 | esp_err_t ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS); 68 | i2c_cmd_link_delete(cmd); 69 | if( ret == ESP_OK) { 70 | ESP_SLAVE_ADDR = slave_addr; 71 | return ESP_SLAVE_ADDR; 72 | } 73 | slave_addr++; 74 | } 75 | return ESP_SLAVE_ADDR; 76 | } 77 | 78 | uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg) 79 | { 80 | uint8_t data=0; 81 | esp_err_t ret = ESP_FAIL; 82 | i2c_cmd_handle_t cmd = i2c_cmd_link_create(); 83 | i2c_master_start(cmd); 84 | i2c_master_write_byte(cmd, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN); 85 | i2c_master_write_byte(cmd, reg, ACK_CHECK_EN); 86 | i2c_master_stop(cmd); 87 | ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS); 88 | i2c_cmd_link_delete(cmd); 89 | if(ret != ESP_OK) return -1; 90 | cmd = i2c_cmd_link_create(); 91 | i2c_master_start(cmd); 92 | i2c_master_write_byte(cmd, ( slv_addr << 1 ) | READ_BIT, ACK_CHECK_EN); 93 | i2c_master_read_byte(cmd, &data, NACK_VAL); 94 | i2c_master_stop(cmd); 95 | ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS); 96 | i2c_cmd_link_delete(cmd); 97 | if(ret != ESP_OK) { 98 | ESP_LOGE(TAG, "SCCB_Read Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", slv_addr, reg, data, ret); 99 | } 100 | return data; 101 | } 102 | 103 | uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data) 104 | { 105 | esp_err_t ret = ESP_FAIL; 106 | i2c_cmd_handle_t cmd = i2c_cmd_link_create(); 107 | i2c_master_start(cmd); 108 | i2c_master_write_byte(cmd, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN); 109 | i2c_master_write_byte(cmd, reg, ACK_CHECK_EN); 110 | i2c_master_write_byte(cmd, data, ACK_CHECK_EN); 111 | i2c_master_stop(cmd); 112 | ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS); 113 | i2c_cmd_link_delete(cmd); 114 | if(ret != ESP_OK) { 115 | ESP_LOGE(TAG, "SCCB_Write Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", slv_addr, reg, data, ret); 116 | } 117 | return ret == ESP_OK ? 0 : -1; 118 | } 119 | 120 | uint8_t SCCB_Read16(uint8_t slv_addr, uint16_t reg) 121 | { 122 | uint8_t data=0; 123 | esp_err_t ret = ESP_FAIL; 124 | uint16_t reg_htons = LITTLETOBIG(reg); 125 | uint8_t *reg_u8 = (uint8_t *)®_htons; 126 | i2c_cmd_handle_t cmd = i2c_cmd_link_create(); 127 | i2c_master_start(cmd); 128 | i2c_master_write_byte(cmd, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN); 129 | i2c_master_write_byte(cmd, reg_u8[0], ACK_CHECK_EN); 130 | i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN); 131 | i2c_master_stop(cmd); 132 | ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS); 133 | i2c_cmd_link_delete(cmd); 134 | if(ret != ESP_OK) return -1; 135 | cmd = i2c_cmd_link_create(); 136 | i2c_master_start(cmd); 137 | i2c_master_write_byte(cmd, ( slv_addr << 1 ) | READ_BIT, ACK_CHECK_EN); 138 | i2c_master_read_byte(cmd, &data, NACK_VAL); 139 | i2c_master_stop(cmd); 140 | ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS); 141 | i2c_cmd_link_delete(cmd); 142 | if(ret != ESP_OK) { 143 | ESP_LOGE(TAG, "W [%04x]=%02x fail\n", reg, data); 144 | } 145 | return data; 146 | } 147 | 148 | uint8_t SCCB_Write16(uint8_t slv_addr, uint16_t reg, uint8_t data) 149 | { 150 | static uint16_t i = 0; 151 | esp_err_t ret = ESP_FAIL; 152 | uint16_t reg_htons = LITTLETOBIG(reg); 153 | uint8_t *reg_u8 = (uint8_t *)®_htons; 154 | i2c_cmd_handle_t cmd = i2c_cmd_link_create(); 155 | i2c_master_start(cmd); 156 | i2c_master_write_byte(cmd, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN); 157 | i2c_master_write_byte(cmd, reg_u8[0], ACK_CHECK_EN); 158 | i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN); 159 | i2c_master_write_byte(cmd, data, ACK_CHECK_EN); 160 | i2c_master_stop(cmd); 161 | ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS); 162 | i2c_cmd_link_delete(cmd); 163 | if(ret != ESP_OK) { 164 | ESP_LOGE(TAG, "W [%04x]=%02x %d fail\n", reg, data, i++); 165 | } 166 | return ret == ESP_OK ? 0 : -1; 167 | } 168 | -------------------------------------------------------------------------------- /air_firmware/components/esp32-camera/driver/sensor.c: -------------------------------------------------------------------------------- 1 | #include "sensor.h" 2 | 3 | const resolution_info_t resolution[FRAMESIZE_INVALID] = { 4 | { 96, 96, ASPECT_RATIO_1X1 }, /* 96x96 */ 5 | { 160, 120, ASPECT_RATIO_4X3 }, /* QQVGA */ 6 | { 176, 144, ASPECT_RATIO_5X4 }, /* QCIF */ 7 | { 240, 176, ASPECT_RATIO_4X3 }, /* HQVGA */ 8 | { 240, 240, ASPECT_RATIO_1X1 }, /* 240x240 */ 9 | { 320, 240, ASPECT_RATIO_4X3 }, /* QVGA */ 10 | { 400, 296, ASPECT_RATIO_4X3 }, /* CIF */ 11 | { 480, 320, ASPECT_RATIO_3X2 }, /* HVGA */ 12 | { 640, 480, ASPECT_RATIO_4X3 }, /* VGA */ 13 | { 800, 600, ASPECT_RATIO_4X3 }, /* SVGA */ 14 | { 1024, 768, ASPECT_RATIO_4X3 }, /* XGA */ 15 | { 1280, 720, ASPECT_RATIO_16X9 }, /* HD */ 16 | { 1280, 1024, ASPECT_RATIO_5X4 }, /* SXGA */ 17 | { 1600, 1200, ASPECT_RATIO_4X3 }, /* UXGA */ 18 | // 3MP Sensors 19 | { 1920, 1080, ASPECT_RATIO_16X9 }, /* FHD */ 20 | { 720, 1280, ASPECT_RATIO_9X16 }, /* Portrait HD */ 21 | { 864, 1536, ASPECT_RATIO_9X16 }, /* Portrait 3MP */ 22 | { 2048, 1536, ASPECT_RATIO_4X3 }, /* QXGA */ 23 | // 5MP Sensors 24 | { 2560, 1440, ASPECT_RATIO_16X9 }, /* QHD */ 25 | { 2560, 1600, ASPECT_RATIO_16X10 }, /* WQXGA */ 26 | { 1088, 1920, ASPECT_RATIO_9X16 }, /* Portrait FHD */ 27 | { 2560, 1920, ASPECT_RATIO_4X3 }, /* QSXGA */ 28 | }; 29 | -------------------------------------------------------------------------------- /air_firmware/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 "esp_system.h" 6 | #include "xclk.h" 7 | 8 | #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) 9 | #include "esp32-hal-log.h" 10 | #else 11 | #include "esp_log.h" 12 | static const char* TAG = "camera_xclk"; 13 | #endif 14 | 15 | esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz) 16 | { 17 | ledc_timer_config_t timer_conf; 18 | timer_conf.duty_resolution = 2; 19 | timer_conf.freq_hz = xclk_freq_hz; 20 | timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE; 21 | #if ESP_IDF_VERSION_MAJOR >= 4 22 | timer_conf.clk_cfg = LEDC_AUTO_CLK; 23 | #endif 24 | timer_conf.timer_num = (ledc_timer_t)ledc_timer; 25 | esp_err_t err = ledc_timer_config(&timer_conf); 26 | if (err != ESP_OK) { 27 | ESP_LOGE(TAG, "ledc_timer_config failed for freq %d, rc=%x", xclk_freq_hz, err); 28 | } 29 | return err; 30 | } 31 | 32 | esp_err_t camera_enable_out_clock(camera_config_t* config) 33 | { 34 | periph_module_enable(PERIPH_LEDC_MODULE); 35 | 36 | esp_err_t err = xclk_timer_conf(config->ledc_timer, config->xclk_freq_hz); 37 | if (err != ESP_OK) { 38 | ESP_LOGE(TAG, "ledc_timer_config failed, rc=%x", err); 39 | return err; 40 | } 41 | 42 | ledc_channel_config_t ch_conf; 43 | ch_conf.gpio_num = config->pin_xclk; 44 | ch_conf.speed_mode = LEDC_HIGH_SPEED_MODE; 45 | ch_conf.channel = config->ledc_channel; 46 | ch_conf.intr_type = LEDC_INTR_DISABLE; 47 | ch_conf.timer_sel = config->ledc_timer; 48 | ch_conf.duty = 2; 49 | ch_conf.hpoint = 0; 50 | err = ledc_channel_config(&ch_conf); 51 | if (err != ESP_OK) { 52 | ESP_LOGE(TAG, "ledc_channel_config failed, rc=%x", err); 53 | return err; 54 | } 55 | return ESP_OK; 56 | } 57 | 58 | void camera_disable_out_clock() 59 | { 60 | periph_module_disable(PERIPH_LEDC_MODULE); 61 | } 62 | -------------------------------------------------------------------------------- /air_firmware/components/esp32-camera/examples/take_picture.c: -------------------------------------------------------------------------------- 1 | /** 2 | * This example takes a picture every 5s and print its size on serial monitor. 3 | */ 4 | 5 | // =============================== SETUP ====================================== 6 | 7 | // 1. Board setup (Uncomment): 8 | // #define BOARD_WROVER_KIT 9 | // #define BOARD_ESP32CAM_AITHINKER 10 | 11 | /** 12 | * 2. Kconfig setup 13 | * 14 | * If you have a Kconfig file, copy the content from 15 | * https://github.com/espressif/esp32-camera/blob/master/Kconfig into it. 16 | * In case you haven't, copy and paste this Kconfig file inside the src directory. 17 | * This Kconfig file has definitions that allows more control over the camera and 18 | * how it will be initialized. 19 | */ 20 | 21 | /** 22 | * 3. Enable PSRAM on sdkconfig: 23 | * 24 | * CONFIG_ESP32_SPIRAM_SUPPORT=y 25 | * 26 | * More info on 27 | * https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/kconfig.html#config-esp32-spiram-support 28 | */ 29 | 30 | // ================================ CODE ====================================== 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "freertos/FreeRTOS.h" 40 | #include "freertos/task.h" 41 | 42 | #include "esp_camera.h" 43 | 44 | // WROVER-KIT PIN Map 45 | #ifdef BOARD_WROVER_KIT 46 | 47 | #define CAM_PIN_PWDN -1 //power down is not used 48 | #define CAM_PIN_RESET -1 //software reset will be performed 49 | #define CAM_PIN_XCLK 21 50 | #define CAM_PIN_SIOD 26 51 | #define CAM_PIN_SIOC 27 52 | 53 | #define CAM_PIN_D7 35 54 | #define CAM_PIN_D6 34 55 | #define CAM_PIN_D5 39 56 | #define CAM_PIN_D4 36 57 | #define CAM_PIN_D3 19 58 | #define CAM_PIN_D2 18 59 | #define CAM_PIN_D1 5 60 | #define CAM_PIN_D0 4 61 | #define CAM_PIN_VSYNC 25 62 | #define CAM_PIN_HREF 23 63 | #define CAM_PIN_PCLK 22 64 | 65 | #endif 66 | 67 | // ESP32Cam (AiThinker) PIN Map 68 | #ifdef BOARD_ESP32CAM_AITHINKER 69 | 70 | #define CAM_PIN_PWDN 32 71 | #define CAM_PIN_RESET -1 //software reset will be performed 72 | #define CAM_PIN_XCLK 0 73 | #define CAM_PIN_SIOD 26 74 | #define CAM_PIN_SIOC 27 75 | 76 | #define CAM_PIN_D7 35 77 | #define CAM_PIN_D6 34 78 | #define CAM_PIN_D5 39 79 | #define CAM_PIN_D4 36 80 | #define CAM_PIN_D3 21 81 | #define CAM_PIN_D2 19 82 | #define CAM_PIN_D1 18 83 | #define CAM_PIN_D0 5 84 | #define CAM_PIN_VSYNC 25 85 | #define CAM_PIN_HREF 23 86 | #define CAM_PIN_PCLK 22 87 | 88 | #endif 89 | 90 | static const char *TAG = "example:take_picture"; 91 | 92 | static camera_config_t camera_config = { 93 | .pin_pwdn = CAM_PIN_PWDN, 94 | .pin_reset = CAM_PIN_RESET, 95 | .pin_xclk = CAM_PIN_XCLK, 96 | .pin_sscb_sda = CAM_PIN_SIOD, 97 | .pin_sscb_scl = CAM_PIN_SIOC, 98 | 99 | .pin_d7 = CAM_PIN_D7, 100 | .pin_d6 = CAM_PIN_D6, 101 | .pin_d5 = CAM_PIN_D5, 102 | .pin_d4 = CAM_PIN_D4, 103 | .pin_d3 = CAM_PIN_D3, 104 | .pin_d2 = CAM_PIN_D2, 105 | .pin_d1 = CAM_PIN_D1, 106 | .pin_d0 = CAM_PIN_D0, 107 | .pin_vsync = CAM_PIN_VSYNC, 108 | .pin_href = CAM_PIN_HREF, 109 | .pin_pclk = CAM_PIN_PCLK, 110 | 111 | //XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental) 112 | .xclk_freq_hz = 20000000, 113 | .ledc_timer = LEDC_TIMER_0, 114 | .ledc_channel = LEDC_CHANNEL_0, 115 | 116 | .pixel_format = PIXFORMAT_JPEG, //YUV422,GRAYSCALE,RGB565,JPEG 117 | .frame_size = FRAMESIZE_VGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG 118 | 119 | .jpeg_quality = 12, //0-63 lower number means higher quality 120 | .fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG 121 | }; 122 | 123 | static esp_err_t init_camera() 124 | { 125 | //initialize the camera 126 | esp_err_t err = esp_camera_init(&camera_config); 127 | if (err != ESP_OK) 128 | { 129 | ESP_LOGE(TAG, "Camera Init Failed"); 130 | return err; 131 | } 132 | 133 | return ESP_OK; 134 | } 135 | 136 | void app_main() 137 | { 138 | init_camera(); 139 | 140 | while (1) 141 | { 142 | ESP_LOGI(TAG, "Taking picture..."); 143 | camera_fb_t *pic = esp_camera_fb_get(); 144 | 145 | // use pic->buf to access the image 146 | ESP_LOGI(TAG, "Picture taken! Its size was: %zu bytes", pic->len); 147 | 148 | vTaskDelay(5000 / portTICK_RATE_MS); 149 | } 150 | } -------------------------------------------------------------------------------- /air_firmware/components/esp32-camera/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "esp32-camera", 3 | "version": "1.0.0", 4 | "keywords": "esp32, camera, espressif, esp32-cam", 5 | "description": "ESP32 compatible driver for OV2640, OV3660, OV5640 and OV7725 image sensors.", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/espressif/esp32-camera" 9 | }, 10 | "frameworks": "espidf", 11 | "platforms": "*", 12 | "build": { 13 | "flags": [ 14 | "-Idriver/include", 15 | "-Iconversions/include", 16 | "-Idriver/private_include", 17 | "-Iconversions/private_include", 18 | "-Isensors/private_include", 19 | "-fno-rtti" 20 | ], 21 | "includeDir": ".", 22 | "srcDir": ".", 23 | "srcFilter": ["-<*>", "+", "+", "+"] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /air_firmware/components/esp32-camera/sensors/private_include/nt99141.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 | * NT99141 driver. 7 | * 8 | */ 9 | #ifndef __NT99141_H__ 10 | #define __NT99141_H__ 11 | 12 | #include "sensor.h" 13 | 14 | int NT99141_init(sensor_t *sensor); 15 | 16 | #endif // __NT99141_H__ 17 | -------------------------------------------------------------------------------- /air_firmware/components/esp32-camera/sensors/private_include/nt99141_regs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NT99141 register definitions. 3 | */ 4 | #ifndef __NT99141_REG_REGS_H__ 5 | #define __NT99141_REG_REGS_H__ 6 | 7 | /* system control registers */ 8 | #define SYSTEM_CTROL0 0x3021 // 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 0x3025 // 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 0x3201 // 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 0x3022 // 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 0x3022 // 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 0x3024// 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 0x306a // 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 0x3021 // 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 0x3401 // 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 0x02 /* 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 0x01 /* Vertical flip enable */ 209 | #define TIMING_TC_REG21_HMIRROR 0x02 /* Horizontal mirror enable */ 210 | 211 | #endif // __NT99141_REG_REGS_H__ 212 | -------------------------------------------------------------------------------- /air_firmware/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 | -------------------------------------------------------------------------------- /air_firmware/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 | -------------------------------------------------------------------------------- /air_firmware/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 | -------------------------------------------------------------------------------- /air_firmware/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 | -------------------------------------------------------------------------------- /air_firmware/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 | static const ratio_settings_t ratio_table[] = { 10 | // mw, mh, sx, sy, ex, ey, ox, oy, tx, ty 11 | { 2048, 1536, 0, 0, 2079, 1547, 16, 6, 2300, 1564 }, //4x3 12 | { 1920, 1280, 64, 128, 2015, 1419, 16, 6, 2172, 1436 }, //3x2 13 | { 2048, 1280, 0, 128, 2079, 1419, 16, 6, 2300, 1436 }, //16x10 14 | { 1920, 1152, 64, 192, 2015, 1355, 16, 6, 2172, 1372 }, //5x3 15 | { 1920, 1080, 64, 242, 2015, 1333, 16, 6, 2172, 1322 }, //16x9 16 | { 2048, 880, 0, 328, 2079, 1219, 16, 6, 2300, 1236 }, //21x9 17 | { 1920, 1536, 64, 0, 2015, 1547, 16, 6, 2172, 1564 }, //5x4 18 | { 1536, 1536, 256, 0, 1823, 1547, 16, 6, 2044, 1564 }, //1x1 19 | { 864, 1536, 592, 0, 1487, 1547, 16, 6, 2044, 1564 } //9x16 20 | }; 21 | 22 | #define REG_DLY 0xffff 23 | #define REGLIST_TAIL 0x0000 24 | 25 | static const DRAM_ATTR uint16_t sensor_default_regs[][2] = { 26 | {SYSTEM_CTROL0, 0x82}, // software reset 27 | {REG_DLY, 10}, // delay 10ms 28 | 29 | {0x3103, 0x13}, 30 | {SYSTEM_CTROL0, 0x42}, 31 | {0x3017, 0xff}, 32 | {0x3018, 0xff}, 33 | {DRIVE_CAPABILITY, 0xc3}, 34 | {CLOCK_POL_CONTROL, 0x21}, 35 | 36 | {0x3611, 0x01}, 37 | {0x3612, 0x2d}, 38 | 39 | {0x3032, 0x00}, 40 | {0x3614, 0x80}, 41 | {0x3618, 0x00}, 42 | {0x3619, 0x75}, 43 | {0x3622, 0x80}, 44 | {0x3623, 0x00}, 45 | {0x3624, 0x03}, 46 | {0x3630, 0x52}, 47 | {0x3632, 0x07}, 48 | {0x3633, 0xd2}, 49 | {0x3704, 0x80}, 50 | {0x3708, 0x66}, 51 | {0x3709, 0x12}, 52 | {0x370b, 0x12}, 53 | {0x3717, 0x00}, 54 | {0x371b, 0x60}, 55 | {0x371c, 0x00}, 56 | {0x3901, 0x13}, 57 | 58 | {0x3600, 0x08}, 59 | {0x3620, 0x43}, 60 | {0x3702, 0x20}, 61 | {0x3739, 0x48}, 62 | {0x3730, 0x20}, 63 | {0x370c, 0x0c}, 64 | 65 | {0x3a18, 0x00}, 66 | {0x3a19, 0xf8}, 67 | 68 | {0x3000, 0x10}, 69 | {0x3004, 0xef}, 70 | 71 | {0x6700, 0x05}, 72 | {0x6701, 0x19}, 73 | {0x6702, 0xfd}, 74 | {0x6703, 0xd1}, 75 | {0x6704, 0xff}, 76 | {0x6705, 0xff}, 77 | 78 | {0x3c01, 0x80}, 79 | {0x3c00, 0x04}, 80 | {0x3a08, 0x00}, {0x3a09, 0x62}, //50Hz Band Width Step (10bit) 81 | {0x3a0e, 0x08}, //50Hz Max Bands in One Frame (6 bit) 82 | {0x3a0a, 0x00}, {0x3a0b, 0x52}, //60Hz Band Width Step (10bit) 83 | {0x3a0d, 0x09}, //60Hz Max Bands in One Frame (6 bit) 84 | 85 | {0x3a00, 0x3a},//night mode off 86 | {0x3a14, 0x09}, 87 | {0x3a15, 0x30}, 88 | {0x3a02, 0x09}, 89 | {0x3a03, 0x30}, 90 | 91 | {COMPRESSION_CTRL0E, 0x08}, 92 | {0x4520, 0x0b}, 93 | {0x460b, 0x37}, 94 | {0x4713, 0x02}, 95 | {0x471c, 0xd0}, 96 | {0x5086, 0x00}, 97 | 98 | {0x5002, 0x00}, 99 | {0x501f, 0x00}, 100 | 101 | {SYSTEM_CTROL0, 0x02}, 102 | 103 | {0x5180, 0xff}, 104 | {0x5181, 0xf2}, 105 | {0x5182, 0x00}, 106 | {0x5183, 0x14}, 107 | {0x5184, 0x25}, 108 | {0x5185, 0x24}, 109 | {0x5186, 0x16}, 110 | {0x5187, 0x16}, 111 | {0x5188, 0x16}, 112 | {0x5189, 0x68}, 113 | {0x518a, 0x60}, 114 | {0x518b, 0xe0}, 115 | {0x518c, 0xb2}, 116 | {0x518d, 0x42}, 117 | {0x518e, 0x35}, 118 | {0x518f, 0x56}, 119 | {0x5190, 0x56}, 120 | {0x5191, 0xf8}, 121 | {0x5192, 0x04}, 122 | {0x5193, 0x70}, 123 | {0x5194, 0xf0}, 124 | {0x5195, 0xf0}, 125 | {0x5196, 0x03}, 126 | {0x5197, 0x01}, 127 | {0x5198, 0x04}, 128 | {0x5199, 0x12}, 129 | {0x519a, 0x04}, 130 | {0x519b, 0x00}, 131 | {0x519c, 0x06}, 132 | {0x519d, 0x82}, 133 | {0x519e, 0x38}, 134 | 135 | {0x5381, 0x1d}, 136 | {0x5382, 0x60}, 137 | {0x5383, 0x03}, 138 | {0x5384, 0x0c}, 139 | {0x5385, 0x78}, 140 | {0x5386, 0x84}, 141 | {0x5387, 0x7d}, 142 | {0x5388, 0x6b}, 143 | {0x5389, 0x12}, 144 | {0x538a, 0x01}, 145 | {0x538b, 0x98}, 146 | 147 | {0x5480, 0x01}, 148 | // {0x5481, 0x05}, 149 | // {0x5482, 0x09}, 150 | // {0x5483, 0x10}, 151 | // {0x5484, 0x3a}, 152 | // {0x5485, 0x4c}, 153 | // {0x5486, 0x5a}, 154 | // {0x5487, 0x68}, 155 | // {0x5488, 0x74}, 156 | // {0x5489, 0x80}, 157 | // {0x548a, 0x8e}, 158 | // {0x548b, 0xa4}, 159 | // {0x548c, 0xb4}, 160 | // {0x548d, 0xc8}, 161 | // {0x548e, 0xde}, 162 | // {0x548f, 0xf0}, 163 | // {0x5490, 0x15}, 164 | 165 | {0x5000, 0xa7}, 166 | {0x5800, 0x0C}, 167 | {0x5801, 0x09}, 168 | {0x5802, 0x0C}, 169 | {0x5803, 0x0C}, 170 | {0x5804, 0x0D}, 171 | {0x5805, 0x17}, 172 | {0x5806, 0x06}, 173 | {0x5807, 0x05}, 174 | {0x5808, 0x04}, 175 | {0x5809, 0x06}, 176 | {0x580a, 0x09}, 177 | {0x580b, 0x0E}, 178 | {0x580c, 0x05}, 179 | {0x580d, 0x01}, 180 | {0x580e, 0x01}, 181 | {0x580f, 0x01}, 182 | {0x5810, 0x05}, 183 | {0x5811, 0x0D}, 184 | {0x5812, 0x05}, 185 | {0x5813, 0x01}, 186 | {0x5814, 0x01}, 187 | {0x5815, 0x01}, 188 | {0x5816, 0x05}, 189 | {0x5817, 0x0D}, 190 | {0x5818, 0x08}, 191 | {0x5819, 0x06}, 192 | {0x581a, 0x05}, 193 | {0x581b, 0x07}, 194 | {0x581c, 0x0B}, 195 | {0x581d, 0x0D}, 196 | {0x581e, 0x12}, 197 | {0x581f, 0x0D}, 198 | {0x5820, 0x0E}, 199 | {0x5821, 0x10}, 200 | {0x5822, 0x10}, 201 | {0x5823, 0x1E}, 202 | {0x5824, 0x53}, 203 | {0x5825, 0x15}, 204 | {0x5826, 0x05}, 205 | {0x5827, 0x14}, 206 | {0x5828, 0x54}, 207 | {0x5829, 0x25}, 208 | {0x582a, 0x33}, 209 | {0x582b, 0x33}, 210 | {0x582c, 0x34}, 211 | {0x582d, 0x16}, 212 | {0x582e, 0x24}, 213 | {0x582f, 0x41}, 214 | {0x5830, 0x50}, 215 | {0x5831, 0x42}, 216 | {0x5832, 0x15}, 217 | {0x5833, 0x25}, 218 | {0x5834, 0x34}, 219 | {0x5835, 0x33}, 220 | {0x5836, 0x24}, 221 | {0x5837, 0x26}, 222 | {0x5838, 0x54}, 223 | {0x5839, 0x25}, 224 | {0x583a, 0x15}, 225 | {0x583b, 0x25}, 226 | {0x583c, 0x53}, 227 | {0x583d, 0xCF}, 228 | 229 | {0x3a0f, 0x30}, 230 | {0x3a10, 0x28}, 231 | {0x3a1b, 0x30}, 232 | {0x3a1e, 0x28}, 233 | {0x3a11, 0x60}, 234 | {0x3a1f, 0x14}, 235 | 236 | {0x5302, 0x28}, 237 | {0x5303, 0x20}, 238 | 239 | {0x5306, 0x1c}, //de-noise offset 1 240 | {0x5307, 0x28}, //de-noise offset 2 241 | 242 | {0x4002, 0xc5}, 243 | {0x4003, 0x81}, 244 | {0x4005, 0x12}, 245 | 246 | {0x5688, 0x11}, 247 | {0x5689, 0x11}, 248 | {0x568a, 0x11}, 249 | {0x568b, 0x11}, 250 | {0x568c, 0x11}, 251 | {0x568d, 0x11}, 252 | {0x568e, 0x11}, 253 | {0x568f, 0x11}, 254 | 255 | {0x5580, 0x06}, 256 | {0x5588, 0x00}, 257 | {0x5583, 0x40}, 258 | {0x5584, 0x2c}, 259 | 260 | {ISP_CONTROL_01, 0x83}, // turn color matrix, awb and SDE 261 | {REGLIST_TAIL, 0x00}, // tail 262 | }; 263 | 264 | static const DRAM_ATTR uint16_t sensor_fmt_jpeg[][2] = { 265 | {FORMAT_CTRL, 0x00}, // YUV422 266 | {FORMAT_CTRL00, 0x30}, // YUYV 267 | {0x3002, 0x00},//0x1c to 0x00 !!! 268 | {0x3006, 0xff},//0xc3 to 0xff !!! 269 | {0x471c, 0x50},//0xd0 to 0x50 !!! 270 | {REGLIST_TAIL, 0x00}, // tail 271 | }; 272 | 273 | static const DRAM_ATTR uint16_t sensor_fmt_raw[][2] = { 274 | {FORMAT_CTRL00, 0x00}, // RAW 275 | {REGLIST_TAIL, 0x00} 276 | }; 277 | 278 | static const DRAM_ATTR uint16_t sensor_fmt_grayscale[][2] = { 279 | {FORMAT_CTRL, 0x00}, // YUV422 280 | {FORMAT_CTRL00, 0x10}, // Y8 281 | {REGLIST_TAIL, 0x00} 282 | }; 283 | 284 | static const DRAM_ATTR uint16_t sensor_fmt_yuv422[][2] = { 285 | {FORMAT_CTRL, 0x00}, // YUV422 286 | {FORMAT_CTRL00, 0x30}, // YUYV 287 | {REGLIST_TAIL, 0x00} 288 | }; 289 | 290 | static const DRAM_ATTR uint16_t sensor_fmt_rgb565[][2] = { 291 | {FORMAT_CTRL, 0x01}, // RGB 292 | {FORMAT_CTRL00, 0x61}, // RGB565 (BGR) 293 | {REGLIST_TAIL, 0x00} 294 | }; 295 | 296 | static const DRAM_ATTR uint8_t sensor_saturation_levels[9][11] = { 297 | {0x1d, 0x60, 0x03, 0x07, 0x48, 0x4f, 0x4b, 0x40, 0x0b, 0x01, 0x98},//-4 298 | {0x1d, 0x60, 0x03, 0x08, 0x54, 0x5c, 0x58, 0x4b, 0x0d, 0x01, 0x98},//-3 299 | {0x1d, 0x60, 0x03, 0x0a, 0x60, 0x6a, 0x64, 0x56, 0x0e, 0x01, 0x98},//-2 300 | {0x1d, 0x60, 0x03, 0x0b, 0x6c, 0x77, 0x70, 0x60, 0x10, 0x01, 0x98},//-1 301 | {0x1d, 0x60, 0x03, 0x0c, 0x78, 0x84, 0x7d, 0x6b, 0x12, 0x01, 0x98},//0 302 | {0x1d, 0x60, 0x03, 0x0d, 0x84, 0x91, 0x8a, 0x76, 0x14, 0x01, 0x98},//+1 303 | {0x1d, 0x60, 0x03, 0x0e, 0x90, 0x9e, 0x96, 0x80, 0x16, 0x01, 0x98},//+2 304 | {0x1d, 0x60, 0x03, 0x10, 0x9c, 0xac, 0xa2, 0x8b, 0x17, 0x01, 0x98},//+3 305 | {0x1d, 0x60, 0x03, 0x11, 0xa8, 0xb9, 0xaf, 0x96, 0x19, 0x01, 0x98},//+4 306 | }; 307 | 308 | static const DRAM_ATTR uint8_t sensor_special_effects[7][4] = { 309 | {0x06, 0x40, 0x2c, 0x08},//Normal 310 | {0x46, 0x40, 0x28, 0x08},//Negative 311 | {0x1e, 0x80, 0x80, 0x08},//Grayscale 312 | {0x1e, 0x80, 0xc0, 0x08},//Red Tint 313 | {0x1e, 0x60, 0x60, 0x08},//Green Tint 314 | {0x1e, 0xa0, 0x40, 0x08},//Blue Tint 315 | {0x1e, 0x40, 0xa0, 0x08},//Sepia 316 | }; 317 | 318 | #endif 319 | -------------------------------------------------------------------------------- /air_firmware/components/esp32-camera/sensors/private_include/ov5640.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __OV5640_H__ 3 | #define __OV5640_H__ 4 | 5 | #include "sensor.h" 6 | 7 | int ov5640_init(sensor_t *sensor); 8 | 9 | #endif // __OV5640_H__ 10 | -------------------------------------------------------------------------------- /air_firmware/components/esp32-camera/sensors/private_include/ov5640_regs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OV5640 register definitions. 3 | */ 4 | #ifndef __OV5640_REG_REGS_H__ 5 | #define __OV5640_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 | #define DRIVE_CAPABILITY 0x302c // Bit[7:6]: 16 | // 00: 1x 17 | // 01: 2x 18 | // 10: 3x 19 | // 11: 4x 20 | 21 | #define SC_PLLS_CTRL0 0x303a // Bit[7]: PLLS bypass 22 | #define SC_PLLS_CTRL1 0x303b // Bit[4:0]: PLLS multiplier 23 | #define SC_PLLS_CTRL2 0x303c // Bit[6:4]: PLLS charge pump control 24 | // Bit[3:0]: PLLS system divider 25 | #define SC_PLLS_CTRL3 0x303d // Bit[5:4]: PLLS pre-divider 26 | // 00: 1 27 | // 01: 1.5 28 | // 10: 2 29 | // 11: 3 30 | // Bit[2]: PLLS root-divider - 1 31 | // Bit[1:0]: PLLS seld5 32 | // 00: 1 33 | // 01: 1 34 | // 10: 2 35 | // 11: 2.5 36 | 37 | /* AEC/AGC control functions */ 38 | #define AEC_PK_MANUAL 0x3503 // AEC Manual Mode Control 39 | // Bit[7:6]: Reserved 40 | // Bit[5]: Gain delay option 41 | // Valid when 0x3503[4]=1’b0 42 | // 0: Delay one frame latch 43 | // 1: One frame latch 44 | // Bit[4:2]: Reserved 45 | // Bit[1]: AGC manual 46 | // 0: Auto enable 47 | // 1: Manual enable 48 | // Bit[0]: AEC manual 49 | // 0: Auto enable 50 | // 1: Manual enable 51 | 52 | //gain = {0x350A[1:0], 0x350B[7:0]} / 16 53 | 54 | 55 | #define X_ADDR_ST_H 0x3800 //Bit[3:0]: X address start[11:8] 56 | #define X_ADDR_ST_L 0x3801 //Bit[7:0]: X address start[7:0] 57 | #define Y_ADDR_ST_H 0x3802 //Bit[2:0]: Y address start[10:8] 58 | #define Y_ADDR_ST_L 0x3803 //Bit[7:0]: Y address start[7:0] 59 | #define X_ADDR_END_H 0x3804 //Bit[3:0]: X address end[11:8] 60 | #define X_ADDR_END_L 0x3805 //Bit[7:0]: 61 | #define Y_ADDR_END_H 0x3806 //Bit[2:0]: Y address end[10:8] 62 | #define Y_ADDR_END_L 0x3807 //Bit[7:0]: 63 | // Size after scaling 64 | #define X_OUTPUT_SIZE_H 0x3808 //Bit[3:0]: DVP output horizontal width[11:8] 65 | #define X_OUTPUT_SIZE_L 0x3809 //Bit[7:0]: 66 | #define Y_OUTPUT_SIZE_H 0x380a //Bit[2:0]: DVP output vertical height[10:8] 67 | #define Y_OUTPUT_SIZE_L 0x380b //Bit[7:0]: 68 | #define X_TOTAL_SIZE_H 0x380c //Bit[3:0]: Total horizontal size[11:8] 69 | #define X_TOTAL_SIZE_L 0x380d //Bit[7:0]: 70 | #define Y_TOTAL_SIZE_H 0x380e //Bit[7:0]: Total vertical size[15:8] 71 | #define Y_TOTAL_SIZE_L 0x380f //Bit[7:0]: 72 | #define X_OFFSET_H 0x3810 //Bit[3:0]: ISP horizontal offset[11:8] 73 | #define X_OFFSET_L 0x3811 //Bit[7:0]: 74 | #define Y_OFFSET_H 0x3812 //Bit[2:0]: ISP vertical offset[10:8] 75 | #define Y_OFFSET_L 0x3813 //Bit[7:0]: 76 | #define X_INCREMENT 0x3814 //Bit[7:4]: Horizontal odd subsample increment 77 | //Bit[3:0]: Horizontal even subsample increment 78 | #define Y_INCREMENT 0x3815 //Bit[7:4]: Vertical odd subsample increment 79 | //Bit[3:0]: Vertical even subsample increment 80 | // Size before scaling 81 | //#define X_INPUT_SIZE (X_ADDR_END - X_ADDR_ST + 1 - (2 * X_OFFSET)) 82 | //#define Y_INPUT_SIZE (Y_ADDR_END - Y_ADDR_ST + 1 - (2 * Y_OFFSET)) 83 | 84 | /* mirror and flip registers */ 85 | #define TIMING_TC_REG20 0x3820 // Timing Control Register 86 | // Bit[2:1]: Vertical flip enable 87 | // 00: Normal 88 | // 11: Vertical flip 89 | // Bit[0]: Vertical binning enable 90 | #define TIMING_TC_REG21 0x3821 // Timing Control Register 91 | // Bit[5]: Compression Enable 92 | // Bit[2:1]: Horizontal mirror enable 93 | // 00: Normal 94 | // 11: Horizontal mirror 95 | // Bit[0]: Horizontal binning enable 96 | 97 | #define PCLK_RATIO 0x3824 // Bit[4:0]: PCLK ratio manual 98 | 99 | /* frame control registers */ 100 | #define FRAME_CTRL01 0x4201 // Control Passed Frame Number When both ON and OFF number set to 0x00,frame control is in bypass mode 101 | // Bit[7:4]: Not used 102 | // Bit[3:0]: Frame ON number 103 | #define FRAME_CTRL02 0x4202 // Control Masked Frame Number When both ON and OFF number set to 0x00,frame control is in bypass mode 104 | // Bit[7:4]: Not used 105 | // BIT[3:0]: Frame OFF number 106 | 107 | /* format control registers */ 108 | #define FORMAT_CTRL00 0x4300 109 | 110 | #define CLOCK_POL_CONTROL 0x4740// Bit[5]: PCLK polarity 0: active low 111 | // 1: active high 112 | // Bit[3]: Gate PCLK under VSYNC 113 | // Bit[2]: Gate PCLK under HREF 114 | // Bit[1]: HREF polarity 115 | // 0: active low 116 | // 1: active high 117 | // Bit[0] VSYNC polarity 118 | // 0: active low 119 | // 1: active high 120 | 121 | #define ISP_CONTROL_01 0x5001 // Bit[5]: Scale enable 122 | // 0: Disable 123 | // 1: Enable 124 | 125 | /* output format control registers */ 126 | #define FORMAT_CTRL 0x501F // Format select 127 | // Bit[2:0]: 128 | // 000: YUV422 129 | // 001: RGB 130 | // 010: Dither 131 | // 011: RAW after DPC 132 | // 101: RAW after CIP 133 | 134 | /* ISP top control registers */ 135 | #define PRE_ISP_TEST_SETTING_1 0x503D // Bit[7]: Test enable 136 | // 0: Test disable 137 | // 1: Color bar enable 138 | // Bit[6]: Rolling 139 | // Bit[5]: Transparent 140 | // Bit[4]: Square black and white 141 | // Bit[3:2]: Color bar style 142 | // 00: Standard 8 color bar 143 | // 01: Gradual change at vertical mode 1 144 | // 10: Gradual change at horizontal 145 | // 11: Gradual change at vertical mode 2 146 | // Bit[1:0]: Test select 147 | // 00: Color bar 148 | // 01: Random data 149 | // 10: Square data 150 | // 11: Black image 151 | 152 | //exposure = {0x3500[3:0], 0x3501[7:0], 0x3502[7:0]} / 16 × tROW 153 | 154 | #define SCALE_CTRL_1 0x5601 // Bit[6:4]: HDIV RW 155 | // DCW scale times 156 | // 000: DCW 1 time 157 | // 001: DCW 2 times 158 | // 010: DCW 4 times 159 | // 100: DCW 8 times 160 | // 101: DCW 16 times 161 | // Others: DCW 16 times 162 | // Bit[2:0]: VDIV RW 163 | // DCW scale times 164 | // 000: DCW 1 time 165 | // 001: DCW 2 times 166 | // 010: DCW 4 times 167 | // 100: DCW 8 times 168 | // 101: DCW 16 times 169 | // Others: DCW 16 times 170 | 171 | #define SCALE_CTRL_2 0x5602 // X_SCALE High Bits 172 | #define SCALE_CTRL_3 0x5603 // X_SCALE Low Bits 173 | #define SCALE_CTRL_4 0x5604 // Y_SCALE High Bits 174 | #define SCALE_CTRL_5 0x5605 // Y_SCALE Low Bits 175 | #define SCALE_CTRL_6 0x5606 // Bit[3:0]: V Offset 176 | 177 | #define VFIFO_CTRL0C 0x460C // Bit[1]: PCLK manual enable 178 | // 0: Auto 179 | // 1: Manual by PCLK_RATIO 180 | 181 | #define VFIFO_X_SIZE_H 0x4602 182 | #define VFIFO_X_SIZE_L 0x4603 183 | #define VFIFO_Y_SIZE_H 0x4604 184 | #define VFIFO_Y_SIZE_L 0x4605 185 | 186 | #define COMPRESSION_CTRL00 0x4400 // 187 | #define COMPRESSION_CTRL01 0x4401 // 188 | #define COMPRESSION_CTRL02 0x4402 // 189 | #define COMPRESSION_CTRL03 0x4403 // 190 | #define COMPRESSION_CTRL04 0x4404 // 191 | #define COMPRESSION_CTRL05 0x4405 // 192 | #define COMPRESSION_CTRL06 0x4406 // 193 | #define COMPRESSION_CTRL07 0x4407 // Bit[5:0]: QS 194 | #define COMPRESSION_ISI_CTRL 0x4408 // 195 | #define COMPRESSION_CTRL09 0x4409 // 196 | #define COMPRESSION_CTRL0a 0x440a // 197 | #define COMPRESSION_CTRL0b 0x440b // 198 | #define COMPRESSION_CTRL0c 0x440c // 199 | #define COMPRESSION_CTRL0d 0x440d // 200 | #define COMPRESSION_CTRL0E 0x440e // 201 | 202 | /** 203 | * @brief register value 204 | */ 205 | #define TEST_COLOR_BAR 0xC0 /* Enable Color Bar roling Test */ 206 | 207 | #define AEC_PK_MANUAL_AGC_MANUALEN 0x02 /* Enable AGC Manual enable */ 208 | #define AEC_PK_MANUAL_AEC_MANUALEN 0x01 /* Enable AEC Manual enable */ 209 | 210 | #define TIMING_TC_REG20_VFLIP 0x06 /* Vertical flip enable */ 211 | #define TIMING_TC_REG21_HMIRROR 0x06 /* Horizontal mirror enable */ 212 | 213 | #endif // __OV3660_REG_REGS_H__ 214 | -------------------------------------------------------------------------------- /air_firmware/components/esp32-camera/sensors/private_include/ov5640_settings.h: -------------------------------------------------------------------------------- 1 | #ifndef _OV5640_SETTINGS_H_ 2 | #define _OV5640_SETTINGS_H_ 3 | 4 | #include 5 | #include 6 | #include "esp_attr.h" 7 | #include "ov5640_regs.h" 8 | 9 | static const ratio_settings_t ratio_table[] = { 10 | // mw, mh, sx, sy, ex, ey, ox, oy, tx, ty 11 | { 2560, 1920, 0, 0, 2623, 1951, 32, 16, 2844, 1968 }, //4x3 12 | { 2560, 1704, 0, 110, 2623, 1843, 32, 16, 2844, 1752 }, //3x2 13 | { 2560, 1600, 0, 160, 2623, 1791, 32, 16, 2844, 1648 }, //16x10 14 | { 2560, 1536, 0, 192, 2623, 1759, 32, 16, 2844, 1584 }, //5x3 15 | { 2560, 1440, 0, 240, 2623, 1711, 32, 16, 2844, 1488 }, //16x9 16 | { 2560, 1080, 0, 420, 2623, 1531, 32, 16, 2844, 1128 }, //21x9 17 | { 2400, 1920, 80, 0, 2543, 1951, 32, 16, 2684, 1968 }, //5x4 18 | { 1920, 1920, 320, 0, 2543, 1951, 32, 16, 2684, 1968 }, //1x1 19 | { 1088, 1920, 736, 0, 1887, 1951, 32, 16, 1884, 1968 } //9x16 20 | }; 21 | 22 | #define REG_DLY 0xffff 23 | #define REGLIST_TAIL 0x0000 24 | 25 | static const DRAM_ATTR uint16_t sensor_default_regs[][2] = { 26 | {SYSTEM_CTROL0, 0x82}, // software reset 27 | {REG_DLY, 10}, // delay 10ms 28 | {SYSTEM_CTROL0, 0x42}, // power down 29 | 30 | //enable pll 31 | {0x3103, 0x13}, 32 | 33 | //io direction 34 | {0x3017, 0xff}, 35 | {0x3018, 0xff}, 36 | 37 | {DRIVE_CAPABILITY, 0xc3}, 38 | {CLOCK_POL_CONTROL, 0x21}, 39 | 40 | {0x4713, 0x02},//jpg mode select 41 | 42 | {ISP_CONTROL_01, 0x83}, // turn color matrix, awb and SDE 43 | 44 | //sys reset 45 | {0x3000, 0x00}, 46 | {0x3002, 0x1c}, 47 | 48 | //clock enable 49 | {0x3004, 0xff}, 50 | {0x3006, 0xc3}, 51 | 52 | //isp control 53 | {0x5000, 0xa7}, 54 | {ISP_CONTROL_01, 0xa3},//+scaling? 55 | {0x5003, 0x08},//special_effect 56 | 57 | //unknown 58 | {0x370c, 0x02},//!!IMPORTANT 59 | {0x3634, 0x40},//!!IMPORTANT 60 | 61 | //AEC/AGC 62 | {0x3a02, 0x03}, 63 | {0x3a03, 0xd8}, 64 | {0x3a08, 0x01}, 65 | {0x3a09, 0x27}, 66 | {0x3a0a, 0x00}, 67 | {0x3a0b, 0xf6}, 68 | {0x3a0d, 0x04}, 69 | {0x3a0e, 0x03}, 70 | {0x3a0f, 0x30},//ae_level 71 | {0x3a10, 0x28},//ae_level 72 | {0x3a11, 0x60},//ae_level 73 | {0x3a13, 0x43}, 74 | {0x3a14, 0x03}, 75 | {0x3a15, 0xd8}, 76 | {0x3a18, 0x00},//gainceiling 77 | {0x3a19, 0xf8},//gainceiling 78 | {0x3a1b, 0x30},//ae_level 79 | {0x3a1e, 0x26},//ae_level 80 | {0x3a1f, 0x14},//ae_level 81 | 82 | //vcm debug 83 | {0x3600, 0x08}, 84 | {0x3601, 0x33}, 85 | 86 | //50/60Hz 87 | {0x3c01, 0xa4}, 88 | {0x3c04, 0x28}, 89 | {0x3c05, 0x98}, 90 | {0x3c06, 0x00}, 91 | {0x3c07, 0x08}, 92 | {0x3c08, 0x00}, 93 | {0x3c09, 0x1c}, 94 | {0x3c0a, 0x9c}, 95 | {0x3c0b, 0x40}, 96 | 97 | {0x460c, 0x22},//disable jpeg footer 98 | 99 | //BLC 100 | {0x4001, 0x02}, 101 | {0x4004, 0x02}, 102 | 103 | //AWB 104 | {0x5180, 0xff}, 105 | {0x5181, 0xf2}, 106 | {0x5182, 0x00}, 107 | {0x5183, 0x14}, 108 | {0x5184, 0x25}, 109 | {0x5185, 0x24}, 110 | {0x5186, 0x09}, 111 | {0x5187, 0x09}, 112 | {0x5188, 0x09}, 113 | {0x5189, 0x75}, 114 | {0x518a, 0x54}, 115 | {0x518b, 0xe0}, 116 | {0x518c, 0xb2}, 117 | {0x518d, 0x42}, 118 | {0x518e, 0x3d}, 119 | {0x518f, 0x56}, 120 | {0x5190, 0x46}, 121 | {0x5191, 0xf8}, 122 | {0x5192, 0x04}, 123 | {0x5193, 0x70}, 124 | {0x5194, 0xf0}, 125 | {0x5195, 0xf0}, 126 | {0x5196, 0x03}, 127 | {0x5197, 0x01}, 128 | {0x5198, 0x04}, 129 | {0x5199, 0x12}, 130 | {0x519a, 0x04}, 131 | {0x519b, 0x00}, 132 | {0x519c, 0x06}, 133 | {0x519d, 0x82}, 134 | {0x519e, 0x38}, 135 | 136 | //color matrix (Saturation) 137 | {0x5381, 0x1e}, 138 | {0x5382, 0x5b}, 139 | {0x5383, 0x08}, 140 | {0x5384, 0x0a}, 141 | {0x5385, 0x7e}, 142 | {0x5386, 0x88}, 143 | {0x5387, 0x7c}, 144 | {0x5388, 0x6c}, 145 | {0x5389, 0x10}, 146 | {0x538a, 0x01}, 147 | {0x538b, 0x98}, 148 | 149 | //CIP control (Sharpness) 150 | {0x5300, 0x10},//sharpness 151 | {0x5301, 0x10},//sharpness 152 | {0x5302, 0x18},//sharpness 153 | {0x5303, 0x19},//sharpness 154 | {0x5304, 0x10}, 155 | {0x5305, 0x10}, 156 | {0x5306, 0x08},//denoise 157 | {0x5307, 0x16}, 158 | {0x5308, 0x40}, 159 | {0x5309, 0x10},//sharpness 160 | {0x530a, 0x10},//sharpness 161 | {0x530b, 0x04},//sharpness 162 | {0x530c, 0x06},//sharpness 163 | 164 | //GAMMA 165 | {0x5480, 0x01}, 166 | {0x5481, 0x00}, 167 | {0x5482, 0x1e}, 168 | {0x5483, 0x3b}, 169 | {0x5484, 0x58}, 170 | {0x5485, 0x66}, 171 | {0x5486, 0x71}, 172 | {0x5487, 0x7d}, 173 | {0x5488, 0x83}, 174 | {0x5489, 0x8f}, 175 | {0x548a, 0x98}, 176 | {0x548b, 0xa6}, 177 | {0x548c, 0xb8}, 178 | {0x548d, 0xca}, 179 | {0x548e, 0xd7}, 180 | {0x548f, 0xe3}, 181 | {0x5490, 0x1d}, 182 | 183 | //Special Digital Effects (SDE) (UV adjust) 184 | {0x5580, 0x06},//enable brightness and contrast 185 | {0x5583, 0x40},//special_effect 186 | {0x5584, 0x10},//special_effect 187 | {0x5586, 0x20},//contrast 188 | {0x5587, 0x00},//brightness 189 | {0x5588, 0x00},//brightness 190 | {0x5589, 0x10}, 191 | {0x558a, 0x00}, 192 | {0x558b, 0xf8}, 193 | {0x501d, 0x40},// enable manual offset of contrast 194 | 195 | //power on 196 | {0x3008, 0x02}, 197 | 198 | //50Hz 199 | {0x3c00, 0x04}, 200 | 201 | {REG_DLY, 300}, 202 | {REGLIST_TAIL, 0x00}, // tail 203 | }; 204 | 205 | static const DRAM_ATTR uint16_t sensor_fmt_jpeg[][2] = { 206 | {FORMAT_CTRL, 0x00}, // YUV422 207 | {FORMAT_CTRL00, 0x30}, // YUYV 208 | {0x3002, 0x00},//0x1c to 0x00 !!! 209 | {0x3006, 0xff},//0xc3 to 0xff !!! 210 | {0x471c, 0x50},//0xd0 to 0x50 !!! 211 | {REGLIST_TAIL, 0x00}, // tail 212 | }; 213 | 214 | static const DRAM_ATTR uint16_t sensor_fmt_raw[][2] = { 215 | {FORMAT_CTRL, 0x03}, // RAW (DPC) 216 | {FORMAT_CTRL00, 0x00}, // RAW 217 | {REGLIST_TAIL, 0x00} 218 | }; 219 | 220 | static const DRAM_ATTR uint16_t sensor_fmt_grayscale[][2] = { 221 | {FORMAT_CTRL, 0x00}, // YUV422 222 | {FORMAT_CTRL00, 0x10}, // Y8 223 | {REGLIST_TAIL, 0x00} 224 | }; 225 | 226 | static const DRAM_ATTR uint16_t sensor_fmt_yuv422[][2] = { 227 | {FORMAT_CTRL, 0x00}, // YUV422 228 | {FORMAT_CTRL00, 0x30}, // YUYV 229 | {REGLIST_TAIL, 0x00} 230 | }; 231 | 232 | static const DRAM_ATTR uint16_t sensor_fmt_rgb565[][2] = { 233 | {FORMAT_CTRL, 0x01}, // RGB 234 | {FORMAT_CTRL00, 0x61}, // RGB565 (BGR) 235 | {REGLIST_TAIL, 0x00} 236 | }; 237 | 238 | static const DRAM_ATTR uint8_t sensor_saturation_levels[9][11] = { 239 | {0x1d, 0x60, 0x03, 0x07, 0x48, 0x4f, 0x4b, 0x40, 0x0b, 0x01, 0x98},//-4 240 | {0x1d, 0x60, 0x03, 0x08, 0x54, 0x5c, 0x58, 0x4b, 0x0d, 0x01, 0x98},//-3 241 | {0x1d, 0x60, 0x03, 0x0a, 0x60, 0x6a, 0x64, 0x56, 0x0e, 0x01, 0x98},//-2 242 | {0x1d, 0x60, 0x03, 0x0b, 0x6c, 0x77, 0x70, 0x60, 0x10, 0x01, 0x98},//-1 243 | {0x1d, 0x60, 0x03, 0x0c, 0x78, 0x84, 0x7d, 0x6b, 0x12, 0x01, 0x98},//0 244 | {0x1d, 0x60, 0x03, 0x0d, 0x84, 0x91, 0x8a, 0x76, 0x14, 0x01, 0x98},//+1 245 | {0x1d, 0x60, 0x03, 0x0e, 0x90, 0x9e, 0x96, 0x80, 0x16, 0x01, 0x98},//+2 246 | {0x1d, 0x60, 0x03, 0x10, 0x9c, 0xac, 0xa2, 0x8b, 0x17, 0x01, 0x98},//+3 247 | {0x1d, 0x60, 0x03, 0x11, 0xa8, 0xb9, 0xaf, 0x96, 0x19, 0x01, 0x98},//+4 248 | }; 249 | 250 | static const DRAM_ATTR uint8_t sensor_special_effects[7][4] = { 251 | {0x06, 0x40, 0x2c, 0x08},//Normal 252 | {0x46, 0x40, 0x28, 0x08},//Negative 253 | {0x1e, 0x80, 0x80, 0x08},//Grayscale 254 | {0x1e, 0x80, 0xc0, 0x08},//Red Tint 255 | {0x1e, 0x60, 0x60, 0x08},//Green Tint 256 | {0x1e, 0xa0, 0x40, 0x08},//Blue Tint 257 | {0x1e, 0x40, 0xa0, 0x08},//Sepia 258 | }; 259 | 260 | static const DRAM_ATTR uint16_t sensor_regs_gamma0[][2] = { 261 | {0x5480, 0x01}, 262 | {0x5481, 0x08}, 263 | {0x5482, 0x14}, 264 | {0x5483, 0x28}, 265 | {0x5484, 0x51}, 266 | {0x5485, 0x65}, 267 | {0x5486, 0x71}, 268 | {0x5487, 0x7d}, 269 | {0x5488, 0x87}, 270 | {0x5489, 0x91}, 271 | {0x548a, 0x9a}, 272 | {0x548b, 0xaa}, 273 | {0x548c, 0xb8}, 274 | {0x548d, 0xcd}, 275 | {0x548e, 0xdd}, 276 | {0x548f, 0xea}, 277 | {0x5490, 0x1d} 278 | }; 279 | 280 | static const DRAM_ATTR uint16_t sensor_regs_gamma1[][2] = { 281 | {0x5480, 0x1}, 282 | {0x5481, 0x0}, 283 | {0x5482, 0x1e}, 284 | {0x5483, 0x3b}, 285 | {0x5484, 0x58}, 286 | {0x5485, 0x66}, 287 | {0x5486, 0x71}, 288 | {0x5487, 0x7d}, 289 | {0x5488, 0x83}, 290 | {0x5489, 0x8f}, 291 | {0x548a, 0x98}, 292 | {0x548b, 0xa6}, 293 | {0x548c, 0xb8}, 294 | {0x548d, 0xca}, 295 | {0x548e, 0xd7}, 296 | {0x548f, 0xe3}, 297 | {0x5490, 0x1d} 298 | }; 299 | 300 | static const DRAM_ATTR uint16_t sensor_regs_awb0[][2] = { 301 | {0x5180, 0xff}, 302 | {0x5181, 0xf2}, 303 | {0x5182, 0x00}, 304 | {0x5183, 0x14}, 305 | {0x5184, 0x25}, 306 | {0x5185, 0x24}, 307 | {0x5186, 0x09}, 308 | {0x5187, 0x09}, 309 | {0x5188, 0x09}, 310 | {0x5189, 0x75}, 311 | {0x518a, 0x54}, 312 | {0x518b, 0xe0}, 313 | {0x518c, 0xb2}, 314 | {0x518d, 0x42}, 315 | {0x518e, 0x3d}, 316 | {0x518f, 0x56}, 317 | {0x5190, 0x46}, 318 | {0x5191, 0xf8}, 319 | {0x5192, 0x04}, 320 | {0x5193, 0x70}, 321 | {0x5194, 0xf0}, 322 | {0x5195, 0xf0}, 323 | {0x5196, 0x03}, 324 | {0x5197, 0x01}, 325 | {0x5198, 0x04}, 326 | {0x5199, 0x12}, 327 | {0x519a, 0x04}, 328 | {0x519b, 0x00}, 329 | {0x519c, 0x06}, 330 | {0x519d, 0x82}, 331 | {0x519e, 0x38} 332 | }; 333 | 334 | #endif 335 | -------------------------------------------------------------------------------- /air_firmware/components/esp32-camera/sensors/private_include/ov7670.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the OpenMV project. 3 | * author: Juan Schiavoni 4 | * This work is licensed under the MIT license, see the file LICENSE for details. 5 | * 6 | * OV7670 driver. 7 | * 8 | */ 9 | #ifndef __OV7670_H__ 10 | #define __OV7670_H__ 11 | #include "sensor.h" 12 | 13 | int ov7670_init(sensor_t *sensor); 14 | #endif // __OV7670_H__ 15 | -------------------------------------------------------------------------------- /air_firmware/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 | -------------------------------------------------------------------------------- /air_firmware/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file was automatically generated for projects 2 | # without default 'CMakeLists.txt' file. 3 | 4 | set(srcs 5 | main.cpp queue.cpp) 6 | 7 | idf_component_register(SRCS "${srcs}" 8 | INCLUDE_DIRS "") -------------------------------------------------------------------------------- /air_firmware/main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | -------------------------------------------------------------------------------- /air_firmware/main/main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | ///////////////////////////////////////////////////////////////////////// 7 | 8 | constexpr size_t WLAN_INCOMING_BUFFER_SIZE = 1024; 9 | constexpr size_t WLAN_OUTGOING_BUFFER_SIZE = 60000; 10 | 11 | //////////////////////////////////////////////////////////////////////////////////// 12 | 13 | struct Stats 14 | { 15 | uint32_t wlan_data_sent = 0; 16 | uint32_t wlan_data_received = 0; 17 | uint16_t wlan_error_count = 0; 18 | uint16_t wlan_received_packets_dropped = 0; 19 | uint32_t video_data = 0; 20 | uint16_t video_frames = 0; 21 | uint32_t sd_data = 0; 22 | uint32_t sd_drops = 0; 23 | }; 24 | 25 | extern Stats s_stats; 26 | -------------------------------------------------------------------------------- /air_firmware/main/queue.cpp: -------------------------------------------------------------------------------- 1 | #include "queue.h" 2 | #include "structures.h" 3 | 4 | 5 | -------------------------------------------------------------------------------- /air_firmware/main/queue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "structures.h" 6 | #ifdef ESP_PLATFORM 7 | #include "freertos/FreeRTOS.h" 8 | #include "freertos/queue.h" 9 | #include "freertos/task.h" 10 | #include "freertos/semphr.h" 11 | #else 12 | #define IRAM_ATTR 13 | #endif 14 | 15 | ///////////////////////////////////////////////////////////////////////// 16 | 17 | struct Queue 18 | { 19 | void init(uint8_t* buffer, size_t size) 20 | { 21 | m_buffer = buffer; 22 | m_capacity = size; 23 | } 24 | 25 | IRAM_ATTR inline size_t count() const 26 | { 27 | return m_count; 28 | } 29 | 30 | IRAM_ATTR inline size_t next_reading_size() 31 | { 32 | if (m_read_start != m_read_end) 33 | return 0; 34 | 35 | if (m_read_start == m_write_start) 36 | return 0; 37 | 38 | size_t size; 39 | memcpy(&size, m_buffer + m_read_start, sizeof(uint32_t)); //read the size 40 | return size; 41 | } 42 | 43 | IRAM_ATTR inline size_t size() const 44 | { 45 | if (m_read_start == m_write_start) 46 | return 0; 47 | 48 | if (m_write_start > m_read_start) //no wrap 49 | return m_write_end - m_read_start; 50 | 51 | if (m_write_start < m_read_start) //wrap 52 | return (m_capacity - m_read_start) + m_write_end; 53 | 54 | return 0; 55 | } 56 | 57 | IRAM_ATTR inline size_t capacity() const 58 | { 59 | return m_capacity; 60 | } 61 | 62 | IRAM_ATTR inline uint8_t* start_writing(size_t size) __attribute__((always_inline)) 63 | { 64 | if (m_write_start != m_write_end) 65 | return nullptr; 66 | 67 | //size_t aligned_size = (size + (CHUNK_SIZE - 1)) & ~CHUNK_MASK; //align the size 68 | size_t end = m_write_start + sizeof(uint32_t) + size; 69 | if (end <= m_capacity) //no wrap 70 | { 71 | //check read collisions 72 | if (m_write_start < m_read_start && end >= m_read_start) 73 | { 74 | // Serial.printf("\tf1: %d < %d && %d >= %d\n", start, m_read_start, end, m_read_start); 75 | return nullptr; 76 | } 77 | 78 | // Serial.printf("\tw1: %d, %d, %d, %d\n", start, end, m_read_start, m_read_end); 79 | memcpy(m_buffer + m_write_start, &size, sizeof(uint32_t)); //write the size before wrapping 80 | m_write_end = end; 81 | return m_buffer + m_write_start + sizeof(uint32_t); 82 | } 83 | else //wrap 84 | { 85 | //check read collisions 86 | if (m_read_start > m_write_start) //if the read offset is between start and the end of the buffer 87 | { 88 | // Serial.printf("\tf2: %d > %d\n", m_read_start, start); 89 | return nullptr; 90 | } 91 | end = size; 92 | //check read collisions 93 | if (end >= m_read_start) 94 | { 95 | // Serial.printf("\tf3: %d >= %d\n", end, m_read_start); 96 | return nullptr; 97 | } 98 | 99 | // Serial.printf("\tw2: %d, %d, %d, %d\n", start, end, m_read_start, m_read_end); 100 | memcpy(m_buffer + m_write_start, &size, sizeof(uint32_t)); //write the size before wrapping 101 | m_write_end = end; 102 | return m_buffer; 103 | } 104 | } 105 | 106 | IRAM_ATTR inline void end_writing() __attribute__((always_inline)) 107 | { 108 | m_write_start = m_write_end; 109 | m_count++; 110 | } 111 | IRAM_ATTR inline void cancel_writing() __attribute__((always_inline)) 112 | { 113 | m_write_end = m_write_start; 114 | } 115 | 116 | IRAM_ATTR inline uint8_t* start_reading(size_t& size) __attribute__((always_inline)) 117 | { 118 | if (m_read_start != m_read_end) 119 | return nullptr; 120 | 121 | if (m_read_start == m_write_start) 122 | { 123 | // Serial.printf("\tf4: %d == %d\n", m_read_start, m_write_start); 124 | size = 0; 125 | return nullptr; 126 | } 127 | size_t start = m_read_start; 128 | memcpy(&size, m_buffer + start, sizeof(uint32_t)); //read the size 129 | //size_t aligned_size = (size + (CHUNK_SIZE - 1)) & ~CHUNK_MASK; //align the size 130 | size_t end = start + sizeof(uint32_t) + size; 131 | if (end <= m_capacity) 132 | { 133 | m_read_end = end; 134 | return m_buffer + start + sizeof(uint32_t); 135 | } 136 | else 137 | { 138 | //m_read_start = 0; 139 | m_read_end = size; 140 | return m_buffer; 141 | } 142 | } 143 | 144 | IRAM_ATTR inline void end_reading() __attribute__((always_inline)) 145 | { 146 | m_read_start = m_read_end; 147 | assert(m_count > 0); 148 | m_count--; 149 | } 150 | IRAM_ATTR inline void cancel_reading() __attribute__((always_inline)) 151 | { 152 | m_read_end = m_read_start; 153 | } 154 | 155 | private: 156 | uint8_t* m_buffer = nullptr; 157 | size_t m_capacity = 0; 158 | size_t m_write_start = 0; 159 | size_t m_write_end = 0; 160 | size_t m_read_start = 0; 161 | size_t m_read_end = 0; 162 | size_t m_count = 0; 163 | }; 164 | 165 | //////////////////////////////////////////////////////////////////////////////////// 166 | -------------------------------------------------------------------------------- /components/common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(srcs fec_codec.cpp fec.cpp safe_printf.cpp structures.cpp crc.cpp) 2 | 3 | idf_component_register(SRCS "${srcs}" 4 | INCLUDE_DIRS . ) 5 | 6 | -------------------------------------------------------------------------------- /components/common/circular_buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #ifdef ESP_PLATFORM 7 | #include "freertos/FreeRTOS.h" 8 | #include "freertos/queue.h" 9 | #include "freertos/task.h" 10 | #include "freertos/semphr.h" 11 | #else 12 | #define IRAM_ATTR 13 | #endif 14 | 15 | class Circular_Buffer 16 | { 17 | public: 18 | Circular_Buffer(uint8_t* buffer, size_t size) 19 | : m_data(buffer) 20 | , m_capacity(size) 21 | { 22 | } 23 | 24 | IRAM_ATTR size_t size() const 25 | { 26 | return m_size; 27 | } 28 | IRAM_ATTR bool empty() const 29 | { 30 | return m_size == 0; 31 | } 32 | 33 | IRAM_ATTR size_t get_space_left() const 34 | { 35 | return m_capacity - m_size; 36 | } 37 | IRAM_ATTR size_t capacity() const 38 | { 39 | return m_capacity; 40 | } 41 | 42 | IRAM_ATTR void resize(size_t size) 43 | { 44 | assert(size < capacity()); 45 | m_size = size; 46 | } 47 | 48 | IRAM_ATTR bool write(const void* data, size_t size) 49 | { 50 | if (size >= get_space_left()) 51 | return false; 52 | 53 | size_t idx = (m_start + m_size) % m_capacity; 54 | 55 | if (idx + size <= m_capacity) //no wrap 56 | memcpy(m_data + idx, data, size); 57 | else //wrap 58 | { 59 | size_t first = m_capacity - idx; 60 | memcpy(m_data + idx, data, first); 61 | memcpy(m_data, (uint8_t*)data + first, size - first); 62 | } 63 | m_size += size; 64 | return true; 65 | } 66 | IRAM_ATTR bool read(void* dst, size_t size) 67 | { 68 | if (m_size < size) 69 | return false; 70 | 71 | if (m_start + size <= m_capacity) //no wrap around 72 | { 73 | memcpy(dst, m_data + m_start, size); 74 | m_start = (m_start + size) % m_capacity; 75 | m_size -= size; 76 | return true; 77 | } 78 | 79 | //wrap around, 2 steps 80 | size_t first = m_capacity - m_start; 81 | memcpy(dst, m_data + m_start, first); 82 | memcpy((uint8_t*)dst + first, m_data, size - (first)); 83 | m_start = (m_start + size) % m_capacity; 84 | m_size -= size; 85 | return true; 86 | } 87 | IRAM_ATTR const void* start_reading(size_t& size) 88 | { 89 | if (m_size == 0) 90 | { 91 | size = 0; 92 | return nullptr; 93 | } 94 | 95 | if (size > m_size) //clamp to the actual size 96 | size = m_size; 97 | 98 | if (m_start + size > m_capacity) //wrap around 99 | size = m_capacity - m_start; 100 | 101 | return m_data + m_start; 102 | } 103 | IRAM_ATTR void end_reading(size_t size) //call with the same size as the one returned by start_reading 104 | { 105 | if (size == 0) 106 | return; 107 | 108 | assert(size <= m_size); 109 | 110 | m_start = (m_start + size) % m_capacity; 111 | m_size -= size; 112 | } 113 | IRAM_ATTR void clear() 114 | { 115 | m_start = 0; 116 | m_size = 0; 117 | } 118 | 119 | private: 120 | uint8_t* m_data; 121 | size_t m_capacity; 122 | size_t m_start = 0; 123 | size_t m_size = 0; 124 | }; 125 | -------------------------------------------------------------------------------- /components/common/component.mk: -------------------------------------------------------------------------------- 1 | 2 | COMPONENT_SRCDIRS := . 3 | COMPONENT_ADD_INCLUDEDIRS := . 4 | 5 | -------------------------------------------------------------------------------- /components/common/crc.cpp: -------------------------------------------------------------------------------- 1 | #include "crc.h" 2 | 3 | static uint8_t s_crc8_table[256]; /* 8-bit table */ 4 | void init_crc8_table() 5 | { 6 | static constexpr uint8_t DI = 0x07; 7 | for (uint16_t i = 0; i < 256; i++) 8 | { 9 | uint8_t crc = (uint8_t)i; 10 | for (uint8_t j = 0; j < 8; j++) 11 | crc = (crc << 1) ^ ((crc & 0x80) ? DI : 0); 12 | s_crc8_table[i] = crc & 0xFF; 13 | } 14 | } 15 | 16 | IRAM_ATTR uint8_t crc8(uint8_t crc, const void *c_ptr, size_t len) 17 | { 18 | const uint8_t *c = reinterpret_cast(c_ptr); 19 | size_t n = (len + 7) >> 3; 20 | switch (len & 7) 21 | { 22 | case 0: 23 | do 24 | { 25 | crc = s_crc8_table[crc ^ (*c++)]; 26 | case 7: 27 | crc = s_crc8_table[crc ^ (*c++)]; 28 | case 6: 29 | crc = s_crc8_table[crc ^ (*c++)]; 30 | case 5: 31 | crc = s_crc8_table[crc ^ (*c++)]; 32 | case 4: 33 | crc = s_crc8_table[crc ^ (*c++)]; 34 | case 3: 35 | crc = s_crc8_table[crc ^ (*c++)]; 36 | case 2: 37 | crc = s_crc8_table[crc ^ (*c++)]; 38 | case 1: 39 | crc = s_crc8_table[crc ^ (*c++)]; 40 | } while (--n > 0); 41 | } 42 | return crc; 43 | } -------------------------------------------------------------------------------- /components/common/crc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #ifdef ESP_PLATFORM 7 | # include "esp_task_wdt.h" 8 | #else 9 | # define IRAM_ATTR 10 | #endif 11 | 12 | void init_crc8_table(); 13 | IRAM_ATTR uint8_t crc8(uint8_t crc, const void *c_ptr, size_t len); 14 | -------------------------------------------------------------------------------- /components/common/fec.h: -------------------------------------------------------------------------------- 1 | /** 2 | * zfec -- fast forward error correction library with Python interface 3 | * 4 | * See README.rst for documentation. 5 | */ 6 | 7 | #include 8 | 9 | typedef unsigned char gf; 10 | 11 | struct fec_t { 12 | unsigned long magic; 13 | unsigned short k, n; /* parameters of the code */ 14 | gf* enc_matrix; 15 | }; 16 | 17 | #if defined(_MSC_VER) 18 | // actually, some of the flavors (i.e. Enterprise) do support restrict 19 | #define restrict 20 | #endif 21 | #define restrict __restrict 22 | 23 | void init_fec (void); 24 | 25 | /** 26 | * param k the number of blocks required to reconstruct 27 | * param m the total number of blocks created 28 | */ 29 | fec_t* fec_new(unsigned short k, unsigned short m); 30 | void fec_free(fec_t* p); 31 | 32 | /** 33 | * @param inpkts the "primary blocks" i.e. the chunks of the input data 34 | * @param fecs buffers into which the secondary blocks will be written 35 | * @param block_nums the numbers of the desired check blocks (the id >= k) which fec_encode() will produce and store into the buffers of the fecs parameter 36 | * @param num_block_nums the length of the block_nums array 37 | * @param sz size of a packet in bytes 38 | */ 39 | void fec_encode(const fec_t* code, const gf*restrict const*restrict const src, gf*restrict const*restrict const fecs, const unsigned*restrict const block_nums, size_t num_block_nums, size_t sz); 40 | 41 | /** 42 | * @param inpkts an array of packets (size k); If a primary block, i, is present then it must be at index i. Secondary blocks can appear anywhere. 43 | * @param outpkts an array of buffers into which the reconstructed output packets will be written (only packets which are not present in the inpkts input will be reconstructed and written to outpkts) 44 | * @param index an array of the blocknums of the packets in inpkts 45 | * @param sz size of a packet in bytes 46 | */ 47 | void fec_decode(const fec_t* code, const gf*restrict const*restrict const inpkts, gf*restrict const*restrict const outpkts, const unsigned*restrict const index, size_t sz); 48 | 49 | #if defined(_MSC_VER) 50 | #define alloca _alloca 51 | #else 52 | #ifdef __GNUC__ 53 | #ifndef alloca 54 | #define alloca(x) __builtin_alloca(x) 55 | #endif 56 | #else 57 | #include 58 | #endif 59 | #endif 60 | 61 | /** 62 | * zfec -- fast forward error correction library with Python interface 63 | * 64 | * Copyright (C) 2007-2008 Allmydata, Inc. 65 | * Author: Zooko Wilcox-O'Hearn 66 | * 67 | * This file is part of zfec. 68 | * 69 | * See README.rst for licensing information. 70 | */ 71 | 72 | /* 73 | * Much of this work is derived from the "fec" software by Luigi Rizzo, et 74 | * al., the copyright notice and licence terms of which are included below 75 | * for reference. 76 | * 77 | * fec.h -- forward error correction based on Vandermonde matrices 78 | * 980614 79 | * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it) 80 | * 81 | * Portions derived from code by Phil Karn (karn@ka9q.ampr.org), 82 | * Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari 83 | * Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995 84 | * 85 | * Modifications by Dan Rubenstein (see Modifications.txt for 86 | * their description. 87 | * Modifications (C) 1998 Dan Rubenstein (drubenst@cs.umass.edu) 88 | * 89 | * Redistribution and use in source and binary forms, with or without 90 | * modification, are permitted provided that the following conditions 91 | * are met: 92 | 93 | * 1. Redistributions of source code must retain the above copyright 94 | * notice, this list of conditions and the following disclaimer. 95 | * 2. Redistributions in binary form must reproduce the above 96 | * copyright notice, this list of conditions and the following 97 | * disclaimer in the documentation and/or other materials 98 | * provided with the distribution. 99 | * 100 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND 101 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 102 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 103 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 104 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 105 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 106 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 107 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 108 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 109 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 110 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 111 | * OF SUCH DAMAGE. 112 | */ 113 | -------------------------------------------------------------------------------- /components/common/fec_codec.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "freertos/FreeRTOS.h" 9 | #include "freertos/queue.h" 10 | #include "freertos/task.h" 11 | #include "freertos/semphr.h" 12 | #include "fec.h" 13 | 14 | class Fec_Codec 15 | { 16 | public: 17 | Fec_Codec(); 18 | 19 | static const uint8_t MAX_CODING_K = 16; 20 | static const uint8_t MAX_CODING_N = 32; 21 | static const size_t PACKET_OVERHEAD = 6; 22 | 23 | enum class Core 24 | { 25 | Any, 26 | Core_0, 27 | Core_1 28 | }; 29 | 30 | struct Descriptor 31 | { 32 | uint8_t coding_k = 2; 33 | uint8_t coding_n = 4; 34 | size_t mtu = 512; 35 | Core core = Core::Any; 36 | uint8_t priority = configMAX_PRIORITIES - 1; 37 | }; 38 | 39 | bool init_encoder(const Descriptor& descriptor); 40 | bool init_decoder(const Descriptor& descriptor); 41 | IRAM_ATTR bool is_initialized() const; 42 | 43 | const Descriptor& get_descriptor() const; 44 | bool is_encoder() const; 45 | 46 | //Callback for when an encoded packet is available 47 | //NOTE: this is called form another thread!!! 48 | void set_data_encoded_cb(void (*cb)(void* data, size_t size)); 49 | 50 | //Add here data that will be encoded. 51 | //Size dosn't have to be a full packet. Can be anything > 0, even bigger than a packet 52 | //NOTE: This has to be called from a single thread only (any thread, as long as it's just one) 53 | IRAM_ATTR bool encode_data(const void* data, size_t size, bool block); 54 | IRAM_ATTR bool flush_encode_packet(bool block); 55 | IRAM_ATTR uint8_t* get_encode_packet_data(bool block); 56 | IRAM_ATTR bool is_encode_packet_empty(); 57 | 58 | //Callback for when a decoded packet is ready. 59 | //NOTE: this is called form another thread!!! 60 | void set_data_decoded_cb(void (*cb)(void* data, size_t size)); 61 | 62 | //Add here data that will be decoded. 63 | //Size dosn't have to be a full packet. Can be anything > 0, even bigger than a packet 64 | //NOTE: This has to be called from a single thread only (any thread, as long as it's just one) 65 | IRAM_ATTR bool decode_data(const void* data, size_t size, bool block); 66 | 67 | private: 68 | bool init(const Descriptor& descriptor, bool is_encoder); 69 | void stop_tasks(); 70 | bool start_tasks(); 71 | 72 | void encoder_task_proc(); 73 | void decoder_task_proc(); 74 | static void static_encoder_task_proc(void* params); 75 | static void static_decoder_task_proc(void* params); 76 | 77 | Descriptor m_descriptor; 78 | 79 | size_t m_encoder_pool_size = 0; 80 | size_t m_decoder_pool_size = 0; 81 | 82 | size_t m_encoded_packet_size = 0; 83 | 84 | fec_t* m_fec = nullptr; 85 | bool m_is_encoder = false; 86 | 87 | struct Encoder 88 | { 89 | struct Packet 90 | { 91 | uint32_t size = 0; 92 | uint8_t* data = nullptr; 93 | }; 94 | QueueHandle_t packet_queue = nullptr; 95 | QueueHandle_t packet_pool = nullptr; 96 | TaskHandle_t task = nullptr; 97 | 98 | uint32_t last_block_index = 0; 99 | 100 | std::vector block_packets; 101 | std::vector block_fec_packets; //these are owned by the array 102 | 103 | std::vector fec_src_ptrs; 104 | std::vector fec_dst_ptrs; 105 | 106 | std::vector packet_pool_owned; 107 | 108 | Packet crt_packet; 109 | 110 | void (*cb)(void* data, size_t size); 111 | } m_encoder; 112 | 113 | void seal_packet(Encoder::Packet& packet, uint32_t block_index, uint8_t packet_index); 114 | 115 | struct Decoder 116 | { 117 | struct Packet 118 | { 119 | bool received_header = false; 120 | bool is_processed = false; 121 | uint32_t size = 0; 122 | uint32_t block_index = 0; 123 | uint32_t packet_index = 0; 124 | uint8_t* data = nullptr; 125 | }; 126 | QueueHandle_t packet_queue = nullptr; 127 | QueueHandle_t packet_pool = nullptr; 128 | TaskHandle_t task = nullptr; 129 | 130 | uint32_t crt_block_index = 0; 131 | std::vector block_packets; 132 | std::vector block_fec_packets; 133 | 134 | std::vector fec_src_ptrs; 135 | std::vector fec_dst_ptrs; 136 | 137 | std::vector fec_decoded_packets; 138 | std::vector packet_pool_owned; 139 | 140 | Packet crt_packet; 141 | 142 | void (*cb)(void* data, size_t size); 143 | } m_decoder; 144 | 145 | Encoder::Packet* pop_encoder_packet_from_pool(); 146 | void push_encoder_packet_to_pool(Encoder::Packet* packet); 147 | Decoder::Packet* pop_decoder_packet_from_pool(); 148 | void push_decoder_packet_to_pool(Decoder::Packet* packet); 149 | }; 150 | -------------------------------------------------------------------------------- /components/common/packets.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "structures.h" 4 | 5 | #pragma pack(push, 1) // exact fit - no padding 6 | 7 | enum class WIFI_Rate : uint8_t 8 | { 9 | /* 0 */ RATE_B_2M_CCK, 10 | /* 1 */ RATE_B_2M_CCK_S, 11 | /* 2 */ RATE_B_5_5M_CCK, 12 | /* 3 */ RATE_B_5_5M_CCK_S, 13 | /* 4 */ RATE_B_11M_CCK, 14 | /* 5 */ RATE_B_11M_CCK_S, 15 | 16 | /* 6 */ RATE_G_6M_ODFM, 17 | /* 7 */ RATE_G_9M_ODFM, 18 | /* 8 */ RATE_G_12M_ODFM, 19 | /* 9 */ RATE_G_18M_ODFM, 20 | /* 10 */ RATE_G_24M_ODFM, 21 | /* 11 */ RATE_G_36M_ODFM, 22 | /* 12 */ RATE_G_48M_ODFM, 23 | /* 13 */ RATE_G_54M_ODFM, 24 | 25 | /* 14 */ RATE_N_6_5M_MCS0, 26 | /* 15 */ RATE_N_7_2M_MCS0_S, 27 | /* 16 */ RATE_N_13M_MCS1, 28 | /* 17 */ RATE_N_14_4M_MCS1_S, 29 | /* 18 */ RATE_N_19_5M_MCS2, 30 | /* 19 */ RATE_N_21_7M_MCS2_S, 31 | /* 20 */ RATE_N_26M_MCS3, 32 | /* 21 */ RATE_N_28_9M_MCS3_S, 33 | /* 22 */ RATE_N_39M_MCS4, 34 | /* 23 */ RATE_N_43_3M_MCS4_S, 35 | /* 24 */ RATE_N_52M_MCS5, 36 | /* 25 */ RATE_N_57_8M_MCS5_S, 37 | /* 26 */ RATE_N_58M_MCS6, 38 | /* 27 */ RATE_N_65M_MCS6_S, 39 | /* 28 */ RATE_N_65M_MCS7, 40 | /* 29 */ RATE_N_72M_MCS7_S, 41 | }; 42 | 43 | static constexpr size_t AIR2GROUND_MTU = WLAN_MAX_PAYLOAD_SIZE - 6; //6 is the fec header size 44 | 45 | /////////////////////////////////////////////////////////////////////////////////////// 46 | 47 | constexpr size_t GROUND2AIR_DATA_MAX_SIZE = 64; 48 | 49 | struct Ground2Air_Header 50 | { 51 | enum class Type : uint8_t 52 | { 53 | Data, 54 | Config, 55 | }; 56 | 57 | Type type = Type::Data; 58 | uint32_t size = 0; 59 | uint8_t crc = 0; 60 | }; 61 | 62 | struct Ground2Air_Data_Packet : Ground2Air_Header 63 | { 64 | }; 65 | static_assert(sizeof(Ground2Air_Data_Packet) <= GROUND2AIR_DATA_MAX_SIZE, ""); 66 | 67 | enum class Resolution : uint8_t 68 | { 69 | QVGA, //320x240 70 | CIF, //400x296 71 | HVGA, //480x320 72 | VGA, //640x480 73 | SVGA, //800x600 74 | XGA, //1024x768 75 | SXGA, //1280x1024 76 | UXGA, //1600x1200 77 | }; 78 | 79 | struct Ground2Air_Config_Packet : Ground2Air_Header 80 | { 81 | uint8_t ping = 0; //used for latency measurement 82 | int8_t wifi_power = 20;//dBm 83 | WIFI_Rate wifi_rate = WIFI_Rate::RATE_G_18M_ODFM; 84 | uint8_t fec_codec_k = 2; 85 | uint8_t fec_codec_n = 3; 86 | uint16_t fec_codec_mtu = AIR2GROUND_MTU; 87 | bool dvr_record = false; 88 | 89 | struct Camera 90 | { 91 | Resolution resolution = Resolution::VGA; 92 | uint8_t fps_limit = 30; 93 | uint8_t quality = 8;//0 - 63 94 | int8_t brightness = 0;//-2 - 2 95 | int8_t contrast = 0;//-2 - 2 96 | int8_t saturation = 0;//-2 - 2 97 | int8_t sharpness = -1;//-1 - 6 98 | uint8_t denoise = 0; 99 | uint8_t special_effect = 0;//0 - 6 100 | bool awb = true; 101 | bool awb_gain = true; 102 | uint8_t wb_mode = 0;//0 - 4 103 | bool aec = true; 104 | bool aec2 = true; 105 | int8_t ae_level = 0;//-2 - 2 106 | uint16_t aec_value = 0;//0 - 1200 107 | bool agc = true; 108 | uint8_t agc_gain = 0;//0 - 30 109 | uint8_t gainceiling = 0;//0 - 6 110 | bool bpc = true; 111 | bool wpc = true; 112 | bool raw_gma = false; 113 | bool lenc = true; 114 | bool hmirror = false; 115 | bool vflip = false; 116 | bool dcw = true; 117 | }; 118 | Camera camera; 119 | }; 120 | static_assert(sizeof(Ground2Air_Config_Packet) <= GROUND2AIR_DATA_MAX_SIZE, ""); 121 | 122 | /////////////////////////////////////////////////////////////////////////////////////// 123 | 124 | struct Air2Ground_Header 125 | { 126 | enum class Type : uint8_t 127 | { 128 | Video, 129 | Telemetry 130 | }; 131 | 132 | Type type = Type::Video; 133 | uint32_t size = 0; 134 | uint8_t pong = 0; //used for latency measurement 135 | uint8_t crc = 0; 136 | }; 137 | 138 | struct Air2Ground_Video_Packet : Air2Ground_Header 139 | { 140 | Resolution resolution; 141 | uint8_t part_index : 7; 142 | uint8_t last_part : 1; 143 | uint32_t frame_index = 0; 144 | //data follows 145 | }; 146 | 147 | static_assert(sizeof(Air2Ground_Video_Packet) == 13, ""); 148 | 149 | /////////////////////////////////////////////////////////////////////////////////////// 150 | 151 | #pragma pack(pop) 152 | 153 | -------------------------------------------------------------------------------- /components/common/safe_printf.cpp: -------------------------------------------------------------------------------- 1 | #include "safe_printf.h" 2 | 3 | SemaphoreHandle_t s_safe_printf_mux = xSemaphoreCreateBinary(); 4 | 5 | static auto _init_result = []() -> bool 6 | { 7 | xSemaphoreGive(s_safe_printf_mux); 8 | return true; 9 | }(); 10 | 11 | 12 | -------------------------------------------------------------------------------- /components/common/safe_printf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "freertos/FreeRTOS.h" 6 | #include "freertos/queue.h" 7 | #include "freertos/task.h" 8 | #include "freertos/semphr.h" 9 | 10 | extern SemaphoreHandle_t s_safe_printf_mux; 11 | 12 | #define SAFE_PRINTF(...) \ 13 | do { xSemaphoreTake(s_safe_printf_mux, portMAX_DELAY); \ 14 | ets_printf(__VA_ARGS__); \ 15 | xSemaphoreGive(s_safe_printf_mux); \ 16 | } while (false) 17 | 18 | -------------------------------------------------------------------------------- /components/common/structures.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeanlemotan/esp32-cam-fpv/adc1e5c040bada4780de0db60716af411d326435/components/common/structures.cpp -------------------------------------------------------------------------------- /components/common/structures.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | constexpr uint8_t WLAN_IEEE_HEADER_AIR2GROUND[] = 8 | { 9 | 0x08, 0x01, 0x00, 0x00, 10 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 11 | 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 12 | 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 13 | 0x10, 0x86 14 | }; 15 | constexpr uint8_t WLAN_IEEE_HEADER_GROUND2AIR[] = 16 | { 17 | 0x08, 0x01, 0x00, 0x00, 18 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 19 | 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 20 | 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 21 | 0x10, 0x86 22 | }; 23 | 24 | constexpr size_t WLAN_IEEE_HEADER_SIZE = sizeof(WLAN_IEEE_HEADER_AIR2GROUND); 25 | constexpr size_t WLAN_MAX_PACKET_SIZE = 1500; 26 | constexpr size_t WLAN_MAX_PAYLOAD_SIZE = WLAN_MAX_PACKET_SIZE - WLAN_IEEE_HEADER_SIZE; 27 | 28 | static_assert(WLAN_IEEE_HEADER_SIZE == 24, ""); 29 | 30 | struct Wlan_Outgoing_Packet 31 | { 32 | uint8_t* ptr = nullptr; 33 | uint8_t* payload_ptr = nullptr; 34 | uint16_t size = 0; 35 | uint16_t offset = 0; 36 | }; 37 | 38 | struct Wlan_Incoming_Packet 39 | { 40 | uint8_t* ptr = nullptr; 41 | uint16_t size = 0; 42 | uint16_t offset = 0; 43 | }; 44 | 45 | //////////////////////////////////////////////////////////////////////////////////// 46 | 47 | 48 | -------------------------------------------------------------------------------- /gs/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "chrono": "cpp", 4 | "array": "cpp", 5 | "iterator": "cpp", 6 | "string": "cpp", 7 | "string_view": "cpp", 8 | "vector": "cpp", 9 | "filesystem": "cpp", 10 | "__locale": "cpp", 11 | "ios": "cpp", 12 | "__bit_reference": "cpp", 13 | "__config": "cpp", 14 | "__debug": "cpp", 15 | "__errc": "cpp", 16 | "__functional_base": "cpp", 17 | "__hash_table": "cpp", 18 | "__mutex_base": "cpp", 19 | "__node_handle": "cpp", 20 | "__nullptr": "cpp", 21 | "__split_buffer": "cpp", 22 | "__string": "cpp", 23 | "__threading_support": "cpp", 24 | "__tuple": "cpp", 25 | "algorithm": "cpp", 26 | "atomic": "cpp", 27 | "bit": "cpp", 28 | "bitset": "cpp", 29 | "cctype": "cpp", 30 | "clocale": "cpp", 31 | "cmath": "cpp", 32 | "complex": "cpp", 33 | "cstdarg": "cpp", 34 | "cstddef": "cpp", 35 | "cstdint": "cpp", 36 | "cstdio": "cpp", 37 | "cstdlib": "cpp", 38 | "cstring": "cpp", 39 | "ctime": "cpp", 40 | "cwchar": "cpp", 41 | "cwctype": "cpp", 42 | "deque": "cpp", 43 | "exception": "cpp", 44 | "fstream": "cpp", 45 | "functional": "cpp", 46 | "future": "cpp", 47 | "initializer_list": "cpp", 48 | "iomanip": "cpp", 49 | "iosfwd": "cpp", 50 | "iostream": "cpp", 51 | "istream": "cpp", 52 | "limits": "cpp", 53 | "locale": "cpp", 54 | "memory": "cpp", 55 | "mutex": "cpp", 56 | "new": "cpp", 57 | "optional": "cpp", 58 | "ostream": "cpp", 59 | "ratio": "cpp", 60 | "sstream": "cpp", 61 | "stack": "cpp", 62 | "stdexcept": "cpp", 63 | "streambuf": "cpp", 64 | "system_error": "cpp", 65 | "thread": "cpp", 66 | "tuple": "cpp", 67 | "type_traits": "cpp", 68 | "typeinfo": "cpp", 69 | "unordered_map": "cpp", 70 | "utility": "cpp", 71 | "__tree": "cpp", 72 | "map": "cpp", 73 | "set": "cpp", 74 | "condition_variable": "cpp" 75 | } 76 | } -------------------------------------------------------------------------------- /gs/Makefile: -------------------------------------------------------------------------------- 1 | # output binary 2 | BIN := gs 3 | 4 | SRCS := src/main.cpp \ 5 | src/droid_sans_font.cpp \ 6 | src/HUD.cpp \ 7 | src/imgui_impl_opengl3.cpp \ 8 | src/PI_HAL.cpp \ 9 | src/Comms.cpp \ 10 | src/Video_Decoder.cpp \ 11 | src/utils/radiotap/radiotap.cpp \ 12 | src/imgui/imgui_impl_sdl.cpp \ 13 | src/imgui/imgui_demo.cpp \ 14 | src/imgui/imgui_draw.cpp \ 15 | src/imgui/imgui.cpp \ 16 | src/imgui/misc/freetype/imgui_freetype.cpp \ 17 | ../components/common/crc.cpp \ 18 | ../components/common/fec.cpp \ 19 | src/fmt/format.cc \ 20 | src/fmt/os.cc \ 21 | 22 | # files included in the tarball generated by 'make dist' (e.g. add LICENSE file) 23 | DISTFILES := $(BIN) 24 | 25 | # filename of the tar archive generated by 'make dist' 26 | DISTOUTPUT := $(BIN).tar.gz 27 | 28 | # intermediate directory for generated object files 29 | OBJDIR := .o 30 | # intermediate directory for generated dependency files 31 | DEPDIR := .d 32 | 33 | # object files, auto generated from source files 34 | OBJS := $(patsubst %,$(OBJDIR)/%.o,$(basename $(SRCS))) 35 | # dependency files, auto generated from source files 36 | DEPS := $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRCS))) 37 | 38 | # compilers (at least gcc and clang) don't create the subdirectories automatically 39 | $(shell mkdir -p $(dir $(OBJS)) >/dev/null) 40 | $(shell mkdir -p $(dir $(DEPS)) >/dev/null) 41 | 42 | # C compiler 43 | CC := gcc 44 | # C++ compiler 45 | CXX := g++ 46 | # linker 47 | LD := g++ 48 | # tar 49 | TAR := tar 50 | 51 | ifeq ($(shell arch), aarch64) 52 | INCLUDE := -Isrc \ 53 | -Isrc/utils \ 54 | -Isrc/imgui \ 55 | -I../components/common \ 56 | -I/opt/vc/include/ \ 57 | -I/usr/include/freetype2 58 | else 59 | INCLUDE := -Isrc \ 60 | -Isrc/utils \ 61 | -Isrc/imgui \ 62 | -I../components/common \ 63 | -I/usr/include/ \ 64 | -I/usr/include/freetype2 65 | endif 66 | 67 | # C flags 68 | CFLAGS := -std=c11 69 | 70 | # C++ flags 71 | CXXFLAGS := -std=c++17 72 | # C/C++ flags 73 | is_pi = 74 | ifeq ($(shell arch), aarch64) 75 | is_pi = yes 76 | endif 77 | ifeq ($(shell arch), armv7l) 78 | is_pi = yes 79 | endif 80 | 81 | ifdef is_pi 82 | CPPFLAGS := -O3 -DNDEBUG -ffast-math -funroll-loops -mcpu=cortex-a8 -mfpu=neon -Wall -DRASPBERRY_PI $(INCLUDE) 83 | else 84 | CPPFLAGS := -O3 -DNDEBUG -ffast-math -funroll-loops -Wall $(INCLUDE) 85 | endif 86 | #CPPFLAGS := -g -Wall -DRASPBERRY_PI $(INCLUDE) 87 | 88 | # linker flags 89 | #LDFLAGS := -L/usr/lib -L=/opt/vc/lib -lstdc++ -lm -lpthread -lz -lrt -lfreetype -lmmal_core -lmmal_util -lmmal_vc_client -lvcos -lbcm_host -lbrcmGLESv2 -lbrcmEGL -lts 90 | #LDFLAGS := -L/usr/lib -L=/opt/vc/lib -lstdc++ -lm -lpthread -lz -lrt -lfreetype -lSDL2 -lGLESv2 -lturbojpeg -lmmal_core -lmmal_util -lmmal_vc_client -lvcos -lepoxy 91 | ifdef is_pi 92 | LDFLAGS := -L/usr/lib -L=/opt/vc/lib -lstdc++ -lm -lpthread -lz -lrt -lfreetype -lSDL2 -lturbojpeg -lpcap -lGLESv2 -lpigpio 93 | else 94 | LDFLAGS := -L/usr/lib 95 | LDLIBS := -std=c++17 -pthread -lGLESv2 -lSDL2 -lfreetype -lpcap -lturbojpeg 96 | endif 97 | 98 | # flags required for dependency generation; passed to compilers 99 | DEPFLAGS = -MT $@ -MD -MP -MF $(DEPDIR)/$*.Td 100 | 101 | # compile C source files 102 | COMPILE.c = $(CC) $(DEPFLAGS) $(CFLAGS) $(CPPFLAGS) -c -o $@ 103 | # compile C++ source files 104 | COMPILE.cc = $(CXX) $(DEPFLAGS) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ 105 | # link object files to binary 106 | ifdef is_pi 107 | LINK.o = $(LD) $(LDFLAGS) $(LDLIBS) -o $@ 108 | else 109 | LINK.o = $(LD) $(LDFLAGS) -o $@ 110 | endif 111 | 112 | # precompile step 113 | PRECOMPILE = 114 | # postcompile step 115 | POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d 116 | 117 | all: $(BIN) 118 | 119 | dist: $(DISTFILES) 120 | $(TAR) -cvzf $(DISTOUTPUT) $^ 121 | 122 | .PHONY: clean 123 | clean: 124 | $(RM) -r $(OBJDIR) $(DEPDIR) 125 | 126 | .PHONY: distclean 127 | distclean: clean 128 | $(RM) $(BIN) $(DISTOUTPUT) 129 | 130 | .PHONY: install 131 | install: 132 | @echo no install tasks configured 133 | 134 | .PHONY: uninstall 135 | uninstall: 136 | @echo no uninstall tasks configured 137 | 138 | .PHONY: check 139 | check: 140 | @echo no tests configured 141 | 142 | .PHONY: help 143 | help: 144 | @echo available targets: all dist clean distclean install uninstall check 145 | 146 | $(BIN): $(OBJS) 147 | ifeq ($(shell arch), aarch64) 148 | $(LINK.o) $^ 149 | else 150 | $(LINK.o) $^ $(LDLIBS) 151 | endif 152 | 153 | $(OBJDIR)/%.o: %.c 154 | $(OBJDIR)/%.o: %.c $(DEPDIR)/%.d 155 | $(PRECOMPILE) 156 | $(COMPILE.c) $< 157 | $(POSTCOMPILE) 158 | 159 | $(OBJDIR)/%.o: %.cpp 160 | $(OBJDIR)/%.o: %.cpp $(DEPDIR)/%.d 161 | $(PRECOMPILE) 162 | $(COMPILE.cc) $< 163 | $(POSTCOMPILE) 164 | 165 | $(OBJDIR)/%.o: %.cc 166 | $(OBJDIR)/%.o: %.cc $(DEPDIR)/%.d 167 | $(PRECOMPILE) 168 | $(COMPILE.cc) $< 169 | $(POSTCOMPILE) 170 | 171 | $(OBJDIR)/%.o: %.cxx 172 | $(OBJDIR)/%.o: %.cxx $(DEPDIR)/%.d 173 | $(PRECOMPILE) 174 | $(COMPILE.cc) $< 175 | $(POSTCOMPILE) 176 | 177 | .PRECIOUS = $(DEPDIR)/%.d 178 | $(DEPDIR)/%.d: ; 179 | 180 | -include $(DEPS) 181 | -------------------------------------------------------------------------------- /gs/src/Clock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef std::chrono::steady_clock Clock; 6 | -------------------------------------------------------------------------------- /gs/src/Comms.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "Clock.h" 9 | 10 | struct fec_t; 11 | 12 | class Comms 13 | { 14 | public: 15 | Comms(); 16 | ~Comms(); 17 | 18 | struct TX_Descriptor 19 | { 20 | std::string interface; 21 | uint32_t coding_k = 12; 22 | uint32_t coding_n = 20; 23 | size_t mtu = 1200; 24 | }; 25 | 26 | struct RX_Descriptor 27 | { 28 | std::vector interfaces; 29 | Clock::duration max_latency = std::chrono::milliseconds(500); 30 | Clock::duration reset_duration = std::chrono::milliseconds(1000); 31 | uint32_t coding_k = 12; 32 | uint32_t coding_n = 20; 33 | size_t mtu = 1200; 34 | }; 35 | 36 | bool init(RX_Descriptor const& rx_descriptor, TX_Descriptor const& tx_descriptor); 37 | 38 | void process(); 39 | 40 | void send(void const* data, size_t size, bool flush); 41 | //std::function on_data_received; 42 | bool receive(void* data, size_t& size); 43 | 44 | size_t get_data_rate() const; 45 | int get_input_dBm() const; 46 | 47 | static std::vector enumerate_interfaces(); 48 | 49 | struct PCap; 50 | struct RX; 51 | struct TX; 52 | 53 | private: 54 | bool prepare_pcap(std::string const& interface, PCap& pcap); 55 | 56 | bool prepare_filter(PCap& pcap); 57 | void prepare_radiotap_header(size_t rate_hz); 58 | void prepare_tx_packet_header(uint8_t* buffer); 59 | bool process_rx_packet(PCap& pcap); 60 | void process_rx_packets(); 61 | 62 | void tx_thread_proc(); 63 | void rx_thread_proc(size_t index); 64 | 65 | TX_Descriptor m_tx_descriptor; 66 | RX_Descriptor m_rx_descriptor; 67 | 68 | struct Impl; 69 | std::unique_ptr m_impl; 70 | bool m_exit = false; 71 | 72 | size_t m_packet_header_offset = 0; 73 | size_t m_payload_offset = 0; 74 | 75 | std::atomic_int m_best_input_dBm = {0}; 76 | std::atomic_int m_latched_input_dBm = {0}; 77 | 78 | size_t m_data_stats_rate = 0; 79 | size_t m_data_stats_data_accumulated = 0; 80 | Clock::time_point m_data_stats_last_tp = Clock::now(); 81 | }; 82 | -------------------------------------------------------------------------------- /gs/src/HUD.cpp: -------------------------------------------------------------------------------- 1 | #include "HUD.h" 2 | #include "IHAL.h" 3 | #include "imgui.h" 4 | 5 | static void AddShadowText(ImDrawList& drawList, const ImVec2& pos, ImU32 col, const char* text) 6 | { 7 | drawList.AddText(ImVec2(pos.x + 1.f, pos.y + 1.f), ImColor(0.f, 0.f, 0.f, ImColor(col).Value.w), text); 8 | drawList.AddText(pos, col, text); 9 | } 10 | 11 | HUD::HUD(IHAL& hal) 12 | : m_hal(hal) 13 | { 14 | 15 | } 16 | 17 | /////////////////////////////////////////////////////////////////////////////////////////////////// 18 | 19 | void HUD::draw() 20 | { 21 | ImVec2 display_size(m_hal.get_display_size()); 22 | ImGui::SetNextWindowPos(ImVec2(0, 0)); 23 | ImGui::SetNextWindowSize(ImVec2(display_size.x, display_size.y)); 24 | ImGui::SetNextWindowBgAlpha(0); 25 | ImGui::Begin("HUD", nullptr, ImGuiWindowFlags_NoTitleBar | 26 | ImGuiWindowFlags_NoResize | 27 | ImGuiWindowFlags_NoMove | 28 | ImGuiWindowFlags_NoScrollbar | 29 | ImGuiWindowFlags_NoInputs); 30 | 31 | ImGui::End(); 32 | } 33 | -------------------------------------------------------------------------------- /gs/src/HUD.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class IHAL; 4 | 5 | class HUD 6 | { 7 | public: 8 | HUD(IHAL& hal); 9 | 10 | void draw(); 11 | 12 | private: 13 | 14 | IHAL& m_hal; 15 | }; 16 | 17 | -------------------------------------------------------------------------------- /gs/src/IHAL.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "imgui.h" 4 | 5 | class IHAL 6 | { 7 | public: 8 | virtual ~IHAL() = default; 9 | 10 | virtual bool init() = 0; 11 | virtual void shutdown() = 0; 12 | 13 | virtual void* get_window() = 0; 14 | virtual void* get_main_context() = 0; 15 | virtual void* lock_main_context() = 0; 16 | virtual void unlock_main_context() = 0; 17 | 18 | virtual ImVec2 get_display_size() const = 0; 19 | virtual void set_backlight(float brightness) = 0; //0..1 20 | 21 | virtual bool process() = 0; 22 | }; 23 | -------------------------------------------------------------------------------- /gs/src/Log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "fmt/format.h" 5 | 6 | enum class LogLevel : uint8_t 7 | { 8 | DBG, //used to debug info. Disabled in Release 9 | INFO, //used to print usefull info both in Debug and Release 10 | WARNING, //used to print warnings that will not crash, both Debug and Release 11 | ERR //used for messages that will probably crash or seriously affect the game. Both Debug and Release 12 | }; 13 | 14 | template 15 | void logf(LogLevel level, char const* file, int line, Fmt const& fmt, Params&&... params) 16 | { 17 | const char* levelStr = ""; 18 | switch (level) 19 | { 20 | case LogLevel::DBG: levelStr = "D"; break; 21 | case LogLevel::INFO: levelStr = "I"; break; 22 | case LogLevel::WARNING: levelStr = "W"; break; 23 | case LogLevel::ERR: levelStr = "E"; break; 24 | } 25 | printf("(%s) %s: %d: %s\n", levelStr, file, line, fmt::format(fmt, std::forward(params)...).c_str()); 26 | } 27 | 28 | #define LOGD(fmt, ...) logf(LogLevel::DBG, __FILE__, __LINE__, fmt, ##__VA_ARGS__) 29 | #define LOGI(fmt, ...) logf(LogLevel::INFO, __FILE__, __LINE__, fmt, ##__VA_ARGS__) 30 | #define LOGW(fmt, ...) logf(LogLevel::WARNING, __FILE__, __LINE__, fmt, ##__VA_ARGS__) 31 | #define LOGE(fmt, ...) logf(LogLevel::ERR, __FILE__, __LINE__, fmt, ##__VA_ARGS__) -------------------------------------------------------------------------------- /gs/src/PI_HAL.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IHAL.h" 4 | #include 5 | 6 | class PI_HAL : virtual public IHAL 7 | { 8 | public: 9 | PI_HAL(); 10 | ~PI_HAL(); 11 | 12 | bool init() override; 13 | void shutdown() override; 14 | 15 | void* get_window() override; 16 | void* get_main_context() override; 17 | void* lock_main_context() override; 18 | void unlock_main_context() override; 19 | 20 | ImVec2 get_display_size() const override; 21 | void set_backlight(float brightness) override; //0..1 22 | 23 | bool process() override; 24 | 25 | private: 26 | struct Impl; 27 | std::unique_ptr m_impl; 28 | 29 | bool init_pigpio(); 30 | void shutdown_pigpio(); 31 | 32 | bool init_display_dispmanx(); 33 | bool init_display_sdl(); 34 | bool init_display(); 35 | 36 | void shutdown_display_dispmanx(); 37 | void shutdown_display_sdl(); 38 | void shutdown_display(); 39 | 40 | bool update_display(); 41 | 42 | bool init_ts(); 43 | void shutdown_ts(); 44 | void update_ts(); 45 | }; 46 | -------------------------------------------------------------------------------- /gs/src/Video_Decoder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "imgui.h" 5 | 6 | class IHAL; 7 | 8 | class Video_Decoder 9 | { 10 | public: 11 | Video_Decoder(); 12 | ~Video_Decoder(); 13 | 14 | bool decode_data(void const* data, size_t size); 15 | void inject_test_data(uint32_t value); 16 | 17 | bool init(IHAL& hal); 18 | 19 | size_t lock_output(); 20 | uint32_t get_video_texture_id(size_t component) const;; 21 | ImVec2 get_video_resolution() const; 22 | bool unlock_output(); 23 | 24 | 25 | struct Impl; 26 | 27 | private: 28 | void decoder_thread_proc(size_t thread_index); 29 | 30 | IHAL* m_hal = nullptr; 31 | bool m_exit = false; 32 | ImVec2 m_resolution; 33 | std::array m_textures; 34 | std::unique_ptr m_impl; 35 | }; 36 | -------------------------------------------------------------------------------- /gs/src/fmt/args.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - dynamic format arguments 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_ARGS_H_ 9 | #define FMT_ARGS_H_ 10 | 11 | #include // std::reference_wrapper 12 | #include // std::unique_ptr 13 | #include 14 | 15 | #include "core.h" 16 | 17 | FMT_BEGIN_NAMESPACE 18 | 19 | namespace detail { 20 | 21 | template struct is_reference_wrapper : std::false_type {}; 22 | template 23 | struct is_reference_wrapper> : std::true_type {}; 24 | 25 | template const T& unwrap(const T& v) { return v; } 26 | template const T& unwrap(const std::reference_wrapper& v) { 27 | return static_cast(v); 28 | } 29 | 30 | class dynamic_arg_list { 31 | // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for 32 | // templates it doesn't complain about inability to deduce single translation 33 | // unit for placing vtable. So storage_node_base is made a fake template. 34 | template struct node { 35 | virtual ~node() = default; 36 | std::unique_ptr> next; 37 | }; 38 | 39 | template struct typed_node : node<> { 40 | T value; 41 | 42 | template 43 | FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} 44 | 45 | template 46 | FMT_CONSTEXPR typed_node(const basic_string_view& arg) 47 | : value(arg.data(), arg.size()) {} 48 | }; 49 | 50 | std::unique_ptr> head_; 51 | 52 | public: 53 | template const T& push(const Arg& arg) { 54 | auto new_node = std::unique_ptr>(new typed_node(arg)); 55 | auto& value = new_node->value; 56 | new_node->next = std::move(head_); 57 | head_ = std::move(new_node); 58 | return value; 59 | } 60 | }; 61 | } // namespace detail 62 | 63 | /** 64 | \rst 65 | A dynamic version of `fmt::format_arg_store`. 66 | It's equipped with a storage to potentially temporary objects which lifetimes 67 | could be shorter than the format arguments object. 68 | 69 | It can be implicitly converted into `~fmt::basic_format_args` for passing 70 | into type-erased formatting functions such as `~fmt::vformat`. 71 | \endrst 72 | */ 73 | template 74 | class dynamic_format_arg_store 75 | #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 76 | // Workaround a GCC template argument substitution bug. 77 | : public basic_format_args 78 | #endif 79 | { 80 | private: 81 | using char_type = typename Context::char_type; 82 | 83 | template struct need_copy { 84 | static constexpr detail::type mapped_type = 85 | detail::mapped_type_constant::value; 86 | 87 | enum { 88 | value = !(detail::is_reference_wrapper::value || 89 | std::is_same>::value || 90 | std::is_same>::value || 91 | (mapped_type != detail::type::cstring_type && 92 | mapped_type != detail::type::string_type && 93 | mapped_type != detail::type::custom_type)) 94 | }; 95 | }; 96 | 97 | template 98 | using stored_type = conditional_t::value && 99 | !has_formatter::value && 100 | !detail::is_reference_wrapper::value, 101 | std::basic_string, T>; 102 | 103 | // Storage of basic_format_arg must be contiguous. 104 | std::vector> data_; 105 | std::vector> named_info_; 106 | 107 | // Storage of arguments not fitting into basic_format_arg must grow 108 | // without relocation because items in data_ refer to it. 109 | detail::dynamic_arg_list dynamic_args_; 110 | 111 | friend class basic_format_args; 112 | 113 | unsigned long long get_types() const { 114 | return detail::is_unpacked_bit | data_.size() | 115 | (named_info_.empty() 116 | ? 0ULL 117 | : static_cast(detail::has_named_args_bit)); 118 | } 119 | 120 | const basic_format_arg* data() const { 121 | return named_info_.empty() ? data_.data() : data_.data() + 1; 122 | } 123 | 124 | template void emplace_arg(const T& arg) { 125 | data_.emplace_back(detail::make_arg(arg)); 126 | } 127 | 128 | template 129 | void emplace_arg(const detail::named_arg& arg) { 130 | if (named_info_.empty()) { 131 | constexpr const detail::named_arg_info* zero_ptr{nullptr}; 132 | data_.insert(data_.begin(), {zero_ptr, 0}); 133 | } 134 | data_.emplace_back(detail::make_arg(detail::unwrap(arg.value))); 135 | auto pop_one = [](std::vector>* data) { 136 | data->pop_back(); 137 | }; 138 | std::unique_ptr>, decltype(pop_one)> 139 | guard{&data_, pop_one}; 140 | named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); 141 | data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; 142 | guard.release(); 143 | } 144 | 145 | public: 146 | /** 147 | \rst 148 | Adds an argument into the dynamic store for later passing to a formatting 149 | function. 150 | 151 | Note that custom types and string types (but not string views) are copied 152 | into the store dynamically allocating memory if necessary. 153 | 154 | **Example**:: 155 | 156 | fmt::dynamic_format_arg_store store; 157 | store.push_back(42); 158 | store.push_back("abc"); 159 | store.push_back(1.5f); 160 | std::string result = fmt::vformat("{} and {} and {}", store); 161 | \endrst 162 | */ 163 | template void push_back(const T& arg) { 164 | if (detail::const_check(need_copy::value)) 165 | emplace_arg(dynamic_args_.push>(arg)); 166 | else 167 | emplace_arg(detail::unwrap(arg)); 168 | } 169 | 170 | /** 171 | \rst 172 | Adds a reference to the argument into the dynamic store for later passing to 173 | a formatting function. 174 | 175 | **Example**:: 176 | 177 | fmt::dynamic_format_arg_store store; 178 | char band[] = "Rolling Stones"; 179 | store.push_back(std::cref(band)); 180 | band[9] = 'c'; // Changing str affects the output. 181 | std::string result = fmt::vformat("{}", store); 182 | // result == "Rolling Scones" 183 | \endrst 184 | */ 185 | template void push_back(std::reference_wrapper arg) { 186 | static_assert( 187 | need_copy::value, 188 | "objects of built-in types and string views are always copied"); 189 | emplace_arg(arg.get()); 190 | } 191 | 192 | /** 193 | Adds named argument into the dynamic store for later passing to a formatting 194 | function. ``std::reference_wrapper`` is supported to avoid copying of the 195 | argument. The name is always copied into the store. 196 | */ 197 | template 198 | void push_back(const detail::named_arg& arg) { 199 | const char_type* arg_name = 200 | dynamic_args_.push>(arg.name).c_str(); 201 | if (detail::const_check(need_copy::value)) { 202 | emplace_arg( 203 | fmt::arg(arg_name, dynamic_args_.push>(arg.value))); 204 | } else { 205 | emplace_arg(fmt::arg(arg_name, arg.value)); 206 | } 207 | } 208 | 209 | /** Erase all elements from the store */ 210 | void clear() { 211 | data_.clear(); 212 | named_info_.clear(); 213 | dynamic_args_ = detail::dynamic_arg_list(); 214 | } 215 | 216 | /** 217 | \rst 218 | Reserves space to store at least *new_cap* arguments including 219 | *new_cap_named* named arguments. 220 | \endrst 221 | */ 222 | void reserve(size_t new_cap, size_t new_cap_named) { 223 | FMT_ASSERT(new_cap >= new_cap_named, 224 | "Set of arguments includes set of named arguments"); 225 | data_.reserve(new_cap); 226 | named_info_.reserve(new_cap_named); 227 | } 228 | }; 229 | 230 | FMT_END_NAMESPACE 231 | 232 | #endif // FMT_ARGS_H_ 233 | -------------------------------------------------------------------------------- /gs/src/fmt/format.cc: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #include "fmt/format-inl.h" 9 | 10 | FMT_BEGIN_NAMESPACE 11 | namespace detail { 12 | 13 | template 14 | int format_float(char* buf, std::size_t size, const char* format, int precision, 15 | T value) { 16 | #ifdef FMT_FUZZ 17 | if (precision > 100000) 18 | throw std::runtime_error( 19 | "fuzz mode - avoid large allocation inside snprintf"); 20 | #endif 21 | // Suppress the warning about nonliteral format string. 22 | int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF; 23 | return precision < 0 ? snprintf_ptr(buf, size, format, value) 24 | : snprintf_ptr(buf, size, format, precision, value); 25 | } 26 | 27 | template FMT_API dragonbox::decimal_fp dragonbox::to_decimal(float x) 28 | FMT_NOEXCEPT; 29 | template FMT_API dragonbox::decimal_fp dragonbox::to_decimal(double x) 30 | FMT_NOEXCEPT; 31 | 32 | // DEPRECATED! This function exists for ABI compatibility. 33 | template 34 | typename basic_format_context>, 35 | Char>::iterator 36 | vformat_to(buffer& buf, basic_string_view format_str, 37 | basic_format_args>>, 39 | type_identity_t>> 40 | args) { 41 | using iterator = std::back_insert_iterator>; 42 | using context = basic_format_context< 43 | std::back_insert_iterator>>, 44 | type_identity_t>; 45 | auto out = iterator(buf); 46 | format_handler h(out, format_str, args, {}); 47 | parse_format_string(format_str, h); 48 | return out; 49 | } 50 | template basic_format_context>, 51 | char>::iterator 52 | vformat_to(buffer&, string_view, 53 | basic_format_args>>, 55 | type_identity_t>>); 56 | } // namespace detail 57 | 58 | template struct FMT_INSTANTIATION_DEF_API detail::basic_data; 59 | 60 | // Workaround a bug in MSVC2013 that prevents instantiation of format_float. 61 | int (*instantiate_format_float)(double, int, detail::float_specs, 62 | detail::buffer&) = detail::format_float; 63 | 64 | #ifndef FMT_STATIC_THOUSANDS_SEPARATOR 65 | template FMT_API detail::locale_ref::locale_ref(const std::locale& loc); 66 | template FMT_API std::locale detail::locale_ref::get() const; 67 | #endif 68 | 69 | // Explicit instantiations for char. 70 | 71 | template FMT_API std::string detail::grouping_impl(locale_ref); 72 | template FMT_API char detail::thousands_sep_impl(locale_ref); 73 | template FMT_API char detail::decimal_point_impl(locale_ref); 74 | 75 | template FMT_API void detail::buffer::append(const char*, const char*); 76 | 77 | template FMT_API void detail::vformat_to( 78 | detail::buffer&, string_view, 79 | basic_format_args, detail::locale_ref); 80 | 81 | template FMT_API int detail::snprintf_float(double, int, detail::float_specs, 82 | detail::buffer&); 83 | template FMT_API int detail::snprintf_float(long double, int, 84 | detail::float_specs, 85 | detail::buffer&); 86 | template FMT_API int detail::format_float(double, int, detail::float_specs, 87 | detail::buffer&); 88 | template FMT_API int detail::format_float(long double, int, detail::float_specs, 89 | detail::buffer&); 90 | 91 | // Explicit instantiations for wchar_t. 92 | 93 | template FMT_API std::string detail::grouping_impl(locale_ref); 94 | template FMT_API wchar_t detail::thousands_sep_impl(locale_ref); 95 | template FMT_API wchar_t detail::decimal_point_impl(locale_ref); 96 | 97 | template FMT_API void detail::buffer::append(const wchar_t*, 98 | const wchar_t*); 99 | FMT_END_NAMESPACE 100 | -------------------------------------------------------------------------------- /gs/src/fmt/locale.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - std::locale support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_LOCALE_H_ 9 | #define FMT_LOCALE_H_ 10 | 11 | #include 12 | 13 | #include "format.h" 14 | 15 | FMT_BEGIN_NAMESPACE 16 | 17 | namespace detail { 18 | template 19 | std::basic_string vformat( 20 | const std::locale& loc, basic_string_view format_str, 21 | basic_format_args>> args) { 22 | basic_memory_buffer buffer; 23 | detail::vformat_to(buffer, format_str, args, detail::locale_ref(loc)); 24 | return fmt::to_string(buffer); 25 | } 26 | } // namespace detail 27 | 28 | template > 29 | inline std::basic_string vformat( 30 | const std::locale& loc, const S& format_str, 31 | basic_format_args>> args) { 32 | return detail::vformat(loc, to_string_view(format_str), args); 33 | } 34 | 35 | template > 36 | inline std::basic_string format(const std::locale& loc, 37 | const S& format_str, Args&&... args) { 38 | return detail::vformat(loc, to_string_view(format_str), 39 | fmt::make_args_checked(format_str, args...)); 40 | } 41 | 42 | template , 44 | FMT_ENABLE_IF(detail::is_output_iterator::value)> 45 | inline OutputIt vformat_to( 46 | OutputIt out, const std::locale& loc, const S& format_str, 47 | basic_format_args>> args) { 48 | decltype(detail::get_buffer(out)) buf(detail::get_buffer_init(out)); 49 | vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc)); 50 | return detail::get_iterator(buf); 51 | } 52 | 53 | template >::value> 55 | inline auto format_to(OutputIt out, const std::locale& loc, const S& format_str, 56 | Args&&... args) -> 57 | typename std::enable_if::type { 58 | const auto& vargs = fmt::make_args_checked(format_str, args...); 59 | return vformat_to(out, loc, to_string_view(format_str), vargs); 60 | } 61 | 62 | FMT_END_NAMESPACE 63 | 64 | #endif // FMT_LOCALE_H_ 65 | -------------------------------------------------------------------------------- /gs/src/fmt/os.cc: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - optional OS-specific functionality 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | // Disable bogus MSVC warnings. 9 | #if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER) 10 | # define _CRT_SECURE_NO_WARNINGS 11 | #endif 12 | 13 | #include "fmt/os.h" 14 | 15 | #include 16 | 17 | #if FMT_USE_FCNTL 18 | # include 19 | # include 20 | 21 | # ifndef _WIN32 22 | # include 23 | # else 24 | # ifndef WIN32_LEAN_AND_MEAN 25 | # define WIN32_LEAN_AND_MEAN 26 | # endif 27 | # include 28 | # include 29 | 30 | # define O_CREAT _O_CREAT 31 | # define O_TRUNC _O_TRUNC 32 | 33 | # ifndef S_IRUSR 34 | # define S_IRUSR _S_IREAD 35 | # endif 36 | 37 | # ifndef S_IWUSR 38 | # define S_IWUSR _S_IWRITE 39 | # endif 40 | 41 | # ifdef __MINGW32__ 42 | # define _SH_DENYNO 0x40 43 | # endif 44 | # endif // _WIN32 45 | #endif // FMT_USE_FCNTL 46 | 47 | #ifdef _WIN32 48 | # include 49 | #endif 50 | 51 | #ifdef fileno 52 | # undef fileno 53 | #endif 54 | 55 | namespace { 56 | #ifdef _WIN32 57 | // Return type of read and write functions. 58 | using RWResult = int; 59 | 60 | // On Windows the count argument to read and write is unsigned, so convert 61 | // it from size_t preventing integer overflow. 62 | inline unsigned convert_rwcount(std::size_t count) { 63 | return count <= UINT_MAX ? static_cast(count) : UINT_MAX; 64 | } 65 | #elif FMT_USE_FCNTL 66 | // Return type of read and write functions. 67 | using RWResult = ssize_t; 68 | 69 | inline std::size_t convert_rwcount(std::size_t count) { return count; } 70 | #endif 71 | } // namespace 72 | 73 | FMT_BEGIN_NAMESPACE 74 | 75 | #ifdef _WIN32 76 | detail::utf16_to_utf8::utf16_to_utf8(wstring_view s) { 77 | if (int error_code = convert(s)) { 78 | FMT_THROW(windows_error(error_code, 79 | "cannot convert string from UTF-16 to UTF-8")); 80 | } 81 | } 82 | 83 | int detail::utf16_to_utf8::convert(wstring_view s) { 84 | if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER; 85 | int s_size = static_cast(s.size()); 86 | if (s_size == 0) { 87 | // WideCharToMultiByte does not support zero length, handle separately. 88 | buffer_.resize(1); 89 | buffer_[0] = 0; 90 | return 0; 91 | } 92 | 93 | int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, nullptr, 0, 94 | nullptr, nullptr); 95 | if (length == 0) return GetLastError(); 96 | buffer_.resize(length + 1); 97 | length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0], 98 | length, nullptr, nullptr); 99 | if (length == 0) return GetLastError(); 100 | buffer_[length] = 0; 101 | return 0; 102 | } 103 | 104 | void windows_error::init(int err_code, string_view format_str, 105 | format_args args) { 106 | error_code_ = err_code; 107 | memory_buffer buffer; 108 | detail::format_windows_error(buffer, err_code, vformat(format_str, args)); 109 | std::runtime_error& base = *this; 110 | base = std::runtime_error(to_string(buffer)); 111 | } 112 | 113 | void detail::format_windows_error(detail::buffer& out, int error_code, 114 | string_view message) FMT_NOEXCEPT { 115 | FMT_TRY { 116 | wmemory_buffer buf; 117 | buf.resize(inline_buffer_size); 118 | for (;;) { 119 | wchar_t* system_message = &buf[0]; 120 | int result = FormatMessageW( 121 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, 122 | error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message, 123 | static_cast(buf.size()), nullptr); 124 | if (result != 0) { 125 | utf16_to_utf8 utf8_message; 126 | if (utf8_message.convert(system_message) == ERROR_SUCCESS) { 127 | format_to(buffer_appender(out), "{}: {}", message, 128 | utf8_message); 129 | return; 130 | } 131 | break; 132 | } 133 | if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 134 | break; // Can't get error message, report error code instead. 135 | buf.resize(buf.size() * 2); 136 | } 137 | } 138 | FMT_CATCH(...) {} 139 | format_error_code(out, error_code, message); 140 | } 141 | 142 | void report_windows_error(int error_code, 143 | fmt::string_view message) FMT_NOEXCEPT { 144 | report_error(detail::format_windows_error, error_code, message); 145 | } 146 | #endif // _WIN32 147 | 148 | buffered_file::~buffered_file() FMT_NOEXCEPT { 149 | if (file_ && FMT_SYSTEM(fclose(file_)) != 0) 150 | report_system_error(errno, "cannot close file"); 151 | } 152 | 153 | buffered_file::buffered_file(cstring_view filename, cstring_view mode) { 154 | FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 155 | nullptr); 156 | if (!file_) 157 | FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str())); 158 | } 159 | 160 | void buffered_file::close() { 161 | if (!file_) return; 162 | int result = FMT_SYSTEM(fclose(file_)); 163 | file_ = nullptr; 164 | if (result != 0) FMT_THROW(system_error(errno, "cannot close file")); 165 | } 166 | 167 | // A macro used to prevent expansion of fileno on broken versions of MinGW. 168 | #define FMT_ARGS 169 | 170 | int buffered_file::fileno() const { 171 | int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_)); 172 | if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor")); 173 | return fd; 174 | } 175 | 176 | #if FMT_USE_FCNTL 177 | file::file(cstring_view path, int oflag) { 178 | int mode = S_IRUSR | S_IWUSR; 179 | # if defined(_WIN32) && !defined(__MINGW32__) 180 | fd_ = -1; 181 | FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode)); 182 | # else 183 | FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode))); 184 | # endif 185 | if (fd_ == -1) 186 | FMT_THROW(system_error(errno, "cannot open file {}", path.c_str())); 187 | } 188 | 189 | file::~file() FMT_NOEXCEPT { 190 | // Don't retry close in case of EINTR! 191 | // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html 192 | if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) 193 | report_system_error(errno, "cannot close file"); 194 | } 195 | 196 | void file::close() { 197 | if (fd_ == -1) return; 198 | // Don't retry close in case of EINTR! 199 | // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html 200 | int result = FMT_POSIX_CALL(close(fd_)); 201 | fd_ = -1; 202 | if (result != 0) FMT_THROW(system_error(errno, "cannot close file")); 203 | } 204 | 205 | long long file::size() const { 206 | # ifdef _WIN32 207 | // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT 208 | // is less than 0x0500 as is the case with some default MinGW builds. 209 | // Both functions support large file sizes. 210 | DWORD size_upper = 0; 211 | HANDLE handle = reinterpret_cast(_get_osfhandle(fd_)); 212 | DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); 213 | if (size_lower == INVALID_FILE_SIZE) { 214 | DWORD error = GetLastError(); 215 | if (error != NO_ERROR) 216 | FMT_THROW(windows_error(GetLastError(), "cannot get file size")); 217 | } 218 | unsigned long long long_size = size_upper; 219 | return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; 220 | # else 221 | using Stat = struct stat; 222 | Stat file_stat = Stat(); 223 | if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) 224 | FMT_THROW(system_error(errno, "cannot get file attributes")); 225 | static_assert(sizeof(long long) >= sizeof(file_stat.st_size), 226 | "return type of file::size is not large enough"); 227 | return file_stat.st_size; 228 | # endif 229 | } 230 | 231 | std::size_t file::read(void* buffer, std::size_t count) { 232 | RWResult result = 0; 233 | FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); 234 | if (result < 0) FMT_THROW(system_error(errno, "cannot read from file")); 235 | return detail::to_unsigned(result); 236 | } 237 | 238 | std::size_t file::write(const void* buffer, std::size_t count) { 239 | RWResult result = 0; 240 | FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); 241 | if (result < 0) FMT_THROW(system_error(errno, "cannot write to file")); 242 | return detail::to_unsigned(result); 243 | } 244 | 245 | file file::dup(int fd) { 246 | // Don't retry as dup doesn't return EINTR. 247 | // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html 248 | int new_fd = FMT_POSIX_CALL(dup(fd)); 249 | if (new_fd == -1) 250 | FMT_THROW(system_error(errno, "cannot duplicate file descriptor {}", fd)); 251 | return file(new_fd); 252 | } 253 | 254 | void file::dup2(int fd) { 255 | int result = 0; 256 | FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); 257 | if (result == -1) { 258 | FMT_THROW(system_error(errno, "cannot duplicate file descriptor {} to {}", 259 | fd_, fd)); 260 | } 261 | } 262 | 263 | void file::dup2(int fd, error_code& ec) FMT_NOEXCEPT { 264 | int result = 0; 265 | FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); 266 | if (result == -1) ec = error_code(errno); 267 | } 268 | 269 | void file::pipe(file& read_end, file& write_end) { 270 | // Close the descriptors first to make sure that assignments don't throw 271 | // and there are no leaks. 272 | read_end.close(); 273 | write_end.close(); 274 | int fds[2] = {}; 275 | # ifdef _WIN32 276 | // Make the default pipe capacity same as on Linux 2.6.11+. 277 | enum { DEFAULT_CAPACITY = 65536 }; 278 | int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); 279 | # else 280 | // Don't retry as the pipe function doesn't return EINTR. 281 | // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html 282 | int result = FMT_POSIX_CALL(pipe(fds)); 283 | # endif 284 | if (result != 0) FMT_THROW(system_error(errno, "cannot create pipe")); 285 | // The following assignments don't throw because read_fd and write_fd 286 | // are closed. 287 | read_end = file(fds[0]); 288 | write_end = file(fds[1]); 289 | } 290 | 291 | buffered_file file::fdopen(const char* mode) { 292 | // Don't retry as fdopen doesn't return EINTR. 293 | # if defined(__MINGW32__) && defined(_POSIX_) 294 | FILE* f = ::fdopen(fd_, mode); 295 | # else 296 | FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode)); 297 | # endif 298 | if (!f) 299 | FMT_THROW( 300 | system_error(errno, "cannot associate stream with file descriptor")); 301 | buffered_file bf(f); 302 | fd_ = -1; 303 | return bf; 304 | } 305 | 306 | long getpagesize() { 307 | # ifdef _WIN32 308 | SYSTEM_INFO si; 309 | GetSystemInfo(&si); 310 | return si.dwPageSize; 311 | # else 312 | long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); 313 | if (size < 0) FMT_THROW(system_error(errno, "cannot get memory page size")); 314 | return size; 315 | # endif 316 | } 317 | 318 | FMT_API void ostream::grow(size_t) { 319 | if (this->size() == this->capacity()) flush(); 320 | } 321 | #endif // FMT_USE_FCNTL 322 | FMT_END_NAMESPACE 323 | -------------------------------------------------------------------------------- /gs/src/fmt/ostream.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - std::ostream support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_OSTREAM_H_ 9 | #define FMT_OSTREAM_H_ 10 | 11 | #include 12 | 13 | #include "format.h" 14 | 15 | FMT_BEGIN_NAMESPACE 16 | 17 | template class basic_printf_parse_context; 18 | template class basic_printf_context; 19 | 20 | namespace detail { 21 | 22 | template class formatbuf : public std::basic_streambuf { 23 | private: 24 | using int_type = typename std::basic_streambuf::int_type; 25 | using traits_type = typename std::basic_streambuf::traits_type; 26 | 27 | buffer& buffer_; 28 | 29 | public: 30 | formatbuf(buffer& buf) : buffer_(buf) {} 31 | 32 | protected: 33 | // The put-area is actually always empty. This makes the implementation 34 | // simpler and has the advantage that the streambuf and the buffer are always 35 | // in sync and sputc never writes into uninitialized memory. The obvious 36 | // disadvantage is that each call to sputc always results in a (virtual) call 37 | // to overflow. There is no disadvantage here for sputn since this always 38 | // results in a call to xsputn. 39 | 40 | int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE { 41 | if (!traits_type::eq_int_type(ch, traits_type::eof())) 42 | buffer_.push_back(static_cast(ch)); 43 | return ch; 44 | } 45 | 46 | std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE { 47 | buffer_.append(s, s + count); 48 | return count; 49 | } 50 | }; 51 | 52 | struct converter { 53 | template ::value)> converter(T); 54 | }; 55 | 56 | template struct test_stream : std::basic_ostream { 57 | private: 58 | void_t<> operator<<(converter); 59 | }; 60 | 61 | // Hide insertion operators for built-in types. 62 | template 63 | void_t<> operator<<(std::basic_ostream&, Char); 64 | template 65 | void_t<> operator<<(std::basic_ostream&, char); 66 | template 67 | void_t<> operator<<(std::basic_ostream&, char); 68 | template 69 | void_t<> operator<<(std::basic_ostream&, signed char); 70 | template 71 | void_t<> operator<<(std::basic_ostream&, unsigned char); 72 | 73 | // Checks if T has a user-defined operator<< (e.g. not a member of 74 | // std::ostream). 75 | template class is_streamable { 76 | private: 77 | template 78 | static bool_constant&>() 79 | << std::declval()), 80 | void_t<>>::value> 81 | test(int); 82 | 83 | template static std::false_type test(...); 84 | 85 | using result = decltype(test(0)); 86 | 87 | public: 88 | is_streamable() = default; 89 | 90 | static const bool value = result::value; 91 | }; 92 | 93 | // Write the content of buf to os. 94 | template 95 | void write_buffer(std::basic_ostream& os, buffer& buf) { 96 | const Char* buf_data = buf.data(); 97 | using unsigned_streamsize = std::make_unsigned::type; 98 | unsigned_streamsize size = buf.size(); 99 | unsigned_streamsize max_size = to_unsigned(max_value()); 100 | do { 101 | unsigned_streamsize n = size <= max_size ? size : max_size; 102 | os.write(buf_data, static_cast(n)); 103 | buf_data += n; 104 | size -= n; 105 | } while (size != 0); 106 | } 107 | 108 | template 109 | void format_value(buffer& buf, const T& value, 110 | locale_ref loc = locale_ref()) { 111 | formatbuf format_buf(buf); 112 | std::basic_ostream output(&format_buf); 113 | #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) 114 | if (loc) output.imbue(loc.get()); 115 | #endif 116 | output << value; 117 | output.exceptions(std::ios_base::failbit | std::ios_base::badbit); 118 | buf.try_resize(buf.size()); 119 | } 120 | 121 | // Formats an object of type T that has an overloaded ostream operator<<. 122 | template 123 | struct fallback_formatter::value>> 124 | : private formatter, Char> { 125 | FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) 126 | -> decltype(ctx.begin()) { 127 | return formatter, Char>::parse(ctx); 128 | } 129 | template >::value)> 132 | auto parse(ParseCtx& ctx) -> decltype(ctx.begin()) { 133 | return ctx.begin(); 134 | } 135 | 136 | template 137 | auto format(const T& value, basic_format_context& ctx) 138 | -> OutputIt { 139 | basic_memory_buffer buffer; 140 | format_value(buffer, value, ctx.locale()); 141 | basic_string_view str(buffer.data(), buffer.size()); 142 | return formatter, Char>::format(str, ctx); 143 | } 144 | template 145 | auto format(const T& value, basic_printf_context& ctx) 146 | -> OutputIt { 147 | basic_memory_buffer buffer; 148 | format_value(buffer, value, ctx.locale()); 149 | return std::copy(buffer.begin(), buffer.end(), ctx.out()); 150 | } 151 | }; 152 | } // namespace detail 153 | 154 | template 155 | void vprint(std::basic_ostream& os, basic_string_view format_str, 156 | basic_format_args>> args) { 157 | basic_memory_buffer buffer; 158 | detail::vformat_to(buffer, format_str, args); 159 | detail::write_buffer(os, buffer); 160 | } 161 | 162 | /** 163 | \rst 164 | Prints formatted data to the stream *os*. 165 | 166 | **Example**:: 167 | 168 | fmt::print(cerr, "Don't {}!", "panic"); 169 | \endrst 170 | */ 171 | template ::value, char_t>> 173 | void print(std::basic_ostream& os, const S& format_str, Args&&... args) { 174 | vprint(os, to_string_view(format_str), 175 | fmt::make_args_checked(format_str, args...)); 176 | } 177 | FMT_END_NAMESPACE 178 | 179 | #endif // FMT_OSTREAM_H_ 180 | -------------------------------------------------------------------------------- /gs/src/fmt/posix.h: -------------------------------------------------------------------------------- 1 | #include "os.h" 2 | #warning "fmt/posix.h is deprecated; use fmt/os.h instead" 3 | -------------------------------------------------------------------------------- /gs/src/imgui/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // COMPILE-TIME OPTIONS FOR DEAR IMGUI 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating imgui, or maintain a patch/branch with your modifications to imconfig.h) 7 | // B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h" 8 | // If you do so you need to make sure that configuration settings are defined consistently _everywhere_ dear imgui is used, which include 9 | // the imgui*.cpp files but also _any_ of your code that uses imgui. This is because some compile-time options have an affect on data structures. 10 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 11 | // Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. 12 | //----------------------------------------------------------------------------- 13 | 14 | #pragma once 15 | 16 | //---- Define assertion handler. Defaults to calling assert(). 17 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 18 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 19 | 20 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows. 21 | //#define IMGUI_API __declspec( dllexport ) 22 | //#define IMGUI_API __declspec( dllimport ) 23 | 24 | //---- Don't define obsolete functions/enums names. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. 25 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 26 | 27 | //---- Don't implement demo windows functionality (ShowDemoWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty) 28 | //---- It is very strongly recommended to NOT disable the demo windows during development. Please read the comments in imgui_demo.cpp. 29 | //#define IMGUI_DISABLE_DEMO_WINDOWS 30 | 31 | //---- Don't implement some functions to reduce linkage requirements. 32 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. 33 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. 34 | //#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself if you don't want to link with vsnprintf. 35 | //#define IMGUI_DISABLE_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 wrapper so you can implement them yourself. Declare your prototypes in imconfig.h. 36 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 37 | 38 | //---- Include imgui_user.h at the end of imgui.h as a convenience 39 | //#define IMGUI_INCLUDE_IMGUI_USER_H 40 | 41 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 42 | //#define IMGUI_USE_BGRA_PACKED_COLOR 43 | 44 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 45 | // By default the embedded implementations are declared static and not available outside of imgui cpp files. 46 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 47 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 48 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 49 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 50 | 51 | //---- Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4. 52 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 53 | /* 54 | #define IM_VEC2_CLASS_EXTRA \ 55 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ 56 | operator MyVec2() const { return MyVec2(x,y); } 57 | 58 | #define IM_VEC4_CLASS_EXTRA \ 59 | ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ 60 | operator MyVec4() const { return MyVec4(x,y,z,w); } 61 | */ 62 | 63 | //---- Use 32-bit vertex indices (default is 16-bit) to allow meshes with more than 64K vertices. Render function needs to support it. 64 | //#define ImDrawIdx unsigned int 65 | 66 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. 67 | /* 68 | namespace ImGui 69 | { 70 | void MyFunction(const char* name, const MyMatrix44& v); 71 | } 72 | */ 73 | -------------------------------------------------------------------------------- /gs/src/imgui/imgui_impl_sdl.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Backend for SDL2 2 | // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) 3 | // (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.) 4 | 5 | // Implemented features: 6 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. 7 | // [X] Platform: Clipboard support. 8 | // [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE). 9 | // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 10 | // Missing features: 11 | // [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME. 12 | 13 | // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 14 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 15 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 16 | 17 | #pragma once 18 | #include "imgui.h" // IMGUI_IMPL_API 19 | 20 | struct SDL_Window; 21 | typedef union SDL_Event SDL_Event; 22 | 23 | IMGUI_IMPL_API void ImGui_ImplSDL2_SetMouseEnabled(bool enabled); 24 | IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); 25 | IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window); 26 | IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window); 27 | IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window); 28 | IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown(); 29 | IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(SDL_Window* window); 30 | IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); 31 | -------------------------------------------------------------------------------- /gs/src/imgui/misc/freetype/imgui_freetype.h: -------------------------------------------------------------------------------- 1 | // Wrapper to use Freetype (instead of stb_truetype) for Dear ImGui 2 | // Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype 3 | // Original code by @Vuhdo (Aleksei Skriabin), maintained by @ocornut 4 | 5 | #pragma once 6 | 7 | #include "imgui.h" // IMGUI_API, ImFontAtlas 8 | 9 | namespace ImGuiFreeType 10 | { 11 | // Hinting greatly impacts visuals (and glyph sizes). 12 | // When disabled, FreeType generates blurrier glyphs, more or less matches the stb's output. 13 | // The Default hinting mode usually looks good, but may distort glyphs in an unusual way. 14 | // The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer. 15 | 16 | // You can set those flags on a per font basis in ImFontConfig::RasterizerFlags. 17 | // Use the 'extra_flags' parameter of BuildFontAtlas() to force a flag on all your fonts. 18 | enum RasterizerFlags 19 | { 20 | // By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter. 21 | NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes. 22 | NoAutoHint = 1 << 1, // Disable auto-hinter. 23 | ForceAutoHint = 1 << 2, // Indicates that the auto-hinter is preferred over the font's native hinter. 24 | LightHinting = 1 << 3, // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text. 25 | MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output. 26 | Bold = 1 << 5, // Styling: Should we artificially embolden the font? 27 | Oblique = 1 << 6 // Styling: Should we slant the font, emulating italic style? 28 | }; 29 | 30 | IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0); 31 | } 32 | -------------------------------------------------------------------------------- /gs/src/imgui_impl_opengl3.h: -------------------------------------------------------------------------------- 1 | // ImGui Renderer for: OpenGL3 (modern OpenGL with shaders / programmatic pipeline) 2 | // This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) 3 | // (Note: We are using GL3W as a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc..) 4 | 5 | // Implemented features: 6 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. 7 | 8 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. 9 | // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. 10 | // https://github.com/ocornut/imgui 11 | 12 | // About GLSL version: 13 | // The 'glsl_version' initialization parameter defaults to "#version 130" if NULL. 14 | // Only override if your GL version doesn't handle this GLSL version (see table at the top of imgui_impl_opengl3.cpp). Keep NULL if unsure! 15 | 16 | IMGUI_IMPL_API void ImGui_SetVideoTextureChannel(unsigned int channel, unsigned int id); 17 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL); 18 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); 19 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); 20 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool rotate); 21 | 22 | // Called by Init/NewFrame/Shutdown 23 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); 24 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); 25 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); 26 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); 27 | -------------------------------------------------------------------------------- /gs/src/main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | //When enabled, it will output a 4Hz pulse (50ms ON, 200ms OFF) on GPIO 17. This can be used to blink a LED pointing inside the camera. 5 | //This is used with a photodiode on the screen to measure with an oscilloscope the delay between the GPIO 17 pulse and the pixels on screen 6 | #if defined(RASPBERRY_PI) 7 | //#define TEST_LATENCY 8 | #else 9 | //#define TEST_LATENCY 10 | #endif 11 | 12 | //When enabled (together with TEST_LATENCY), it will output a 4Hz pulse (50ms ON, 200ms OFF) on GPIO 17. 13 | //On top of this, together with the on/off pulse it will send a white/black frame to the decoding thread. 14 | //This is used with a photodiode on the screen to measure with an oscilloscope the delay between the GPIO 17 pulse and the pixels on screen 15 | //This measurement excludes the air unit and is used to measure the latency of the ground station alone. 16 | //#define TEST_DISPLAY_LATENCY 17 | 18 | #define CHECK_GL_ERRORS 19 | 20 | #if defined(CHECK_GL_ERRORS) 21 | #define GLCHK(X) \ 22 | do { \ 23 | GLenum err = GL_NO_ERROR; \ 24 | X; \ 25 | while ((err = glGetError())) \ 26 | { \ 27 | LOGE("GL error {} in " #X " file {} line {}", err, __FILE__,__LINE__); \ 28 | } \ 29 | } while(0) 30 | #define SDLCHK(X) \ 31 | do { \ 32 | int err = X; \ 33 | if (err != 0) LOGE("SDL error {} in " #X " file {} line {}", err, __FILE__,__LINE__); \ 34 | } while (0) 35 | #else 36 | #define GLCHK(X) X 37 | #define SDLCHK(X) X 38 | #endif 39 | -------------------------------------------------------------------------------- /gs/src/utils/Pool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | template struct Pool 13 | { 14 | std::function on_acquire; 15 | std::function on_release; 16 | 17 | typedef std::shared_ptr Ptr; 18 | Pool(); 19 | Ptr acquire(); 20 | 21 | private: 22 | std::function m_garbage_collector; 23 | std::mutex m_mutex; 24 | std::vector> m_items; 25 | 26 | int x_reused = 0; 27 | int x_new = 0; 28 | int x_returned = 0; 29 | }; 30 | 31 | 32 | template Pool::Pool() 33 | { 34 | m_garbage_collector = [this](T* t) 35 | { 36 | x_returned++; 37 | if (on_release) 38 | on_release(*t); 39 | 40 | std::lock_guard lg(m_mutex); 41 | m_items.emplace_back(static_cast(t)); //will create a unique pointer from the raw one 42 | // printf("%d// new:%d reused:%d returned:%d\n", this, x_new, x_reused, x_returned); 43 | }; 44 | } 45 | 46 | template auto Pool::acquire() -> Ptr 47 | { 48 | //this will be called when the last shared_ptr to T dies. We can safetly return the object to pur pool 49 | 50 | std::lock_guard lg(m_mutex); 51 | T* item = nullptr; 52 | if (!m_items.empty()) 53 | { 54 | x_reused++; 55 | item = m_items.back().release(); //release the raw ptr from the control of the unique ptr 56 | m_items.pop_back(); 57 | // printf("%d// new:%d reused:%d returned:%d\n", this, x_new, x_reused, x_returned); 58 | } 59 | else 60 | { 61 | x_new++; 62 | item = new T; 63 | // printf("%d// new:%d reused:%d returned:%d\n", this, x_new, x_reused, x_returned); 64 | } 65 | assert(item); 66 | 67 | if (on_acquire) 68 | on_acquire(static_cast(*item)); 69 | 70 | return Ptr(item, [this](T* item) { m_garbage_collector(item); }); 71 | } 72 | -------------------------------------------------------------------------------- /gs/src/utils/radiotap/radiotap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Radiotap parser 3 | * 4 | * Copyright 2007 Andy Green 5 | */ 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "radiotap.h" 20 | 21 | /** 22 | * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization 23 | * @iterator: radiotap_iterator to initialize 24 | * @radiotap_header: radiotap header to parse 25 | * @max_length: total length we can parse into (eg, whole packet length) 26 | * 27 | * Returns: 0 or a negative error code if there is a problem. 28 | * 29 | * This function initializes an opaque iterator struct which can then 30 | * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap 31 | * argument which is present in the header. It knows about extended 32 | * present headers and handles them. 33 | * 34 | * How to use: 35 | * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator 36 | * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) 37 | * checking for a good 0 return code. Then loop calling 38 | * __ieee80211_radiotap_iterator_next()... it returns either 0, 39 | * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. 40 | * The iterator's @this_arg member points to the start of the argument 41 | * associated with the current argument index that is present, which can be 42 | * found in the iterator's @this_arg_index member. This arg index corresponds 43 | * to the IEEE80211_RADIOTAP_... defines. 44 | * 45 | * Radiotap header length: 46 | * You can find the CPU-endian total radiotap header length in 47 | * iterator->max_length after executing ieee80211_radiotap_iterator_init() 48 | * successfully. 49 | * 50 | * Example code: 51 | * See Documentation/networking/radiotap-headers.txt 52 | */ 53 | 54 | int ieee80211_radiotap_iterator_init( 55 | struct ieee80211_radiotap_iterator *iterator, 56 | struct ieee80211_radiotap_header *radiotap_header, 57 | int max_length) 58 | { 59 | /* Linux only supports version 0 radiotap format */ 60 | if (radiotap_header->it_version) 61 | return -EINVAL; 62 | 63 | /* sanity check for allowed length and radiotap length field */ 64 | if (max_length < radiotap_header->it_len) 65 | return -EINVAL; 66 | 67 | iterator->rtheader = radiotap_header; 68 | iterator->max_length = radiotap_header->it_len; 69 | iterator->arg_index = 0; 70 | iterator->bitmap_shifter = radiotap_header->it_present; 71 | iterator->arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header); 72 | iterator->this_arg = 0; 73 | 74 | /* find payload start allowing for extended bitmap(s) */ 75 | 76 | if (iterator->bitmap_shifter & (1<arg)) & 78 | (1<arg += sizeof(uint32_t); 80 | 81 | /* 82 | * check for insanity where the present bitmaps 83 | * keep claiming to extend up to or even beyond the 84 | * stated radiotap header length 85 | */ 86 | 87 | if (((ulong)iterator->arg - 88 | (ulong)iterator->rtheader) > iterator->max_length) 89 | return -EINVAL; 90 | } 91 | 92 | iterator->arg += sizeof(uint32_t); 93 | 94 | /* 95 | * no need to check again for blowing past stated radiotap 96 | * header length, because ieee80211_radiotap_iterator_next 97 | * checks it before it is dereferenced 98 | */ 99 | } 100 | 101 | /* we are all initialized happily */ 102 | 103 | return 0; 104 | } 105 | 106 | 107 | /** 108 | * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg 109 | * @iterator: radiotap_iterator to move to next arg (if any) 110 | * 111 | * Returns: 0 if there is an argument to handle, 112 | * -ENOENT if there are no more args or -EINVAL 113 | * if there is something else wrong. 114 | * 115 | * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) 116 | * in @this_arg_index and sets @this_arg to point to the 117 | * payload for the field. It takes care of alignment handling and extended 118 | * present fields. @this_arg can be changed by the caller (eg, 119 | * incremented to move inside a compound argument like 120 | * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in 121 | * little-endian format whatever the endianess of your CPU. 122 | */ 123 | 124 | int ieee80211_radiotap_iterator_next( 125 | struct ieee80211_radiotap_iterator *iterator) 126 | { 127 | 128 | /* 129 | * small length lookup table for all radiotap types we heard of 130 | * starting from b0 in the bitmap, so we can walk the payload 131 | * area of the radiotap header 132 | * 133 | * There is a requirement to pad args, so that args 134 | * of a given length must begin at a boundary of that length 135 | * -- but note that compound args are allowed (eg, 2 x u16 136 | * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not 137 | * a reliable indicator of alignment requirement. 138 | * 139 | * upper nybble: content alignment for arg 140 | * lower nybble: content length for arg 141 | */ 142 | 143 | static const uint8_t rt_sizes[] = { 144 | [IEEE80211_RADIOTAP_TSFT] = 0x88, 145 | [IEEE80211_RADIOTAP_FLAGS] = 0x11, 146 | [IEEE80211_RADIOTAP_RATE] = 0x11, 147 | [IEEE80211_RADIOTAP_CHANNEL] = 0x24, 148 | [IEEE80211_RADIOTAP_FHSS] = 0x22, 149 | [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, 150 | [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, 151 | [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, 152 | [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, 153 | [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, 154 | [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, 155 | [IEEE80211_RADIOTAP_ANTENNA] = 0x11, 156 | [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, 157 | [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11 158 | /* 159 | * add more here as they are defined in 160 | * include/net/ieee80211_radiotap.h 161 | */ 162 | }; 163 | 164 | /* 165 | * for every radiotap entry we can at 166 | * least skip (by knowing the length)... 167 | */ 168 | 169 | while (iterator->arg_index < sizeof(rt_sizes)) { 170 | int hit = 0; 171 | int pad; 172 | 173 | if (!(iterator->bitmap_shifter & 1)) 174 | goto next_entry; /* arg not present */ 175 | 176 | /* 177 | * arg is present, account for alignment padding 178 | * 8-bit args can be at any alignment 179 | * 16-bit args must start on 16-bit boundary 180 | * 32-bit args must start on 32-bit boundary 181 | * 64-bit args must start on 64-bit boundary 182 | * 183 | * note that total arg size can differ from alignment of 184 | * elements inside arg, so we use upper nybble of length 185 | * table to base alignment on 186 | * 187 | * also note: these alignments are ** relative to the 188 | * start of the radiotap header **. There is no guarantee 189 | * that the radiotap header itself is aligned on any 190 | * kind of boundary. 191 | */ 192 | 193 | pad = (((ulong)iterator->arg) - 194 | ((ulong)iterator->rtheader)) & 195 | ((rt_sizes[iterator->arg_index] >> 4) - 1); 196 | 197 | if (pad) 198 | iterator->arg += 199 | (rt_sizes[iterator->arg_index] >> 4) - pad; 200 | 201 | /* 202 | * this is what we will return to user, but we need to 203 | * move on first so next call has something fresh to test 204 | */ 205 | iterator->this_arg_index = iterator->arg_index; 206 | iterator->this_arg = iterator->arg; 207 | hit = 1; 208 | 209 | /* internally move on the size of this arg */ 210 | iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; 211 | 212 | /* 213 | * check for insanity where we are given a bitmap that 214 | * claims to have more arg content than the length of the 215 | * radiotap section. We will normally end up equalling this 216 | * max_length on the last arg, never exceeding it. 217 | */ 218 | 219 | if (((ulong)iterator->arg - (ulong)iterator->rtheader) > 220 | iterator->max_length) 221 | return -EINVAL; 222 | 223 | next_entry: 224 | iterator->arg_index++; 225 | if ((iterator->arg_index & 31) == 0) { 226 | /* completed current u32 bitmap */ 227 | if (iterator->bitmap_shifter & 1) { 228 | /* b31 was set, there is more */ 229 | /* move to next u32 bitmap */ 230 | iterator->bitmap_shifter = *iterator->next_bitmap; 231 | iterator->next_bitmap++; 232 | } else { 233 | /* no more bitmaps: end */ 234 | iterator->arg_index = sizeof(rt_sizes); 235 | } 236 | } else { /* just try the next bit */ 237 | iterator->bitmap_shifter >>= 1; 238 | } 239 | 240 | /* if we found a valid arg earlier, return it now */ 241 | if (hit) 242 | return 0; 243 | } 244 | 245 | /* we don't know how to handle any more args, we're done */ 246 | return -ENOENT; 247 | } 248 | 249 | -------------------------------------------------------------------------------- /gs/src/utils/radiotap/radiotap.h: -------------------------------------------------------------------------------- 1 | #include "ieee80211_radiotap.h" 2 | 3 | /* Radiotap header iteration 4 | * implemented in net/wireless/radiotap.c 5 | * docs in Documentation/networking/radiotap-headers.txt 6 | */ 7 | /** 8 | * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args 9 | * @rtheader: pointer to the radiotap header we are walking through 10 | * @max_length: length of radiotap header in cpu byte ordering 11 | * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg 12 | * @this_arg: pointer to current radiotap arg 13 | * @arg_index: internal next argument index 14 | * @arg: internal next argument pointer 15 | * @next_bitmap: internal pointer to next present u32 16 | * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present 17 | */ 18 | 19 | struct ieee80211_radiotap_iterator { 20 | struct ieee80211_radiotap_header *rtheader; 21 | int max_length; 22 | int this_arg_index; 23 | uint8_t *this_arg; 24 | 25 | int arg_index; 26 | uint8_t *arg; 27 | __le32 *next_bitmap; 28 | uint32_t bitmap_shifter; 29 | }; 30 | 31 | extern int ieee80211_radiotap_iterator_init( 32 | struct ieee80211_radiotap_iterator *iterator, 33 | struct ieee80211_radiotap_header *radiotap_header, 34 | int max_length); 35 | 36 | extern int ieee80211_radiotap_iterator_next( 37 | struct ieee80211_radiotap_iterator *iterator); 38 | 39 | --------------------------------------------------------------------------------