M5_Cam-test.ino


1
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
16
#include <stdio.h>
17
#include <stdlib.h>
18
#include <string.h>
19
20
#include "freertos/FreeRTOS.h"
21
#include "freertos/task.h"
22
#include "freertos/semphr.h"
23
#include "freertos/event_groups.h"
24
25
#include "esp_system.h"
26
#include "esp_wifi.h"
27
#include "esp_event_loop.h"
28
#include "esp_log.h"
29
#include "esp_err.h"
30
#include "nvs_flash.h"
31
32
#include "driver/gpio.h"
33
34
extern "C" {
35
    #include "camera.h"
36
    #include "bitmap.h"
37
    #include "http_server.h"
38
}
39
40
/* The examples use simple WiFi configuration that you can set via
41
   'make menuconfig'.
42
43
   If you'd rather not, just change the below entries to strings with
44
   the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
45
46
 0x20001 | ESP_ERR_CAMERA_NOT_DETECTED | Check SCCB connection.
47
 0x20002 | ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE | Check that resolution is supported.
48
 0x20003 | ESP_ERR_CAMERA_NOT_SUPPORTED | Check if camera-model is supported/activated.
49
*/
50
#define EXAMPLE_ESP_WIFI_MODE_AP true  // true:AP false:STA
51
#define EXAMPLE_ESP_WIFI_SSID "ESP32-CAM"
52
#define EXAMPLE_ESP_WIFI_PASS ""
53
54
//#define EXAMPLE_ESP_WIFI_MODE_AP false  // true:AP false:STA
55
//#define EXAMPLE_ESP_WIFI_SSID "xxxxxxx" 
56
//#define EXAMPLE_ESP_WIFI_PASS "xxxxxxx"
57
58
#define EXAMPLE_MAX_STA_CONN 1
59
#define CAMERA_LED_GPIO 16
60
61
#if EXAMPLE_ESP_WIFI_MODE_AP
62
static void wifi_init_softap(void);
63
#else
64
static void wifi_init_sta(void);
65
#endif 
66
67
static void handle_grayscale_pgm(http_context_t http_ctx, void* ctx);
68
static void handle_rgb_bmp(http_context_t http_ctx, void* ctx);
69
static void handle_rgb_bmp_stream(http_context_t http_ctx, void* ctx);
70
static void handle_jpg(http_context_t http_ctx, void* ctx);
71
static void handle_jpg_stream(http_context_t http_ctx, void* ctx);
72
static esp_err_t event_handler(void *ctx, system_event_t *event);
73
74
75
static const char* TAG = "camera_demo";
76
77
static const char* STREAM_CONTENT_TYPE =
78
        "multipart/x-mixed-replace; boundary=123456789000000000000987654321";
79
80
static const char* STREAM_BOUNDARY = "--123456789000000000000987654321";
81
82
static EventGroupHandle_t s_wifi_event_group;
83
const int CONNECTED_BIT = BIT0;
84
static ip4_addr_t s_ip_addr;
85
static camera_pixelformat_t s_pixel_format;
86
87
#define CAMERA_PIXEL_FORMAT CAMERA_PF_JPEG
88
#define CAMERA_FRAME_SIZE CAMERA_FS_SVGA
89
90
91
void setup()
92
{
93
    esp_log_level_set("wifi", ESP_LOG_INFO);
94
    esp_log_level_set("gpio", ESP_LOG_WARN);
95
    esp_log_level_set("isr", ESP_LOG_INFO);
96
    esp_log_level_set("http_server", ESP_LOG_NONE);
97
    esp_log_level_set("camera", ESP_LOG_INFO);
98
    esp_log_level_set("camera_xclk", ESP_LOG_NONE);
99
100
    esp_err_t err = nvs_flash_init();
101
    if (err != ESP_OK) {
102
        ESP_ERROR_CHECK( nvs_flash_erase() );
103
        ESP_ERROR_CHECK( nvs_flash_init() );
104
    }
105
106
    ESP_ERROR_CHECK(gpio_install_isr_service(0));
107
    gpio_set_direction(GPIO_NUM_16, GPIO_MODE_OUTPUT);
108
    gpio_set_level(GPIO_NUM_16, HIGH);
109
    
110
    camera_config_t camera_config = {
111
        .pin_reset = 15,
112
        .pin_xclk = 27,
113
        .pin_sscb_sda = 25,
114
        .pin_sscb_scl = 23,
115
        .pin_d7 = 19,
116
        .pin_d6 = 36,
117
        .pin_d5 = 18,
118
        .pin_d4 = 39,
119
        .pin_d3 = 5,
120
        .pin_d2 = 34,
121
        .pin_d1 = 35,
122
        .pin_d0 = 17,
123
        .pin_vsync = 22,
124
        .pin_href = 26,
125
        .pin_pclk = 21,
126
        .xclk_freq_hz = 8000000, 
127
        .ledc_timer = LEDC_TIMER_0,
128
        .ledc_channel = LEDC_CHANNEL_0,
129
    };
130
131
    camera_model_t camera_model;
132
    err = camera_probe(&camera_config, &camera_model);
133
    if (err != ESP_OK) {
134
        ESP_LOGE(TAG, "Camera probe failed with error 0x%x", err);
135
        return;
136
    }
137
138
    if (camera_model == CAMERA_OV7725) {
139
        s_pixel_format = CAMERA_PIXEL_FORMAT;
140
        camera_config.frame_size = CAMERA_FRAME_SIZE;
141
        ESP_LOGI(TAG, "Detected OV7725 camera, using %s bitmap format",
142
                CAMERA_PIXEL_FORMAT == CAMERA_PF_GRAYSCALE ?
143
                        "grayscale" : "RGB565");
144
    } else if (camera_model == CAMERA_OV2640) {
145
        ESP_LOGI(TAG, "Detected OV2640 camera, using JPEG format");
146
        s_pixel_format = CAMERA_PF_JPEG;
147
        camera_config.frame_size = CAMERA_FRAME_SIZE;
148
        camera_config.jpeg_quality = 15;
149
    } else {
150
        ESP_LOGE(TAG, "Camera not supported");
151
        return;
152
    }
153
154
    camera_config.pixel_format = s_pixel_format;
155
    err = camera_init(&camera_config);
156
    if (err != ESP_OK) {
157
        ESP_LOGE(TAG, "Camera init failed with error 0x%x", err);
158
        return;
159
    }
160
161
#if EXAMPLE_ESP_WIFI_MODE_AP
162
    ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");
163
    wifi_init_softap();
164
#else
165
    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
166
    wifi_init_sta();
167
    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
168
#endif
169
170
    http_server_t server;
171
    http_server_options_t http_options = HTTP_SERVER_OPTIONS_DEFAULT();
172
    ESP_ERROR_CHECK( http_server_start(&http_options, &server) );
173
174
    if (s_pixel_format == CAMERA_PF_GRAYSCALE) {
175
        ESP_ERROR_CHECK( http_register_handler(server, "/pgm", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_grayscale_pgm, NULL) );
176
        ESP_LOGI(TAG, "Open http://" IPSTR "/pgm for a single image/x-portable-graymap image", IP2STR(&s_ip_addr));
177
    }
178
    if (s_pixel_format == CAMERA_PF_RGB565) {
179
        ESP_ERROR_CHECK( http_register_handler(server, "/bmp", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_rgb_bmp, NULL) );
180
        ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for single image/bitmap image", IP2STR(&s_ip_addr));
181
        ESP_ERROR_CHECK( http_register_handler(server, "/bmp_stream", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_rgb_bmp_stream, NULL) );
182
        ESP_LOGI(TAG, "Open http://" IPSTR "/bmp_stream for multipart/x-mixed-replace stream of bitmaps", IP2STR(&s_ip_addr));
183
    }
184
    if (s_pixel_format == CAMERA_PF_JPEG) {
185
        ESP_ERROR_CHECK( http_register_handler(server, "/jpg", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_jpg, NULL) );
186
        ESP_LOGI(TAG, "Open http://" IPSTR "/jpg for single image/jpg image", IP2STR(&s_ip_addr));
187
        ESP_ERROR_CHECK( http_register_handler(server, "/jpg_stream", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_jpg_stream, NULL) );
188
        ESP_LOGI(TAG, "Open http://" IPSTR "/jpg_stream for multipart/x-mixed-replace stream of JPEGs", IP2STR(&s_ip_addr));
189
        ESP_ERROR_CHECK( http_register_handler(server, "/", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_jpg_stream, NULL) );
190
    }
191
    ESP_LOGI(TAG, "Free heap: %u", xPortGetFreeHeapSize());
192
    ESP_LOGI(TAG, "Camera demo ready");
193
194
}
195
196
void loop() {}
197
198
static esp_err_t write_frame(http_context_t http_ctx)
199
{
200
    http_buffer_t fb_data = {
201
            .data = camera_get_fb(),
202
            .size = camera_get_data_size(),
203
            .data_is_persistent = true
204
    };
205
    return http_response_write(http_ctx, &fb_data);
206
}
207
208
static void handle_grayscale_pgm(http_context_t http_ctx, void* ctx)
209
{
210
    esp_err_t err = camera_run();
211
    if (err != ESP_OK) {
212
        ESP_LOGD(TAG, "Camera capture failed with error = %d", err);
213
        return;
214
    }
215
    char* pgm_header_str;
216
    asprintf(&pgm_header_str, "P5 %d %d %d\n",
217
            camera_get_fb_width(), camera_get_fb_height(), 255);
218
    if (pgm_header_str == NULL) {
219
        return;
220
    }
221
222
    size_t response_size = strlen(pgm_header_str) + camera_get_data_size();
223
    http_response_begin(http_ctx, 200, "image/x-portable-graymap", response_size);
224
    http_response_set_header(http_ctx, "Content-disposition", "inline; filename=capture.pgm");
225
    http_buffer_t pgm_header = { .data = pgm_header_str };
226
    http_response_write(http_ctx, &pgm_header);
227
    free(pgm_header_str);
228
229
    write_frame(http_ctx);
230
    http_response_end(http_ctx);
231
}
232
233
static void handle_rgb_bmp(http_context_t http_ctx, void* ctx)
234
{
235
    esp_err_t err = camera_run();
236
    if (err != ESP_OK) {
237
        ESP_LOGD(TAG, "Camera capture failed with error = %d", err);
238
        return;
239
    }
240
241
    bitmap_header_t* header = bmp_create_header(camera_get_fb_width(), camera_get_fb_height());
242
    if (header == NULL) {
243
        return;
244
    }
245
246
    http_response_begin(http_ctx, 200, "image/bmp", sizeof(*header) + camera_get_data_size());
247
    http_buffer_t bmp_header = {
248
            .data = header,
249
            .size = sizeof(*header)
250
    };
251
    http_response_set_header(http_ctx, "Content-disposition", "inline; filename=capture.bmp");
252
    http_response_write(http_ctx, &bmp_header);
253
    free(header);
254
255
    write_frame(http_ctx);
256
    http_response_end(http_ctx);
257
}
258
259
static void handle_jpg(http_context_t http_ctx, void* ctx)
260
{
261
    esp_err_t err = camera_run();
262
    if (err != ESP_OK) {
263
        ESP_LOGD(TAG, "Camera capture failed with error = %d", err);
264
        return;
265
    }
266
267
    http_response_begin(http_ctx, 200, "image/jpeg", camera_get_data_size());
268
    http_response_set_header(http_ctx, "Content-disposition", "inline; filename=capture.jpg");
269
    write_frame(http_ctx);
270
    http_response_end(http_ctx);
271
}
272
273
274
static void handle_rgb_bmp_stream(http_context_t http_ctx, void* ctx)
275
{
276
    http_response_begin(http_ctx, 200, STREAM_CONTENT_TYPE, HTTP_RESPONSE_SIZE_UNKNOWN);
277
    bitmap_header_t* header = bmp_create_header(camera_get_fb_width(), camera_get_fb_height());
278
    if (header == NULL) {
279
        return;
280
    }
281
    http_buffer_t bmp_header = {
282
            .data = header,
283
            .size = sizeof(*header)
284
    };
285
286
287
    while (true) {
288
        esp_err_t err = camera_run();
289
        if (err != ESP_OK) {
290
            ESP_LOGD(TAG, "Camera capture failed with error = %d", err);
291
            return;
292
        }
293
294
        err = http_response_begin_multipart(http_ctx, "image/bitmap",
295
                camera_get_data_size() + sizeof(*header));
296
        if (err != ESP_OK) {
297
            break;
298
        }
299
        err = http_response_write(http_ctx, &bmp_header);
300
        if (err != ESP_OK) {
301
            break;
302
        }
303
        err = write_frame(http_ctx);
304
        if (err != ESP_OK) {
305
            break;
306
        }
307
        err = http_response_end_multipart(http_ctx, STREAM_BOUNDARY);
308
        if (err != ESP_OK) {
309
            break;
310
        }
311
    }
312
313
    free(header);
314
    http_response_end(http_ctx);
315
}
316
317
static void handle_jpg_stream(http_context_t http_ctx, void* ctx)
318
{
319
    http_response_begin(http_ctx, 200, STREAM_CONTENT_TYPE, HTTP_RESPONSE_SIZE_UNKNOWN);
320
321
    while (true) {
322
        esp_err_t err = camera_run();
323
        if (err != ESP_OK) {
324
            ESP_LOGD(TAG, "Camera capture failed with error = %d", err);
325
            return;
326
        }
327
        err = http_response_begin_multipart(http_ctx, "image/jpg",
328
                camera_get_data_size());
329
        if (err != ESP_OK) {
330
            break;
331
        }
332
        err = write_frame(http_ctx);
333
        if (err != ESP_OK) {
334
            break;
335
        }
336
        err = http_response_end_multipart(http_ctx, STREAM_BOUNDARY);
337
        if (err != ESP_OK) {
338
            break;
339
        }
340
    }
341
    http_response_end(http_ctx);
342
}
343
344
345
// /* FreeRTOS event group to signal when we are connected*/
346
// static EventGroupHandle_t s_wifi_event_group;
347
348
// /* The event group allows multiple bits for each event,
349
//    but we only care about one event - are we connected
350
//    to the AP with an IP? */
351
// const int WIFI_CONNECTED_BIT = BIT0;
352
353
static esp_err_t event_handler(void* ctx, system_event_t* event) 
354
{
355
  switch (event->event_id) {
356
    case SYSTEM_EVENT_STA_START:
357
      esp_wifi_connect();
358
      break;
359
    case SYSTEM_EVENT_STA_GOT_IP:
360
      ESP_LOGI(TAG, "got ip:%s", ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
361
      s_ip_addr = event->event_info.got_ip.ip_info.ip;
362
      xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);
363
      break;
364
    case SYSTEM_EVENT_AP_STACONNECTED:
365
      ESP_LOGI(TAG, "station:" MACSTR " join, AID=%d", MAC2STR(event->event_info.sta_connected.mac),
366
               event->event_info.sta_connected.aid);
367
#if EXAMPLE_ESP_WIFI_MODE_AP
368
      xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);
369
#endif
370
      break;
371
    case SYSTEM_EVENT_AP_STADISCONNECTED:
372
      ESP_LOGI(TAG, "station:" MACSTR "leave, AID=%d", MAC2STR(event->event_info.sta_disconnected.mac),
373
               event->event_info.sta_disconnected.aid);
374
#if EXAMPLE_ESP_WIFI_MODE_AP
375
      xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);
376
#endif
377
      break;
378
    case SYSTEM_EVENT_STA_DISCONNECTED:
379
      esp_wifi_connect();
380
      xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);
381
      break;
382
    default:
383
      break;
384
  }
385
  return ESP_OK;
386
}
387
388
#if EXAMPLE_ESP_WIFI_MODE_AP
389
390
static void wifi_init_softap() 
391
{
392
  s_wifi_event_group = xEventGroupCreate();
393
394
  tcpip_adapter_init();
395
  ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
396
397
  wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
398
  ESP_ERROR_CHECK(esp_wifi_init(&cfg));
399
    wifi_config_t wifi_config;
400
    strcpy(reinterpret_cast<char*>(wifi_config.ap.ssid), EXAMPLE_ESP_WIFI_SSID);
401
    strcpy(reinterpret_cast<char*>(wifi_config.ap.password), EXAMPLE_ESP_WIFI_PASS);
402
    wifi_config.ap.ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID);
403
    wifi_config.ap.max_connection = EXAMPLE_MAX_STA_CONN;
404
    wifi_config.ap.authmode = WIFI_AUTH_WPA2_PSK;
405
406
    if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {
407
    wifi_config.ap.authmode = WIFI_AUTH_OPEN;
408
  }
409
410
  ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
411
  ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
412
  ESP_ERROR_CHECK(esp_wifi_start());
413
414
  uint8_t addr[4] = {192, 168, 4, 1};
415
  s_ip_addr = *(ip4_addr_t*)&addr;
416
417
  ESP_LOGI(TAG, "wifi_init_softap finished.SSID:%s password:%s",
418
           EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
419
}
420
421
#else
422
423
static void wifi_init_sta() 
424
{
425
    s_wifi_event_group = xEventGroupCreate();
426
427
    tcpip_adapter_init();
428
    ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
429
430
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
431
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
432
    //wifi_config_t wifi_config = {
433
    //    .sta = {.ssid = EXAMPLE_ESP_WIFI_SSID, .password = EXAMPLE_ESP_WIFI_PASS},
434
    //};
435
    wifi_config_t wifi_config { };
436
    strcpy((char*)wifi_config.sta.ssid, (const char*)EXAMPLE_ESP_WIFI_SSID);
437
    strcpy((char*)wifi_config.sta.password, (const char*)EXAMPLE_ESP_WIFI_PASS);
438
439
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
440
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
441
    ESP_ERROR_CHECK(esp_wifi_start());
442
443
    ESP_LOGI(TAG, "wifi_init_sta finished.");
444
    ESP_LOGI(TAG, "connect to ap SSID:%s password:%s", EXAMPLE_ESP_WIFI_SSID,
445
            EXAMPLE_ESP_WIFI_PASS);
446
    
447
    xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
448
}
449
#endif