├── _config.yml ├── examples ├── Basic │ ├── data │ │ └── sewing.jpg │ ├── image.h │ └── Basic.ino └── Camera │ ├── src │ ├── ov7725.h │ ├── ov264_drive.h │ ├── sccb.h │ ├── OV2640.h │ ├── twi.h │ ├── camera_common.h │ ├── sccb.c │ ├── OV2640.cpp │ ├── sensor.h │ ├── camera.h │ ├── ov2640_regs.h │ ├── twi.c │ ├── ov7725.c │ ├── ov7725_regs.h │ ├── ov264_drive.c │ └── camera.c │ └── Camera.ino ├── library.properties ├── README.md └── src ├── LineNotifyESP32.h └── LineNotifyESP32.cpp /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /examples/Basic/data/sewing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobizt/Line-Notify-ESP32/master/examples/Basic/data/sewing.jpg -------------------------------------------------------------------------------- /examples/Camera/src/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 | -------------------------------------------------------------------------------- /examples/Camera/src/ov264_drive.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_DRIVE_H__ 10 | #define __OV2640_DRIVE_H__ 11 | #include "sensor.h" 12 | int ov2640_init(sensor_t *sensor); 13 | #endif // __OV2640_DRIVE_H__ 14 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=ESP32 LINE Notify 2 | 3 | version=1.0.1 4 | 5 | author=Mobizt 6 | 7 | maintainer=Mobizt 8 | 9 | sentence=LINE Notify Arduino Library for ESP32. 10 | 11 | paragraph=Arduino library allows ESP32 to send LINE Notify message, sticker, SD card image and camera image. 12 | 13 | category=Communication 14 | 15 | url=https://github.com/mobizt/Line-Notify-ESP32 16 | 17 | architectures=esp32 18 | -------------------------------------------------------------------------------- /examples/Camera/src/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 | #endif // __SCCB_H__ 17 | -------------------------------------------------------------------------------- /examples/Camera/src/OV2640.h: -------------------------------------------------------------------------------- 1 | #ifndef OV2640_H_ 2 | #define OV2640_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "esp_log.h" 8 | #include "esp_attr.h" 9 | #include "camera.h" 10 | 11 | class OV2640 12 | { 13 | public: 14 | OV2640(){}; 15 | ~OV2640(){}; 16 | esp_err_t init(camera_config_t config); 17 | void run(void); 18 | size_t getSize(void); 19 | uint8_t *getfb(void); 20 | int getWidth(void); 21 | int getHeight(void); 22 | camera_framesize_t getFrameSize(void); 23 | camera_pixelformat_t getPixelFormat(void); 24 | 25 | void setFrameSize(camera_framesize_t size); 26 | void setPixelFormat(camera_pixelformat_t format); 27 | void setVflip(bool enable); 28 | 29 | private: 30 | // camera_framesize_t _frame_size; 31 | // camera_pixelformat_t _pixel_format; 32 | camera_config_t _cam_config; 33 | }; 34 | 35 | #endif //OV2640_H_ -------------------------------------------------------------------------------- /examples/Camera/src/twi.h: -------------------------------------------------------------------------------- 1 | /* 2 | twi.h - Software I2C library for ESP31B 3 | 4 | Copyright (c) 2015 Hristo Gochkov. All rights reserved. 5 | This file is part of the ESP31B core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #ifndef SI2C_h 22 | #define SI2C_h 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | #define systick_sleep(t) delay(t) 29 | #define __disable_irq() 30 | #define __enable_irq() 31 | 32 | void twi_init(unsigned char sda, unsigned char scl); 33 | void twi_stop(void); 34 | void twi_setClock(unsigned int freq); 35 | uint8_t twi_writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop); 36 | uint8_t twi_readFrom(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | 42 | #endif -------------------------------------------------------------------------------- /examples/Camera/src/camera_common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "rom/lldesc.h" 7 | #include "esp_err.h" 8 | #include "esp_intr_alloc.h" 9 | #include "freertos/FreeRTOS.h" 10 | #include "freertos/semphr.h" 11 | #include "freertos/task.h" 12 | #include "camera.h" 13 | #include "sensor.h" 14 | 15 | typedef union { 16 | struct { 17 | uint8_t sample2; 18 | uint8_t unused2; 19 | uint8_t sample1; 20 | uint8_t unused1; 21 | }; 22 | uint32_t val; 23 | } dma_elem_t; 24 | 25 | typedef enum { 26 | /* camera sends byte sequence: s1, s2, s3, s4, ... 27 | * fifo receives: 00 s1 00 s2, 00 s2 00 s3, 00 s3 00 s4, ... 28 | */ 29 | SM_0A0B_0B0C = 0, 30 | /* camera sends byte sequence: s1, s2, s3, s4, ... 31 | * fifo receives: 00 s1 00 s2, 00 s3 00 s4, ... 32 | */ 33 | SM_0A0B_0C0D = 1, 34 | /* camera sends byte sequence: s1, s2, s3, s4, ... 35 | * fifo receives: 00 s1 00 00, 00 s2 00 00, 00 s3 00 00, ... 36 | */ 37 | SM_0A00_0B00 = 3, 38 | } i2s_sampling_mode_t; 39 | 40 | typedef void (*dma_filter_t)(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst); 41 | 42 | typedef struct { 43 | camera_config_t config; 44 | sensor_t sensor; 45 | uint8_t *fb; 46 | size_t fb_size; 47 | size_t data_size; 48 | size_t width; 49 | size_t height; 50 | size_t in_bytes_per_pixel; 51 | size_t fb_bytes_per_pixel; 52 | size_t stride; 53 | size_t frame_count; 54 | 55 | lldesc_t *dma_desc; 56 | dma_elem_t **dma_buf; 57 | bool dma_done; 58 | size_t dma_desc_count; 59 | size_t dma_desc_cur; 60 | size_t dma_received_count; 61 | size_t dma_filtered_count; 62 | size_t dma_per_line; 63 | size_t dma_buf_width; 64 | size_t dma_sample_count; 65 | i2s_sampling_mode_t sampling_mode; 66 | dma_filter_t dma_filter; 67 | intr_handle_t i2s_intr_handle; 68 | QueueHandle_t data_ready; 69 | SemaphoreHandle_t frame_ready; 70 | TaskHandle_t dma_filter_task; 71 | } camera_state_t; 72 | 73 | -------------------------------------------------------------------------------- /examples/Camera/src/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 "sccb.h" 11 | #include "twi.h" 12 | #include 13 | 14 | #define SCCB_FREQ (100000) // We don't need fast I2C. 100KHz is fine here. 15 | #define TIMEOUT (1000) /* Can't be sure when I2C routines return. Interrupts 16 | while polling hardware may result in unknown delays. */ 17 | 18 | 19 | int SCCB_Init(int pin_sda, int pin_scl) 20 | { 21 | twi_init(pin_sda, pin_scl); 22 | return 0; 23 | } 24 | 25 | uint8_t SCCB_Probe() 26 | { 27 | 28 | uint8_t reg = 0x00; 29 | uint8_t slv_addr = 0x00; 30 | 31 | for (uint8_t i=0; i<127; i++) { 32 | if (twi_writeTo(i, ®, 1, true) == 0) { 33 | slv_addr = i; 34 | break; 35 | } 36 | 37 | if (i!=126) { 38 | systick_sleep(1); // Necessary for OV7725 camera (not for OV2640). 39 | } 40 | } 41 | return slv_addr; 42 | } 43 | 44 | uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg) 45 | { 46 | uint8_t data=0; 47 | 48 | __disable_irq(); 49 | int rc = twi_writeTo(slv_addr, ®, 1, true); 50 | if (rc != 0) { 51 | data = 0xff; 52 | } 53 | else { 54 | rc = twi_readFrom(slv_addr, &data, 1, true); 55 | if (rc != 0) { 56 | data=0xFF; 57 | } 58 | } 59 | __enable_irq(); 60 | if (rc != 0) { 61 | printf("SCCB_Read [%02x] failed rc=%d\n", reg, rc); 62 | } 63 | return data; 64 | } 65 | 66 | uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data) 67 | { 68 | uint8_t ret=0; 69 | uint8_t buf[] = {reg, data}; 70 | 71 | __disable_irq(); 72 | if(twi_writeTo(slv_addr, buf, 2, true) != 0) { 73 | ret=0xFF; 74 | } 75 | __enable_irq(); 76 | if (ret != 0) { 77 | printf("SCCB_Write [%02x]=%02x failed\n", reg, data); 78 | } 79 | return ret; 80 | } 81 | -------------------------------------------------------------------------------- /examples/Camera/src/OV2640.cpp: -------------------------------------------------------------------------------- 1 | #include "OV2640.h" 2 | 3 | #define TAG "OV2640" 4 | 5 | void OV2640::run(void) 6 | { 7 | camera_run(); 8 | } 9 | 10 | int OV2640::getWidth(void) 11 | { 12 | return camera_get_fb_width(); 13 | } 14 | 15 | int OV2640::getHeight(void) 16 | { 17 | return camera_get_fb_height(); 18 | } 19 | 20 | size_t OV2640::getSize(void) 21 | { 22 | return camera_get_data_size(); 23 | } 24 | 25 | uint8_t *OV2640::getfb(void) 26 | { 27 | return camera_get_fb(); 28 | } 29 | 30 | camera_framesize_t OV2640::getFrameSize(void) 31 | { 32 | return _cam_config.frame_size; 33 | } 34 | 35 | void OV2640::setFrameSize(camera_framesize_t size) 36 | { 37 | switch (size) 38 | { 39 | case CAMERA_FS_QQVGA: 40 | case CAMERA_FS_QVGA: 41 | case CAMERA_FS_VGA: 42 | case CAMERA_FS_SVGA: 43 | _cam_config.frame_size = size; 44 | break; 45 | default: 46 | _cam_config.frame_size = CAMERA_FS_SVGA; 47 | break; 48 | } 49 | } 50 | 51 | camera_pixelformat_t OV2640::getPixelFormat(void) 52 | { 53 | return _cam_config.pixel_format; 54 | } 55 | 56 | void OV2640::setPixelFormat(camera_pixelformat_t format) 57 | { 58 | switch (format) 59 | { 60 | case CAMERA_PF_RGB565: 61 | case CAMERA_PF_YUV422: 62 | case CAMERA_PF_GRAYSCALE: 63 | case CAMERA_PF_JPEG: 64 | _cam_config.pixel_format = format; 65 | break; 66 | default: 67 | _cam_config.pixel_format = CAMERA_PF_GRAYSCALE; 68 | break; 69 | } 70 | } 71 | 72 | void OV2640::setVflip(bool enable) 73 | { 74 | camera_set_vflip(enable); 75 | } 76 | 77 | 78 | esp_err_t OV2640::init(camera_config_t config) 79 | { 80 | camera_model_t camera_model; 81 | memset(&_cam_config, 0, sizeof(_cam_config)); 82 | memcpy(&_cam_config, &config, sizeof(config)); 83 | 84 | esp_err_t err = camera_probe(&_cam_config, &camera_model); 85 | if (err != ESP_OK) 86 | { 87 | ESP_LOGD(TAG, "Camera probe failed with error 0x%x", err); 88 | return err; 89 | } 90 | if (camera_model == CAMERA_OV7725) 91 | { 92 | ESP_LOGD(TAG, "Detected OV7725 camera"); 93 | } 94 | else if (camera_model == CAMERA_OV2640) 95 | { 96 | ESP_LOGD(TAG,"Detected OV2640 camera"); 97 | _cam_config.jpeg_quality = 15; 98 | } 99 | else 100 | { 101 | ESP_LOGD(TAG,"Camera not supported"); 102 | return ESP_ERR_CAMERA_NOT_SUPPORTED; 103 | } 104 | ESP_ERROR_CHECK(gpio_install_isr_service(0)); 105 | 106 | err = camera_init(&_cam_config); 107 | if (err != ESP_OK) 108 | { 109 | ESP_LOGE(TAG, "Camera init failed with error 0x%x", err); 110 | return err; 111 | } 112 | 113 | return ESP_OK; 114 | } 115 | -------------------------------------------------------------------------------- /examples/Camera/Camera.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This example uses OV2640 Camera connected to ESP32 3 | 4 | 1. Install HTTPClientESP32Ex library from https://github.com/mobizt/HTTPClientESP32Ex 5 | 6 | 2. Change the WIFI_SSID, WIFI_PASSWORD and LINE_TOKEN in sketch. 7 | 8 | 3. Compile and upload sketch 9 | 10 | */ 11 | 12 | #include 13 | #include "FS.h" 14 | #include "SPIFFS.h" 15 | #include "LineNotifyESP32.h" 16 | #include "src/OV2640.h" 17 | 18 | #define WIFI_SSID "YOUR_WIFI_AP" 19 | #define WIFI_PASSWORD "YOUR_WIFI_PASSWORD" 20 | #define LINE_TOKEN "YOUR_LINE_NOTIFY_TOKEN" 21 | 22 | HTTPClientESP32Ex http; 23 | OV2640 cam; 24 | 25 | void setup() 26 | { 27 | 28 | Serial.begin(115200); 29 | 30 | WiFi.begin(WIFI_SSID, WIFI_PASSWORD); 31 | while (WiFi.status() != WL_CONNECTED) 32 | { 33 | Serial.print("."); 34 | delay(200); 35 | } 36 | Serial.println(""); 37 | Serial.println("WiFi connected."); 38 | Serial.println("IP address: "); 39 | Serial.println(WiFi.localIP()); 40 | 41 | //Change to match your pin configuration between OV2640 Camera and ESP32 connection 42 | //This config is for ThaiEasyElec's Camera Expansion for ESPino32 (OV2640) 43 | camera_config_t camera_config; 44 | camera_config.ledc_channel = LEDC_CHANNEL_0; 45 | camera_config.ledc_timer = LEDC_TIMER_0; 46 | camera_config.pin_d0 = 33; 47 | camera_config.pin_d1 = 39; 48 | camera_config.pin_d2 = 36; 49 | camera_config.pin_d3 = 32; 50 | camera_config.pin_d4 = 34; 51 | camera_config.pin_d5 = 35; 52 | camera_config.pin_d6 = 04; 53 | camera_config.pin_d7 = 15; 54 | camera_config.pin_xclk = 13; 55 | camera_config.pin_pclk = 12; 56 | camera_config.pin_vsync = 14; 57 | camera_config.pin_href = 27; 58 | camera_config.pin_sscb_sda = 21; 59 | camera_config.pin_sscb_scl = 22; 60 | camera_config.pin_reset = 25; 61 | camera_config.xclk_freq_hz = 10000000; 62 | 63 | /* 64 | * For M5Stack ESP32 Camera (OV2640) 65 | * 66 | 67 | camera_config.ledc_channel = LEDC_CHANNEL_0; 68 | camera_config.ledc_timer = LEDC_TIMER_0; 69 | camera_config.pin_d0 = 17; 70 | camera_config.pin_d1 = 35; 71 | camera_config.pin_d2 = 34; 72 | camera_config.pin_d3 = 5; 73 | camera_config.pin_d4 = 39; 74 | camera_config.pin_d5 = 18; 75 | camera_config.pin_d6 = 36; 76 | camera_config.pin_d7 = 19; 77 | camera_config.pin_xclk = 27; 78 | camera_config.pin_pclk = 21; 79 | camera_config.pin_vsync = 22; 80 | camera_config.pin_href = 26; 81 | camera_config.pin_sscb_sda = 25; 82 | camera_config.pin_sscb_scl = 23; 83 | camera_config.pin_reset = 15; 84 | camera_config.xclk_freq_hz = 20000000; 85 | */ 86 | 87 | camera_config.pixel_format = CAMERA_PF_JPEG; 88 | camera_config.frame_size = CAMERA_FS_SVGA; 89 | 90 | cam.init(camera_config); 91 | 92 | delay(100); 93 | 94 | cam.run(); 95 | 96 | lineNotify.init(LINE_TOKEN); 97 | 98 | uint8_t status = lineNotify.sendLineImageData(http, "This is the image camera", "image.jpg", cam.getfb(), cam.getSize()); 99 | if (status == LineNotifyESP32::LineStatus::SENT_COMPLETED) 100 | { 101 | Serial.println("send image data from camera completed"); 102 | Serial.println("Text message limit: " + String(lineNotify.textMessageLimit())); 103 | Serial.println("Text message remaining: " + String(lineNotify.textMessageRemaining())); 104 | Serial.println("Image message limit: " + String(lineNotify.imageMessageLimit())); 105 | Serial.println("Image message remaining: " + String(lineNotify.imageMessageRemaining())); 106 | } 107 | else if (status == LineNotifyESP32::LineStatus::SENT_FAILED) 108 | Serial.println("Send image data from camera was failed!"); 109 | else if (status == LineNotifyESP32::LineStatus::CONNECTION_FAILED) 110 | Serial.println("Connection to LINE sevice faild!"); 111 | Serial.println(); 112 | } 113 | 114 | void loop() 115 | { 116 | } 117 | -------------------------------------------------------------------------------- /examples/Basic/image.h: -------------------------------------------------------------------------------- 1 | uint8_t dummyImageData[] = { 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x60, 2 | 0x00, 0x60, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x3E, 0x43, 0x52, 0x45, 0x41, 0x54, 0x4F, 0x52, 0x3A, 3 | 0x20, 0x67, 0x64, 0x2D, 0x6A, 0x70, 0x65, 0x67, 0x20, 0x76, 0x31, 0x2E, 0x30, 0x20, 0x28, 0x75, 4 | 0x73, 0x69, 0x6E, 0x67, 0x20, 0x49, 0x4A, 0x47, 0x20, 0x4A, 0x50, 0x45, 0x47, 0x20, 0x76, 0x38, 5 | 0x30, 0x29, 0x2C, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x20, 0x71, 0x75, 0x61, 0x6C, 6 | 0x69, 0x74, 0x79, 0x0A, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 7 | 0x07, 0x07, 0x07, 0x09, 0x09, 0x08, 0x0A, 0x0C, 0x14, 0x0D, 0x0C, 0x0B, 0x0B, 0x0C, 0x19, 0x12, 8 | 0x13, 0x0F, 0x14, 0x1D, 0x1A, 0x1F, 0x1E, 0x1D, 0x1A, 0x1C, 0x1C, 0x20, 0x24, 0x2E, 0x27, 0x20, 9 | 0x22, 0x2C, 0x23, 0x1C, 0x1C, 0x28, 0x37, 0x29, 0x2C, 0x30, 0x31, 0x34, 0x34, 0x34, 0x1F, 0x27, 10 | 0x39, 0x3D, 0x38, 0x32, 0x3C, 0x2E, 0x33, 0x34, 0x32, 0xFF, 0xDB, 0x00, 0x43, 0x01, 0x09, 0x09, 11 | 0x09, 0x0C, 0x0B, 0x0C, 0x18, 0x0D, 0x0D, 0x18, 0x32, 0x21, 0x1C, 0x21, 0x32, 0x32, 0x32, 0x32, 12 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 13 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 14 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0xFF, 0xC0, 15 | 0x00, 0x11, 0x08, 0x00, 0x14, 0x00, 0x14, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 16 | 0x01, 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 17 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 18 | 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 19 | 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 20 | 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 21 | 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 22 | 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 23 | 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 24 | 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 25 | 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 26 | 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 27 | 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 28 | 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 29 | 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00, 0x1F, 0x01, 0x00, 0x03, 30 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 31 | 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x11, 0x00, 32 | 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 33 | 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 34 | 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 35 | 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 36 | 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 37 | 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 38 | 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 39 | 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 40 | 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 41 | 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 42 | 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 43 | 0xFA, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00, 0xD6, 44 | 0xA2, 0xAD, 0x4D, 0x24, 0x4C, 0xB8, 0x5F, 0x2C, 0x65, 0x94, 0x80, 0x14, 0x8C, 0x70, 0x73, 0xCF, 45 | 0xD6, 0x98, 0x0C, 0x42, 0xE0, 0x14, 0x7D, 0x91, 0xE3, 0xAB, 0x8C, 0x9F, 0xE5, 0xD6, 0xBF, 0x37, 46 | 0x71, 0x57, 0xDC, 0xFC, 0x91, 0xC1, 0x5F, 0x72, 0x0A, 0x2A, 0xD3, 0xCA, 0x0B, 0x66, 0x37, 0x89, 47 | 0x17, 0x1F, 0x77, 0x67, 0x43, 0xDF, 0xB5, 0x14, 0x38, 0xAE, 0xE0, 0xE1, 0x15, 0xD7, 0xFA, 0xFB, 48 | 0xCA, 0xB4, 0x51, 0x45, 0x41, 0x98, 0x51, 0x45, 0x14, 0x01, 0xFF, 0xD9 49 | }; 50 | -------------------------------------------------------------------------------- /examples/Camera/src/sensor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the OpenMV project. 3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader 4 | * This work is licensed under the MIT license, see the file LICENSE for details. 5 | * 6 | * Sensor abstraction layer. 7 | * 8 | */ 9 | #ifndef __SENSOR_H__ 10 | #define __SENSOR_H__ 11 | #include 12 | 13 | #define OV9650_PID (0x96) 14 | #define OV2640_PID (0x26) 15 | #define OV7725_PID (0x77) 16 | 17 | 18 | typedef struct { 19 | uint8_t MIDH; 20 | uint8_t MIDL; 21 | uint8_t PID; 22 | uint8_t VER; 23 | } sensor_id_t; 24 | 25 | typedef enum { 26 | PIXFORMAT_RGB565, // 2BPP/RGB565 27 | PIXFORMAT_YUV422, // 2BPP/YUV422 28 | PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE 29 | PIXFORMAT_JPEG, // JPEG/COMPRESSED 30 | } pixformat_t; 31 | 32 | typedef enum { 33 | FRAMESIZE_40x30, // 40x30 34 | FRAMESIZE_64x32, // 64x32 35 | FRAMESIZE_64x64, // 64x64 36 | FRAMESIZE_QQCIF, // 88x72 37 | FRAMESIZE_QQVGA, // 160x120 38 | FRAMESIZE_QQVGA2, // 128x160 39 | FRAMESIZE_QCIF, // 176x144 40 | FRAMESIZE_HQVGA, // 220x160 41 | FRAMESIZE_QVGA, // 320x240 42 | FRAMESIZE_CIF, // 352x288 43 | FRAMESIZE_VGA, // 640x480 44 | FRAMESIZE_SVGA, // 800x600 45 | FRAMESIZE_SXGA, // 1280x1024 46 | FRAMESIZE_UXGA, // 1600x1200 47 | } framesize_t; 48 | 49 | typedef enum { 50 | FRAMERATE_2FPS =0x9F, 51 | FRAMERATE_8FPS =0x87, 52 | FRAMERATE_15FPS=0x83, 53 | FRAMERATE_30FPS=0x81, 54 | FRAMERATE_60FPS=0x80, 55 | } framerate_t; 56 | 57 | typedef enum { 58 | GAINCEILING_2X, 59 | GAINCEILING_4X, 60 | GAINCEILING_8X, 61 | GAINCEILING_16X, 62 | GAINCEILING_32X, 63 | GAINCEILING_64X, 64 | GAINCEILING_128X, 65 | } gainceiling_t; 66 | 67 | typedef enum { 68 | SDE_NORMAL, 69 | SDE_NEGATIVE, 70 | } sde_t; 71 | 72 | typedef enum { 73 | ATTR_CONTRAST=0, 74 | ATTR_BRIGHTNESS, 75 | ATTR_SATURATION, 76 | ATTR_GAINCEILING, 77 | } sensor_attr_t; 78 | 79 | typedef enum { 80 | ACTIVE_LOW, 81 | ACTIVE_HIGH 82 | } reset_polarity_t; 83 | 84 | typedef void (*line_filter_t) (uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, void *args); 85 | 86 | #define SENSOR_HW_FLAGS_VSYNC (0) // vertical sync polarity. 87 | #define SENSOR_HW_FLAGS_HSYNC (1) // horizontal sync polarity. 88 | #define SENSOR_HW_FLAGS_PIXCK (2) // pixel clock edge. 89 | #define SENSOR_HW_FLAGS_FSYNC (3) // hardware frame sync. 90 | #define SENSOR_HW_FLAGS_JPEGE (4) // hardware JPEG encoder. 91 | #define SENSOR_HW_FLAGS_GET(s, x) ((s)->hw_flags & (1<hw_flags |= (v<hw_flags &= ~(1< **Include Library** -> **Add .ZIP Library...** and choose **Line-Notify-ESP32-master.zip** that previously downloaded. 51 | 52 | Go to menu **Files** -> **Examples** -> **Line-Notify-ESP32-master** and choose one from examples 53 | 54 | 55 | 56 | ## Usages 57 | 58 | 59 | See [full examples](https://github.com/mobizt/Line-Notify-ESP32/tree/master/examples) for all features usages. 60 | 61 | 62 | 63 | ## All Supported Functions 64 | 65 | 66 | **The LINE Notify Service's credentials initialization.** 67 | 68 | param *`token`* - LINE Notify token String. 69 | 70 | ```C++ 71 | init(const String &token); 72 | ``` 73 | 74 | 75 | 76 | 77 | 78 | **Set the LINE Notify token.** 79 | 80 | param *`token`* - LINE Notify token string. 81 | 82 | ```C++ 83 | void setToken(const String &token); 84 | ``` 85 | 86 | 87 | 88 | 89 | **Send text message.** 90 | 91 | param *`client`* - SSL WiFi client from WiFiClientSecure initialization. 92 | 93 | param *`msg`* - The text message String to be send. 94 | 95 | return *`The LineStatus structed value`*, SENT_COMPLETED = 0, SENT_FAILED = 1, CONNECTION_FAILED = 2. 96 | 97 | ```C++ 98 | uint8_t sendLineMessage(HTTPClientESP32Ex &http, const String &msg); 99 | ``` 100 | 101 | 102 | 103 | 104 | **Send text message with sticker.** 105 | 106 | param *`client`* - SSL WiFi client from WiFiClientSecure initialization. 107 | 108 | param *`msg`* - The text message String to be send. 109 | 110 | param *`stickerPackageId`* - Sticker Package ID number to send, see https://devdocs.line.me/files/sticker_list.pdf for STKPKGID. 111 | 112 | param *`stickerId`* - Sticker ID number to send, see https://devdocs.line.me/files/sticker_list.pdf for STKID. 113 | 114 | return *`The LineStatus structed value`*, SENT_COMPLETED = 0, SENT_FAILED = 1, CONNECTION_FAILED = 2. 115 | 116 | ```C++ 117 | uint8_t sendLineSticker(HTTPClientESP32Ex &http, const String &msg, uint16_t stickerPackageId, uint16_t stickerId); 118 | ``` 119 | 120 | 121 | 122 | 123 | **Send Image message. The image data from flash memory or EEPROM** 124 | 125 | param *`client`* - SSL WiFi client from WiFiClientSecure initialization. 126 | 127 | param *`msg`* - The text message String to be send. 128 | 129 | param *`fileName`* - The user's specified file name String. 130 | 131 | param *`imageData`* - The byte data of image from memory or EEPROM. 132 | 133 | param *`imageLength`* - The byte length of image data. 134 | 135 | return *`The LineStatus structed value`*, SENT_COMPLETED = 0, SENT_FAILED = 1, CONNECTION_FAILED = 2. 136 | 137 | ```C++ 138 | uint8_t sendLineImageData(HTTPClientESP32Ex &http, const String &msg, const String &fileName, const uint8_t *imageData, size_t imageLength); 139 | ``` 140 | 141 | 142 | 143 | 144 | **Send Image message. The image data from web URL.** 145 | 146 | param *`client`* - SSL WiFi client from WiFiClientSecure initialization. 147 | 148 | param *`msg`* - The text message String to be send. 149 | 150 | param *`imageURL`* - The image URL String. 151 | 152 | return *`The LineStatus structed value`*, SENT_COMPLETED = 0, SENT_FAILED = 1, CONNECTION_FAILED = 2. 153 | 154 | ```C++ 155 | uint8_t sendLineImageURL(HTTPClientESP32Ex &http, const String &msg, const String &imageURL); 156 | ``` 157 | 158 | 159 | 160 | 161 | **Send Image message. The image data from SPI Flash File.** 162 | 163 | param *`client`* - SSL WiFi client from WiFiClientSecure initialization. 164 | 165 | param *`msg`* - The text message String to be send. 166 | 167 | param *`filePath`* - The image file name and path String inside SPIF. 168 | 169 | return *`The LineStatus structed value`*, SENT_COMPLETED = 0, SENT_FAILED = 1, CONNECTION_FAILED = 2. 170 | 171 | ```C++ 172 | uint8_t sendLineImageSPIF(HTTPClientESP32Ex &http, const String &msg, const String &filePath); 173 | ``` 174 | 175 | 176 | 177 | 178 | **Send Image message. The image data from SD card File.** 179 | 180 | param *`client`* - SSL WiFi client from WiFiClientSecure initialization. 181 | 182 | param *`msg`* - The text message String to be send. 183 | 184 | param *`filePath`* - The image file name and path String inside SD card. 185 | 186 | return *`The LineStatus structed value`*, SENT_COMPLETED = 0, SENT_FAILED = 1, CONNECTION_FAILED = 2. 187 | 188 | ```C++ 189 | uint8_t sendLineImageSD(HTTPClientESP32Ex &http, const String &msg, const String &filePath); 190 | ``` 191 | 192 | 193 | 194 | 195 | **Get the text message limit.** 196 | 197 | return *`The limit count of sending text message.`* 198 | 199 | ```C++ 200 | uint16_t textMessageLimit(void); 201 | ``` 202 | 203 | 204 | 205 | 206 | **Get the image message limit.** 207 | 208 | return *`The limit count of sending image message.`* 209 | 210 | ```C++ 211 | uint16_t imageMessageLimit(void); 212 | ``` 213 | 214 | 215 | 216 | 217 | **Get the remaining count of sending text message.** 218 | 219 | return *`The remaining count of sending text message.`* 220 | 221 | ```C++ 222 | uint16_t textMessageRemaining(void); 223 | ``` 224 | 225 | 226 | 227 | 228 | **Get the remaining count of sending image message.** 229 | 230 | return *`The remaining count of sending image message.`* 231 | 232 | ```C++ 233 | uint16_t imageMessageRemaining(void); 234 | ``` 235 | 236 | 237 | 238 | **End Line Notify.** 239 | 240 | ```C++ 241 | void end(void); 242 | ``` 243 | 244 | -------------------------------------------------------------------------------- /examples/Basic/Basic.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 1. Install HTTPClientESP32Ex library from https://github.com/mobizt/HTTPClientESP32Ex 4 | * 5 | * 2. Install the Arduino ESP32 filesystem uploader plugin in Arduino from 6 | * https://github.com/me-no-dev/arduino-esp32fs-plugin 7 | * 8 | * 3. From Arduino IDE, select Tools - > ESP32 Sketch Data Upload (Serial Monitor Window need to be close) 9 | * This will upload sewing.jpg in data folder inside Basic examples folder to device and use in 10 | * lineNotify.sendLineImageSPIF(client,"This image from device", "/sewing.jpg"); 11 | * 12 | * 4. Change the WIFI_SSID, WIFI_PASSWORD and LINE_TOKEN in sketch. 13 | * 14 | * 4. Compile and upload sketch 15 | * 16 | */ 17 | 18 | #include 19 | #include "FS.h" 20 | #include "SPIFFS.h" 21 | #include "SD.h" 22 | #include "LineNotifyESP32.h" 23 | 24 | //Demo image data 25 | #include "image.h" 26 | 27 | #define WIFI_SSID "YOUR_WIFI_AP" 28 | #define WIFI_PASSWORD "YOUR_WIFI_PASSWORD" 29 | #define LINE_TOKEN "YOUR_LINE_NOTIFY_TOKEN" 30 | 31 | HTTPClientESP32Ex http; 32 | 33 | bool sdOK = false; 34 | 35 | void setup() 36 | { 37 | 38 | Serial.begin(115200); 39 | 40 | WiFi.begin(WIFI_SSID, WIFI_PASSWORD); 41 | while (WiFi.status() != WL_CONNECTED) 42 | { 43 | Serial.print("."); 44 | delay(200); 45 | } 46 | Serial.println(""); 47 | Serial.println("WiFi connected."); 48 | Serial.println("IP address: "); 49 | Serial.println(WiFi.localIP()); 50 | 51 | //Write demo image to SD card 52 | 53 | if (SD.begin()) 54 | { 55 | sdOK = true; 56 | 57 | File file = SD.open("/test.jpg", FILE_WRITE); 58 | 59 | int len = sizeof(dummyImageData); 60 | int pos = 0; 61 | 62 | while (len) 63 | { 64 | size_t toWrite = len; 65 | if (toWrite > 512) 66 | { 67 | toWrite = 512; 68 | } 69 | file.write(dummyImageData + pos, toWrite); 70 | len -= toWrite; 71 | pos += toWrite; 72 | } 73 | 74 | file.close(); 75 | } 76 | 77 | //Init Line notify with token 78 | lineNotify.init(LINE_TOKEN); 79 | 80 | uint8_t status; 81 | 82 | status = lineNotify.sendLineMessage(http, "Hello!"); 83 | if (status == LineNotifyESP32::LineStatus::SENT_COMPLETED) 84 | { 85 | Serial.println("Send text message completed"); 86 | Serial.println("Text message limit: " + String(lineNotify.textMessageLimit())); 87 | Serial.println("Text message remaining: " + String(lineNotify.textMessageRemaining())); 88 | Serial.println("Image message limit: " + String(lineNotify.imageMessageLimit())); 89 | Serial.println("Image message remaining: " + String(lineNotify.imageMessageRemaining())); 90 | } 91 | else if (status == LineNotifyESP32::LineStatus::SENT_FAILED) 92 | Serial.println("Send text message was failed!"); 93 | else if (status == LineNotifyESP32::LineStatus::CONNECTION_FAILED) 94 | Serial.println("Connection to LINE sevice faild!"); 95 | Serial.println(); 96 | 97 | status = lineNotify.sendLineImageData(http, "This is the image from memory", "image.jpg", dummyImageData, sizeof(dummyImageData)); 98 | if (status == LineNotifyESP32::LineStatus::SENT_COMPLETED) 99 | { 100 | Serial.println("send image data completed"); 101 | Serial.println("Text message limit: " + String(lineNotify.textMessageLimit())); 102 | Serial.println("Text message remaining: " + String(lineNotify.textMessageRemaining())); 103 | Serial.println("Image message limit: " + String(lineNotify.imageMessageLimit())); 104 | Serial.println("Image message remaining: " + String(lineNotify.imageMessageRemaining())); 105 | } 106 | else if (status == LineNotifyESP32::LineStatus::SENT_FAILED) 107 | Serial.println("Send image data was failed!"); 108 | else if (status == LineNotifyESP32::LineStatus::CONNECTION_FAILED) 109 | Serial.println("Connection to LINE sevice faild!"); 110 | Serial.println(); 111 | 112 | status = lineNotify.sendLineSticker(http, "Goodbye", 2, 157); 113 | if (status == LineNotifyESP32::LineStatus::SENT_COMPLETED) 114 | { 115 | Serial.println("Send sticker completed"); 116 | Serial.println("Text message limit: " + String(lineNotify.textMessageLimit())); 117 | Serial.println("Text message remaining: " + String(lineNotify.textMessageRemaining())); 118 | Serial.println("Image message limit: " + String(lineNotify.imageMessageLimit())); 119 | Serial.println("Image message remaining: " + String(lineNotify.imageMessageRemaining())); 120 | } 121 | else if (status == LineNotifyESP32::LineStatus::SENT_FAILED) 122 | Serial.println("Send sticker was failed!"); 123 | else if (status == LineNotifyESP32::LineStatus::CONNECTION_FAILED) 124 | Serial.println("Connection to LINE sevice faild!"); 125 | Serial.println(); 126 | 127 | status = lineNotify.sendLineImageURL(http, "This is image I found on web.", "https://cdn.pixabay.com/photo/2017/05/17/18/35/sewing-2321532_640.jpg"); 128 | if (status == LineNotifyESP32::LineStatus::SENT_COMPLETED) 129 | { 130 | Serial.println("Send image URL completed"); 131 | Serial.println("Text message limit: " + String(lineNotify.textMessageLimit())); 132 | Serial.println("Text message remaining: " + String(lineNotify.textMessageRemaining())); 133 | Serial.println("Image message limit: " + String(lineNotify.imageMessageLimit())); 134 | Serial.println("Image message remaining: " + String(lineNotify.imageMessageRemaining())); 135 | } 136 | else if (status == LineNotifyESP32::LineStatus::SENT_FAILED) 137 | Serial.println("Send image URL failed!"); 138 | else if (status == LineNotifyESP32::LineStatus::CONNECTION_FAILED) 139 | Serial.println("Connection to LINE sevice faild!"); 140 | Serial.println(); 141 | 142 | status = lineNotify.sendLineImageSPIF(http, "This image from device", "/sewing.jpg"); 143 | if (status == LineNotifyESP32::LineStatus::SENT_COMPLETED) 144 | { 145 | Serial.println("Send image from SPIFS file completed"); 146 | Serial.println("Text message limit: " + String(lineNotify.textMessageLimit())); 147 | Serial.println("Text message remaining: " + String(lineNotify.textMessageRemaining())); 148 | Serial.println("Image message limit: " + String(lineNotify.imageMessageLimit())); 149 | Serial.println("Image message remaining: " + String(lineNotify.imageMessageRemaining())); 150 | } 151 | else if (status == LineNotifyESP32::LineStatus::SENT_FAILED) 152 | Serial.println("Send image from SPIFS was failed!"); 153 | else if (status == LineNotifyESP32::LineStatus::CONNECTION_FAILED) 154 | Serial.println("Connection to LINE sevice faild!"); 155 | Serial.println(); 156 | 157 | if (sdOK) 158 | { 159 | status = lineNotify.sendLineImageSD(http, "This image from SD card", "/test.jpg"); 160 | if (status == LineNotifyESP32::LineStatus::SENT_COMPLETED) 161 | { 162 | Serial.println("Send image from SD card completed"); 163 | Serial.println("Text message limit: " + String(lineNotify.textMessageLimit())); 164 | Serial.println("Text message remaining: " + String(lineNotify.textMessageRemaining())); 165 | Serial.println("Image message limit: " + String(lineNotify.imageMessageLimit())); 166 | Serial.println("Image message remaining: " + String(lineNotify.imageMessageRemaining())); 167 | } 168 | else if (status == LineNotifyESP32::LineStatus::SENT_FAILED) 169 | Serial.println("Send image from SD card was failed!"); 170 | else if (status == LineNotifyESP32::LineStatus::CONNECTION_FAILED) 171 | Serial.println("Connection to LINE sevice faild!"); 172 | Serial.println(); 173 | } 174 | } 175 | 176 | void loop() 177 | { 178 | } 179 | -------------------------------------------------------------------------------- /examples/Camera/src/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 QS 0x44 12 | #define HSIZE 0x51 13 | #define VSIZE 0x52 14 | #define XOFFL 0x53 15 | #define YOFFL 0x54 16 | #define VHYX 0x55 17 | #define DPRP 0x56 18 | #define TEST 0x57 19 | #define ZMOW 0x5A 20 | #define ZMOH 0x5B 21 | #define ZMHH 0x5C 22 | #define BPADDR 0x7C 23 | #define BPDATA 0x7D 24 | #define SIZEL 0x8C 25 | #define HSIZE8 0xC0 26 | #define VSIZE8 0xC1 27 | #define CTRL1 0xC3 28 | #define MS_SP 0xF0 29 | #define SS_ID 0xF7 30 | #define SS_CTRL 0xF7 31 | #define MC_AL 0xFA 32 | #define MC_AH 0xFB 33 | #define MC_D 0xFC 34 | #define P_CMD 0xFD 35 | #define P_STATUS 0xFE 36 | 37 | #define CTRLI 0x50 38 | #define CTRLI_LP_DP 0x80 39 | #define CTRLI_ROUND 0x40 40 | 41 | #define CTRL0 0xC2 42 | #define CTRL0_AEC_EN 0x80 43 | #define CTRL0_AEC_SEL 0x40 44 | #define CTRL0_STAT_SEL 0x20 45 | #define CTRL0_VFIRST 0x10 46 | #define CTRL0_YUV422 0x08 47 | #define CTRL0_YUV_EN 0x04 48 | #define CTRL0_RGB_EN 0x02 49 | #define CTRL0_RAW_EN 0x01 50 | 51 | #define CTRL2 0x86 52 | #define CTRL2_DCW_EN 0x20 53 | #define CTRL2_SDE_EN 0x10 54 | #define CTRL2_UV_ADJ_EN 0x08 55 | #define CTRL2_UV_AVG_EN 0x04 56 | #define CTRL2_CMX_EN 0x01 57 | 58 | #define CTRL3 0x87 59 | #define CTRL3_BPC_EN 0x80 60 | #define CTRL3_WPC_EN 0x40 61 | #define R_DVP_SP 0xD3 62 | #define R_DVP_SP_AUTO_MODE 0x80 63 | 64 | #define R_BYPASS 0x05 65 | #define R_BYPASS_DSP_EN 0x00 66 | #define R_BYPASS_DSP_BYPAS 0x01 67 | 68 | #define IMAGE_MODE 0xDA 69 | #define IMAGE_MODE_Y8_DVP_EN 0x40 70 | #define IMAGE_MODE_JPEG_EN 0x10 71 | #define IMAGE_MODE_YUV422 0x00 72 | #define IMAGE_MODE_RAW10 0x04 73 | #define IMAGE_MODE_RGB565 0x08 74 | #define IMAGE_MODE_HREF_VSYNC 0x02 75 | #define IMAGE_MODE_LBYTE_FIRST 0x01 76 | 77 | #define RESET 0xE0 78 | #define RESET_MICROC 0x40 79 | #define RESET_SCCB 0x20 80 | #define RESET_JPEG 0x10 81 | #define RESET_DVP 0x04 82 | #define RESET_IPU 0x02 83 | #define RESET_CIF 0x01 84 | 85 | #define MC_BIST 0xF9 86 | #define MC_BIST_RESET 0x80 87 | #define MC_BIST_BOOT_ROM_SEL 0x40 88 | #define MC_BIST_12KB_SEL 0x20 89 | #define MC_BIST_12KB_MASK 0x30 90 | #define MC_BIST_512KB_SEL 0x08 91 | #define MC_BIST_512KB_MASK 0x0C 92 | #define MC_BIST_BUSY_BIT_R 0x02 93 | #define MC_BIST_MC_RES_ONE_SH_W 0x02 94 | #define MC_BIST_LAUNCH 0x01 95 | 96 | #define BANK_SEL 0xFF 97 | #define BANK_SEL_DSP 0x00 98 | #define BANK_SEL_SENSOR 0x01 99 | 100 | /* Sensor register bank FF=0x01*/ 101 | #define GAIN 0x00 102 | #define COM1 0x03 103 | #define REG_PID 0x0A 104 | #define REG_VER 0x0B 105 | #define COM4 0x0D 106 | #define AEC 0x10 107 | #define CLKRC 0x11 108 | #define COM10 0x15 109 | #define HSTART 0x17 110 | #define HSTOP 0x18 111 | #define VSTART 0x19 112 | #define VSTOP 0x1A 113 | #define MIDH 0x1C 114 | #define MIDL 0x1D 115 | #define AEW 0x24 116 | #define AEB 0x25 117 | #define REG2A 0x2A 118 | #define FRARL 0x2B 119 | #define ADDVSL 0x2D 120 | #define ADDVSH 0x2E 121 | #define YAVG 0x2F 122 | #define HSDY 0x30 123 | #define HEDY 0x31 124 | #define ARCOM2 0x34 125 | #define REG45 0x45 126 | #define FLL 0x46 127 | #define FLH 0x47 128 | #define COM19 0x48 129 | #define ZOOMS 0x49 130 | #define COM22 0x4B 131 | #define COM25 0x4E 132 | #define BD50 0x4F 133 | #define BD60 0x50 134 | #define REG5D 0x5D 135 | #define REG5E 0x5E 136 | #define REG5F 0x5F 137 | #define REG60 0x60 138 | #define HISTO_LOW 0x61 139 | #define HISTO_HIGH 0x62 140 | 141 | #define REG04 0x04 142 | #define REG04_DEFAULT 0x28 143 | #define REG04_VFLIP_IMG 0x40 144 | #define REG04_HFLIP_IMG 0x80 145 | #define REG04_VREF_EN 0x10 146 | #define REG04_HREF_EN 0x08 147 | #define REG04_SET(x) (REG04_DEFAULT|x) 148 | 149 | #define REG08 0x08 150 | #define COM2 0x09 151 | #define COM2_STDBY 0x10 152 | #define COM2_OUT_DRIVE_1x 0x00 153 | #define COM2_OUT_DRIVE_2x 0x01 154 | #define COM2_OUT_DRIVE_3x 0x02 155 | #define COM2_OUT_DRIVE_4x 0x03 156 | 157 | #define COM3 0x0C 158 | #define COM3_DEFAULT 0x38 159 | #define COM3_BAND_50Hz 0x04 160 | #define COM3_BAND_60Hz 0x00 161 | #define COM3_BAND_AUTO 0x02 162 | #define COM3_BAND_SET(x) (COM3_DEFAULT|x) 163 | 164 | #define COM7 0x12 165 | #define COM7_SRST 0x80 166 | #define COM7_RES_UXGA 0x00 /* UXGA */ 167 | #define COM7_RES_SVGA 0x40 /* SVGA */ 168 | #define COM7_RES_CIF 0x20 /* CIF */ 169 | #define COM7_ZOOM_EN 0x04 /* Enable Zoom */ 170 | #define COM7_COLOR_BAR 0x02 /* Enable Color Bar Test */ 171 | 172 | #define COM8 0x13 173 | #define COM8_DEFAULT 0xC0 174 | #define COM8_BNDF_EN 0x20 /* Enable Banding filter */ 175 | #define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */ 176 | #define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */ 177 | #define COM8_SET(x) (COM8_DEFAULT|x) 178 | 179 | #define COM9 0x14 /* AGC gain ceiling */ 180 | #define COM9_DEFAULT 0x08 181 | #define COM9_AGC_GAIN_2x 0x00 /* AGC: 2x */ 182 | #define COM9_AGC_GAIN_4x 0x01 /* AGC: 4x */ 183 | #define COM9_AGC_GAIN_8x 0x02 /* AGC: 8x */ 184 | #define COM9_AGC_GAIN_16x 0x03 /* AGC: 16x */ 185 | #define COM9_AGC_GAIN_32x 0x04 /* AGC: 32x */ 186 | #define COM9_AGC_GAIN_64x 0x05 /* AGC: 64x */ 187 | #define COM9_AGC_GAIN_128x 0x06 /* AGC: 128x */ 188 | #define COM9_AGC_SET(x) (COM9_DEFAULT|(x<<5)) 189 | 190 | #define COM10 0x15 191 | #define COM10_HREF_EN 0x80 /* HSYNC changes to HREF */ 192 | #define COM10_HSYNC_EN 0x40 /* HREF changes to HSYNC */ 193 | #define COM10_PCLK_FREE 0x20 /* PCLK output option: free running PCLK */ 194 | #define COM10_PCLK_EDGE 0x10 /* Data is updated at the rising edge of PCLK */ 195 | #define COM10_HREF_NEG 0x08 /* HREF negative */ 196 | #define COM10_VSYNC_NEG 0x02 /* VSYNC negative */ 197 | #define COM10_HSYNC_NEG 0x01 /* HSYNC negative */ 198 | 199 | #define CTRL1_AWB 0x08 /* Enable AWB */ 200 | 201 | #define VV 0x26 202 | #define VV_AGC_TH_SET(h,l) ((h<<4)|(l&0x0F)) 203 | 204 | #define REG32 0x32 205 | #define REG32_UXGA 0x36 206 | #define REG32_SVGA 0x09 207 | #define REG32_CIF 0x00 208 | #endif //__REG_REGS_H__ 209 | -------------------------------------------------------------------------------- /examples/Camera/src/twi.c: -------------------------------------------------------------------------------- 1 | /* 2 | si2c.c - Software I2C library for ESP31B 3 | 4 | Copyright (c) 2015 Hristo Gochkov. All rights reserved. 5 | This file is part of the ESP31B core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #include 22 | #include 23 | #include "twi.h" 24 | #include "soc/gpio_reg.h" 25 | #include 26 | #include "esp32-hal-gpio.h" 27 | 28 | unsigned char twi_dcount = 18; 29 | static unsigned char twi_sda, twi_scl; 30 | 31 | static inline void SDA_LOW() 32 | { 33 | //Enable SDA (becomes output and since GPO is 0 for the pin, 34 | // it will pull the line low) 35 | if (twi_sda < 32) 36 | { 37 | REG_WRITE(GPIO_ENABLE_W1TS_REG, BIT(twi_sda)); 38 | } 39 | else 40 | { 41 | REG_WRITE(GPIO_ENABLE1_W1TS_REG, BIT(twi_sda - 32)); 42 | } 43 | } 44 | 45 | static inline void SDA_HIGH() 46 | { 47 | //Disable SDA (becomes input and since it has pullup it will go high) 48 | if (twi_sda < 32) 49 | { 50 | REG_WRITE(GPIO_ENABLE_W1TC_REG, BIT(twi_sda)); 51 | } 52 | else 53 | { 54 | REG_WRITE(GPIO_ENABLE1_W1TC_REG, BIT(twi_sda - 32)); 55 | } 56 | } 57 | 58 | static inline uint32_t SDA_READ() 59 | { 60 | if (twi_sda < 32) 61 | { 62 | return (REG_READ(GPIO_IN_REG) & BIT(twi_sda)) != 0; 63 | } 64 | else 65 | { 66 | return (REG_READ(GPIO_IN1_REG) & BIT(twi_sda - 32)) != 0; 67 | } 68 | } 69 | 70 | static void SCL_LOW() 71 | { 72 | if (twi_scl < 32) 73 | { 74 | REG_WRITE(GPIO_ENABLE_W1TS_REG, BIT(twi_scl)); 75 | } 76 | else 77 | { 78 | REG_WRITE(GPIO_ENABLE1_W1TS_REG, BIT(twi_scl - 32)); 79 | } 80 | } 81 | 82 | static void SCL_HIGH() 83 | { 84 | if (twi_scl < 32) 85 | { 86 | REG_WRITE(GPIO_ENABLE_W1TC_REG, BIT(twi_scl)); 87 | } 88 | else 89 | { 90 | REG_WRITE(GPIO_ENABLE1_W1TC_REG, BIT(twi_scl - 32)); 91 | } 92 | } 93 | 94 | static uint32_t SCL_READ() 95 | { 96 | if (twi_scl < 32) 97 | { 98 | return (REG_READ(GPIO_IN_REG) & BIT(twi_scl)) != 0; 99 | } 100 | else 101 | { 102 | return (REG_READ(GPIO_IN1_REG) & BIT(twi_scl - 32)) != 0; 103 | } 104 | } 105 | 106 | #ifndef FCPU80 107 | #define FCPU80 80000000L 108 | #endif 109 | 110 | #if F_CPU == FCPU80 111 | #define TWI_CLOCK_STRETCH 800 112 | #else 113 | #define TWI_CLOCK_STRETCH 1600 114 | #endif 115 | 116 | void twi_setClock(unsigned int freq) 117 | { 118 | #if F_CPU == FCPU80 119 | if (freq <= 100000) 120 | twi_dcount = 19; //about 100KHz 121 | else if (freq <= 200000) 122 | twi_dcount = 8; //about 200KHz 123 | else if (freq <= 300000) 124 | twi_dcount = 3; //about 300KHz 125 | else if (freq <= 400000) 126 | twi_dcount = 1; //about 400KHz 127 | else 128 | twi_dcount = 1; //about 400KHz 129 | #else 130 | if (freq <= 100000) 131 | twi_dcount = 32; //about 100KHz 132 | else if (freq <= 200000) 133 | twi_dcount = 14; //about 200KHz 134 | else if (freq <= 300000) 135 | twi_dcount = 8; //about 300KHz 136 | else if (freq <= 400000) 137 | twi_dcount = 5; //about 400KHz 138 | else if (freq <= 500000) 139 | twi_dcount = 3; //about 500KHz 140 | else if (freq <= 600000) 141 | twi_dcount = 2; //about 600KHz 142 | else 143 | twi_dcount = 1; //about 700KHz 144 | #endif 145 | } 146 | 147 | void i2c_pinMode(int pin, int mode) 148 | { 149 | gpio_config_t conf = {0}; 150 | conf.pin_bit_mask = 1LL << pin; 151 | if (mode == OUTPUT) 152 | { 153 | conf.mode = GPIO_MODE_OUTPUT; 154 | } 155 | if (mode == INPUT || mode == INPUT_PULLUP) 156 | { 157 | conf.mode = GPIO_MODE_INPUT; 158 | } 159 | if (mode == INPUT) 160 | { 161 | conf.pull_down_en = GPIO_PULLDOWN_DISABLE; 162 | conf.pull_up_en = GPIO_PULLUP_DISABLE; 163 | } 164 | else if (mode == INPUT_PULLUP) 165 | { 166 | conf.pull_down_en = GPIO_PULLDOWN_DISABLE; 167 | conf.pull_up_en = GPIO_PULLUP_ENABLE; 168 | } 169 | gpio_config(&conf); 170 | } 171 | 172 | void twi_init(unsigned char sda, unsigned char scl) 173 | { 174 | twi_sda = sda; 175 | twi_scl = scl; 176 | i2c_pinMode(twi_sda, OUTPUT); 177 | i2c_pinMode(twi_scl, OUTPUT); 178 | 179 | gpio_set_level(twi_sda, 0); 180 | gpio_set_level(twi_scl, 0); 181 | 182 | i2c_pinMode(twi_sda, INPUT_PULLUP); 183 | i2c_pinMode(twi_scl, INPUT_PULLUP); 184 | twi_setClock(100000); 185 | } 186 | 187 | void twi_stop(void) 188 | { 189 | i2c_pinMode(twi_sda, INPUT); 190 | i2c_pinMode(twi_scl, INPUT); 191 | } 192 | 193 | static void twi_delay(unsigned char v) 194 | { 195 | unsigned int i; 196 | #pragma GCC diagnostic push 197 | #pragma GCC diagnostic ignored "-Wunused-but-set-variable" 198 | unsigned int reg; 199 | for (i = 0; i < v; i++) 200 | reg = REG_READ(GPIO_IN_REG); 201 | #pragma GCC diagnostic pop 202 | } 203 | 204 | static bool twi_write_start(void) 205 | { 206 | SCL_HIGH(); 207 | SDA_HIGH(); 208 | if (SDA_READ() == 0) 209 | return false; 210 | twi_delay(twi_dcount); 211 | SDA_LOW(); 212 | twi_delay(twi_dcount); 213 | return true; 214 | } 215 | 216 | static bool twi_write_stop(void) 217 | { 218 | unsigned int i = 0; 219 | SCL_LOW(); 220 | SDA_LOW(); 221 | twi_delay(twi_dcount); 222 | SCL_HIGH(); 223 | while (SCL_READ() == 0 && (i++) < TWI_CLOCK_STRETCH) 224 | ; // Clock stretching (up to 100us) 225 | twi_delay(twi_dcount); 226 | SDA_HIGH(); 227 | twi_delay(twi_dcount); 228 | 229 | return true; 230 | } 231 | 232 | bool do_log = false; 233 | static bool twi_write_bit(bool bit) 234 | { 235 | unsigned int i = 0; 236 | SCL_LOW(); 237 | if (bit) 238 | { 239 | SDA_HIGH(); 240 | if (do_log) 241 | { 242 | twi_delay(twi_dcount + 1); 243 | } 244 | } 245 | else 246 | { 247 | SDA_LOW(); 248 | if (do_log) 249 | { 250 | } 251 | } 252 | twi_delay(twi_dcount + 1); 253 | SCL_HIGH(); 254 | while (SCL_READ() == 0 && (i++) < TWI_CLOCK_STRETCH) 255 | ; // Clock stretching (up to 100us) 256 | twi_delay(twi_dcount); 257 | return true; 258 | } 259 | 260 | static bool twi_read_bit(void) 261 | { 262 | unsigned int i = 0; 263 | SCL_LOW(); 264 | SDA_HIGH(); 265 | twi_delay(twi_dcount + 2); 266 | SCL_HIGH(); 267 | while (SCL_READ() == 0 && (i++) < TWI_CLOCK_STRETCH) 268 | ; // Clock stretching (up to 100us) 269 | bool bit = SDA_READ(); 270 | twi_delay(twi_dcount); 271 | return bit; 272 | } 273 | 274 | static bool twi_write_byte(unsigned char byte) 275 | { 276 | 277 | if (byte == 0x43) 278 | { 279 | // printf("TWB %02x ", (uint32_t) byte); 280 | // do_log = true; 281 | } 282 | unsigned char bit; 283 | for (bit = 0; bit < 8; bit++) 284 | { 285 | twi_write_bit((byte & 0x80) != 0); 286 | byte <<= 1; 287 | } 288 | if (do_log) 289 | { 290 | printf("\n"); 291 | do_log = false; 292 | } 293 | return !twi_read_bit(); //NACK/ACK 294 | } 295 | 296 | static unsigned char twi_read_byte(bool nack) 297 | { 298 | unsigned char byte = 0; 299 | unsigned char bit; 300 | for (bit = 0; bit < 8; bit++) 301 | byte = (byte << 1) | twi_read_bit(); 302 | twi_write_bit(nack); 303 | return byte; 304 | } 305 | 306 | unsigned char twi_writeTo(unsigned char address, unsigned char *buf, unsigned int len, unsigned char sendStop) 307 | { 308 | unsigned int i; 309 | if (!twi_write_start()) 310 | return 4; //line busy 311 | if (!twi_write_byte(((address << 1) | 0) & 0xFF)) 312 | { 313 | if (sendStop) 314 | twi_write_stop(); 315 | return 2; //received NACK on transmit of address 316 | } 317 | for (i = 0; i < len; i++) 318 | { 319 | if (!twi_write_byte(buf[i])) 320 | { 321 | if (sendStop) 322 | twi_write_stop(); 323 | return 3; //received NACK on transmit of data 324 | } 325 | } 326 | if (sendStop) 327 | twi_write_stop(); 328 | i = 0; 329 | while (SDA_READ() == 0 && (i++) < 10) 330 | { 331 | SCL_LOW(); 332 | twi_delay(twi_dcount); 333 | SCL_HIGH(); 334 | twi_delay(twi_dcount); 335 | } 336 | return 0; 337 | } 338 | 339 | unsigned char twi_readFrom(unsigned char address, unsigned char *buf, unsigned int len, unsigned char sendStop) 340 | { 341 | unsigned int i; 342 | if (!twi_write_start()) 343 | return 4; //line busy 344 | if (!twi_write_byte(((address << 1) | 1) & 0xFF)) 345 | { 346 | if (sendStop) 347 | twi_write_stop(); 348 | return 2; //received NACK on transmit of address 349 | } 350 | for (i = 0; i < (len - 1); i++) 351 | buf[i] = twi_read_byte(false); 352 | buf[len - 1] = twi_read_byte(true); 353 | if (sendStop) 354 | twi_write_stop(); 355 | i = 0; 356 | while (SDA_READ() == 0 && (i++) < 10) 357 | { 358 | SCL_LOW(); 359 | twi_delay(twi_dcount); 360 | SCL_HIGH(); 361 | twi_delay(twi_dcount); 362 | } 363 | return 0; 364 | } 365 | -------------------------------------------------------------------------------- /examples/Camera/src/ov7725.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the OpenMV project. 3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader 4 | * This work is licensed under the MIT license, see the file LICENSE for details. 5 | * 6 | * OV7725 driver. 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include "sccb.h" 13 | #include "ov7725.h" 14 | #include "ov7725_regs.h" 15 | #include 16 | 17 | static const uint8_t default_regs[][2] = { 18 | {COM3, COM3_SWAP_YUV}, 19 | {COM7, COM7_RES_QVGA | COM7_FMT_YUV}, 20 | 21 | {COM4, 0x01}, /* bypass PLL */ 22 | {CLKRC, 0xC0}, /* Res/Bypass pre-scalar */ 23 | 24 | // QVGA Window Size 25 | {HSTART, 0x3F}, 26 | {HSIZE, 0x50}, 27 | {VSTART, 0x03}, 28 | {VSIZE, 0x78}, 29 | {HREF, 0x00}, 30 | 31 | // Scale down to QVGA Resolution 32 | {HOUTSIZE, 0x50}, 33 | {VOUTSIZE, 0x78}, 34 | 35 | {COM12, 0x03}, 36 | {EXHCH, 0x00}, 37 | {TGT_B, 0x7F}, 38 | {FIXGAIN, 0x09}, 39 | {AWB_CTRL0, 0xE0}, 40 | {DSP_CTRL1, 0xFF}, 41 | 42 | {DSP_CTRL2, DSP_CTRL2_VDCW_EN | DSP_CTRL2_HDCW_EN | DSP_CTRL2_HZOOM_EN | DSP_CTRL2_VZOOM_EN}, 43 | 44 | {DSP_CTRL3, 0x00}, 45 | {DSP_CTRL4, 0x00}, 46 | {DSPAUTO, 0xFF}, 47 | 48 | {COM8, 0xF0}, 49 | {COM6, 0xC5}, 50 | {COM9, 0x11}, 51 | {COM10, COM10_VSYNC_NEG | COM10_PCLK_MASK}, //Invert VSYNC and MASK PCLK 52 | {BDBASE, 0x7F}, 53 | {DBSTEP, 0x03}, 54 | {AEW, 0x96}, 55 | {AEB, 0x64}, 56 | {VPT, 0xA1}, 57 | {EXHCL, 0x00}, 58 | {AWB_CTRL3, 0xAA}, 59 | {COM8, 0xFF}, 60 | 61 | //Gamma 62 | {GAM1, 0x0C}, 63 | {GAM2, 0x16}, 64 | {GAM3, 0x2A}, 65 | {GAM4, 0x4E}, 66 | {GAM5, 0x61}, 67 | {GAM6, 0x6F}, 68 | {GAM7, 0x7B}, 69 | {GAM8, 0x86}, 70 | {GAM9, 0x8E}, 71 | {GAM10, 0x97}, 72 | {GAM11, 0xA4}, 73 | {GAM12, 0xAF}, 74 | {GAM13, 0xC5}, 75 | {GAM14, 0xD7}, 76 | {GAM15, 0xE8}, 77 | 78 | {SLOP, 0x20}, 79 | {EDGE1, 0x05}, 80 | {EDGE2, 0x03}, 81 | {EDGE3, 0x00}, 82 | {DNSOFF, 0x01}, 83 | 84 | {MTX1, 0xB0}, 85 | {MTX2, 0x9D}, 86 | {MTX3, 0x13}, 87 | {MTX4, 0x16}, 88 | {MTX5, 0x7B}, 89 | {MTX6, 0x91}, 90 | {MTX_CTRL, 0x1E}, 91 | 92 | {BRIGHTNESS, 0x08}, 93 | {CONTRAST, 0x30}, 94 | {UVADJ0, 0x81}, 95 | {SDE, (SDE_CONT_BRIGHT_EN | SDE_SATURATION_EN)}, 96 | 97 | // For 30 fps/60Hz 98 | {DM_LNL, 0x00}, 99 | {DM_LNH, 0x00}, 100 | {BDBASE, 0x7F}, 101 | {DBSTEP, 0x03}, 102 | 103 | // Lens Correction, should be tuned with real camera module 104 | {LC_RADI, 0x10}, 105 | {LC_COEF, 0x10}, 106 | {LC_COEFB, 0x14}, 107 | {LC_COEFR, 0x17}, 108 | {LC_CTR, 0x05}, 109 | {COM5, 0xF5}, //0x65 110 | 111 | {0x00, 0x00}, 112 | }; 113 | 114 | 115 | static int reset(sensor_t *sensor) 116 | { 117 | int i=0; 118 | const uint8_t (*regs)[2]; 119 | 120 | // Reset all registers 121 | SCCB_Write(sensor->slv_addr, COM7, COM7_RESET); 122 | 123 | // Delay 10 ms 124 | systick_sleep(10); 125 | 126 | // Write default regsiters 127 | for (i=0, regs = default_regs; regs[i][0]; i++) { 128 | SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); 129 | } 130 | 131 | // Delay 132 | systick_sleep(30); 133 | 134 | return 0; 135 | } 136 | 137 | 138 | static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) 139 | { 140 | int ret=0; 141 | // Read register COM7 142 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM7); 143 | 144 | switch (pixformat) { 145 | case PIXFORMAT_RGB565: 146 | reg = COM7_SET_FMT(reg, COM7_FMT_RGB) | COM7_FMT_RGB565; 147 | break; 148 | case PIXFORMAT_YUV422: 149 | case PIXFORMAT_GRAYSCALE: 150 | reg = COM7_SET_FMT(reg, COM7_FMT_YUV); 151 | break; 152 | default: 153 | return -1; 154 | } 155 | 156 | // Write back register COM7 157 | ret = SCCB_Write(sensor->slv_addr, COM7, reg); 158 | 159 | // Delay 160 | systick_sleep(30); 161 | 162 | return ret; 163 | } 164 | 165 | static int set_framesize(sensor_t *sensor, framesize_t framesize) 166 | { 167 | int ret=0; 168 | uint16_t w = resolution[framesize][0]; 169 | uint16_t h = resolution[framesize][1]; 170 | 171 | // Write MSBs 172 | ret |= SCCB_Write(sensor->slv_addr, HOUTSIZE, w>>2); 173 | ret |= SCCB_Write(sensor->slv_addr, VOUTSIZE, h>>1); 174 | 175 | // Write LSBs 176 | ret |= SCCB_Write(sensor->slv_addr, EXHCH, ((w&0x3) | ((h&0x1) << 2))); 177 | 178 | if (framesize < FRAMESIZE_VGA) { 179 | // Enable auto-scaling/zooming factors 180 | ret |= SCCB_Write(sensor->slv_addr, DSPAUTO, 0xFF); 181 | } else { 182 | // Disable auto-scaling/zooming factors 183 | ret |= SCCB_Write(sensor->slv_addr, DSPAUTO, 0xF3); 184 | 185 | // Clear auto-scaling/zooming factors 186 | ret |= SCCB_Write(sensor->slv_addr, SCAL0, 0x00); 187 | ret |= SCCB_Write(sensor->slv_addr, SCAL1, 0x00); 188 | ret |= SCCB_Write(sensor->slv_addr, SCAL2, 0x00); 189 | } 190 | 191 | // Delay 192 | systick_sleep(30); 193 | 194 | if (ret == 0) { 195 | sensor->framesize = framesize; 196 | } 197 | 198 | return ret; 199 | } 200 | 201 | static int set_colorbar(sensor_t *sensor, int enable) 202 | { 203 | int ret=0; 204 | uint8_t reg; 205 | 206 | // Read reg COM3 207 | reg = SCCB_Read(sensor->slv_addr, COM3); 208 | // Enable colorbar test pattern output 209 | reg = COM3_SET_CBAR(reg, enable); 210 | // Write back COM3 211 | ret |= SCCB_Write(sensor->slv_addr, COM3, reg); 212 | 213 | // Read reg DSP_CTRL3 214 | reg = SCCB_Read(sensor->slv_addr, DSP_CTRL3); 215 | // Enable DSP colorbar output 216 | reg = DSP_CTRL3_SET_CBAR(reg, enable); 217 | // Write back DSP_CTRL3 218 | ret |= SCCB_Write(sensor->slv_addr, DSP_CTRL3, reg); 219 | 220 | return ret; 221 | } 222 | 223 | static int set_whitebal(sensor_t *sensor, int enable) 224 | { 225 | // Read register COM8 226 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM8); 227 | 228 | // Set white bal on/off 229 | reg = COM8_SET_AWB(reg, enable); 230 | 231 | // Write back register COM8 232 | return SCCB_Write(sensor->slv_addr, COM8, reg); 233 | } 234 | 235 | static int set_gain_ctrl(sensor_t *sensor, int enable) 236 | { 237 | // Read register COM8 238 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM8); 239 | 240 | // Set white bal on/off 241 | reg = COM8_SET_AGC(reg, enable); 242 | 243 | // Write back register COM8 244 | return SCCB_Write(sensor->slv_addr, COM8, reg); 245 | } 246 | 247 | static int set_exposure_ctrl(sensor_t *sensor, int enable) 248 | { 249 | // Read register COM8 250 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM8); 251 | 252 | // Set white bal on/off 253 | reg = COM8_SET_AEC(reg, enable); 254 | 255 | // Write back register COM8 256 | return SCCB_Write(sensor->slv_addr, COM8, reg); 257 | } 258 | 259 | static int set_hmirror(sensor_t *sensor, int enable) 260 | { 261 | // Read register COM3 262 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM3); 263 | 264 | // Set mirror on/off 265 | reg = COM3_SET_MIRROR(reg, enable); 266 | 267 | // Write back register COM3 268 | return SCCB_Write(sensor->slv_addr, COM3, reg); 269 | } 270 | 271 | static int set_vflip(sensor_t *sensor, int enable) 272 | { 273 | // Read register COM3 274 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM3); 275 | 276 | // Set mirror on/off 277 | reg = COM3_SET_FLIP(reg, enable); 278 | 279 | // Write back register COM3 280 | return SCCB_Write(sensor->slv_addr, COM3, reg); 281 | } 282 | 283 | int ov7725_init(sensor_t *sensor) 284 | { 285 | // Set function pointers 286 | sensor->reset = reset; 287 | sensor->set_pixformat = set_pixformat; 288 | sensor->set_framesize = set_framesize; 289 | sensor->set_colorbar = set_colorbar; 290 | sensor->set_whitebal = set_whitebal; 291 | sensor->set_gain_ctrl = set_gain_ctrl; 292 | sensor->set_exposure_ctrl = set_exposure_ctrl; 293 | sensor->set_hmirror = set_hmirror; 294 | sensor->set_vflip = set_vflip; 295 | 296 | // Retrieve sensor's signature 297 | sensor->id.MIDH = SCCB_Read(sensor->slv_addr, REG_MIDH); 298 | sensor->id.MIDL = SCCB_Read(sensor->slv_addr, REG_MIDL); 299 | sensor->id.PID = SCCB_Read(sensor->slv_addr, REG_PID); 300 | sensor->id.VER = SCCB_Read(sensor->slv_addr, REG_VER); 301 | 302 | // Set sensor flags 303 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_VSYNC, 1); 304 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_HSYNC, 0); 305 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_PIXCK, 1); 306 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 1); 307 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 0); 308 | 309 | return 0; 310 | } 311 | -------------------------------------------------------------------------------- /src/LineNotifyESP32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LINE Notify Arduino Library for ESP32 version 1.0.1 3 | * 4 | * March 10, 2019 5 | * 6 | * This library provides ESP32 to perform REST API call to LINE Notify service to post the several message types. 7 | * 8 | * The library was test and work well with ESP32s based module. 9 | * 10 | * The MIT License (MIT) 11 | * Copyright (c) 2019 K. Suwatchai (Mobizt) 12 | * 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 15 | * this software and associated documentation files (the "Software"), to deal in 16 | * the Software without restriction, including without limitation the rights to 17 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 18 | * the Software, and to permit persons to whom the Software is furnished to do so, 19 | * subject to the following conditions: 20 | * 21 | * The above copyright notice and this permission notice shall be included in all 22 | * copies or substantial portions of the Software. 23 | * 24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 26 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 27 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 28 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | */ 31 | 32 | #ifndef LineNotifyESP32_H 33 | #define LineNotifyESP32_H 34 | 35 | #include 36 | #include 37 | #include 38 | #include "FS.h" 39 | #include "SPIFFS.h" 40 | #include 41 | #include 42 | #include 43 | 44 | 45 | static const char ESP32_LINE_NOTIFY_STR_1[] PROGMEM = "notify-api.line.me"; 46 | static const char ESP32_LINE_NOTIFY_STR_2[] PROGMEM = "{BOUNDARY}"; 47 | static const char ESP32_LINE_NOTIFY_STR_3[] PROGMEM = "ESP32"; 48 | static const char ESP32_LINE_NOTIFY_STR_4[] PROGMEM = "\r\n"; 49 | static const char ESP32_LINE_NOTIFY_STR_5[] PROGMEM = "POST /api/notify HTTP/1.1"; 50 | static const char ESP32_LINE_NOTIFY_STR_6[] PROGMEM = "cache-control: no-cache"; 51 | static const char ESP32_LINE_NOTIFY_STR_7[] PROGMEM = "Authorization: Bearer "; 52 | static const char ESP32_LINE_NOTIFY_STR_8[] PROGMEM = "Content-Type: multipart/form-data; boundary="; 53 | static const char ESP32_LINE_NOTIFY_STR_9[] PROGMEM = "User-Agent: "; 54 | static const char ESP32_LINE_NOTIFY_STR_10[] PROGMEM = "Accept: */*"; 55 | static const char ESP32_LINE_NOTIFY_STR_11[] PROGMEM = "Host: "; 56 | static const char ESP32_LINE_NOTIFY_STR_12[] PROGMEM = "accept-encoding: gzip, deflate"; 57 | static const char ESP32_LINE_NOTIFY_STR_13[] PROGMEM = "Connection: close"; 58 | static const char ESP32_LINE_NOTIFY_STR_14[] PROGMEM = "content-length: "; 59 | static const char ESP32_LINE_NOTIFY_STR_15[] PROGMEM = "/api/notify"; 60 | static const char ESP32_LINE_NOTIFY_STR_16[] PROGMEM = "Content-Disposition: form-data; name=\"imageFile\"; filename=\""; 61 | static const char ESP32_LINE_NOTIFY_STR_17[] PROGMEM = "Content-Type: "; 62 | static const char ESP32_LINE_NOTIFY_STR_18[] PROGMEM = "Content-Disposition: form-data; name=\""; 63 | static const char ESP32_LINE_NOTIFY_STR_19[] PROGMEM = "message"; 64 | static const char ESP32_LINE_NOTIFY_STR_20[] PROGMEM = "stickerPackageId"; 65 | static const char ESP32_LINE_NOTIFY_STR_21[] PROGMEM = "stickerId"; 66 | static const char ESP32_LINE_NOTIFY_STR_22[] PROGMEM = "imageThumbnail"; 67 | static const char ESP32_LINE_NOTIFY_STR_23[] PROGMEM = "imageFullsize"; 68 | static const char ESP32_LINE_NOTIFY_STR_24[] PROGMEM = "--"; 69 | static const char ESP32_LINE_NOTIFY_STR_25[] PROGMEM = "\""; 70 | static const char ESP32_LINE_NOTIFY_STR_26[] PROGMEM = ".jpg"; 71 | static const char ESP32_LINE_NOTIFY_STR_27[] PROGMEM = ".jpeg"; 72 | static const char ESP32_LINE_NOTIFY_STR_28[] PROGMEM = "image/jpeg"; 73 | static const char ESP32_LINE_NOTIFY_STR_29[] PROGMEM = ".gif"; 74 | static const char ESP32_LINE_NOTIFY_STR_30[] PROGMEM = "image/gif"; 75 | static const char ESP32_LINE_NOTIFY_STR_31[] PROGMEM = ".png"; 76 | static const char ESP32_LINE_NOTIFY_STR_32[] PROGMEM = "image/png"; 77 | static const char ESP32_LINE_NOTIFY_STR_33[] PROGMEM = ".bmp"; 78 | static const char ESP32_LINE_NOTIFY_STR_34[] PROGMEM = "image/bmp"; 79 | static const char ESP32_LINE_NOTIFY_STR_35[] PROGMEM = "."; 80 | static const char ESP32_LINE_NOTIFY_STR_36[] PROGMEM = "HTTP/1.1 "; 81 | static const char ESP32_LINE_NOTIFY_STR_37[] PROGMEM = " "; 82 | static const char ESP32_LINE_NOTIFY_STR_38[] PROGMEM = "X-RateLimit-Limit: "; 83 | static const char ESP32_LINE_NOTIFY_STR_39[] PROGMEM = "X-RateLimit-ImageLimit: "; 84 | static const char ESP32_LINE_NOTIFY_STR_40[] PROGMEM = "X-RateLimit-Remaining: "; 85 | static const char ESP32_LINE_NOTIFY_STR_41[] PROGMEM = "X-RateLimit-ImageRemaining: "; 86 | static const char ESP32_LINE_NOTIFY_STR_42[] PROGMEM = " "; 87 | static const char ESP32_LINE_NOTIFY_STR_43[] PROGMEM = "/esp.32"; 88 | 89 | class LineNotifyESP32 90 | { 91 | 92 | public: 93 | struct LineStatus 94 | { 95 | static const uint8_t SENT_COMPLETED = 0; 96 | static const uint8_t SENT_FAILED = 1; 97 | static const uint8_t CONNECTION_FAILED = 2; 98 | }; 99 | 100 | LineNotifyESP32(); 101 | ~LineNotifyESP32(); 102 | 103 | /* 104 | 105 | The LINE Notify Service's credentials initialization. 106 | 107 | @param token - LINE Notify token String. 108 | 109 | */ 110 | void 111 | init(const String &token); 112 | 113 | /* 114 | 115 | Set the LINE Notify token. 116 | 117 | @param token - LINE Notify token string. 118 | 119 | */ 120 | void setToken(const String &token); 121 | 122 | /* 123 | 124 | Send text message. 125 | 126 | @param client - SSL WiFi client from WiFiClientSecure initialization. 127 | @param msg - The text message String to be send. 128 | 129 | @return The LineStatus structed value, SENT_COMPLETED = 0, SENT_FAILED = 1, CONNECTION_FAILED = 2. 130 | 131 | */ 132 | uint8_t sendLineMessage(HTTPClientESP32Ex &http, const String &msg); 133 | 134 | /* 135 | 136 | Send text message with sticker. 137 | 138 | @param client - SSL WiFi client from WiFiClientSecure initialization. 139 | @param msg - The text message String to be send. 140 | @param stickerPackageId - Sticker Package ID number to send, see https://devdocs.line.me/files/sticker_list.pdf for STKPKGID 141 | @param stickerId - Sticker ID number to send, see https://devdocs.line.me/files/sticker_list.pdf for STKID 142 | 143 | return The LineStatus structed value, SENT_COMPLETED = 0, SENT_FAILED = 1, CONNECTION_FAILED = 2. 144 | 145 | */ 146 | uint8_t sendLineSticker(HTTPClientESP32Ex &http, const String &msg, uint16_t stickerPackageId, uint16_t stickerId); 147 | 148 | 149 | /* 150 | 151 | Send Image message. The image data from flash memory or EEPROM 152 | 153 | @param client - SSL WiFi client from WiFiClientSecure initialization. 154 | @param msg - The text message String to be send. 155 | @param fileName - The user's specified file name String. 156 | @param imageData - The byte data of image from memory or EEPROM. 157 | @param imageLength - The byte length of image data. 158 | 159 | @return The LineStatus structed value, SENT_COMPLETED = 0, SENT_FAILED = 1, CONNECTION_FAILED = 2. 160 | 161 | */ 162 | uint8_t sendLineImageData(HTTPClientESP32Ex &http, const String &msg, const String &fileName, const uint8_t *imageData, size_t imageLength); 163 | 164 | 165 | /** 166 | Send Image message. The image data from web URL. 167 | 168 | @param client - SSL WiFi client from WiFiClientSecure initialization. 169 | @param msg - The text message String to be send. 170 | @param imageURL - The image URL String. 171 | 172 | @return The LineStatus structed value, SENT_COMPLETED = 0, SENT_FAILED = 1, CONNECTION_FAILED = 2. 173 | 174 | */ 175 | uint8_t sendLineImageURL(HTTPClientESP32Ex &http, const String &msg, const String &imageURL); 176 | 177 | 178 | /* 179 | 180 | Send Image message. The image data from SPI Flash File. 181 | 182 | @param client - SSL WiFi client from WiFiClientSecure initialization. 183 | @param msg - The text message String to be send. 184 | @param filePath - The image file name and path String inside SPIF. 185 | 186 | @return The LineStatus structed value, SENT_COMPLETED = 0, SENT_FAILED = 1, CONNECTION_FAILED = 2. 187 | 188 | */ 189 | uint8_t sendLineImageSPIF(HTTPClientESP32Ex &http, const String &msg, const String &filePath); 190 | 191 | 192 | /* 193 | 194 | Send Image message. The image data from SD card File. 195 | 196 | @param client - SSL WiFi client from WiFiClientSecure initialization. 197 | @param msg - The text message String to be send. 198 | @param filePath - The image file name and path String inside SD card. 199 | 200 | @return The LineStatus structed value, SENT_COMPLETED = 0, SENT_FAILED = 1, CONNECTION_FAILED = 2. 201 | 202 | */ 203 | uint8_t sendLineImageSD(HTTPClientESP32Ex &http, const String &msg, const String &filePath); 204 | 205 | /* 206 | Get the text message limit. 207 | 208 | @return The limit count of sending text message. 209 | 210 | */ 211 | uint16_t textMessageLimit(void); 212 | 213 | /* 214 | 215 | Get the image message limit. 216 | 217 | @return The limit count of sending image message. 218 | 219 | */ 220 | uint16_t imageMessageLimit(void); 221 | 222 | /* 223 | Get the remaining count of sending text message. 224 | 225 | @return The remaining count of sending text message. 226 | 227 | */ 228 | uint16_t textMessageRemaining(void); 229 | 230 | /* 231 | Get the remaining count of sending image message. 232 | 233 | @return The remaining count of sending image message. 234 | 235 | */ 236 | uint16_t imageMessageRemaining(void); 237 | 238 | /* 239 | End Line Notify. 240 | */ 241 | void end(void); 242 | 243 | private: 244 | const uint16_t LINE_PORT = 443; 245 | std::string _token=""; 246 | int _textLimit; 247 | int _imageLimit; 248 | int _textRemaining; 249 | int _imageRemaining; 250 | 251 | uint8_t sendLineImageFile(HTTPClientESP32Ex &http, const String &msg, const String &filePath, bool internal); 252 | bool sdTest(); 253 | int send_request_header(HTTPClientESP32Ex &http, const std::string &token, size_t contentLength); 254 | void set_multipart_header(std::string &data, const std::string &arg); 255 | void set_multipart_boundary(std::string &data); 256 | bool waitLineResponse(HTTPClientESP32Ex &http); 257 | void getContentType(const std::string &filename, std::string &buf); 258 | inline std::string trim(std::string &str); 259 | 260 | }; 261 | 262 | extern LineNotifyESP32 lineNotify; 263 | 264 | #endif 265 | -------------------------------------------------------------------------------- /src/LineNotifyESP32.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * LINE Notify Arduino Library for ESP32 version 1.0.1 3 | * 4 | * March 10, 2019 5 | * 6 | * This library provides ESP32 to perform REST API call to LINE Notify service to post the several message types. 7 | * 8 | * The library was test and work well with ESP32s based module. 9 | * 10 | * The MIT License (MIT) 11 | * Copyright (c) 2019 K. Suwatchai (Mobizt) 12 | * 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 15 | * this software and associated documentation files (the "Software"), to deal in 16 | * the Software without restriction, including without limitation the rights to 17 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 18 | * the Software, and to permit persons to whom the Software is furnished to do so, 19 | * subject to the following conditions: 20 | * 21 | * The above copyright notice and this permission notice shall be included in all 22 | * copies or substantial portions of the Software. 23 | * 24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 26 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 27 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 28 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | */ 31 | 32 | #ifndef LineNotifyESP32_CPP 33 | #define LineNotifyESP32_CPP 34 | 35 | #include "LineNotifyESP32.h" 36 | 37 | LineNotifyESP32::LineNotifyESP32(){}; 38 | 39 | LineNotifyESP32::~LineNotifyESP32() 40 | { 41 | end(); 42 | }; 43 | 44 | 45 | void LineNotifyESP32::end() 46 | { 47 | std::string().swap(_token); 48 | }; 49 | 50 | void LineNotifyESP32::init(const String &token) 51 | { 52 | SPIFFS.begin(true); 53 | _token = token.c_str(); 54 | } 55 | 56 | void LineNotifyESP32::setToken(const String &token) 57 | { 58 | _token = token.c_str(); 59 | } 60 | 61 | int LineNotifyESP32::send_request_header(HTTPClientESP32Ex &http, const std::string &token, size_t contentLength) 62 | { 63 | std::string data = ""; 64 | char *val = new char[10]; 65 | memset(val, 0, 10); 66 | 67 | data = ESP32_LINE_NOTIFY_STR_5; 68 | data += ESP32_LINE_NOTIFY_STR_4; 69 | 70 | data += ESP32_LINE_NOTIFY_STR_6; 71 | data += ESP32_LINE_NOTIFY_STR_4; 72 | 73 | data += ESP32_LINE_NOTIFY_STR_7; 74 | data += token; 75 | data += ESP32_LINE_NOTIFY_STR_4; 76 | 77 | data += ESP32_LINE_NOTIFY_STR_8; 78 | data += ESP32_LINE_NOTIFY_STR_2; 79 | data += ESP32_LINE_NOTIFY_STR_4; 80 | 81 | data += ESP32_LINE_NOTIFY_STR_9; 82 | data += ESP32_LINE_NOTIFY_STR_3; 83 | data += ESP32_LINE_NOTIFY_STR_4; 84 | 85 | data += ESP32_LINE_NOTIFY_STR_10; 86 | data += ESP32_LINE_NOTIFY_STR_4; 87 | 88 | data += ESP32_LINE_NOTIFY_STR_11; 89 | data += ESP32_LINE_NOTIFY_STR_1; 90 | data += ESP32_LINE_NOTIFY_STR_4; 91 | 92 | data += ESP32_LINE_NOTIFY_STR_12; 93 | data += ESP32_LINE_NOTIFY_STR_4; 94 | 95 | data += ESP32_LINE_NOTIFY_STR_13; 96 | data += ESP32_LINE_NOTIFY_STR_4; 97 | 98 | data += ESP32_LINE_NOTIFY_STR_14; 99 | itoa(contentLength, val, 10); 100 | data += val; 101 | data += ESP32_LINE_NOTIFY_STR_4; 102 | data += ESP32_LINE_NOTIFY_STR_4; 103 | 104 | int res = http.http_sendRequest(data.c_str(), ""); 105 | 106 | std::string().swap(data); 107 | delete[] val; 108 | 109 | return res; 110 | } 111 | 112 | void LineNotifyESP32::set_multipart_header(std::string &data, const std::string &arg) 113 | { 114 | 115 | data += ESP32_LINE_NOTIFY_STR_24; 116 | data += ESP32_LINE_NOTIFY_STR_2; 117 | data += ESP32_LINE_NOTIFY_STR_4; 118 | 119 | if (arg == ESP32_LINE_NOTIFY_STR_19 || arg == ESP32_LINE_NOTIFY_STR_20 || arg == ESP32_LINE_NOTIFY_STR_21 || arg == ESP32_LINE_NOTIFY_STR_22 || arg == ESP32_LINE_NOTIFY_STR_23) 120 | { 121 | data += ESP32_LINE_NOTIFY_STR_18; 122 | data += arg; 123 | data += ESP32_LINE_NOTIFY_STR_25; 124 | data += ESP32_LINE_NOTIFY_STR_4; 125 | data += ESP32_LINE_NOTIFY_STR_4; 126 | } 127 | else 128 | { 129 | data += ESP32_LINE_NOTIFY_STR_16; 130 | data += arg; 131 | data += ESP32_LINE_NOTIFY_STR_25; 132 | data += ESP32_LINE_NOTIFY_STR_4; 133 | 134 | data += ESP32_LINE_NOTIFY_STR_17; 135 | getContentType(arg, data); 136 | data += ESP32_LINE_NOTIFY_STR_4; 137 | data += ESP32_LINE_NOTIFY_STR_4; 138 | } 139 | } 140 | 141 | void LineNotifyESP32::set_multipart_boundary(std::string &data) 142 | { 143 | data += ESP32_LINE_NOTIFY_STR_24; 144 | data += ESP32_LINE_NOTIFY_STR_2; 145 | data += ESP32_LINE_NOTIFY_STR_24; 146 | data += ESP32_LINE_NOTIFY_STR_4; 147 | } 148 | 149 | uint8_t LineNotifyESP32::sendLineMessage(HTTPClientESP32Ex &http, const String &msg) 150 | { 151 | std::string uri = ESP32_LINE_NOTIFY_STR_15; 152 | 153 | http.http_begin(ESP32_LINE_NOTIFY_STR_1, LINE_PORT, uri.c_str(), (const char *)NULL); 154 | 155 | std::string textHeader = ""; 156 | set_multipart_header(textHeader, ESP32_LINE_NOTIFY_STR_19); 157 | textHeader += msg.c_str(); 158 | textHeader += ESP32_LINE_NOTIFY_STR_4; 159 | set_multipart_boundary(textHeader); 160 | 161 | send_request_header(http, _token.c_str(), textHeader.length()); 162 | http.http_sendRequest("", textHeader.c_str()); 163 | 164 | std::string().swap(textHeader); 165 | std::string().swap(uri); 166 | 167 | if (waitLineResponse(http)) 168 | return LineNotifyESP32::LineStatus::SENT_COMPLETED; 169 | else 170 | return LineNotifyESP32::LineStatus::SENT_FAILED; 171 | } 172 | 173 | uint8_t LineNotifyESP32::sendLineSticker(HTTPClientESP32Ex &http, const String &msg, uint16_t stickerPackageId, uint16_t stickerId) 174 | { 175 | std::string uri = ESP32_LINE_NOTIFY_STR_15; 176 | 177 | http.http_begin(ESP32_LINE_NOTIFY_STR_1, LINE_PORT, uri.c_str(), (const char *)NULL); 178 | 179 | char *val = new char[20]; 180 | std::string textHeader = ""; 181 | 182 | set_multipart_header(textHeader, ESP32_LINE_NOTIFY_STR_19); 183 | textHeader += msg.c_str(); 184 | textHeader += ESP32_LINE_NOTIFY_STR_4; 185 | 186 | set_multipart_header(textHeader, ESP32_LINE_NOTIFY_STR_20); 187 | memset(val, 0, 20); 188 | itoa(stickerPackageId, val, 10); 189 | textHeader += val; 190 | textHeader += ESP32_LINE_NOTIFY_STR_4; 191 | 192 | set_multipart_header(textHeader, ESP32_LINE_NOTIFY_STR_21); 193 | memset(val, 0, 20); 194 | itoa(stickerId, val, 10); 195 | textHeader += val; 196 | textHeader += ESP32_LINE_NOTIFY_STR_4; 197 | 198 | set_multipart_boundary(textHeader); 199 | 200 | delete[] val; 201 | 202 | if (send_request_header(http, _token, textHeader.length()) == 0) 203 | { 204 | 205 | http.http_sendRequest("", textHeader.c_str()); 206 | 207 | std::string().swap(textHeader); 208 | std::string().swap(uri); 209 | 210 | if (waitLineResponse(http)) 211 | return LineNotifyESP32::LineStatus::SENT_COMPLETED; 212 | else 213 | return LineNotifyESP32::LineStatus::SENT_FAILED; 214 | } 215 | 216 | std::string().swap(textHeader); 217 | std::string().swap(uri); 218 | 219 | return HTTPC_ERROR_CONNECTION_REFUSED; 220 | } 221 | 222 | uint8_t LineNotifyESP32::sendLineImageData(HTTPClientESP32Ex &http, const String &msg, const String &fileName, const uint8_t *imageData, size_t imageLength) 223 | { 224 | 225 | std::string uri = ESP32_LINE_NOTIFY_STR_15; 226 | 227 | http.http_begin(ESP32_LINE_NOTIFY_STR_1, LINE_PORT, uri.c_str(), (const char *)NULL); 228 | 229 | std::string textHeader = ""; 230 | std::string imageHeader = ""; 231 | std::string boundary = ""; 232 | 233 | set_multipart_header(textHeader, ESP32_LINE_NOTIFY_STR_19); 234 | textHeader += msg.c_str(); 235 | textHeader += ESP32_LINE_NOTIFY_STR_4; 236 | 237 | set_multipart_header(imageHeader, fileName.c_str()); 238 | 239 | set_multipart_boundary(boundary); 240 | 241 | uint32_t contentLength = textHeader.length() + imageHeader.length() + imageLength + boundary.length(); 242 | 243 | if (send_request_header(http, _token, contentLength) == 0) 244 | { 245 | 246 | http.http_sendRequest("", textHeader.c_str()); 247 | http.http_sendRequest("", imageHeader.c_str()); 248 | 249 | size_t chunkSize = 512; 250 | 251 | size_t byteRead = 0; 252 | 253 | WiFiClient *tcp = http.http_getStreamPtr(); 254 | 255 | while (byteRead < imageLength) 256 | { 257 | if (byteRead + chunkSize < imageLength) 258 | { 259 | tcp->write(imageData, chunkSize); 260 | imageData += chunkSize; 261 | byteRead += chunkSize; 262 | } 263 | else 264 | { 265 | tcp->write(imageData, imageLength - byteRead); 266 | imageData += chunkSize; 267 | byteRead = imageLength; 268 | } 269 | yield(); 270 | } 271 | 272 | http.http_sendRequest("", ESP32_LINE_NOTIFY_STR_4); 273 | http.http_sendRequest("", boundary.c_str()); 274 | 275 | std::string().swap(textHeader); 276 | std::string().swap(imageHeader); 277 | std::string().swap(boundary); 278 | std::string().swap(uri); 279 | 280 | if (waitLineResponse(http)) 281 | return LineNotifyESP32::LineStatus::SENT_COMPLETED; 282 | else 283 | return LineNotifyESP32::LineStatus::SENT_FAILED; 284 | } 285 | 286 | std::string().swap(textHeader); 287 | std::string().swap(imageHeader); 288 | std::string().swap(boundary); 289 | std::string().swap(uri); 290 | 291 | return HTTPC_ERROR_CONNECTION_REFUSED; 292 | } 293 | 294 | uint8_t LineNotifyESP32::sendLineImageURL(HTTPClientESP32Ex &http, const String &msg, const String &imageURL) 295 | { 296 | 297 | std::string uri = ESP32_LINE_NOTIFY_STR_15; 298 | 299 | http.http_begin(ESP32_LINE_NOTIFY_STR_1, LINE_PORT, uri.c_str(), (const char *)NULL); 300 | 301 | std::string textHeader = ""; 302 | 303 | set_multipart_header(textHeader, ESP32_LINE_NOTIFY_STR_19); 304 | textHeader += msg.c_str(); 305 | textHeader += ESP32_LINE_NOTIFY_STR_4; 306 | 307 | set_multipart_header(textHeader, ESP32_LINE_NOTIFY_STR_22); 308 | textHeader += imageURL.c_str(); 309 | textHeader += ESP32_LINE_NOTIFY_STR_4; 310 | 311 | set_multipart_header(textHeader, ESP32_LINE_NOTIFY_STR_23); 312 | textHeader += imageURL.c_str(); 313 | textHeader += ESP32_LINE_NOTIFY_STR_4; 314 | 315 | set_multipart_boundary(textHeader); 316 | 317 | if (send_request_header(http, _token, textHeader.length()) == 0) 318 | { 319 | 320 | http.http_sendRequest("", textHeader.c_str()); 321 | 322 | std::string().swap(textHeader); 323 | std::string().swap(uri); 324 | 325 | if (waitLineResponse(http)) 326 | return LineNotifyESP32::LineStatus::SENT_COMPLETED; 327 | else 328 | return LineNotifyESP32::LineStatus::SENT_FAILED; 329 | } 330 | std::string().swap(textHeader); 331 | std::string().swap(uri); 332 | return HTTPC_ERROR_CONNECTION_REFUSED; 333 | } 334 | 335 | uint8_t LineNotifyESP32::sendLineImageFile(HTTPClientESP32Ex &http, const String &msg, const String &filePath, bool internal) 336 | { 337 | bool fileExisted = false; 338 | 339 | if (internal) 340 | fileExisted = SPIFFS.exists(filePath); 341 | else 342 | { 343 | if (!sdTest()) 344 | return LineNotifyESP32::LineStatus::SENT_FAILED; 345 | 346 | fileExisted = SD.exists(filePath); 347 | } 348 | 349 | if (fileExisted) 350 | { 351 | std::string textHeader = ""; 352 | std::string imageHeader = ""; 353 | std::string boundary = ""; 354 | 355 | File file; 356 | 357 | if (internal) 358 | file = SPIFFS.open(filePath, "r"); 359 | else 360 | file = SD.open(filePath, "r"); 361 | 362 | uint32_t imageLength = file.size(); 363 | 364 | std::string uri = ESP32_LINE_NOTIFY_STR_15; 365 | 366 | http.http_begin(ESP32_LINE_NOTIFY_STR_1, LINE_PORT, uri.c_str(), (const char *)NULL); 367 | 368 | set_multipart_header(textHeader, ESP32_LINE_NOTIFY_STR_19); 369 | textHeader += msg.c_str(); 370 | textHeader += ESP32_LINE_NOTIFY_STR_4; 371 | 372 | set_multipart_header(imageHeader, filePath.c_str()); 373 | 374 | set_multipart_boundary(boundary); 375 | 376 | uint32_t contentLength = textHeader.length() + imageHeader.length() + imageLength + boundary.length(); 377 | 378 | if (send_request_header(http, _token, contentLength) == 0) 379 | { 380 | 381 | http.http_sendRequest("", textHeader.c_str()); 382 | 383 | http.http_sendRequest("", imageHeader.c_str()); 384 | 385 | size_t chunkSize = 512; 386 | uint8_t chunk[chunkSize]; 387 | size_t byteRead = 0; 388 | 389 | WiFiClient *tcp = http.http_getStreamPtr(); 390 | 391 | while (byteRead < imageLength) 392 | { 393 | memset(chunk, 0, sizeof chunk); 394 | if (byteRead + chunkSize < imageLength) 395 | { 396 | file.read(chunk, chunkSize); 397 | tcp->write(chunk, chunkSize); 398 | byteRead += chunkSize; 399 | } 400 | else 401 | { 402 | file.read(chunk, imageLength - byteRead); 403 | tcp->write(chunk, imageLength - byteRead); 404 | byteRead = imageLength; 405 | break; 406 | } 407 | yield(); 408 | } 409 | 410 | file.close(); 411 | 412 | http.http_sendRequest("", ESP32_LINE_NOTIFY_STR_4); 413 | http.http_sendRequest("", boundary.c_str()); 414 | 415 | std::string().swap(textHeader); 416 | std::string().swap(imageHeader); 417 | std::string().swap(boundary); 418 | std::string().swap(uri); 419 | 420 | if (waitLineResponse(http)) 421 | return LineNotifyESP32::LineStatus::SENT_COMPLETED; 422 | else 423 | return LineNotifyESP32::LineStatus::SENT_FAILED; 424 | } 425 | 426 | std::string().swap(textHeader); 427 | std::string().swap(imageHeader); 428 | std::string().swap(boundary); 429 | std::string().swap(uri); 430 | 431 | return HTTPC_ERROR_CONNECTION_REFUSED; 432 | } 433 | } 434 | 435 | uint8_t LineNotifyESP32::sendLineImageSPIF(HTTPClientESP32Ex &http, const String &msg, const String &filePath) 436 | { 437 | return sendLineImageFile(http, msg, filePath, true); 438 | } 439 | 440 | uint8_t LineNotifyESP32::sendLineImageSD(HTTPClientESP32Ex &http, const String &msg, const String &filePath) 441 | { 442 | return sendLineImageFile(http, msg, filePath, false); 443 | } 444 | 445 | bool LineNotifyESP32::sdTest() 446 | { 447 | 448 | if (!SD.begin()) 449 | return false; 450 | 451 | File file = SD.open(ESP32_LINE_NOTIFY_STR_43, FILE_WRITE); 452 | if (!file) 453 | return false; 454 | 455 | if (!file.write(32)) 456 | return false; 457 | file.close(); 458 | 459 | file = SD.open(ESP32_LINE_NOTIFY_STR_43); 460 | if (!file) 461 | return false; 462 | 463 | while (file.available()) 464 | { 465 | if (file.read() != 32) 466 | return false; 467 | } 468 | file.close(); 469 | 470 | SD.remove(ESP32_LINE_NOTIFY_STR_43); 471 | 472 | return true; 473 | } 474 | 475 | bool LineNotifyESP32::waitLineResponse(HTTPClientESP32Ex &http) 476 | { 477 | 478 | std::string lineBuf = ""; 479 | long dataTime = millis(); 480 | char c; 481 | int p1, p2; 482 | 483 | int httpCode = -1000; 484 | _textLimit = 0; 485 | _textRemaining = 0; 486 | _imageLimit = 0; 487 | _imageRemaining = 0; 488 | 489 | WiFiClient *tcp = http.http_getStreamPtr(); 490 | 491 | while (tcp->connected() && !tcp->available() && millis() - dataTime < http.tcpTimeout) 492 | delay(1); 493 | 494 | dataTime = millis(); 495 | if (tcp->connected() && tcp->available()) 496 | { 497 | while (tcp->available()) 498 | { 499 | 500 | yield(); 501 | 502 | c = tcp->read(); 503 | lineBuf.append(1, c); 504 | 505 | if (c == '\n') 506 | { 507 | 508 | dataTime = millis(); 509 | trim(lineBuf); 510 | 511 | p1 = lineBuf.find(ESP32_LINE_NOTIFY_STR_36); 512 | if (p1 != std::string::npos) 513 | { 514 | p2 = lineBuf.find(ESP32_LINE_NOTIFY_STR_37, p1 + strlen(ESP32_LINE_NOTIFY_STR_36)); 515 | if (p2 != std::string::npos) 516 | httpCode = atoi(lineBuf.substr(p1 + strlen(ESP32_LINE_NOTIFY_STR_36), p2 - p1 - strlen(ESP32_LINE_NOTIFY_STR_36)).c_str()); 517 | } 518 | else 519 | { 520 | 521 | p1 = lineBuf.find(ESP32_LINE_NOTIFY_STR_38); 522 | if (p1 != std::string::npos) 523 | _textLimit = atoi(lineBuf.substr(p1 + strlen(ESP32_LINE_NOTIFY_STR_38)).c_str()); 524 | 525 | p1 = lineBuf.find(ESP32_LINE_NOTIFY_STR_39); 526 | if (p1 != std::string::npos) 527 | _imageLimit = atoi(lineBuf.substr(p1 + strlen(ESP32_LINE_NOTIFY_STR_39)).c_str()); 528 | 529 | p1 = lineBuf.find(ESP32_LINE_NOTIFY_STR_40); 530 | if (p1 != std::string::npos) 531 | _textRemaining = atoi(lineBuf.substr(p1 + strlen(ESP32_LINE_NOTIFY_STR_40)).c_str()); 532 | 533 | p1 = lineBuf.find(ESP32_LINE_NOTIFY_STR_41); 534 | if (p1 != std::string::npos) 535 | _imageRemaining = atoi(lineBuf.substr(p1 + strlen(ESP32_LINE_NOTIFY_STR_41)).c_str()); 536 | } 537 | 538 | lineBuf.clear(); 539 | } 540 | 541 | if (millis() - dataTime > http.tcpTimeout) 542 | { 543 | httpCode = HTTPC_ERROR_READ_TIMEOUT; 544 | break; 545 | } 546 | } 547 | } 548 | 549 | std::string().swap(lineBuf); 550 | 551 | return httpCode == HTTP_CODE_OK; 552 | } 553 | 554 | void LineNotifyESP32::getContentType(const std::string &filename, std::string &buf) 555 | { 556 | int p1 = filename.find_last_of(ESP32_LINE_NOTIFY_STR_35); 557 | if (p1 != std::string::npos) 558 | { 559 | if (filename.find(ESP32_LINE_NOTIFY_STR_26, p1) != std::string::npos || filename.find(ESP32_LINE_NOTIFY_STR_27, p1) != std::string::npos) 560 | { 561 | buf += ESP32_LINE_NOTIFY_STR_28; 562 | return; 563 | } 564 | else if (filename.find(ESP32_LINE_NOTIFY_STR_29, p1) != std::string::npos) 565 | { 566 | buf += ESP32_LINE_NOTIFY_STR_30; 567 | return; 568 | } 569 | else if (filename.find(ESP32_LINE_NOTIFY_STR_31, p1) != std::string::npos) 570 | { 571 | buf += ESP32_LINE_NOTIFY_STR_32; 572 | return; 573 | } 574 | else if (filename.find(ESP32_LINE_NOTIFY_STR_33, p1) != std::string::npos) 575 | { 576 | buf += ESP32_LINE_NOTIFY_STR_34; 577 | return; 578 | } 579 | } 580 | } 581 | 582 | uint16_t LineNotifyESP32::textMessageLimit(void) 583 | { 584 | return _textLimit; 585 | } 586 | 587 | uint16_t LineNotifyESP32::textMessageRemaining(void) 588 | { 589 | return _textRemaining; 590 | } 591 | 592 | uint16_t LineNotifyESP32::imageMessageLimit(void) 593 | { 594 | return _imageLimit; 595 | } 596 | 597 | uint16_t LineNotifyESP32::imageMessageRemaining(void) 598 | { 599 | return _imageRemaining; 600 | } 601 | 602 | inline std::string LineNotifyESP32::trim(std::string &str) 603 | { 604 | str.erase(0, str.find_first_not_of(' ')); 605 | str.erase(str.find_last_not_of(' ') + 1); 606 | str.erase(std::remove(str.begin(), str.end(), '\r'), str.end()); 607 | str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); 608 | return str; 609 | } 610 | 611 | LineNotifyESP32 lineNotify = LineNotifyESP32(); 612 | 613 | #endif 614 | -------------------------------------------------------------------------------- /examples/Camera/src/ov7725_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 | #define GAIN 0x00 /* AGC – Gain control gain setting */ 11 | #define BLUE 0x01 /* AWB – Blue channel gain setting */ 12 | #define RED 0x02 /* AWB – Red channel gain setting */ 13 | #define GREEN 0x03 /* AWB – Green channel gain setting */ 14 | #define BAVG 0x05 /* U/B Average Level */ 15 | #define GAVG 0x06 /* Y/Gb Average Level */ 16 | #define RAVG 0x07 /* V/R Average Level */ 17 | #define AECH 0x08 /* Exposure Value – AEC MSBs */ 18 | 19 | #define COM2 0x09 /* Common Control 2 */ 20 | #define COM2_SOFT_SLEEP 0x10 /* Soft sleep mode */ 21 | #define COM2_OUT_DRIVE_1x 0x00 /* Output drive capability 1x */ 22 | #define COM2_OUT_DRIVE_2x 0x01 /* Output drive capability 2x */ 23 | #define COM2_OUT_DRIVE_3x 0x02 /* Output drive capability 3x */ 24 | #define COM2_OUT_DRIVE_4x 0x03 /* Output drive capability 4x */ 25 | 26 | #define REG_PID 0x0A /* Product ID Number MSB */ 27 | #define REG_VER 0x0B /* Product ID Number LSB */ 28 | 29 | #define COM3 0x0C /* Common Control 3 */ 30 | #define COM3_VFLIP 0x80 /* Vertical flip image ON/OFF selection */ 31 | #define COM3_MIRROR 0x40 /* Horizontal mirror image ON/OFF selection */ 32 | #define COM3_SWAP_BR 0x20 /* Swap B/R output sequence in RGB output mode */ 33 | #define COM3_SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV output mode */ 34 | #define COM3_SWAP_MSB 0x08 /* Swap output MSB/LSB */ 35 | #define COM3_TRI_CLOCK 0x04 /* Tri-state option for output clock at power-down period */ 36 | #define COM3_TRI_DATA 0x02 /* Tri-state option for output data at power-down period */ 37 | #define COM3_COLOR_BAR 0x01 /* Sensor color bar test pattern output enable */ 38 | #define COM3_SET_CBAR(r, x) ((r&0xFE)|((x&1)<<0)) 39 | #define COM3_SET_MIRROR(r, x) ((r&0xBF)|((x&1)<<6)) 40 | #define COM3_SET_FLIP(r, x) ((r&0x7F)|((x&1)<<7)) 41 | 42 | #define COM4 0x0D /* Common Control 4 */ 43 | #define COM4_PLL_BYPASS 0x00 /* Bypass PLL */ 44 | #define COM4_PLL_4x 0x40 /* PLL frequency 4x */ 45 | #define COM4_PLL_6x 0x80 /* PLL frequency 6x */ 46 | #define COM4_PLL_8x 0xc0 /* PLL frequency 8x */ 47 | #define COM4_AEC_FULL 0x00 /* AEC evaluate full window */ 48 | #define COM4_AEC_1_2 0x10 /* AEC evaluate 1/2 window */ 49 | #define COM4_AEC_1_4 0x20 /* AEC evaluate 1/4 window */ 50 | #define COM4_AEC_2_3 0x30 /* AEC evaluate 2/3 window */ 51 | 52 | #define COM5 0x0E /* Common Control 5 */ 53 | #define COM5_AFR 0x80 /* Auto frame rate control ON/OFF selection (night mode) */ 54 | #define COM5_AFR_SPEED 0x40 /* Auto frame rate control speed selection */ 55 | #define COM5_AFR_0 0x00 /* No reduction of frame rate */ 56 | #define COM5_AFR_1_2 0x10 /* Max reduction to 1/2 frame rate */ 57 | #define COM5_AFR_1_4 0x20 /* Max reduction to 1/4 frame rate */ 58 | #define COM5_AFR_1_8 0x30 /* Max reduction to 1/8 frame rate */ 59 | #define COM5_AFR_4x 0x04 /* Add frame when AGC reaches 4x gain */ 60 | #define COM5_AFR_8x 0x08 /* Add frame when AGC reaches 8x gain */ 61 | #define COM5_AFR_16x 0x0c /* Add frame when AGC reaches 16x gain */ 62 | #define COM5_AEC_NO_LIMIT 0x01 /* No limit to AEC increase step */ 63 | 64 | #define COM6 0x0F /* Common Control 6 */ 65 | #define COM6_AUTO_WINDOW 0x01 /* Auto window setting ON/OFF selection when format changes */ 66 | 67 | #define AEC 0x10 /* AEC[7:0] (see register AECH for AEC[15:8]) */ 68 | #define CLKRC 0x11 /* Internal Clock */ 69 | 70 | #define COM7 0x12 /* Common Control 7 */ 71 | #define COM7_RESET 0x80 /* SCCB Register Reset */ 72 | #define COM7_RES_VGA 0x00 /* Resolution VGA */ 73 | #define COM7_RES_QVGA 0x40 /* Resolution QVGA */ 74 | #define COM7_BT656 0x20 /* BT.656 protocol ON/OFF */ 75 | #define COM7_SENSOR_RAW 0x10 /* Sensor RAW */ 76 | #define COM7_FMT_GBR422 0x00 /* RGB output format GBR422 */ 77 | #define COM7_FMT_RGB565 0x04 /* RGB output format RGB565 */ 78 | #define COM7_FMT_RGB555 0x08 /* RGB output format RGB555 */ 79 | #define COM7_FMT_RGB444 0x0C /* RGB output format RGB444 */ 80 | #define COM7_FMT_YUV 0x00 /* Output format YUV */ 81 | #define COM7_FMT_P_BAYER 0x01 /* Output format Processed Bayer RAW */ 82 | #define COM7_FMT_RGB 0x02 /* Output format RGB */ 83 | #define COM7_FMT_R_BAYER 0x03 /* Output format Bayer RAW */ 84 | #define COM7_SET_FMT(r, x) ((r&0xFC)|((x&0x3)<<0)) 85 | 86 | #define COM8 0x13 /* Common Control 8 */ 87 | #define COM8_FAST_AUTO 0x80 /* Enable fast AGC/AEC algorithm */ 88 | #define COM8_STEP_VSYNC 0x00 /* AEC - Step size limited to vertical blank */ 89 | #define COM8_STEP_UNLIMIT 0x40 /* AEC - Step size unlimited step size */ 90 | #define COM8_BANDF_EN 0x20 /* Banding filter ON/OFF */ 91 | #define COM8_AEC_BANDF 0x10 /* Enable AEC below banding value */ 92 | #define COM8_AEC_FINE_EN 0x08 /* Fine AEC ON/OFF control */ 93 | #define COM8_AGC_EN 0x04 /* AGC Enable */ 94 | #define COM8_AWB_EN 0x02 /* AWB Enable */ 95 | #define COM8_AEC_EN 0x01 /* AEC Enable */ 96 | #define COM8_SET_AGC(r, x) ((r&0xFB)|((x&0x1)<<2)) 97 | #define COM8_SET_AWB(r, x) ((r&0xFD)|((x&0x1)<<1)) 98 | #define COM8_SET_AEC(r, x) ((r&0xFE)|((x&0x1)<<0)) 99 | 100 | #define COM9 0x14 /* Common Control 9 */ 101 | #define COM9_HISTO_AVG 0x80 /* Histogram or average based AEC/AGC selection */ 102 | #define COM9_AGC_GAIN_2x 0x00 /* Automatic Gain Ceiling 2x */ 103 | #define COM9_AGC_GAIN_4x 0x10 /* Automatic Gain Ceiling 4x */ 104 | #define COM9_AGC_GAIN_8x 0x20 /* Automatic Gain Ceiling 8x */ 105 | #define COM9_AGC_GAIN_16x 0x30 /* Automatic Gain Ceiling 16x */ 106 | #define COM9_AGC_GAIN_32x 0x40 /* Automatic Gain Ceiling 32x */ 107 | #define COM9_DROP_VSYNC 0x04 /* Drop VSYNC output of corrupt frame */ 108 | #define COM9_DROP_HREF 0x02 /* Drop HREF output of corrupt frame */ 109 | #define COM9_SET_AGC(r, x) ((r&0x8F)|((x&0x07)<<4)) 110 | 111 | #define COM10 0x15 /* Common Control 10 */ 112 | #define COM10_NEGATIVE 0x80 /* Output negative data */ 113 | #define COM10_HSYNC_EN 0x40 /* HREF changes to HSYNC */ 114 | #define COM10_PCLK_FREE 0x00 /* PCLK output option: free running PCLK */ 115 | #define COM10_PCLK_MASK 0x20 /* PCLK output option: masked during horizontal blank */ 116 | #define COM10_PCLK_REV 0x10 /* PCLK reverse */ 117 | #define COM10_HREF_REV 0x08 /* HREF reverse */ 118 | #define COM10_VSYNC_FALLING 0x00 /* VSYNC changes on falling edge of PCLK */ 119 | #define COM10_VSYNC_RISING 0x04 /* VSYNC changes on rising edge of PCLK */ 120 | #define COM10_VSYNC_NEG 0x02 /* VSYNC negative */ 121 | #define COM10_OUT_RANGE_8 0x01 /* Output data range: Full range */ 122 | #define COM10_OUT_RANGE_10 0x00 /* Output data range: Data from [10] to [F0] (8 MSBs) */ 123 | 124 | #define REG16 0x16 /* Register 16 */ 125 | #define REG16_BIT_SHIFT 0x80 /* Bit shift test pattern options */ 126 | #define HSTART 0x17 /* Horizontal Frame (HREF column) Start 8 MSBs (2 LSBs are at HREF[5:4]) */ 127 | #define HSIZE 0x18 /* Horizontal Sensor Size (2 LSBs are at HREF[1:0]) */ 128 | #define VSTART 0x19 /* Vertical Frame (row) Start 8 MSBs (1 LSB is at HREF[6]) */ 129 | #define VSIZE 0x1A /* Vertical Sensor Size (1 LSB is at HREF[2]) */ 130 | #define PSHFT 0x1B /* Data Format - Pixel Delay Select */ 131 | #define REG_MIDH 0x1C /* Manufacturer ID Byte – High */ 132 | #define REG_MIDL 0x1D /* Manufacturer ID Byte – Low */ 133 | #define LAEC 0x1F /* Fine AEC Value - defines exposure value less than one row period */ 134 | 135 | #define COM11 0x20 /* Common Control 11 */ 136 | #define COM11_SNGL_FRAME_EN 0x02 /* Single frame ON/OFF selection */ 137 | #define COM11_SNGL_XFR_TRIG 0x01 /* Single frame transfer trigger */ 138 | 139 | #define BDBASE 0x22 /* Banding Filter Minimum AEC Value */ 140 | #define DBSTEP 0x23 /* Banding Filter Maximum Step */ 141 | #define AEW 0x24 /* AGC/AEC - Stable Operating Region (Upper Limit) */ 142 | #define AEB 0x25 /* AGC/AEC - Stable Operating Region (Lower Limit) */ 143 | #define VPT 0x26 /* AGC/AEC Fast Mode Operating Region */ 144 | #define REG28 0x28 /* Selection on the number of dummy rows, N */ 145 | #define HOUTSIZE 0x29 /* Horizontal Data Output Size MSBs (2 LSBs at register EXHCH[1:0]) */ 146 | #define EXHCH 0x2A /* Dummy Pixel Insert MSB */ 147 | #define EXHCL 0x2B /* Dummy Pixel Insert LSB */ 148 | #define VOUTSIZE 0x2C /* Vertical Data Output Size MSBs (LSB at register EXHCH[2]) */ 149 | #define ADVFL 0x2D /* LSB of Insert Dummy Rows in Vertical Sync (1 bit equals 1 row) */ 150 | #define ADVFH 0x2E /* MSB of Insert Dummy Rows in Vertical Sync */ 151 | #define YAVE 0x2F /* Y/G Channel Average Value */ 152 | #define LUMHTH 0x30 /* Histogram AEC/AGC Luminance High Level Threshold */ 153 | #define LUMLTH 0x31 /* Histogram AEC/AGC Luminance Low Level Threshold */ 154 | #define HREF 0x32 /* Image Start and Size Control */ 155 | #define DM_LNL 0x33 /* Dummy Row Low 8 Bits */ 156 | #define DM_LNH 0x34 /* Dummy Row High 8 Bits */ 157 | #define ADOFF_B 0x35 /* AD Offset Compensation Value for B Channel */ 158 | #define ADOFF_R 0x36 /* AD Offset Compensation Value for R Channel */ 159 | #define ADOFF_GB 0x37 /* AD Offset Compensation Value for GB Channel */ 160 | #define ADOFF_GR 0x38 /* AD Offset Compensation Value for GR Channel */ 161 | #define OFF_B 0x39 /* AD Offset Compensation Value for B Channel */ 162 | #define OFF_R 0x3A /* AD Offset Compensation Value for R Channel */ 163 | #define OFF_GB 0x3B /* AD Offset Compensation Value for GB Channel */ 164 | #define OFF_GR 0x3C /* AD Offset Compensation Value for GR Channel */ 165 | #define COM12 0x3D /* DC offset compensation for analog process */ 166 | 167 | #define COM13 0x3E /* Common Control 13 */ 168 | #define COM13_BLC_EN 0x80 /* BLC enable */ 169 | #define COM13_ADC_EN 0x40 /* ADC channel BLC ON/OFF control */ 170 | #define COM13_ANALOG_BLC 0x20 /* Analog processing channel BLC ON/OFF control */ 171 | #define COM13_ABLC_GAIN_EN 0x04 /* ABLC gain trigger enable */ 172 | 173 | #define COM14 0x3F /* Common Control 14 */ 174 | #define COM15 0x40 /* Common Control 15 */ 175 | #define COM16 0x41 /* Common Control 16 */ 176 | #define TGT_B 0x42 /* BLC Blue Channel Target Value */ 177 | #define TGT_R 0x43 /* BLC Red Channel Target Value */ 178 | #define TGT_GB 0x44 /* BLC Gb Channel Target Value */ 179 | #define TGT_GR 0x45 /* BLC Gr Channel Target Value */ 180 | 181 | #define LC_CTR 0x46 /* Lens Correction Control */ 182 | #define LC_CTR_RGB_COMP_1 0x00 /* R, G, and B channel compensation coefficient is set by LC_COEF (0x49) */ 183 | #define LC_CTR_RGB_COMP_3 0x04 /* R, G, and B channel compensation coefficient is set by registers 184 | LC_COEFB (0x4B), LC_COEF (0x49), and LC_COEFR (0x4C), respectively */ 185 | #define LC_CTR_EN 0x01 /* Lens correction enable */ 186 | #define LC_XC 0x47 /* X Coordinate of Lens Correction Center Relative to Array Center */ 187 | #define LC_YC 0x48 /* Y Coordinate of Lens Correction Center Relative to Array Center */ 188 | #define LC_COEF 0x49 /* Lens Correction Coefficient */ 189 | #define LC_RADI 0x4A /* Lens Correction Radius */ 190 | #define LC_COEFB 0x4B /* Lens Correction B Channel Compensation Coefficient */ 191 | #define LC_COEFR 0x4C /* Lens Correction R Channel Compensation Coefficient */ 192 | 193 | #define FIXGAIN 0x4D /* Analog Fix Gain Amplifier */ 194 | #define AREF0 0x4E /* Sensor Reference Control */ 195 | #define AREF1 0x4F /* Sensor Reference Current Control */ 196 | #define AREF2 0x50 /* Analog Reference Control */ 197 | #define AREF3 0x51 /* ADC Reference Control */ 198 | #define AREF4 0x52 /* ADC Reference Control */ 199 | #define AREF5 0x53 /* ADC Reference Control */ 200 | #define AREF6 0x54 /* Analog Reference Control */ 201 | #define AREF7 0x55 /* Analog Reference Control */ 202 | #define UFIX 0x60 /* U Channel Fixed Value Output */ 203 | #define VFIX 0x61 /* V Channel Fixed Value Output */ 204 | #define AWBB_BLK 0x62 /* AWB Option for Advanced AWB */ 205 | 206 | #define AWB_CTRL0 0x63 /* AWB Control Byte 0 */ 207 | #define AWB_CTRL0_GAIN_EN 0x80 /* AWB gain enable */ 208 | #define AWB_CTRL0_CALC_EN 0x40 /* AWB calculate enable */ 209 | #define AWB_CTRL0_WBC_MASK 0x0F /* WBC threshold 2 */ 210 | 211 | #define DSP_CTRL1 0x64 /* DSP Control Byte 1 */ 212 | #define DSP_CTRL1_FIFO_EN 0x80 /* FIFO enable/disable selection */ 213 | #define DSP_CTRL1_UV_EN 0x40 /* UV adjust function ON/OFF selection */ 214 | #define DSP_CTRL1_SDE_EN 0x20 /* SDE enable */ 215 | #define DSP_CTRL1_MTRX_EN 0x10 /* Color matrix ON/OFF selection */ 216 | #define DSP_CTRL1_INTRP_EN 0x08 /* Interpolation ON/OFF selection */ 217 | #define DSP_CTRL1_GAMMA_EN 0x04 /* Gamma function ON/OFF selection */ 218 | #define DSP_CTRL1_BLACK_EN 0x02 /* Black defect auto correction ON/OFF */ 219 | #define DSP_CTRL1_WHITE_EN 0x01 /* White defect auto correction ON/OFF */ 220 | 221 | #define DSP_CTRL2 0x65 /* DSP Control Byte 2 */ 222 | #define DSP_CTRL2_VDCW_EN 0x08 /* Vertical DCW enable */ 223 | #define DSP_CTRL2_HDCW_EN 0x04 /* Horizontal DCW enable */ 224 | #define DSP_CTRL2_VZOOM_EN 0x02 /* Vertical zoom out enable */ 225 | #define DSP_CTRL2_HZOOM_EN 0x01 /* Horizontal zoom out enable */ 226 | 227 | #define DSP_CTRL3 0x66 /* DSP Control Byte 3 */ 228 | #define DSP_CTRL3_UV_EN 0x80 /* UV output sequence option */ 229 | #define DSP_CTRL3_CBAR_EN 0x20 /* DSP color bar ON/OFF selection */ 230 | #define DSP_CTRL3_FIFO_EN 0x08 /* FIFO power down ON/OFF selection */ 231 | #define DSP_CTRL3_SCAL1_PWDN 0x04 /* Scaling module power down control 1 */ 232 | #define DSP_CTRL3_SCAL2_PWDN 0x02 /* Scaling module power down control 2 */ 233 | #define DSP_CTRL3_INTRP_PWDN 0x01 /* Interpolation module power down control */ 234 | #define DSP_CTRL3_SET_CBAR(r, x) ((r&0xDF)|((x&1)<<5)) 235 | 236 | 237 | #define DSP_CTRL4 0x67 /* DSP Control Byte 4 */ 238 | #define DSP_CTRL4_YUV_RGB 0x00 /* Output selection YUV or RGB */ 239 | #define DSP_CTRL4_RAW8 0x02 /* Output selection RAW8 */ 240 | #define DSP_CTRL4_RAW10 0x03 /* Output selection RAW10 */ 241 | 242 | 243 | #define AWB_BIAS 0x68 /* AWB BLC Level Clip */ 244 | #define AWB_CTRL1 0x69 /* AWB Control 1 */ 245 | #define AWB_CTRL2 0x6A /* AWB Control 2 */ 246 | 247 | #define AWB_CTRL3 0x6B /* AWB Control 3 */ 248 | #define AWB_CTRL3_ADVANCED 0x80 /* AWB mode select - Advanced AWB */ 249 | #define AWB_CTRL3_SIMPLE 0x00 /* AWB mode select - Simple AWB */ 250 | 251 | #define AWB_CTRL4 0x6C /* AWB Control 4 */ 252 | #define AWB_CTRL5 0x6D /* AWB Control 5 */ 253 | #define AWB_CTRL6 0x6E /* AWB Control 6 */ 254 | #define AWB_CTRL7 0x6F /* AWB Control 7 */ 255 | #define AWB_CTRL8 0x70 /* AWB Control 8 */ 256 | #define AWB_CTRL9 0x71 /* AWB Control 9 */ 257 | #define AWB_CTRL10 0x72 /* AWB Control 10 */ 258 | #define AWB_CTRL11 0x73 /* AWB Control 11 */ 259 | #define AWB_CTRL12 0x74 /* AWB Control 12 */ 260 | #define AWB_CTRL13 0x75 /* AWB Control 13 */ 261 | #define AWB_CTRL14 0x76 /* AWB Control 14 */ 262 | #define AWB_CTRL15 0x77 /* AWB Control 15 */ 263 | #define AWB_CTRL16 0x78 /* AWB Control 16 */ 264 | #define AWB_CTRL17 0x79 /* AWB Control 17 */ 265 | #define AWB_CTRL18 0x7A /* AWB Control 18 */ 266 | #define AWB_CTRL19 0x7B /* AWB Control 19 */ 267 | #define AWB_CTRL20 0x7C /* AWB Control 20 */ 268 | #define AWB_CTRL21 0x7D /* AWB Control 21 */ 269 | #define GAM1 0x7E /* Gamma Curve 1st Segment Input End Point 0x04 Output Value */ 270 | #define GAM2 0x7F /* Gamma Curve 2nd Segment Input End Point 0x08 Output Value */ 271 | #define GAM3 0x80 /* Gamma Curve 3rd Segment Input End Point 0x10 Output Value */ 272 | #define GAM4 0x81 /* Gamma Curve 4th Segment Input End Point 0x20 Output Value */ 273 | #define GAM5 0x82 /* Gamma Curve 5th Segment Input End Point 0x28 Output Value */ 274 | #define GAM6 0x83 /* Gamma Curve 6th Segment Input End Point 0x30 Output Value */ 275 | #define GAM7 0x84 /* Gamma Curve 7th Segment Input End Point 0x38 Output Value */ 276 | #define GAM8 0x85 /* Gamma Curve 8th Segment Input End Point 0x40 Output Value */ 277 | #define GAM9 0x86 /* Gamma Curve 9th Segment Input End Point 0x48 Output Value */ 278 | #define GAM10 0x87 /* Gamma Curve 10th Segment Input End Point 0x50 Output Value */ 279 | #define GAM11 0x88 /* Gamma Curve 11th Segment Input End Point 0x60 Output Value */ 280 | #define GAM12 0x89 /* Gamma Curve 12th Segment Input End Point 0x70 Output Value */ 281 | #define GAM13 0x8A /* Gamma Curve 13th Segment Input End Point 0x90 Output Value */ 282 | #define GAM14 0x8B /* Gamma Curve 14th Segment Input End Point 0xB0 Output Value */ 283 | #define GAM15 0x8C /* Gamma Curve 15th Segment Input End Point 0xD0 Output Value */ 284 | #define SLOP 0x8D /* Gamma Curve Highest Segment Slope */ 285 | #define DNSTH 0x8E /* De-noise Threshold */ 286 | #define EDGE0 0x8F /* Edge Enhancement Strength Control */ 287 | #define EDGE1 0x90 /* Edge Enhancement Threshold Control */ 288 | #define DNSOFF 0x91 /* Auto De-noise Threshold Control */ 289 | #define EDGE2 0x92 /* Edge Enhancement Strength Upper Limit */ 290 | #define EDGE3 0x93 /* Edge Enhancement Strength Upper Limit */ 291 | #define MTX1 0x94 /* Matrix Coefficient 1 */ 292 | #define MTX2 0x95 /* Matrix Coefficient 2 */ 293 | #define MTX3 0x96 /* Matrix Coefficient 3 */ 294 | #define MTX4 0x97 /* Matrix Coefficient 4 */ 295 | #define MTX5 0x98 /* Matrix Coefficient 5 */ 296 | #define MTX6 0x99 /* Matrix Coefficient 6 */ 297 | 298 | #define MTX_CTRL 0x9A /* Matrix Control */ 299 | #define MTX_CTRL_DBL_EN 0x80 /* Matrix double ON/OFF selection */ 300 | 301 | #define BRIGHTNESS 0x9B /* Brightness Control */ 302 | #define CONTRAST 0x9C /* Contrast Gain */ 303 | #define UVADJ0 0x9E /* Auto UV Adjust Control 0 */ 304 | #define UVADJ1 0x9F /* Auto UV Adjust Control 1 */ 305 | #define SCAL0 0xA0 /* DCW Ratio Control */ 306 | #define SCAL1 0xA1 /* Horizontal Zoom Out Control */ 307 | #define SCAL2 0xA2 /* Vertical Zoom Out Control */ 308 | #define FIFODLYM 0xA3 /* FIFO Manual Mode Delay Control */ 309 | #define FIFODLYA 0xA4 /* FIFO Auto Mode Delay Control */ 310 | 311 | #define SDE 0xA6 /* Special Digital Effect Control */ 312 | #define SDE_NEGATIVE_EN 0x40 /* Negative image enable */ 313 | #define SDE_GRAYSCALE_EN 0x20 /* Gray scale image enable */ 314 | #define SDE_V_FIXED_EN 0x10 /* V fixed value enable */ 315 | #define SDE_U_FIXED_EN 0x08 /* U fixed value enable */ 316 | #define SDE_CONT_BRIGHT_EN 0x04 /* Contrast/Brightness enable */ 317 | #define SDE_SATURATION_EN 0x02 /* Saturation enable */ 318 | #define SDE_HUE_EN 0x01 /* Hue enable */ 319 | 320 | #define USAT 0xA7 /* U Component Saturation Gain */ 321 | #define VSAT 0xA8 /* V Component Saturation Gain */ 322 | #define HUECOS 0xA9 /* Cosine value × 0x80 */ 323 | #define HUESIN 0xAA /* Sine value × 0x80 */ 324 | #define SIGN_BIT 0xAB /* Sign Bit for Hue and Brightness */ 325 | 326 | #define DSPAUTO 0xAC /* DSP Auto Function ON/OFF Control */ 327 | #define DSPAUTO_AWB_EN 0x80 /* AWB auto threshold control */ 328 | #define DSPAUTO_DENOISE_EN 0x40 /* De-noise auto threshold control */ 329 | #define DSPAUTO_EDGE_EN 0x20 /* Sharpness (edge enhancement) auto strength control */ 330 | #define DSPAUTO_UV_EN 0x10 /* UV adjust auto slope control */ 331 | #define DSPAUTO_SCAL0_EN 0x08 /* Auto scaling factor control (register SCAL0 (0xA0)) */ 332 | #define DSPAUTO_SCAL1_EN 0x04 /* Auto scaling factor control (registers SCAL1 (0xA1 and SCAL2 (0xA2))*/ 333 | #define SET_REG(reg, x) (##reg_DEFAULT|x) 334 | #endif //__REG_REGS_H__ 335 | -------------------------------------------------------------------------------- /examples/Camera/src/ov264_drive.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 | * OV2640 driver. 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include "sccb.h" 13 | #include "ov264_drive.h" 14 | #include "ov2640_regs.h" 15 | 16 | #define SVGA_HSIZE (800) 17 | #define SVGA_VSIZE (600) 18 | 19 | #define UXGA_HSIZE (1600) 20 | #define UXGA_VSIZE (1200) 21 | 22 | static const uint8_t default_regs[][2] = { 23 | { BANK_SEL, BANK_SEL_DSP }, 24 | { 0x2c, 0xff }, 25 | { 0x2e, 0xdf }, 26 | { BANK_SEL, BANK_SEL_SENSOR }, 27 | { 0x3c, 0x32 }, 28 | { CLKRC, 0x80 }, /* Set PCLK divider */ 29 | { COM2, COM2_OUT_DRIVE_3x }, /* Output drive x2 */ 30 | #ifdef OPENMV2 31 | { REG04, 0xF8}, /* Mirror/VFLIP/AEC[1:0] */ 32 | #else 33 | { REG04_SET(REG04_HREF_EN)}, 34 | #endif 35 | { COM8, COM8_SET(COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN) }, 36 | { COM9, COM9_AGC_SET(COM9_AGC_GAIN_8x)}, 37 | {COM10, 0}, //Invert VSYNC 38 | { 0x2c, 0x0c }, 39 | { 0x33, 0x78 }, 40 | { 0x3a, 0x33 }, 41 | { 0x3b, 0xfb }, 42 | { 0x3e, 0x00 }, 43 | { 0x43, 0x11 }, 44 | { 0x16, 0x10 }, 45 | { 0x39, 0x02 }, 46 | { 0x35, 0x88 }, 47 | { 0x22, 0x0a }, 48 | { 0x37, 0x40 }, 49 | { 0x23, 0x00 }, 50 | { ARCOM2, 0xa0 }, 51 | { 0x06, 0x02 }, 52 | { 0x06, 0x88 }, 53 | { 0x07, 0xc0 }, 54 | { 0x0d, 0xb7 }, 55 | { 0x0e, 0x01 }, 56 | { 0x4c, 0x00 }, 57 | { 0x4a, 0x81 }, 58 | { 0x21, 0x99 }, 59 | { AEW, 0x40 }, 60 | { AEB, 0x38 }, 61 | /* AGC/AEC fast mode operating region */ 62 | { VV, VV_AGC_TH_SET(0x08, 0x02) }, 63 | { COM19, 0x00 }, /* Zoom control 2 MSBs */ 64 | { ZOOMS, 0x00 }, /* Zoom control 8 MSBs */ 65 | { 0x5c, 0x00 }, 66 | { 0x63, 0x00 }, 67 | { FLL, 0x00 }, 68 | { FLH, 0x00 }, 69 | 70 | /* Set banding filter */ 71 | { COM3, COM3_BAND_SET(COM3_BAND_AUTO) }, 72 | { REG5D, 0x55 }, 73 | { REG5E, 0x7d }, 74 | { REG5F, 0x7d }, 75 | { REG60, 0x55 }, 76 | { HISTO_LOW, 0x70 }, 77 | { HISTO_HIGH, 0x80 }, 78 | { 0x7c, 0x05 }, 79 | { 0x20, 0x80 }, 80 | { 0x28, 0x30 }, 81 | { 0x6c, 0x00 }, 82 | { 0x6d, 0x80 }, 83 | { 0x6e, 0x00 }, 84 | { 0x70, 0x02 }, 85 | { 0x71, 0x94 }, 86 | { 0x73, 0xc1 }, 87 | { 0x3d, 0x34 }, 88 | //{ COM7, COM7_RES_UXGA | COM7_ZOOM_EN }, 89 | { 0x5a, 0x57 }, 90 | { BD50, 0xbb }, 91 | { BD60, 0x9c }, 92 | 93 | { BANK_SEL, BANK_SEL_DSP }, 94 | { 0xe5, 0x7f }, 95 | { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL }, 96 | { 0x41, 0x24 }, 97 | { RESET, RESET_JPEG | RESET_DVP }, 98 | { 0x76, 0xff }, 99 | { 0x33, 0xa0 }, 100 | { 0x42, 0x20 }, 101 | { 0x43, 0x18 }, 102 | { 0x4c, 0x00 }, 103 | { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 }, 104 | { 0x88, 0x3f }, 105 | { 0xd7, 0x03 }, 106 | { 0xd9, 0x10 }, 107 | { R_DVP_SP , R_DVP_SP_AUTO_MODE | 0x2 }, 108 | { 0xc8, 0x08 }, 109 | { 0xc9, 0x80 }, 110 | { BPADDR, 0x00 }, 111 | { BPDATA, 0x00 }, 112 | { BPADDR, 0x03 }, 113 | { BPDATA, 0x48 }, 114 | { BPDATA, 0x48 }, 115 | { BPADDR, 0x08 }, 116 | { BPDATA, 0x20 }, 117 | { BPDATA, 0x10 }, 118 | { BPDATA, 0x0e }, 119 | { 0x90, 0x00 }, 120 | { 0x91, 0x0e }, 121 | { 0x91, 0x1a }, 122 | { 0x91, 0x31 }, 123 | { 0x91, 0x5a }, 124 | { 0x91, 0x69 }, 125 | { 0x91, 0x75 }, 126 | { 0x91, 0x7e }, 127 | { 0x91, 0x88 }, 128 | { 0x91, 0x8f }, 129 | { 0x91, 0x96 }, 130 | { 0x91, 0xa3 }, 131 | { 0x91, 0xaf }, 132 | { 0x91, 0xc4 }, 133 | { 0x91, 0xd7 }, 134 | { 0x91, 0xe8 }, 135 | { 0x91, 0x20 }, 136 | { 0x92, 0x00 }, 137 | { 0x93, 0x06 }, 138 | { 0x93, 0xe3 }, 139 | { 0x93, 0x03 }, 140 | { 0x93, 0x03 }, 141 | { 0x93, 0x00 }, 142 | { 0x93, 0x02 }, 143 | { 0x93, 0x00 }, 144 | { 0x93, 0x00 }, 145 | { 0x93, 0x00 }, 146 | { 0x93, 0x00 }, 147 | { 0x93, 0x00 }, 148 | { 0x93, 0x00 }, 149 | { 0x93, 0x00 }, 150 | { 0x96, 0x00 }, 151 | { 0x97, 0x08 }, 152 | { 0x97, 0x19 }, 153 | { 0x97, 0x02 }, 154 | { 0x97, 0x0c }, 155 | { 0x97, 0x24 }, 156 | { 0x97, 0x30 }, 157 | { 0x97, 0x28 }, 158 | { 0x97, 0x26 }, 159 | { 0x97, 0x02 }, 160 | { 0x97, 0x98 }, 161 | { 0x97, 0x80 }, 162 | { 0x97, 0x00 }, 163 | { 0x97, 0x00 }, 164 | { 0xa4, 0x00 }, 165 | { 0xa8, 0x00 }, 166 | { 0xc5, 0x11 }, 167 | { 0xc6, 0x51 }, 168 | { 0xbf, 0x80 }, 169 | { 0xc7, 0x10 }, 170 | { 0xb6, 0x66 }, 171 | { 0xb8, 0xA5 }, 172 | { 0xb7, 0x64 }, 173 | { 0xb9, 0x7C }, 174 | { 0xb3, 0xaf }, 175 | { 0xb4, 0x97 }, 176 | { 0xb5, 0xFF }, 177 | { 0xb0, 0xC5 }, 178 | { 0xb1, 0x94 }, 179 | { 0xb2, 0x0f }, 180 | { 0xc4, 0x5c }, 181 | { 0xa6, 0x00 }, 182 | { 0xa7, 0x20 }, 183 | { 0xa7, 0xd8 }, 184 | { 0xa7, 0x1b }, 185 | { 0xa7, 0x31 }, 186 | { 0xa7, 0x00 }, 187 | { 0xa7, 0x18 }, 188 | { 0xa7, 0x20 }, 189 | { 0xa7, 0xd8 }, 190 | { 0xa7, 0x19 }, 191 | { 0xa7, 0x31 }, 192 | { 0xa7, 0x00 }, 193 | { 0xa7, 0x18 }, 194 | { 0xa7, 0x20 }, 195 | { 0xa7, 0xd8 }, 196 | { 0xa7, 0x19 }, 197 | { 0xa7, 0x31 }, 198 | { 0xa7, 0x00 }, 199 | { 0xa7, 0x18 }, 200 | { 0x7f, 0x00 }, 201 | { 0xe5, 0x1f }, 202 | { 0xe1, 0x77 }, 203 | { 0xdd, 0x7f }, 204 | { CTRL0, CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN }, 205 | { 0x00, 0x00 } 206 | }; 207 | 208 | static const uint8_t cif_regs[][2] = { 209 | }; 210 | 211 | static const uint8_t svga_regs[][2] = { 212 | { BANK_SEL, BANK_SEL_SENSOR }, 213 | /* DSP input image resoultion and window size control */ 214 | { COM7, COM7_RES_SVGA}, 215 | { COM1, 0x0F }, /* UXGA=0x0F, SVGA=0x0A, CIF=0x06 */ 216 | { REG32, 0x09 }, /* UXGA=0x36, SVGA/CIF=0x09 */ 217 | 218 | { HSTART, 0x11 }, /* UXGA=0x11, SVGA/CIF=0x11 */ 219 | { HSTOP, 0x43 }, /* UXGA=0x75, SVGA/CIF=0x43 */ 220 | 221 | { VSTART, 0x00 }, /* UXGA=0x01, SVGA/CIF=0x00 */ 222 | { VSTOP, 0x4b }, /* UXGA=0x97, SVGA/CIF=0x4b */ 223 | { 0x3d, 0x38 }, /* UXGA=0x34, SVGA/CIF=0x38 */ 224 | 225 | { 0x35, 0xda }, 226 | { 0x22, 0x1a }, 227 | { 0x37, 0xc3 }, 228 | { 0x34, 0xc0 }, 229 | { 0x06, 0x88 }, 230 | { 0x0d, 0x87 }, 231 | { 0x0e, 0x41 }, 232 | { 0x42, 0x03 }, 233 | 234 | /* Set DSP input image size and offset. 235 | The sensor output image can be scaled with OUTW/OUTH */ 236 | { BANK_SEL, BANK_SEL_DSP }, 237 | { R_BYPASS, R_BYPASS_DSP_BYPAS }, 238 | 239 | { RESET, RESET_DVP }, 240 | { HSIZE8, (SVGA_HSIZE>>3)}, /* Image Horizontal Size HSIZE[10:3] */ 241 | { VSIZE8, (SVGA_VSIZE>>3)}, /* Image Vertiacl Size VSIZE[10:3] */ 242 | 243 | /* {HSIZE[11], HSIZE[2:0], VSIZE[2:0]} */ 244 | { SIZEL, ((SVGA_HSIZE>>6)&0x40) | ((SVGA_HSIZE&0x7)<<3) | (SVGA_VSIZE&0x7)}, 245 | 246 | { XOFFL, 0x00 }, /* OFFSET_X[7:0] */ 247 | { YOFFL, 0x00 }, /* OFFSET_Y[7:0] */ 248 | { HSIZE, ((SVGA_HSIZE>>2)&0xFF) }, /* H_SIZE[7:0]= HSIZE/4 */ 249 | { VSIZE, ((SVGA_VSIZE>>2)&0xFF) }, /* V_SIZE[7:0]= VSIZE/4 */ 250 | 251 | /* V_SIZE[8]/OFFSET_Y[10:8]/H_SIZE[8]/OFFSET_X[10:8] */ 252 | { VHYX, ((SVGA_VSIZE>>3)&0x80) | ((SVGA_HSIZE>>7)&0x08) }, 253 | { TEST, (SVGA_HSIZE>>4)&0x80}, /* H_SIZE[9] */ 254 | 255 | { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | 256 | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN }, 257 | 258 | /* H_DIVIDER/V_DIVIDER */ 259 | { CTRLI, CTRLI_LP_DP | 0x00}, 260 | /* DVP prescalar */ 261 | { R_DVP_SP, R_DVP_SP_AUTO_MODE}, 262 | 263 | { R_BYPASS, R_BYPASS_DSP_EN }, 264 | { RESET, 0x00 }, 265 | {0, 0}, 266 | }; 267 | 268 | static const uint8_t uxga_regs[][2] = { 269 | { BANK_SEL, BANK_SEL_SENSOR }, 270 | /* DSP input image resoultion and window size control */ 271 | { COM7, COM7_RES_UXGA}, 272 | { COM1, 0x0F }, /* UXGA=0x0F, SVGA=0x0A, CIF=0x06 */ 273 | { REG32, 0x36 }, /* UXGA=0x36, SVGA/CIF=0x09 */ 274 | 275 | { HSTART, 0x11 }, /* UXGA=0x11, SVGA/CIF=0x11 */ 276 | { HSTOP, 0x75 }, /* UXGA=0x75, SVGA/CIF=0x43 */ 277 | 278 | { VSTART, 0x01 }, /* UXGA=0x01, SVGA/CIF=0x00 */ 279 | { VSTOP, 0x97 }, /* UXGA=0x97, SVGA/CIF=0x4b */ 280 | { 0x3d, 0x34 }, /* UXGA=0x34, SVGA/CIF=0x38 */ 281 | 282 | { 0x35, 0x88 }, 283 | { 0x22, 0x0a }, 284 | { 0x37, 0x40 }, 285 | { 0x34, 0xa0 }, 286 | { 0x06, 0x02 }, 287 | { 0x0d, 0xb7 }, 288 | { 0x0e, 0x01 }, 289 | { 0x42, 0x83 }, 290 | 291 | /* Set DSP input image size and offset. 292 | The sensor output image can be scaled with OUTW/OUTH */ 293 | { BANK_SEL, BANK_SEL_DSP }, 294 | { R_BYPASS, R_BYPASS_DSP_BYPAS }, 295 | 296 | { RESET, RESET_DVP }, 297 | { HSIZE8, (UXGA_HSIZE>>3)}, /* Image Horizontal Size HSIZE[10:3] */ 298 | { VSIZE8, (UXGA_VSIZE>>3)}, /* Image Vertiacl Size VSIZE[10:3] */ 299 | 300 | /* {HSIZE[11], HSIZE[2:0], VSIZE[2:0]} */ 301 | { SIZEL, ((UXGA_HSIZE>>6)&0x40) | ((UXGA_HSIZE&0x7)<<3) | (UXGA_VSIZE&0x7)}, 302 | 303 | { XOFFL, 0x00 }, /* OFFSET_X[7:0] */ 304 | { YOFFL, 0x00 }, /* OFFSET_Y[7:0] */ 305 | { HSIZE, ((UXGA_HSIZE>>2)&0xFF) }, /* H_SIZE[7:0] real/4 */ 306 | { VSIZE, ((UXGA_VSIZE>>2)&0xFF) }, /* V_SIZE[7:0] real/4 */ 307 | 308 | /* V_SIZE[8]/OFFSET_Y[10:8]/H_SIZE[8]/OFFSET_X[10:8] */ 309 | { VHYX, ((UXGA_VSIZE>>3)&0x80) | ((UXGA_HSIZE>>7)&0x08) }, 310 | { TEST, (UXGA_HSIZE>>4)&0x80}, /* H_SIZE[9] */ 311 | 312 | { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | 313 | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN }, 314 | 315 | /* H_DIVIDER/V_DIVIDER */ 316 | { CTRLI, CTRLI_LP_DP | 0x00}, 317 | /* DVP prescalar */ 318 | { R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x04}, 319 | 320 | { R_BYPASS, R_BYPASS_DSP_EN }, 321 | { RESET, 0x00 }, 322 | {0, 0}, 323 | }; 324 | 325 | static const uint8_t yuv422_regs[][2] = { 326 | { BANK_SEL, BANK_SEL_DSP }, 327 | { RESET, RESET_DVP}, 328 | { IMAGE_MODE, IMAGE_MODE_YUV422 }, 329 | { 0xD7, 0x01 }, 330 | { 0xE1, 0x67 }, 331 | { RESET, 0x00 }, 332 | {0, 0}, 333 | }; 334 | 335 | static const uint8_t rgb565_regs[][2] = { 336 | { BANK_SEL, BANK_SEL_DSP }, 337 | { RESET, RESET_DVP}, 338 | { IMAGE_MODE, IMAGE_MODE_RGB565 }, 339 | { 0xD7, 0x03 }, 340 | { 0xE1, 0x77 }, 341 | { RESET, 0x00 }, 342 | {0, 0}, 343 | }; 344 | 345 | static const uint8_t jpeg_regs[][2] = { 346 | { BANK_SEL, BANK_SEL_DSP }, 347 | { RESET, RESET_DVP}, 348 | { IMAGE_MODE, IMAGE_MODE_JPEG_EN|IMAGE_MODE_RGB565 }, 349 | { 0xD7, 0x03 }, 350 | { 0xE1, 0x77 }, 351 | { QS, 0x0C }, 352 | { RESET, 0x00 }, 353 | {0, 0}, 354 | }; 355 | 356 | //|IMAGE_MODE_HREF_VSYNC 357 | 358 | #define NUM_BRIGHTNESS_LEVELS (5) 359 | static const uint8_t brightness_regs[NUM_BRIGHTNESS_LEVELS + 1][5] = { 360 | { BPADDR, BPDATA, BPADDR, BPDATA, BPDATA }, 361 | { 0x00, 0x04, 0x09, 0x00, 0x00 }, /* -2 */ 362 | { 0x00, 0x04, 0x09, 0x10, 0x00 }, /* -1 */ 363 | { 0x00, 0x04, 0x09, 0x20, 0x00 }, /* 0 */ 364 | { 0x00, 0x04, 0x09, 0x30, 0x00 }, /* +1 */ 365 | { 0x00, 0x04, 0x09, 0x40, 0x00 }, /* +2 */ 366 | }; 367 | 368 | #define NUM_CONTRAST_LEVELS (5) 369 | static const uint8_t contrast_regs[NUM_CONTRAST_LEVELS + 1][7] = { 370 | { BPADDR, BPDATA, BPADDR, BPDATA, BPDATA, BPDATA, BPDATA }, 371 | { 0x00, 0x04, 0x07, 0x20, 0x18, 0x34, 0x06 }, /* -2 */ 372 | { 0x00, 0x04, 0x07, 0x20, 0x1c, 0x2a, 0x06 }, /* -1 */ 373 | { 0x00, 0x04, 0x07, 0x20, 0x20, 0x20, 0x06 }, /* 0 */ 374 | { 0x00, 0x04, 0x07, 0x20, 0x24, 0x16, 0x06 }, /* +1 */ 375 | { 0x00, 0x04, 0x07, 0x20, 0x28, 0x0c, 0x06 }, /* +2 */ 376 | }; 377 | 378 | #define NUM_SATURATION_LEVELS (5) 379 | static const uint8_t saturation_regs[NUM_SATURATION_LEVELS + 1][5] = { 380 | { BPADDR, BPDATA, BPADDR, BPDATA, BPDATA }, 381 | { 0x00, 0x02, 0x03, 0x28, 0x28 }, /* -2 */ 382 | { 0x00, 0x02, 0x03, 0x38, 0x38 }, /* -1 */ 383 | { 0x00, 0x02, 0x03, 0x48, 0x48 }, /* 0 */ 384 | { 0x00, 0x02, 0x03, 0x58, 0x58 }, /* +1 */ 385 | { 0x00, 0x02, 0x03, 0x58, 0x58 }, /* +2 */ 386 | }; 387 | 388 | static int reset(sensor_t *sensor) 389 | { 390 | int i=0; 391 | const uint8_t (*regs)[2]; 392 | 393 | /* Reset all registers */ 394 | SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 395 | SCCB_Write(sensor->slv_addr, COM7, COM7_SRST); 396 | 397 | /* delay n ms */ 398 | delay(10); 399 | 400 | i = 0; 401 | regs = default_regs; 402 | /* Write initial regsiters */ 403 | while (regs[i][0]) { 404 | SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); 405 | i++; 406 | } 407 | 408 | i = 0; 409 | regs = svga_regs; 410 | /* Write DSP input regsiters */ 411 | while (regs[i][0]) { 412 | SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); 413 | i++; 414 | } 415 | 416 | return 0; 417 | } 418 | 419 | static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) 420 | { 421 | int i=0; 422 | const uint8_t (*regs)[2]=NULL; 423 | 424 | /* read pixel format reg */ 425 | switch (pixformat) { 426 | case PIXFORMAT_RGB565: 427 | regs = rgb565_regs; 428 | break; 429 | case PIXFORMAT_YUV422: 430 | case PIXFORMAT_GRAYSCALE: 431 | regs = yuv422_regs; 432 | break; 433 | case PIXFORMAT_JPEG: 434 | regs = jpeg_regs; 435 | break; 436 | default: 437 | return -1; 438 | } 439 | 440 | /* Write initial regsiters */ 441 | while (regs[i][0]) { 442 | SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); 443 | i++; 444 | } 445 | 446 | /* delay n ms */ 447 | delay(30); 448 | 449 | return 0; 450 | } 451 | 452 | static int set_framesize(sensor_t *sensor, framesize_t framesize) 453 | { 454 | int ret=0; 455 | uint8_t clkrc; 456 | uint16_t w = resolution[framesize][0]; 457 | uint16_t h = resolution[framesize][1]; 458 | 459 | int i=0; 460 | const uint8_t (*regs)[2]; 461 | 462 | if (framesize <= FRAMESIZE_SVGA) { 463 | clkrc =0x83; 464 | regs = svga_regs; 465 | } else { 466 | clkrc =0x87; 467 | regs = uxga_regs; 468 | } 469 | 470 | /* Disable DSP */ 471 | 472 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); 473 | ret |= SCCB_Write(sensor->slv_addr, R_BYPASS, R_BYPASS_DSP_BYPAS); 474 | 475 | /* Write output width */ 476 | ret |= SCCB_Write(sensor->slv_addr, ZMOW, (w>>2)&0xFF); // OUTW[7:0] (real/4) 477 | ret |= SCCB_Write(sensor->slv_addr, ZMOH, (h>>2)&0xFF); // OUTH[7:0] (real/4) 478 | ret |= SCCB_Write(sensor->slv_addr, ZMHH, ((h>>8)&0x04)|((w>>10)&0x03)); // OUTH[8]/OUTW[9:8] 479 | 480 | /* Set CLKRC */ 481 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 482 | ret |= SCCB_Write(sensor->slv_addr, CLKRC, clkrc); 483 | 484 | /* Write DSP input regsiters */ 485 | while (regs[i][0]) { 486 | SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); 487 | i++; 488 | } 489 | 490 | /* Enable DSP */ 491 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); 492 | ret |= SCCB_Write(sensor->slv_addr, R_BYPASS, R_BYPASS_DSP_EN); 493 | /* delay n ms */ 494 | delay(30); 495 | 496 | return ret; 497 | } 498 | 499 | static int set_framerate(sensor_t *sensor, framerate_t framerate) 500 | { 501 | return 0; 502 | } 503 | 504 | static int set_contrast(sensor_t *sensor, int level) 505 | { 506 | int ret=0; 507 | 508 | level += (NUM_CONTRAST_LEVELS / 2 + 1); 509 | if (level < 0 || level > NUM_CONTRAST_LEVELS) { 510 | return -1; 511 | } 512 | 513 | /* Switch to DSP register bank */ 514 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); 515 | 516 | /* Write contrast registers */ 517 | for (int i=0; islv_addr, contrast_regs[0][i], contrast_regs[level][i]); 519 | } 520 | 521 | return ret; 522 | } 523 | 524 | static int set_brightness(sensor_t *sensor, int level) 525 | { 526 | int ret=0; 527 | 528 | level += (NUM_BRIGHTNESS_LEVELS / 2 + 1); 529 | if (level < 0 || level > NUM_BRIGHTNESS_LEVELS) { 530 | return -1; 531 | } 532 | 533 | /* Switch to DSP register bank */ 534 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); 535 | 536 | /* Write brightness registers */ 537 | for (int i=0; islv_addr, brightness_regs[0][i], brightness_regs[level][i]); 539 | } 540 | 541 | return ret; 542 | } 543 | 544 | static int set_saturation(sensor_t *sensor, int level) 545 | { 546 | int ret=0; 547 | 548 | level += (NUM_SATURATION_LEVELS / 2 + 1); 549 | if (level < 0 || level > NUM_SATURATION_LEVELS) { 550 | return -1; 551 | } 552 | 553 | /* Switch to DSP register bank */ 554 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); 555 | 556 | /* Write contrast registers */ 557 | for (int i=0; islv_addr, saturation_regs[0][i], saturation_regs[level][i]); 559 | } 560 | 561 | return ret; 562 | } 563 | 564 | static int set_gainceiling(sensor_t *sensor, gainceiling_t gainceiling) 565 | { 566 | int ret =0; 567 | 568 | /* Switch to SENSOR register bank */ 569 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 570 | 571 | /* Write gain ceiling register */ 572 | ret |= SCCB_Write(sensor->slv_addr, COM9, COM9_AGC_SET(gainceiling)); 573 | 574 | return ret; 575 | } 576 | 577 | static int set_quality(sensor_t *sensor, int qs) 578 | { 579 | int ret=0; 580 | 581 | /* Switch to DSP register bank */ 582 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); 583 | 584 | /* Write QS register */ 585 | ret |= SCCB_Write(sensor->slv_addr, QS, qs); 586 | 587 | return ret; 588 | } 589 | 590 | static int set_colorbar(sensor_t *sensor, int enable) 591 | { 592 | int ret=0; 593 | uint8_t reg; 594 | 595 | /* Switch to SENSOR register bank */ 596 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 597 | 598 | /* Update COM7 */ 599 | reg = SCCB_Read(sensor->slv_addr, COM7); 600 | 601 | if (enable) { 602 | reg |= COM7_COLOR_BAR; 603 | } else { 604 | reg &= ~COM7_COLOR_BAR; 605 | } 606 | 607 | ret |= SCCB_Write(sensor->slv_addr, COM7, reg); 608 | return ret; 609 | } 610 | 611 | static int set_whitebal(sensor_t *sensor, int enable) 612 | { 613 | int ret=0; 614 | uint8_t reg; 615 | 616 | /* Switch to SENSOR register bank */ 617 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); 618 | 619 | /* Update CTRL1 */ 620 | reg = SCCB_Read(sensor->slv_addr, CTRL1); 621 | 622 | if (enable) { 623 | reg |= CTRL1_AWB; 624 | } else { 625 | reg &= ~CTRL1_AWB; 626 | } 627 | 628 | ret |= SCCB_Write(sensor->slv_addr, CTRL1, reg); 629 | return ret; 630 | } 631 | 632 | static int set_gain_ctrl(sensor_t *sensor, int enable) 633 | { 634 | int ret=0; 635 | uint8_t reg; 636 | 637 | /* Switch to SENSOR register bank */ 638 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 639 | 640 | /* Update COM8 */ 641 | reg = SCCB_Read(sensor->slv_addr, COM8); 642 | 643 | if (enable) { 644 | reg |= COM8_AGC_EN; 645 | } else { 646 | reg &= ~COM8_AGC_EN; 647 | } 648 | 649 | ret |= SCCB_Write(sensor->slv_addr, COM8, reg); 650 | return ret; 651 | } 652 | 653 | static int set_exposure_ctrl(sensor_t *sensor, int enable) 654 | { 655 | int ret=0; 656 | uint8_t reg; 657 | 658 | /* Switch to SENSOR register bank */ 659 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 660 | 661 | /* Update COM8 */ 662 | reg = SCCB_Read(sensor->slv_addr, COM8); 663 | 664 | if (enable) { 665 | reg |= COM8_AEC_EN; 666 | } else { 667 | reg &= ~COM8_AEC_EN; 668 | } 669 | 670 | ret |= SCCB_Write(sensor->slv_addr, COM8, reg); 671 | return ret; 672 | } 673 | 674 | static int set_hmirror(sensor_t *sensor, int enable) 675 | { 676 | int ret=0; 677 | uint8_t reg; 678 | 679 | /* Switch to SENSOR register bank */ 680 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 681 | 682 | /* Update REG04 */ 683 | reg = SCCB_Read(sensor->slv_addr, REG04); 684 | 685 | if (enable) { 686 | reg |= REG04_HFLIP_IMG; 687 | } else { 688 | reg &= ~REG04_HFLIP_IMG; 689 | } 690 | 691 | ret |= SCCB_Write(sensor->slv_addr, REG04, reg); 692 | return ret; 693 | } 694 | 695 | static int set_vflip(sensor_t *sensor, int enable) 696 | { 697 | int ret=0; 698 | uint8_t reg; 699 | 700 | /* Switch to SENSOR register bank */ 701 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 702 | 703 | /* Update REG04 */ 704 | reg = SCCB_Read(sensor->slv_addr, REG04); 705 | 706 | if (enable) { 707 | reg |= REG04_VFLIP_IMG; 708 | } else { 709 | reg &= ~REG04_VFLIP_IMG; 710 | } 711 | 712 | ret |= SCCB_Write(sensor->slv_addr, REG04, reg); 713 | return ret; 714 | } 715 | 716 | int ov2640_init(sensor_t *sensor) 717 | { 718 | /* set function pointers */ 719 | sensor->reset = reset; 720 | sensor->set_pixformat = set_pixformat; 721 | sensor->set_framesize = set_framesize; 722 | sensor->set_framerate = set_framerate; 723 | sensor->set_contrast = set_contrast; 724 | sensor->set_brightness= set_brightness; 725 | sensor->set_saturation= set_saturation; 726 | sensor->set_gainceiling = set_gainceiling; 727 | sensor->set_quality = set_quality; 728 | sensor->set_colorbar = set_colorbar; 729 | sensor->set_gain_ctrl = set_gain_ctrl; 730 | sensor->set_exposure_ctrl = set_exposure_ctrl; 731 | sensor->set_whitebal = set_whitebal; 732 | sensor->set_hmirror = set_hmirror; 733 | sensor->set_vflip = set_vflip; 734 | 735 | // Set sensor flags 736 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_VSYNC, 1); 737 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_HSYNC, 0); 738 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_PIXCK, 1); 739 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 1); 740 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 0); 741 | 742 | return 0; 743 | } 744 | -------------------------------------------------------------------------------- /examples/Camera/src/camera.c: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #include 15 | #include 16 | #include 17 | #include "time.h" 18 | #include "sys/time.h" 19 | #include "freertos/FreeRTOS.h" 20 | #include "freertos/task.h" 21 | #include "freertos/semphr.h" 22 | #include "rom/lldesc.h" 23 | #include "soc/soc.h" 24 | #include "soc/gpio_sig_map.h" 25 | #include "soc/i2s_reg.h" 26 | #include "soc/i2s_struct.h" 27 | #include "soc/io_mux_reg.h" 28 | #include "driver/gpio.h" 29 | #include "driver/rtc_io.h" 30 | #include "driver/periph_ctrl.h" 31 | #include "esp_intr_alloc.h" 32 | #include "esp_log.h" 33 | #include "sccb.h" 34 | #include "camera.h" 35 | #include "camera_common.h" 36 | #if CONFIG_OV2640_SUPPORT 37 | #include "ov264_drive.h" 38 | #endif 39 | #if CONFIG_OV7725_SUPPORT 40 | #include "ov7725.h" 41 | #endif 42 | 43 | #define ENABLE_TEST_PATTERN CONFIG_ENABLE_TEST_PATTERN 44 | 45 | #define REG_PID 0x0A 46 | #define REG_VER 0x0B 47 | #define REG_MIDH 0x1C 48 | #define REG_MIDL 0x1D 49 | 50 | static esp_err_t camera_enable_out_clock(camera_config_t *config); 51 | static void camera_disable_out_clock(); 52 | 53 | static const char *TAG = "camera"; 54 | 55 | camera_state_t *s_state = NULL; 56 | 57 | const int resolution[][2] = { 58 | {40, 30}, /* 40x30 */ 59 | {64, 32}, /* 64x32 */ 60 | {64, 64}, /* 64x64 */ 61 | {88, 72}, /* QQCIF */ 62 | {160, 120}, /* QQVGA */ 63 | {128, 160}, /* QQVGA2*/ 64 | {176, 144}, /* QCIF */ 65 | {240, 160}, /* HQVGA */ 66 | {320, 240}, /* QVGA */ 67 | {352, 288}, /* CIF */ 68 | {640, 480}, /* VGA */ 69 | {800, 600}, /* SVGA */ 70 | {1280, 1024}, /* SXGA */ 71 | {1600, 1200}, /* UXGA */ 72 | }; 73 | 74 | static void i2s_init(); 75 | static void i2s_run(); 76 | static void IRAM_ATTR gpio_isr(void *arg); 77 | static void IRAM_ATTR i2s_isr(void *arg); 78 | static esp_err_t dma_desc_init(); 79 | static void dma_desc_deinit(); 80 | static void dma_filter_task(void *pvParameters); 81 | static void dma_filter_grayscale(const dma_elem_t *src, lldesc_t *dma_desc, uint8_t *dst); 82 | static void dma_filter_grayscale_highspeed(const dma_elem_t *src, lldesc_t *dma_desc, uint8_t *dst); 83 | static void dma_filter_jpeg(const dma_elem_t *src, lldesc_t *dma_desc, uint8_t *dst); 84 | static void dma_filter_rgb565(const dma_elem_t *src, lldesc_t *dma_desc, uint8_t *dst); 85 | static void i2s_stop(); 86 | 87 | static bool is_hs_mode() 88 | { 89 | return s_state->config.xclk_freq_hz > 10000000; 90 | } 91 | 92 | static size_t i2s_bytes_per_sample(i2s_sampling_mode_t mode) 93 | { 94 | switch (mode) 95 | { 96 | case SM_0A00_0B00: 97 | return 4; 98 | case SM_0A0B_0B0C: 99 | return 4; 100 | case SM_0A0B_0C0D: 101 | return 2; 102 | default: 103 | assert(0 && "invalid sampling mode"); 104 | return 0; 105 | } 106 | } 107 | 108 | static void vsync_intr_disable() 109 | { 110 | gpio_set_intr_type(s_state->config.pin_vsync, GPIO_INTR_DISABLE); 111 | } 112 | 113 | static void vsync_intr_enable() 114 | { 115 | gpio_set_intr_type(s_state->config.pin_vsync, GPIO_INTR_NEGEDGE); 116 | } 117 | 118 | esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out_camera_model) 119 | { 120 | if (s_state != NULL) 121 | { 122 | return ESP_ERR_INVALID_STATE; 123 | } 124 | 125 | s_state = (camera_state_t *)calloc(sizeof(*s_state), 1); 126 | if (!s_state) 127 | { 128 | return ESP_ERR_NO_MEM; 129 | } 130 | 131 | ESP_LOGI(TAG, "Enabling XCLK output"); 132 | camera_enable_out_clock(config); 133 | 134 | ESP_LOGD(TAG, "Initializing SSCB"); 135 | SCCB_Init(config->pin_sscb_sda, config->pin_sscb_scl); 136 | 137 | ESP_LOGD(TAG, "Resetting camera"); 138 | gpio_config_t conf = {0}; 139 | conf.pin_bit_mask = 1LL << config->pin_reset; 140 | conf.mode = GPIO_MODE_OUTPUT; 141 | gpio_config(&conf); 142 | 143 | gpio_set_level(config->pin_reset, 0); 144 | delay(10); 145 | gpio_set_level(config->pin_reset, 1); 146 | delay(10); 147 | 148 | ESP_LOGD(TAG, "Searching for camera address"); 149 | /* Probe the sensor */ 150 | delay(10); 151 | uint8_t slv_addr = SCCB_Probe(); 152 | if (slv_addr == 0) 153 | { 154 | *out_camera_model = CAMERA_NONE; 155 | return ESP_ERR_CAMERA_NOT_DETECTED; 156 | } 157 | s_state->sensor.slv_addr = slv_addr; 158 | ESP_LOGD(TAG, "Detected camera at address=0x%02x", slv_addr); 159 | sensor_id_t *id = &s_state->sensor.id; 160 | id->PID = SCCB_Read(slv_addr, REG_PID); 161 | id->VER = SCCB_Read(slv_addr, REG_VER); 162 | id->MIDL = SCCB_Read(slv_addr, REG_MIDL); 163 | id->MIDH = SCCB_Read(slv_addr, REG_MIDH); 164 | delay(10); 165 | ESP_LOGI(TAG, "Camera PID=0x%02x VER=0x%02x MIDL=0x%02x MIDH=0x%02x", 166 | id->PID, id->VER, id->MIDH, id->MIDL); 167 | 168 | switch (id->PID) 169 | { 170 | #if CONFIG_OV2640_SUPPORT 171 | case OV2640_PID: 172 | *out_camera_model = CAMERA_OV2640; 173 | ov2640_init(&s_state->sensor); 174 | break; 175 | #endif 176 | #if CONFIG_OV7725_SUPPORT 177 | case OV7725_PID: 178 | *out_camera_model = CAMERA_OV7725; 179 | ov7725_init(&s_state->sensor); 180 | break; 181 | #endif 182 | default: 183 | id->PID = 0; 184 | *out_camera_model = CAMERA_UNKNOWN; 185 | ESP_LOGD(TAG, "Detected camera not supported."); 186 | return ESP_ERR_CAMERA_NOT_SUPPORTED; 187 | } 188 | 189 | ESP_LOGD(TAG, "Doing SW reset of sensor"); 190 | s_state->sensor.reset(&s_state->sensor); 191 | 192 | return ESP_OK; 193 | } 194 | 195 | esp_err_t camera_init(const camera_config_t *config) 196 | { 197 | if (!s_state) 198 | { 199 | return ESP_ERR_INVALID_STATE; 200 | } 201 | if (s_state->sensor.id.PID == 0) 202 | { 203 | return ESP_ERR_CAMERA_NOT_SUPPORTED; 204 | } 205 | memcpy(&s_state->config, config, sizeof(*config)); 206 | esp_err_t err = ESP_OK; 207 | framesize_t frame_size = (framesize_t)config->frame_size; 208 | pixformat_t pix_format = (pixformat_t)config->pixel_format; 209 | s_state->width = resolution[frame_size][0]; 210 | s_state->height = resolution[frame_size][1]; 211 | s_state->sensor.set_pixformat(&s_state->sensor, pix_format); 212 | 213 | ESP_LOGD(TAG, "Setting frame size to %dx%d", s_state->width, s_state->height); 214 | if (s_state->sensor.set_framesize(&s_state->sensor, FRAMESIZE_SVGA) != 0) 215 | { 216 | ESP_LOGE(TAG, "Failed to set frame size"); 217 | err = ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE; 218 | goto fail; 219 | } 220 | s_state->sensor.set_pixformat(&s_state->sensor, pix_format); 221 | 222 | #if ENABLE_TEST_PATTERN 223 | /* Test pattern may get handy 224 | if you are unable to get the live image right. 225 | Once test pattern is enable, sensor will output 226 | vertical shaded bars instead of live image. 227 | */ 228 | s_state->sensor.set_colorbar(&s_state->sensor, 1); 229 | ESP_LOGD(TAG, "Test pattern enabled"); 230 | #endif 231 | 232 | if (pix_format == PIXFORMAT_GRAYSCALE) 233 | { 234 | if (s_state->sensor.id.PID != OV7725_PID) 235 | { 236 | ESP_LOGE(TAG, "Grayscale format is only supported for ov7225"); 237 | err = ESP_ERR_NOT_SUPPORTED; 238 | goto fail; 239 | } 240 | s_state->fb_size = s_state->width * s_state->height; 241 | if (is_hs_mode()) 242 | { 243 | s_state->sampling_mode = SM_0A0B_0B0C; 244 | s_state->dma_filter = &dma_filter_grayscale_highspeed; 245 | } 246 | else 247 | { 248 | s_state->sampling_mode = SM_0A0B_0C0D; 249 | s_state->dma_filter = &dma_filter_grayscale; 250 | } 251 | s_state->in_bytes_per_pixel = 2; // camera sends YUYV 252 | s_state->fb_bytes_per_pixel = 1; // frame buffer stores Y8 253 | } 254 | else if (pix_format == PIXFORMAT_RGB565) 255 | { 256 | if (s_state->sensor.id.PID != OV7725_PID) 257 | { 258 | ESP_LOGE(TAG, "RGB565 format is only supported for ov7225"); 259 | err = ESP_ERR_NOT_SUPPORTED; 260 | goto fail; 261 | } 262 | s_state->fb_size = s_state->width * s_state->height * 3; 263 | if (is_hs_mode()) 264 | { 265 | s_state->sampling_mode = SM_0A0B_0B0C; 266 | } 267 | else 268 | { 269 | s_state->sampling_mode = SM_0A00_0B00; 270 | } 271 | s_state->in_bytes_per_pixel = 2; // camera sends RGB565 (2 bytes) 272 | s_state->fb_bytes_per_pixel = 3; // frame buffer stores RGB888 273 | s_state->dma_filter = &dma_filter_rgb565; 274 | } 275 | else if (pix_format == PIXFORMAT_JPEG) 276 | { 277 | if (s_state->sensor.id.PID != OV2640_PID) 278 | { 279 | ESP_LOGE(TAG, "JPEG format is only supported for ov2640"); 280 | err = ESP_ERR_NOT_SUPPORTED; 281 | goto fail; 282 | } 283 | int qp = config->jpeg_quality; 284 | int compression_ratio_bound; 285 | if (qp >= 30) 286 | { 287 | compression_ratio_bound = 5; 288 | } 289 | else if (qp >= 10) 290 | { 291 | compression_ratio_bound = 10; 292 | } 293 | else 294 | { 295 | compression_ratio_bound = 20; 296 | } 297 | (*s_state->sensor.set_quality)(&s_state->sensor, qp); 298 | size_t equiv_line_count = s_state->height / compression_ratio_bound; 299 | s_state->fb_size = s_state->width * equiv_line_count * 2 /* bpp */; 300 | s_state->dma_filter = &dma_filter_jpeg; 301 | if (is_hs_mode()) 302 | { 303 | s_state->sampling_mode = SM_0A0B_0B0C; 304 | } 305 | else 306 | { 307 | s_state->sampling_mode = SM_0A00_0B00; 308 | } 309 | s_state->in_bytes_per_pixel = 2; 310 | s_state->fb_bytes_per_pixel = 2; 311 | } 312 | else 313 | { 314 | ESP_LOGE(TAG, "Requested format is not supported"); 315 | err = ESP_ERR_NOT_SUPPORTED; 316 | goto fail; 317 | } 318 | 319 | ESP_LOGD(TAG, "in_bpp: %d, fb_bpp: %d, fb_size: %d, mode: %d, width: %d height: %d", 320 | s_state->in_bytes_per_pixel, s_state->fb_bytes_per_pixel, 321 | s_state->fb_size, s_state->sampling_mode, 322 | s_state->width, s_state->height); 323 | 324 | ESP_LOGD(TAG, "Allocating frame buffer (%d bytes)", s_state->fb_size); 325 | s_state->fb = (uint8_t *)calloc(s_state->fb_size, 1); 326 | if (s_state->fb == NULL) 327 | { 328 | ESP_LOGE(TAG, "Failed to allocate frame buffer"); 329 | err = ESP_ERR_NO_MEM; 330 | goto fail; 331 | } 332 | 333 | ESP_LOGD(TAG, "Initializing I2S and DMA"); 334 | i2s_init(); 335 | err = dma_desc_init(); 336 | if (err != ESP_OK) 337 | { 338 | ESP_LOGE(TAG, "Failed to initialize I2S and DMA"); 339 | goto fail; 340 | } 341 | 342 | s_state->data_ready = xQueueCreate(16, sizeof(size_t)); 343 | s_state->frame_ready = xSemaphoreCreateBinary(); 344 | if (s_state->data_ready == NULL || s_state->frame_ready == NULL) 345 | { 346 | ESP_LOGE(TAG, "Failed to create semaphores"); 347 | err = ESP_ERR_NO_MEM; 348 | goto fail; 349 | } 350 | if (!xTaskCreatePinnedToCore(&dma_filter_task, "dma_filter", 4096, NULL, 10, &s_state->dma_filter_task, 1)) 351 | { 352 | ESP_LOGE(TAG, "Failed to create DMA filter task"); 353 | err = ESP_ERR_NO_MEM; 354 | goto fail; 355 | } 356 | 357 | ESP_LOGD(TAG, "Initializing GPIO interrupts"); 358 | vsync_intr_disable(); 359 | err = gpio_isr_handler_add(s_state->config.pin_vsync, &gpio_isr, NULL); 360 | if (err != ESP_OK) 361 | { 362 | ESP_LOGE(TAG, "gpio_isr_handler_add failed (%x)", err); 363 | goto fail; 364 | } 365 | 366 | // skip at least one frame after changing camera settings 367 | while (gpio_get_level(s_state->config.pin_vsync) == 0) 368 | { 369 | ; 370 | } 371 | while (gpio_get_level(s_state->config.pin_vsync) != 0) 372 | { 373 | ; 374 | } 375 | while (gpio_get_level(s_state->config.pin_vsync) == 0) 376 | { 377 | ; 378 | } 379 | s_state->frame_count = 0; 380 | ESP_LOGD(TAG, "Init done"); 381 | return ESP_OK; 382 | 383 | fail: 384 | camera_deinit(); 385 | return err; 386 | } 387 | 388 | esp_err_t camera_deinit() 389 | { 390 | if (s_state == NULL) 391 | { 392 | return ESP_ERR_INVALID_STATE; 393 | } 394 | if (s_state->dma_filter_task) 395 | { 396 | vTaskDelete(s_state->dma_filter_task); 397 | } 398 | if (s_state->data_ready) 399 | { 400 | vQueueDelete(s_state->data_ready); 401 | } 402 | if (s_state->frame_ready) 403 | { 404 | vSemaphoreDelete(s_state->frame_ready); 405 | } 406 | gpio_isr_handler_remove(s_state->config.pin_vsync); 407 | if (s_state->i2s_intr_handle) 408 | { 409 | esp_intr_disable(s_state->i2s_intr_handle); 410 | esp_intr_free(s_state->i2s_intr_handle); 411 | } 412 | dma_desc_deinit(); 413 | free(s_state->fb); 414 | free(s_state); 415 | s_state = NULL; 416 | camera_disable_out_clock(); 417 | periph_module_disable(PERIPH_I2S0_MODULE); 418 | return ESP_OK; 419 | } 420 | 421 | uint8_t *camera_get_fb() 422 | { 423 | if (s_state == NULL) 424 | { 425 | return NULL; 426 | } 427 | return s_state->fb; 428 | } 429 | 430 | int camera_get_fb_width() 431 | { 432 | if (s_state == NULL) 433 | { 434 | return 0; 435 | } 436 | return s_state->width; 437 | } 438 | 439 | int camera_get_fb_height() 440 | { 441 | if (s_state == NULL) 442 | { 443 | return 0; 444 | } 445 | return s_state->height; 446 | } 447 | 448 | size_t camera_get_data_size() 449 | { 450 | if (s_state == NULL) 451 | { 452 | return 0; 453 | } 454 | return s_state->data_size; 455 | } 456 | 457 | esp_err_t camera_run() 458 | { 459 | if (s_state == NULL) 460 | { 461 | return ESP_ERR_INVALID_STATE; 462 | } 463 | struct timeval tv_start; 464 | gettimeofday(&tv_start, NULL); 465 | #ifndef _NDEBUG 466 | memset(s_state->fb, 0, s_state->fb_size); 467 | #endif // _NDEBUG 468 | i2s_run(); 469 | ESP_LOGD(TAG, "Waiting for frame"); 470 | xSemaphoreTake(s_state->frame_ready, portMAX_DELAY); 471 | struct timeval tv_end; 472 | gettimeofday(&tv_end, NULL); 473 | int time_ms = (tv_end.tv_sec - tv_start.tv_sec) * 1000 + (tv_end.tv_usec - tv_start.tv_usec) / 1000; 474 | ESP_LOGI(TAG, "Frame %d done in %d ms", s_state->frame_count, time_ms); 475 | s_state->frame_count++; 476 | return ESP_OK; 477 | } 478 | 479 | static esp_err_t dma_desc_init() 480 | { 481 | assert(s_state->width % 4 == 0); 482 | size_t line_size = s_state->width * s_state->in_bytes_per_pixel * 483 | i2s_bytes_per_sample(s_state->sampling_mode); 484 | ESP_LOGD(TAG, "Line width (for DMA): %d bytes", line_size); 485 | size_t dma_per_line = 1; 486 | size_t buf_size = line_size; 487 | while (buf_size >= 4096) 488 | { 489 | buf_size /= 2; 490 | dma_per_line *= 2; 491 | } 492 | size_t dma_desc_count = dma_per_line * 4; 493 | s_state->dma_buf_width = line_size; 494 | s_state->dma_per_line = dma_per_line; 495 | s_state->dma_desc_count = dma_desc_count; 496 | ESP_LOGD(TAG, "DMA buffer size: %d, DMA buffers per line: %d", buf_size, dma_per_line); 497 | ESP_LOGD(TAG, "DMA buffer count: %d", dma_desc_count); 498 | 499 | s_state->dma_buf = (dma_elem_t **)malloc(sizeof(dma_elem_t *) * dma_desc_count); 500 | if (s_state->dma_buf == NULL) 501 | { 502 | return ESP_ERR_NO_MEM; 503 | } 504 | s_state->dma_desc = (lldesc_t *)malloc(sizeof(lldesc_t) * dma_desc_count); 505 | if (s_state->dma_desc == NULL) 506 | { 507 | return ESP_ERR_NO_MEM; 508 | } 509 | size_t dma_sample_count = 0; 510 | for (int i = 0; i < dma_desc_count; ++i) 511 | { 512 | ESP_LOGD(TAG, "Allocating DMA buffer #%d, size=%d", i, buf_size); 513 | dma_elem_t *buf = (dma_elem_t *)malloc(buf_size); 514 | if (buf == NULL) 515 | { 516 | return ESP_ERR_NO_MEM; 517 | } 518 | s_state->dma_buf[i] = buf; 519 | ESP_LOGV(TAG, "dma_buf[%d]=%p", i, buf); 520 | 521 | lldesc_t *pd = &s_state->dma_desc[i]; 522 | pd->length = buf_size; 523 | if (s_state->sampling_mode == SM_0A0B_0B0C && 524 | (i + 1) % dma_per_line == 0) 525 | { 526 | pd->length -= 4; 527 | } 528 | dma_sample_count += pd->length / 4; 529 | pd->size = pd->length; 530 | pd->owner = 1; 531 | pd->sosf = 1; 532 | pd->buf = (uint8_t *)buf; 533 | pd->offset = 0; 534 | pd->empty = 0; 535 | pd->eof = 1; 536 | pd->qe.stqe_next = &s_state->dma_desc[(i + 1) % dma_desc_count]; 537 | } 538 | s_state->dma_done = false; 539 | s_state->dma_sample_count = dma_sample_count; 540 | return ESP_OK; 541 | } 542 | 543 | static void dma_desc_deinit() 544 | { 545 | if (s_state->dma_buf) 546 | { 547 | for (int i = 0; i < s_state->dma_desc_count; ++i) 548 | { 549 | free(s_state->dma_buf[i]); 550 | } 551 | } 552 | free(s_state->dma_buf); 553 | free(s_state->dma_desc); 554 | } 555 | 556 | static inline void i2s_conf_reset() 557 | { 558 | const uint32_t lc_conf_reset_flags = I2S_IN_RST_M | I2S_AHBM_RST_M | I2S_AHBM_FIFO_RST_M; 559 | I2S0.lc_conf.val |= lc_conf_reset_flags; 560 | I2S0.lc_conf.val &= ~lc_conf_reset_flags; 561 | 562 | const uint32_t conf_reset_flags = I2S_RX_RESET_M | I2S_RX_FIFO_RESET_M | I2S_TX_RESET_M | I2S_TX_FIFO_RESET_M; 563 | I2S0.conf.val |= conf_reset_flags; 564 | I2S0.conf.val &= ~conf_reset_flags; 565 | while (I2S0.state.rx_fifo_reset_back) 566 | { 567 | ; 568 | } 569 | } 570 | 571 | static void i2s_init() 572 | { 573 | camera_config_t *config = &s_state->config; 574 | 575 | // Configure input GPIOs 576 | gpio_num_t pins[] = { 577 | config->pin_d7, 578 | config->pin_d6, 579 | config->pin_d5, 580 | config->pin_d4, 581 | config->pin_d3, 582 | config->pin_d2, 583 | config->pin_d1, 584 | config->pin_d0, 585 | config->pin_vsync, 586 | config->pin_href, 587 | config->pin_pclk}; 588 | gpio_config_t conf = { 589 | .mode = GPIO_MODE_INPUT, 590 | .pull_up_en = GPIO_PULLUP_ENABLE, 591 | .pull_down_en = GPIO_PULLDOWN_DISABLE, 592 | .intr_type = GPIO_INTR_DISABLE}; 593 | for (int i = 0; i < sizeof(pins) / sizeof(gpio_num_t); ++i) 594 | { 595 | if (rtc_gpio_is_valid_gpio(pins[i])) 596 | { 597 | rtc_gpio_deinit(pins[i]); 598 | } 599 | conf.pin_bit_mask = 1LL << pins[i]; 600 | gpio_config(&conf); 601 | } 602 | 603 | // Route input GPIOs to I2S peripheral using GPIO matrix 604 | gpio_matrix_in(config->pin_d0, I2S0I_DATA_IN0_IDX, false); 605 | gpio_matrix_in(config->pin_d1, I2S0I_DATA_IN1_IDX, false); 606 | gpio_matrix_in(config->pin_d2, I2S0I_DATA_IN2_IDX, false); 607 | gpio_matrix_in(config->pin_d3, I2S0I_DATA_IN3_IDX, false); 608 | gpio_matrix_in(config->pin_d4, I2S0I_DATA_IN4_IDX, false); 609 | gpio_matrix_in(config->pin_d5, I2S0I_DATA_IN5_IDX, false); 610 | gpio_matrix_in(config->pin_d6, I2S0I_DATA_IN6_IDX, false); 611 | gpio_matrix_in(config->pin_d7, I2S0I_DATA_IN7_IDX, false); 612 | gpio_matrix_in(config->pin_vsync, I2S0I_V_SYNC_IDX, false); 613 | gpio_matrix_in(0x38, I2S0I_H_SYNC_IDX, false); 614 | gpio_matrix_in(config->pin_href, I2S0I_H_ENABLE_IDX, false); 615 | gpio_matrix_in(config->pin_pclk, I2S0I_WS_IN_IDX, false); 616 | 617 | // Enable and configure I2S peripheral 618 | periph_module_enable(PERIPH_I2S0_MODULE); 619 | // Toggle some reset bits in LC_CONF register 620 | // Toggle some reset bits in CONF register 621 | i2s_conf_reset(); 622 | // Enable slave mode (sampling clock is external) 623 | I2S0.conf.rx_slave_mod = 1; 624 | // Enable parallel mode 625 | I2S0.conf2.lcd_en = 1; 626 | // Use HSYNC/VSYNC/HREF to control sampling 627 | I2S0.conf2.camera_en = 1; 628 | // Configure clock divider 629 | I2S0.clkm_conf.clkm_div_a = 1; 630 | I2S0.clkm_conf.clkm_div_b = 0; 631 | I2S0.clkm_conf.clkm_div_num = 2; 632 | // FIFO will sink data to DMA 633 | I2S0.fifo_conf.dscr_en = 1; 634 | // FIFO configuration 635 | I2S0.fifo_conf.rx_fifo_mod = s_state->sampling_mode; 636 | I2S0.fifo_conf.rx_fifo_mod_force_en = 1; 637 | I2S0.conf_chan.rx_chan_mod = 1; 638 | // Clear flags which are used in I2S serial mode 639 | I2S0.sample_rate_conf.rx_bits_mod = 0; 640 | I2S0.conf.rx_right_first = 0; 641 | I2S0.conf.rx_msb_right = 0; 642 | I2S0.conf.rx_msb_shift = 0; 643 | I2S0.conf.rx_mono = 0; 644 | I2S0.conf.rx_short_sync = 0; 645 | I2S0.timing.val = 0; 646 | 647 | // Allocate I2S interrupt, keep it disabled 648 | esp_intr_alloc(ETS_I2S0_INTR_SOURCE, 649 | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM, 650 | &i2s_isr, NULL, &s_state->i2s_intr_handle); 651 | } 652 | 653 | static void i2s_stop() 654 | { 655 | esp_intr_disable(s_state->i2s_intr_handle); 656 | vsync_intr_disable(); 657 | i2s_conf_reset(); 658 | I2S0.conf.rx_start = 0; 659 | size_t val = SIZE_MAX; 660 | BaseType_t higher_priority_task_woken; 661 | xQueueSendFromISR(s_state->data_ready, &val, &higher_priority_task_woken); 662 | } 663 | 664 | static void i2s_run() 665 | { 666 | #ifndef _NDEBUG 667 | for (int i = 0; i < s_state->dma_desc_count; ++i) 668 | { 669 | lldesc_t *d = &s_state->dma_desc[i]; 670 | ESP_LOGV(TAG, "DMA desc %2d: %u %u %u %u %u %u %p %p", 671 | i, d->length, d->size, d->offset, d->eof, d->sosf, d->owner, d->buf, d->qe.stqe_next); 672 | memset(s_state->dma_buf[i], 0, d->length); 673 | } 674 | #endif 675 | 676 | // wait for vsync 677 | ESP_LOGD(TAG, "Waiting for positive edge on VSYNC"); 678 | while (gpio_get_level(s_state->config.pin_vsync) == 0) 679 | { 680 | ; 681 | } 682 | while (gpio_get_level(s_state->config.pin_vsync) != 0) 683 | { 684 | ; 685 | } 686 | ESP_LOGD(TAG, "Got VSYNC"); 687 | 688 | s_state->dma_done = false; 689 | s_state->dma_desc_cur = 0; 690 | s_state->dma_received_count = 0; 691 | s_state->dma_filtered_count = 0; 692 | esp_intr_disable(s_state->i2s_intr_handle); 693 | i2s_conf_reset(); 694 | 695 | I2S0.rx_eof_num = s_state->dma_sample_count; 696 | I2S0.in_link.addr = (uint32_t)&s_state->dma_desc[0]; 697 | I2S0.in_link.start = 1; 698 | I2S0.int_clr.val = I2S0.int_raw.val; 699 | I2S0.int_ena.val = 0; 700 | I2S0.int_ena.in_done = 1; 701 | esp_intr_enable(s_state->i2s_intr_handle); 702 | if (s_state->config.pixel_format == CAMERA_PF_JPEG) 703 | { 704 | vsync_intr_enable(); 705 | } 706 | I2S0.conf.rx_start = 1; 707 | } 708 | 709 | static void IRAM_ATTR signal_dma_buf_received(bool *need_yield) 710 | { 711 | size_t dma_desc_filled = s_state->dma_desc_cur; 712 | s_state->dma_desc_cur = (dma_desc_filled + 1) % s_state->dma_desc_count; 713 | s_state->dma_received_count++; 714 | BaseType_t higher_priority_task_woken; 715 | BaseType_t ret = xQueueSendFromISR(s_state->data_ready, &dma_desc_filled, &higher_priority_task_woken); 716 | if (ret != pdTRUE) 717 | { 718 | ESP_EARLY_LOGW(TAG, "queue send failed (%d), dma_received_count=%d", ret, s_state->dma_received_count); 719 | } 720 | *need_yield = (ret == pdTRUE && higher_priority_task_woken == pdTRUE); 721 | } 722 | 723 | static void IRAM_ATTR i2s_isr(void *arg) 724 | { 725 | I2S0.int_clr.val = I2S0.int_raw.val; 726 | bool need_yield; 727 | signal_dma_buf_received(&need_yield); 728 | ESP_EARLY_LOGV(TAG, "isr, cnt=%d", s_state->dma_received_count); 729 | if (s_state->dma_received_count == s_state->height * s_state->dma_per_line) 730 | { 731 | i2s_stop(); 732 | } 733 | if (need_yield) 734 | { 735 | portYIELD_FROM_ISR(); 736 | } 737 | } 738 | 739 | static void IRAM_ATTR gpio_isr(void *arg) 740 | { 741 | bool need_yield = false; 742 | ESP_EARLY_LOGV(TAG, "gpio isr, cnt=%d", s_state->dma_received_count); 743 | if (gpio_get_level(s_state->config.pin_vsync) == 0 && 744 | s_state->dma_received_count > 0 && 745 | !s_state->dma_done) 746 | { 747 | signal_dma_buf_received(&need_yield); 748 | i2s_stop(); 749 | } 750 | if (need_yield) 751 | { 752 | portYIELD_FROM_ISR(); 753 | } 754 | } 755 | 756 | static size_t get_fb_pos() 757 | { 758 | return s_state->dma_filtered_count * s_state->width * 759 | s_state->fb_bytes_per_pixel / s_state->dma_per_line; 760 | } 761 | 762 | static void IRAM_ATTR dma_filter_task(void *pvParameters) 763 | { 764 | while (true) 765 | { 766 | size_t buf_idx; 767 | xQueueReceive(s_state->data_ready, &buf_idx, portMAX_DELAY); 768 | if (buf_idx == SIZE_MAX) 769 | { 770 | s_state->data_size = get_fb_pos(); 771 | xSemaphoreGive(s_state->frame_ready); 772 | continue; 773 | } 774 | 775 | size_t fb_pos = get_fb_pos(); 776 | assert(fb_pos <= s_state->fb_size + s_state->width * 777 | s_state->fb_bytes_per_pixel / s_state->dma_per_line); 778 | 779 | uint8_t *pfb = s_state->fb + fb_pos; 780 | const dma_elem_t *buf = s_state->dma_buf[buf_idx]; 781 | lldesc_t *desc = &s_state->dma_desc[buf_idx]; 782 | (*s_state->dma_filter)(buf, desc, pfb); 783 | s_state->dma_filtered_count++; 784 | ESP_LOGV(TAG, "dma_flt: flt_count=%d ", s_state->dma_filtered_count); 785 | } 786 | } 787 | 788 | static void IRAM_ATTR dma_filter_grayscale(const dma_elem_t *src, lldesc_t *dma_desc, uint8_t *dst) 789 | { 790 | assert(s_state->sampling_mode == SM_0A0B_0C0D); 791 | size_t end = dma_desc->length / sizeof(dma_elem_t) / 4; 792 | for (size_t i = 0; i < end; ++i) 793 | { 794 | // manually unrolling 4 iterations of the loop here 795 | dst[0] = src[0].sample1; 796 | dst[1] = src[1].sample1; 797 | dst[2] = src[2].sample1; 798 | dst[3] = src[3].sample1; 799 | src += 4; 800 | dst += 4; 801 | } 802 | } 803 | 804 | static void IRAM_ATTR dma_filter_grayscale_highspeed(const dma_elem_t *src, lldesc_t *dma_desc, uint8_t *dst) 805 | { 806 | assert(s_state->sampling_mode == SM_0A0B_0B0C); 807 | size_t end = dma_desc->length / sizeof(dma_elem_t) / 8; 808 | for (size_t i = 0; i < end; ++i) 809 | { 810 | // manually unrolling 4 iterations of the loop here 811 | dst[0] = src[0].sample1; 812 | dst[1] = src[2].sample1; 813 | dst[2] = src[4].sample1; 814 | dst[3] = src[6].sample1; 815 | src += 8; 816 | dst += 4; 817 | } 818 | // the final sample of a line in SM_0A0B_0B0C sampling mode needs special handling 819 | if ((dma_desc->length & 0x7) != 0) 820 | { 821 | dst[0] = src[0].sample1; 822 | dst[1] = src[2].sample1; 823 | } 824 | } 825 | 826 | static void IRAM_ATTR dma_filter_jpeg(const dma_elem_t *src, lldesc_t *dma_desc, uint8_t *dst) 827 | { 828 | assert(s_state->sampling_mode == SM_0A0B_0B0C || 829 | s_state->sampling_mode == SM_0A00_0B00); 830 | size_t end = dma_desc->length / sizeof(dma_elem_t) / 4; 831 | // manually unrolling 4 iterations of the loop here 832 | for (size_t i = 0; i < end; ++i) 833 | { 834 | dst[0] = src[0].sample1; 835 | dst[1] = src[1].sample1; 836 | dst[2] = src[2].sample1; 837 | dst[3] = src[3].sample1; 838 | src += 4; 839 | dst += 4; 840 | } 841 | // the final sample of a line in SM_0A0B_0B0C sampling mode needs special handling 842 | if ((dma_desc->length & 0x7) != 0) 843 | { 844 | dst[0] = src[0].sample1; 845 | dst[1] = src[1].sample1; 846 | dst[2] = src[2].sample1; 847 | dst[3] = src[2].sample2; 848 | } 849 | } 850 | 851 | static inline void rgb565_to_888(uint8_t in1, uint8_t in2, uint8_t *dst) 852 | { 853 | dst[0] = (in2 & 0b00011111) << 3; // blue 854 | dst[1] = ((in1 & 0b111) << 5) | ((in2 & 0b11100000 >> 5)); // green 855 | dst[2] = in1 & 0b11111000; // red 856 | } 857 | 858 | static void IRAM_ATTR dma_filter_rgb565(const dma_elem_t *src, lldesc_t *dma_desc, uint8_t *dst) 859 | { 860 | assert(s_state->sampling_mode == SM_0A0B_0B0C || 861 | s_state->sampling_mode == SM_0A00_0B00); 862 | 863 | const int unroll = 2; // manually unrolling 2 iterations of the loop 864 | const int samples_per_pixel = 2; 865 | const int bytes_per_pixel = 3; 866 | size_t end = dma_desc->length / sizeof(dma_elem_t) / unroll / samples_per_pixel; 867 | for (size_t i = 0; i < end; ++i) 868 | { 869 | rgb565_to_888(src[0].sample1, src[1].sample1, &dst[0]); 870 | rgb565_to_888(src[2].sample1, src[3].sample1, &dst[3]); 871 | dst += bytes_per_pixel * unroll; 872 | src += samples_per_pixel * unroll; 873 | } 874 | if ((dma_desc->length & 0x7) != 0) 875 | { 876 | rgb565_to_888(src[0].sample1, src[1].sample1, &dst[0]); 877 | rgb565_to_888(src[2].sample1, src[2].sample2, &dst[3]); 878 | } 879 | } 880 | 881 | void camera_print_fb() 882 | { 883 | /* Number of pixels to skip 884 | in order to fit into terminal screen. 885 | Assumed picture to be 80 columns wide. 886 | Skip twice as more rows as they look higher. 887 | */ 888 | int pixels_to_skip = s_state->width / 80; 889 | 890 | for (int ih = 0; ih < s_state->height; ih += pixels_to_skip * 2) 891 | { 892 | for (int iw = 0; iw < s_state->width * 2; iw += pixels_to_skip) 893 | { 894 | uint8_t px = (s_state->fb[iw + (ih * s_state->width * 2)]); 895 | if (px < 26) 896 | printf(" "); 897 | else if (px < 51) 898 | printf("."); 899 | else if (px < 77) 900 | printf(":"); 901 | else if (px < 102) 902 | printf("-"); 903 | else if (px < 128) 904 | printf("="); 905 | else if (px < 154) 906 | printf("+"); 907 | else if (px < 179) 908 | printf("*"); 909 | else if (px < 205) 910 | printf("#"); 911 | else if (px < 230) 912 | printf("%%"); 913 | else 914 | printf("@"); 915 | } 916 | printf("\n"); 917 | } 918 | } 919 | 920 | static esp_err_t camera_enable_out_clock(camera_config_t *config) 921 | { 922 | periph_module_enable(PERIPH_LEDC_MODULE); 923 | 924 | ledc_timer_config_t timer_conf; 925 | timer_conf.duty_resolution = 1; 926 | timer_conf.freq_hz = config->xclk_freq_hz; 927 | timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE; 928 | timer_conf.timer_num = config->ledc_timer; 929 | esp_err_t err = ledc_timer_config(&timer_conf); 930 | if (err != ESP_OK) 931 | { 932 | ESP_LOGE(TAG, "ledc_timer_config failed, rc=%x", err); 933 | return err; 934 | } 935 | 936 | ledc_channel_config_t ch_conf; 937 | ch_conf.channel = config->ledc_channel; 938 | ch_conf.timer_sel = config->ledc_timer; 939 | ch_conf.intr_type = LEDC_INTR_DISABLE; 940 | ch_conf.duty = 1; 941 | ch_conf.speed_mode = LEDC_HIGH_SPEED_MODE; 942 | ch_conf.gpio_num = config->pin_xclk; 943 | ch_conf.hpoint = 0; 944 | err = ledc_channel_config(&ch_conf); 945 | if (err != ESP_OK) 946 | { 947 | ESP_LOGE(TAG, "ledc_channel_config failed, rc=%x", err); 948 | return err; 949 | } 950 | return ESP_OK; 951 | } 952 | 953 | static void camera_disable_out_clock() 954 | { 955 | periph_module_disable(PERIPH_LEDC_MODULE); 956 | } 957 | 958 | int camera_set_hmirror(int en) 959 | { 960 | return s_state->sensor.set_hmirror(&s_state->sensor, en); 961 | } 962 | 963 | int camera_set_gainceiling(gainceiling_t gain) 964 | { 965 | return s_state->sensor.set_gainceiling(&s_state->sensor, gain); 966 | } 967 | 968 | int camera_set_vflip(int en) 969 | { 970 | return s_state->sensor.set_vflip(&s_state->sensor, en); 971 | } --------------------------------------------------------------------------------