From 55f6e7a130bf77de4e6432216124584ca0e36303 Mon Sep 17 00:00:00 2001 From: junkyu han Date: Thu, 25 Jan 2018 16:56:29 +0900 Subject: [PATCH] Add Camera Module Change-Id: Ied88305155686af7ed9f89d464bbe3c77a746394 (cherry picked from commit 7620cf9b6c5af514c1883789092ac4761891f715) --- CMakeLists.txt | 3 + inc/controller_util.h | 1 + inc/resource.h | 1 + inc/resource/resource_camera.h | 30 +++ inc/webutil.h | 2 + packaging/org.tizen.position-finder-server.spec | 1 + res/pi.conf | 3 +- src/connection_manager.c | 20 -- src/controller.c | 53 ++++++ src/controller_util.c | 24 +++ src/resource/resource_camera.c | 233 ++++++++++++++++++++++++ src/webutil.c | 124 ++++++++++++- tizen-manifest.xml.in | 3 +- 13 files changed, 474 insertions(+), 24 deletions(-) create mode 100644 inc/resource/resource_camera.h create mode 100644 src/resource/resource_camera.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d2914d..49fd759 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,8 @@ pkg_check_modules(APP_PKGS REQUIRED glib-2.0 json-glib-1.0 capi-system-info + capi-network-connection + capi-media-camera ) ADD_DEFINITIONS(-DCBOR_FILE_IN_RES="${INSTALL_RESDIR}/${CBOR_FILE}") @@ -60,6 +62,7 @@ ADD_EXECUTABLE(${PROJECT_NAME} ${PROJECT_ROOT_DIR}/src/resource/resource_gas_detection_sensor.c ${PROJECT_ROOT_DIR}/src/resource/resource_sound_level_sensor.c ${PROJECT_ROOT_DIR}/src/resource/resource_adc_mcp3008.c + ${PROJECT_ROOT_DIR}/src/resource/resource_camera.c ) TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} -lm) diff --git a/inc/controller_util.h b/inc/controller_util.h index 29b5e46..f36973a 100644 --- a/inc/controller_util.h +++ b/inc/controller_util.h @@ -24,6 +24,7 @@ int controller_util_get_path(const char **path); int controller_util_get_address(const char **address); +int controller_util_get_image_address(const char **image_upload); void controller_util_free(void); #endif /* __POSITION_FINDER_CONTROLLER_UTIL_H__ */ diff --git a/inc/resource.h b/inc/resource.h index 783fd8f..f3ffe3c 100755 --- a/inc/resource.h +++ b/inc/resource.h @@ -38,5 +38,6 @@ #include "resource/resource_tilt_sensor.h" #include "resource/resource_gas_detection_sensor.h" #include "resource/resource_sound_level_sensor.h" +#include "resource/resource_camera.h" #endif /* __POSITION_FINDER_RESOURCE_H__ */ diff --git a/inc/resource/resource_camera.h b/inc/resource/resource_camera.h new file mode 100644 index 0000000..545e9b9 --- /dev/null +++ b/inc/resource/resource_camera.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Contact: Jin Yoon + * Geunsun Lee + * Eunyoung Lee + * Junkyu Han + * + * Licensed under the Flora License, Version 1.1 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define MAX_IMAGE_FILE_LEN 256 +#define DEFAULT_FILE_PATH "/home/owner/media" + +typedef void (*capture_completed_cb)(const void *image, unsigned int size, void *user_data); + +int resource_capture_camera(capture_completed_cb capture_completed_cb, void *data); +void resource_close_camera(void); diff --git a/inc/webutil.h b/inc/webutil.h index 8947bc2..a229e07 100644 --- a/inc/webutil.h +++ b/inc/webutil.h @@ -68,6 +68,8 @@ struct _web_util_sensor_data_s { int web_util_noti_init(void); void web_util_noti_fini(void); int web_util_noti_post(const char *resource, const char *json_data); +int web_util_noti_post_image_data(const char *url, const char *device_id, + const void *image_data, unsigned int image_size); int web_util_noti_get(const char *resource, char **res); int web_util_json_init(void); diff --git a/packaging/org.tizen.position-finder-server.spec b/packaging/org.tizen.position-finder-server.spec index dd4e98a..8f50c9b 100644 --- a/packaging/org.tizen.position-finder-server.spec +++ b/packaging/org.tizen.position-finder-server.spec @@ -28,6 +28,7 @@ BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(json-glib-1.0) BuildRequires: pkgconfig(capi-system-info) BuildRequires: pkgconfig(capi-network-connection) +BuildRequires: pkgconfig(capi-media-camera) %description Server for Position Finder diff --git a/res/pi.conf b/res/pi.conf index b55530e..b7e63e9 100644 --- a/res/pi.conf +++ b/res/pi.conf @@ -1,3 +1,4 @@ [default] -path=/door/1 +path=sensor-pi-1 address=http://showiot.xyz/api/tt/data +image_address=http://test.showiot.xyz/api/image/ diff --git a/src/connection_manager.c b/src/connection_manager.c index ef5fd7e..443cd1f 100644 --- a/src/connection_manager.c +++ b/src/connection_manager.c @@ -1,23 +1,3 @@ -/* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. - * - * Contact: Jin Yoon - * Geunsun Lee - * Eunyoung Lee - * Junkyu Han - * - * Licensed under the Flora License, Version 1.1 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://floralicense.org/license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ /* * Copyright (c) 2017 Samsung Electronics Co., Ltd. * diff --git a/src/controller.c b/src/controller.c index a442f82..7b35e9f 100644 --- a/src/controller.c +++ b/src/controller.c @@ -34,16 +34,69 @@ #define CONNECTIVITY_KEY "opened" #define SENSORING_TIME_INTERVAL 5.0f +#define CAMERA_TIME_INTERVAL 2 +#define TEST_CAMERA_SAVE 0 +#define CAMERA_ENABLED 0 typedef struct app_data_s { Ecore_Timer *getter_timer; connectivity_resource_s *resource_info; } app_data; +static void __resource_camera_capture_completed_cb(const void *image, unsigned int size, void *user_data) +{ + /* TODO */ + const char *path = NULL; + const char *url = NULL; + + controller_util_get_path(&path); + + controller_util_get_image_address(&url); + + web_util_noti_post_image_data(url, path, image, size); + +#if TEST_CAMERA_SAVE + FILE *fp = NULL; + char *data_path = NULL; + char file[256]; + + data_path = app_get_data_path(); + + snprintf(file, sizeof(file), "%sjjoggoba.jpg", data_path); + free(data_path); + _D("File : %s", file); + + fp = fopen(file, "w"); + if (!fp) { + _E("Failed to open file: %s", file); + return; + } + + if (fwrite(image, size, 1, fp) != 1) { + _E("Failed to write image to file"); + return; + } + + fclose(fp); +#endif +} + static Eina_Bool control_sensors_cb(void *data) { app_data *ad = data; int value = 1; + int ret = 0; +#if CAMERA_ENABLED + static unsigned int count = 0; + + if (count % CAMERA_TIME_INTERVAL == 0) { + ret = resource_capture_camera(__resource_camera_capture_completed_cb, NULL); + if (ret < 0) + _E("Failed to capture camera"); + } + + count++; +#endif /* This is example, get value from sensors first */ if (connectivity_notify_int(ad->resource_info, "Motion", value) == -1) diff --git a/src/controller_util.c b/src/controller_util.c index 3bba0d5..5bb65dc 100644 --- a/src/controller_util.c +++ b/src/controller_util.c @@ -28,11 +28,13 @@ #define CONF_GROUP_DEFAULT_NAME "default" #define CONF_KEY_PATH_NAME "path" #define CONF_KEY_ADDRESS_NAME "address" +#define CONF_KEY_IMAGE_UPLOAD_NAME "image_address" #define CONF_FILE_NAME "pi.conf" struct controller_util_s { char *path; char *address; + char *image_upload; }; struct controller_util_s controller_util = { 0, }; @@ -71,6 +73,13 @@ static int _read_conf_file(void) if (!controller_util.address) _E("could not get the key string"); + controller_util.image_upload = g_key_file_get_string(gkf, + CONF_GROUP_DEFAULT_NAME, + CONF_KEY_IMAGE_UPLOAD_NAME, + NULL); + if (!controller_util.image_upload) + _E("could not get the key string"); + g_key_file_free(gkf); return 0; @@ -106,6 +115,21 @@ int controller_util_get_address(const char **address) return 0; } +int controller_util_get_image_address(const char **image_upload) +{ + retv_if(!image_upload, -1); + + if (!controller_util.image_upload) { + int ret = -1; + ret = _read_conf_file(); + retv_if(-1 == ret, -1); + } + + *image_upload = controller_util.image_upload; + + return 0; +} + void controller_util_free(void) { if (controller_util.path) { diff --git a/src/resource/resource_camera.c b/src/resource/resource_camera.c new file mode 100644 index 0000000..64ae611 --- /dev/null +++ b/src/resource/resource_camera.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Contact: Jin Yoon + * Geunsun Lee + * Eunyoung Lee + * Junkyu Han + * + * Licensed under the Flora License, Version 1.1 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "log.h" +#include "resource/resource_camera.h" + +#define RESOLUTION_W 320 +#define RESOLUTION_H 240 + +static int __init(void); +static void __completed_cb(void *user_data); +static bool __resolution_list_cb(int width, int height, void *user_data); +static void __capturing_cb(camera_image_data_s *image, camera_image_data_s *postview, + camera_image_data_s *thumbnail, void *user_data); + +struct __camera_data { + camera_h cam_handle; + int resolution_w; + int resolution_h; + void *captured_file; + unsigned int image_size; + capture_completed_cb completed_cb; + void *completed_cb_data; +}; + +static struct __camera_data *camera_data = NULL; + +int resource_capture_camera(capture_completed_cb capture_completed, void *user_data) +{ + camera_state_e state; + int ret = CAMERA_ERROR_NONE; + + if (camera_data == NULL) { + _I("Camera is not initialized"); + ret = __init(); + if (ret < 0) { + _E("Failed to initialize camera"); + return -1; + } + } + + ret = camera_get_state(camera_data->cam_handle, &state); + if (ret != CAMERA_ERROR_NONE) { + _E("Failed to get camera state"); + return -1; + } + + if (state >= CAMERA_STATE_CAPTURING) { + _D("Camera is now capturing"); + return 0; + } + + if (state != CAMERA_STATE_PREVIEW) { + _I("Preview is not started"); + ret = camera_start_preview(camera_data->cam_handle); + if (ret != CAMERA_ERROR_NONE) { + _E("Failed to start preview"); + return -1; + } + } + + ret = camera_start_capture(camera_data->cam_handle, __capturing_cb, __completed_cb, camera_data); + if (ret != CAMERA_ERROR_NONE) { + _E("Failed to start capturing"); + return -1; + } + + camera_data->completed_cb = capture_completed; + camera_data->completed_cb_data = user_data; + + return 0; +} + +void resource_close_camera(void) +{ + if (camera_data == NULL) + return; + + camera_stop_preview(camera_data->cam_handle); + + camera_destroy(camera_data->cam_handle); + camera_data->cam_handle = NULL; + + free(camera_data); + camera_data = NULL; +} + +static void __capturing_cb(camera_image_data_s *image, camera_image_data_s *postview, + camera_image_data_s *thumbnail, void *user_data) +{ + struct __camera_data *camera_data = user_data; + if (image == NULL) { + _E("Image is NULL"); + return; + } + + camera_data->captured_file = malloc(image->size); + if (camera_data->captured_file == NULL) + return; + + _D("Now is on Capturing: Image size[%d x %d]", image->width, image->height); + + memcpy(camera_data->captured_file, image->data, image->size); + camera_data->image_size = image->size; + + return; +} + +static void __completed_cb(void *user_data) +{ + struct __camera_data *camera_data = user_data; + int ret = CAMERA_ERROR_NONE; + + if (camera_data->completed_cb) + camera_data->completed_cb(camera_data->captured_file, camera_data->image_size, camera_data->completed_cb_data); + + free(camera_data->captured_file); + camera_data->captured_file = NULL; + + if (!camera_data->cam_handle) { + _E("Camera is NULL"); + return; + } + _D("Capture is completed"); + + ret = camera_start_preview(camera_data->cam_handle); + if (ret != CAMERA_ERROR_NONE) { + _E("Failed to start preview"); + return; + } + + ret = camera_stop_preview(camera_data->cam_handle); + if (ret != CAMERA_ERROR_NONE) { + _E("Failed to stop preview"); + return; + } + + return; +} + +static bool __resolution_list_cb(int width, int height, void *user_data) +{ + _D("Supported resolution - Width[%d], Height[%d]", width, height); + + if (width > camera_data->resolution_w && width <= RESOLUTION_W && + height > camera_data->resolution_h && height <= RESOLUTION_H) { + camera_data->resolution_w = width; + camera_data->resolution_h = height; + } + _D("Fixed Resolution is Width[%d], Height[%d]", camera_data->resolution_w, camera_data->resolution_h); + + return true; +} + +static int __init(void) +{ + int ret = CAMERA_ERROR_NONE; + + camera_data = malloc(sizeof(struct __camera_data)); + if (camera_data == NULL) { + _E("Failed to allocate Camera data"); + return -1; + } + memset(camera_data, 0, sizeof(struct __camera_data)); + + ret = camera_create(CAMERA_DEVICE_CAMERA0, &(camera_data->cam_handle)); + if (ret != CAMERA_ERROR_NONE) { + _E("Failed to create camera"); + goto ERROR; + } + + ret = camera_foreach_supported_capture_resolution(camera_data->cam_handle, __resolution_list_cb, NULL); + if (ret != CAMERA_ERROR_NONE) { + _E("Failed to foreach supported capture resolution"); + goto ERROR; + } + + ret = camera_set_preview_resolution(camera_data->cam_handle, camera_data->resolution_w, camera_data->resolution_h); + if (ret != CAMERA_ERROR_NONE) { + _E("Failed to set preview resolution"); + goto ERROR; + } + + ret = camera_set_capture_resolution(camera_data->cam_handle, camera_data->resolution_w, camera_data->resolution_h); + if (ret != CAMERA_ERROR_NONE) { + _E("Failed to set capture resolution"); + goto ERROR; + } + + ret = camera_set_capture_format(camera_data->cam_handle, CAMERA_PIXEL_FORMAT_JPEG); + if (ret != CAMERA_ERROR_NONE) { + _E("Failed to set capture resolution"); + goto ERROR; + } + + ret = camera_start_preview(camera_data->cam_handle); + if (ret != CAMERA_ERROR_NONE) { + _E("Failed to start preview[%d]", ret); + goto ERROR; + } + + return 0; + +ERROR: + camera_destroy(camera_data->cam_handle); + free(camera_data); + return -1; +} + diff --git a/src/webutil.c b/src/webutil.c index 27f8a37..7afde87 100644 --- a/src/webutil.c +++ b/src/webutil.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include "log.h" #include "webutil.h" @@ -67,6 +67,62 @@ static size_t _get_response_write_callback(void *ptr, size_t size, size_t nmemb, return res_size; } +static int __curl_debug(CURL *handle, curl_infotype type, + char *data, size_t size, void *userptr) +{ + const char *prefix = NULL; + char *message = NULL; + + switch (type) { + case CURLINFO_END: + return 0; + case CURLINFO_TEXT: + _D("== text Info: %s", data); + return 0; + case CURLINFO_HEADER_OUT: + prefix = "=> Send header:"; + break; + case CURLINFO_DATA_OUT: + prefix = "=> Send data:"; + break; + case CURLINFO_SSL_DATA_OUT: + prefix = "=> Send SSL data:"; + break; + case CURLINFO_HEADER_IN: + prefix = "<= Recv header:"; + break; + case CURLINFO_DATA_IN: + prefix = "<= Recv data:"; + break; + case CURLINFO_SSL_DATA_IN: + prefix = "<= Recv SSL data:"; + break; + } + message = g_strndup(data, size); + _D("%s %s", prefix, message); + g_free(message); + return 0; +} + +static const char *_get_time_str(void) +{ + struct timeval val; + struct tm *ptm; + static char res_time[40] = {0, }; + + gettimeofday(&val, NULL); + ptm = localtime(&val.tv_sec); + + // format : YY-MM-DD_hh:mm:ss:uuuuuu + snprintf(res_time, sizeof(res_time), "%04d-%02d-%02d_%02d:%02d:%02d:%06ld" + , ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday + , ptm->tm_hour, ptm->tm_min, ptm->tm_sec + , val.tv_usec); + + return (const char *)res_time; +} + + int web_util_noti_init(void) { int ret = 0; @@ -86,6 +142,71 @@ void web_util_noti_fini(void) return; } +int web_util_noti_post_image_data(const char *url, const char *device_id, + const void *image_data, unsigned int image_size) +{ + int ret = 0; + CURL *curl = NULL; + CURLcode response = CURLE_OK; + struct curl_httppost *formpost = NULL; + struct curl_httppost *lastptr = NULL; + char *filename = NULL; + char *post_url = NULL; + + retv_if(url == NULL, -1); + retv_if(device_id == NULL, -1); + retv_if(image_data == NULL, -1); + retv_if(image_size == 0, -1); + + curl = curl_easy_init(); + + if (!curl) { + _E("fail to init curl"); + return -1; + } + + filename = g_strdup_printf("%s_%s.jpg", device_id, _get_time_str()); + post_url = g_strdup_printf("%s?id=%s", url, device_id); + _D("FileName: [%s], PostUrl: [%s]", filename, post_url); + + curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, "content-type:", + CURLFORM_COPYCONTENTS, "multipart/form-data", + CURLFORM_END); + + curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, "imageFile", + CURLFORM_BUFFER, filename, + CURLFORM_BUFFERPTR, image_data, + CURLFORM_BUFFERLENGTH, image_size, + CURLFORM_END); + + curl_easy_setopt(curl, CURLOPT_URL, post_url); + curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + + /* if CURLOPT_VERBOSE is enabled, __curl_debug() function will be called */ + // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, __curl_debug); + + // curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, REQ_CON_TIMEOUT); + // curl_easy_setopt(curl, CURLOPT_TIMEOUT, REQ_TIMEOUT); + + response = curl_easy_perform(curl); + + if (response != CURLE_OK) { + _E("curl_easy_perform() failed: %s", + curl_easy_strerror(response)); + ret = -1; + } + + curl_easy_cleanup(curl); + curl_formfree(formpost); + g_free(post_url); + g_free(filename); + + return ret; +} + int web_util_noti_post(const char *resource, const char *json_data) { int ret = 0; @@ -399,7 +520,6 @@ int web_util_json_add_sensor_data(const char* sensorpi_id, web_util_sensor_data_ } */ - json_builder_begin_object(Json_h.builder); json_builder_set_member_name(Json_h.builder, n_id); diff --git a/tizen-manifest.xml.in b/tizen-manifest.xml.in index 2ea5ef4..e014ce2 100644 --- a/tizen-manifest.xml.in +++ b/tizen-manifest.xml.in @@ -5,7 +5,7 @@ Geunsun Lee Eunyoung Lee Junkyu Han - + @PROJECT_NAME@.png @@ -13,5 +13,6 @@ http://tizen.org/privilege/network.get http://tizen.org/privilege/internet http://tizen.org/privilege/peripheralio + http://tizen.org/privilege/camera -- 2.7.4