summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjunkyu han <junkyu.han@samsung.com>2018-03-26 09:43:19 +0900
committerjunkyu han <junkyu.han@samsung.com>2018-03-26 09:43:19 +0900
commitb72b9e4d9c3b91ef61d48cec0c89250356e6c104 (patch)
tree64249331a23053dc812435b9ce981ccd9d8c1b3b
parentb4baa8bfad7303a70278193b0b47e8335942b63e (diff)
parent1f1e85d3dd548012fc7ba79b3e3e06ecefbabb18 (diff)
downloadgear-racing-car-b72b9e4d9c3b91ef61d48cec0c89250356e6c104.tar.gz
gear-racing-car-b72b9e4d9c3b91ef61d48cec0c89250356e6c104.tar.bz2
gear-racing-car-b72b9e4d9c3b91ef61d48cec0c89250356e6c104.zip
Merge remote-tracking branch 'privategit/master'
-rw-r--r--.gitignore52
-rw-r--r--CMakeLists.txt54
-rw-r--r--README.md1
-rw-r--r--inc/connection_manager.h35
-rw-r--r--inc/log.h106
-rw-r--r--inc/message.h50
-rw-r--r--inc/receiver.h30
-rw-r--r--inc/receiver_internal.h52
-rw-r--r--inc/receiver_type.h35
-rw-r--r--inc/receiver_udp.h24
-rw-r--r--inc/resource.h31
-rw-r--r--inc/resource/resource_PCA9685.h29
-rw-r--r--inc/resource/resource_infrared_obstacle_avoidance_sensor.h38
-rw-r--r--inc/resource/resource_infrared_obstacle_avoidance_sensor_internal.h31
-rw-r--r--inc/resource/resource_motor_driver_L298N.h82
-rw-r--r--inc/resource/resource_motor_driver_L298N_internal.h27
-rw-r--r--inc/resource/resource_servo_motor.h36
-rw-r--r--inc/resource/resource_servo_motor_internal.h25
-rw-r--r--inc/resource_internal.h52
-rw-r--r--inc/resource_type.h28
-rw-r--r--org.tizen.car-app.manifest5
-rw-r--r--packaging/car-app.spec82
-rw-r--r--shared/res/default_icon.pngbin0 -> 57662 bytes
-rw-r--r--src/app.c297
-rw-r--r--src/connection_manager.c237
-rw-r--r--src/log.c138
-rw-r--r--src/message.c120
-rw-r--r--src/receiver.c328
-rw-r--r--src/receiver_udp.c477
-rw-r--r--src/resource.c48
-rw-r--r--src/resource/resource_PCA9685.c249
-rw-r--r--src/resource/resource_infrared_obstacle_avoidance_sensor.c143
-rw-r--r--src/resource/resource_motor_driver_L298N.c333
-rw-r--r--src/resource/resource_servo_motor.c75
-rw-r--r--tizen-manifest.xml.in13
35 files changed, 3363 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c6127b3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,52 @@
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..95c94d6
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,54 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(${P_NAME} C)
+
+SET(INSTALL_EXEC_PREFIX "${INSTALL_PREFIX}/bin")
+SET(CMAKE_VERBOSE_MAKEFILE 0)
+
+SET(PROJECT_ROOT_DIR "${CMAKE_SOURCE_DIR}")
+SET(PROJECT_RESOURCES_DIR "${PROJECT_ROOT_DIR}/res")
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(APP_PKGS REQUIRED
+ dlog
+ capi-appfw-application
+ capi-appfw-service-application
+ capi-system-peripheral-io
+ glib-2.0
+ gio-2.0
+ capi-network-connection
+)
+
+FOREACH (flag ${APP_PKGS_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Wall -Winline -g -fno-builtin-malloc -fPIE")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie")
+
+INCLUDE_DIRECTORIES(${PROJECT_ROOT_DIR}/inc)
+
+ADD_EXECUTABLE(${PROJECT_NAME}
+ ${PROJECT_ROOT_DIR}/src/app.c
+ ${PROJECT_ROOT_DIR}/src/log.c
+ ${PROJECT_ROOT_DIR}/src/connection_manager.c
+ ${PROJECT_ROOT_DIR}/src/resource.c
+ ${PROJECT_ROOT_DIR}/src/message.c
+ ${PROJECT_ROOT_DIR}/src/receiver.c
+ ${PROJECT_ROOT_DIR}/src/receiver_udp.c
+ ${PROJECT_ROOT_DIR}/src/resource/resource_infrared_obstacle_avoidance_sensor.c
+ ${PROJECT_ROOT_DIR}/src/resource/resource_motor_driver_L298N.c
+ ${PROJECT_ROOT_DIR}/src/resource/resource_PCA9685.c
+ ${PROJECT_ROOT_DIR}/src/resource/resource_servo_motor.c
+)
+
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} -lm)
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${APP_PKGS_LDFLAGS})
+
+CONFIGURE_FILE(${PROJECT_ROOT_DIR}/tizen-manifest.xml.in ${ORG_PREFIX}.${PROJECT_NAME}.xml @ONLY)
+# Install
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${INSTALL_EXEC_PREFIX})
+INSTALL(FILES ${ORG_PREFIX}.${PROJECT_NAME}.xml DESTINATION ${SYS_PACKAGES_DIR})
+INSTALL(FILES ${PROJECT_ROOT_DIR}/shared/res/default_icon.png DESTINATION ${SYS_ICONS_DIR} RENAME ${PROJECT_NAME}.png)
+
+# End of a file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d9896a8
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+# car-app \ No newline at end of file
diff --git a/inc/connection_manager.h b/inc/connection_manager.h
new file mode 100644
index 0000000..14a054f
--- /dev/null
+++ b/inc/connection_manager.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+
+#ifndef __POSITION_FINDER_CONN_MGR_H__
+#define __POSITION_FINDER_CONN_MGR_H__
+
+typedef enum {
+ CONNECTION_STATE_DISCONNECTED,
+ CONNECTION_STATE_CONNECTED,
+} connection_state_e;
+
+typedef void(*connection_state_changed_cb)
+ (connection_state_e state, const char *ip, void* user_data);
+
+int connection_manager_get_ip(const char **ip);
+int connection_manager_init(void);
+int connection_manager_fini(void);
+int connection_manager_set_state_changed_cb(
+ connection_state_changed_cb state_cb, void *user_data);
+
+#endif /* __POSITION_FINDER_CONN_MGR_H__ */
diff --git a/inc/log.h b/inc/log.h
new file mode 100644
index 0000000..ba19887
--- /dev/null
+++ b/inc/log.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jeonghoon Park <jh1979.park@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef __CAR_APP_LOG_H__
+#define __CAR_APP_LOG_H__
+
+#include <dlog.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "CAR_APP"
+
+#if !defined(_D)
+#define _D(fmt, arg...) log_print(DLOG_DEBUG, LOG_TAG, "[%s:%d] " fmt "\n", __func__, __LINE__, ##arg)
+#endif
+
+#if !defined(_I)
+#define _I(fmt, arg...) log_print(DLOG_INFO, LOG_TAG, "[%s:%d] " fmt "\n", __func__, __LINE__, ##arg)
+#endif
+
+#if !defined(_W)
+#define _W(fmt, arg...) log_print(DLOG_WARN, LOG_TAG, "[%s:%d] " fmt "\n", __func__, __LINE__, ##arg)
+#endif
+
+#if !defined(_E)
+#define _E(fmt, arg...) log_print(DLOG_ERROR, LOG_TAG, "[%s:%d] " fmt "\n", __func__, __LINE__, ##arg)
+#endif
+
+#define retvm_if(expr, val, fmt, arg...) do { \
+ if (expr) { \
+ _E(fmt, ##arg); \
+ _E("(%s) -> %s() return", #expr, __FUNCTION__); \
+ return val; \
+ } \
+} while (0)
+
+#define retv_if(expr, val) do { \
+ if (expr) { \
+ _E("(%s) -> %s() return", #expr, __FUNCTION__); \
+ return (val); \
+ } \
+} while (0)
+
+#define retm_if(expr, fmt, arg...) do { \
+ if (expr) { \
+ _E(fmt, ##arg); \
+ _E("(%s) -> %s() return", #expr, __FUNCTION__); \
+ return; \
+ } \
+} while (0)
+
+#define ret_if(expr) do { \
+ if (expr) { \
+ _E("(%s) -> %s() return", #expr, __FUNCTION__); \
+ return; \
+ } \
+} while (0)
+
+#define goto_if(expr, val) do { \
+ if (expr) { \
+ _E("(%s) -> goto", #expr); \
+ goto val; \
+ } \
+} while (0)
+
+#define break_if(expr) { \
+ if (expr) { \
+ _E("(%s) -> break", #expr); \
+ break; \
+ } \
+}
+
+#define continue_if(expr) { \
+ if (expr) { \
+ _E("(%s) -> continue", #expr); \
+ continue; \
+ } \
+}
+
+typedef enum {
+ LOG_TYPE_DLOG = 0,
+ LOG_TYPE_FILE,
+ LOG_TYPE_ALL,
+} log_type;
+
+int log_print(log_priority prio, const char *tag, const char *fmt, ...);
+int log_type_set(log_type type);
+void log_file_close(void);
+
+#endif /* __CAR_APP_LOG_H__ */
diff --git a/inc/message.h b/inc/message.h
new file mode 100644
index 0000000..c29f600
--- /dev/null
+++ b/inc/message.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CAR_APP_MESSAGE_H__
+#define __CAR_APP_MESSAGE_H__
+
+typedef enum __message_cmd_e {
+ MESSAGE_CMD_HELLO, /* to use keep alive, if needed */
+ MESSAGE_CMD_CALIBRATION,
+ MESSAGE_CMD_DRIVE,
+ MESSAGE_CMD_BYE, /* to notify explicitly closing connection */
+} message_cmd_e;
+
+struct __message_type_s {
+ unsigned long long int seq_num;
+ message_cmd_e cmd;
+ int servo;
+ int speed;
+ unsigned long long int time; /* to be used to order messages */
+};
+typedef struct __message_type_s message_s;
+
+int message_new_to_send(message_cmd_e cmd,
+ int servo, int speed, message_s *new_msg);
+
+void message_reset_seq_num(void);
+
+int message_queue_new(void);
+void message_queue_clear(void);
+
+void message_push_to_inqueue(message_s *msg);
+message_s *message_pop_from_inqueue(void);
+
+void message_push_to_outqueue(message_s *msg);
+message_s *message_pop_from_outqueue(void);
+
+#endif /* __CAR_APP_MESSAGE_H__ */
diff --git a/inc/receiver.h b/inc/receiver.h
new file mode 100644
index 0000000..e194460
--- /dev/null
+++ b/inc/receiver.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CAR_APP_RECEIVER_H__
+#define __CAR_APP_RECEIVER_H__
+
+#include "receiver_type.h"
+
+int receiver_init(receiver_type_e type);
+void receiver_fini(receiver_type_e type);
+int receiver_start(receiver_type_e type);
+int receiver_stop(receiver_type_e type);
+receiver_state_e receiver_get_state(receiver_type_e type);
+int receiver_set_state_changed_cb(receiver_type_e type,
+ receiver_state_changed_cb callback, void *user_data);
+
+#endif /* __CAR_APP_RECEIVER_H__ */
diff --git a/inc/receiver_internal.h b/inc/receiver_internal.h
new file mode 100644
index 0000000..30fb318
--- /dev/null
+++ b/inc/receiver_internal.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CAR_APP_RECEIVER_INTERNAL_H__
+#define __CAR_APP_RECEIVER_INTERNAL_H__
+
+#include "receiver_type.h"
+
+/* TODO */
+typedef int (*receiver_init_func) (void *data);
+typedef int (*receiver_fini_func) (void *data);
+typedef int (*receiver_start_func) (void *data);
+typedef int (*receiver_stop_func) (void *data);
+typedef receiver_state_e (*receiver_get_state_func) (void *data);
+
+typedef struct __receiver_module_h receiver_module_h;
+
+int receiver_set_module_data(receiver_module_h *handle, void *module_data);
+void *receiver_get_module_data(receiver_module_h *handle);
+
+int receiver_set_module_init_function(
+ receiver_module_h *handle, receiver_init_func func);
+
+int receiver_set_module_fini_function(
+ receiver_module_h *handle, receiver_fini_func func);
+
+int receiver_set_module_start_function(
+ receiver_module_h *handle, receiver_start_func func);
+
+int receiver_set_module_stop_function(
+ receiver_module_h *handle, receiver_stop_func func);
+
+int receiver_set_module_get_state_function(
+ receiver_module_h *handle, receiver_get_state_func func);
+
+void receiver_module_state_changed(
+ receiver_module_h *handle, receiver_state_e state);
+
+#endif /* __CAR_APP_RECEIVER_INTERNAL_H__ */
diff --git a/inc/receiver_type.h b/inc/receiver_type.h
new file mode 100644
index 0000000..81e99d6
--- /dev/null
+++ b/inc/receiver_type.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CAR_APP_RECEIVER_TYPE_H__
+#define __CAR_APP_RECEIVER_TYPE_H__
+
+typedef enum __receiver_type_e {
+ RECEIVER_TYPE_UDP = (1 << 0),
+ RECEIVER_TYPE_BLUETOOTH = (1 << 1),
+} receiver_type_e;
+
+typedef enum __receiver_state_e {
+ RECEIVER_STATE_NONE,
+ RECEIVER_STATE_INIT,
+ RECEIVER_STATE_READY,
+ RECEIVER_STATE_CONNECTED,
+} receiver_state_e;
+
+typedef void(*receiver_state_changed_cb)
+ (receiver_type_e type, receiver_state_e state, void* user_data);
+
+#endif /* __CAR_APP_RECEIVER_TYPE_H__ */
diff --git a/inc/receiver_udp.h b/inc/receiver_udp.h
new file mode 100644
index 0000000..ad0a100
--- /dev/null
+++ b/inc/receiver_udp.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CAR_APP_RECEIVER_UDP_H__
+#define __CAR_APP_RECEIVER_UDP_H__
+
+#include "receiver_internal.h"
+
+int receiver_udp_module_register(receiver_module_h *handle);
+
+#endif /* __CAR_APP_RECEIVER_UDP_H__ */
diff --git a/inc/resource.h b/inc/resource.h
new file mode 100644
index 0000000..5aacc4a
--- /dev/null
+++ b/inc/resource.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jin Yoon <jinny.yoon@samsung.com>
+ * Geunsun Lee <gs86.lee@samsung.com>
+ * Eunyoung Lee <ey928.lee@samsung.com>
+ * Junkyu Han <junkyu.han@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef __POSITION_FINDER_RESOURCE_H__
+#define __POSITION_FINDER_RESOURCE_H__
+
+#include "resource/resource_infrared_obstacle_avoidance_sensor.h"
+#include "resource/resource_motor_driver_L298N.h"
+#include "resource/resource_servo_motor.h"
+
+void resource_close_all(void);
+
+#endif /* __POSITION_FINDER_RESOURCE_H__ */
diff --git a/inc/resource/resource_PCA9685.h b/inc/resource/resource_PCA9685.h
new file mode 100644
index 0000000..aa45477
--- /dev/null
+++ b/inc/resource/resource_PCA9685.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jeonghoon Park <jh1979.park@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef __RESOURCE_PCA9685_H__
+#define __RESOURCE_PCA9685_H__
+
+#define PCA9685_CH_MAX 15
+
+int resource_pca9685_init(unsigned int ch);
+int resource_pca9685_fini(unsigned int ch);
+int resource_pca9685_set_frequency(unsigned int freq_hz);
+int resource_pca9685_set_value_to_channel(unsigned int channel, int on, int off);
+
+#endif /* __RESOURCE_PCA9685_H__ */
diff --git a/inc/resource/resource_infrared_obstacle_avoidance_sensor.h b/inc/resource/resource_infrared_obstacle_avoidance_sensor.h
new file mode 100644
index 0000000..20d088e
--- /dev/null
+++ b/inc/resource/resource_infrared_obstacle_avoidance_sensor.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jin Yoon <jinny.yoon@samsung.com>
+ * Geunsun Lee <gs86.lee@samsung.com>
+ * Eunyoung Lee <ey928.lee@samsung.com>
+ * Junkyu Han <junkyu.han@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef __POSITION_FINDER_RESOURCE_INFRARED_OBSTACLE_AVOIDANCE_SENSOR_H__
+#define __POSITION_FINDER_RESOURCE_INFRARED_OBSTACLE_AVOIDANCE_SENSOR_H__
+
+#include "resource_type.h"
+
+/**
+ * @brief Reads the value of gpio connected infrared obstacle avoidance sensor.
+ * @param[in] pin_num The number of the gpio pin connected to the infrared obstacle avoidance sensor
+ * @param[out] out_value The value of the gpio (zero or non-zero)
+ * @return 0 on success, otherwise a negative error value
+ * @see If the gpio pin is not open, creates gpio handle before reading the value of gpio.
+ */
+extern int resource_read_infrared_obstacle_avoidance_sensor(int pin_num, unsigned int *out_value);
+
+extern int resource_set_infrared_obstacle_avoidance_sensor_interrupted_cb(int pin_num, resource_changed_cb cb, void *data);
+
+#endif /* __POSITION_FINDER_RESOURCE_INFRARED_OBSTACLE_AVOIDANCE_SENSOR_H__ */
diff --git a/inc/resource/resource_infrared_obstacle_avoidance_sensor_internal.h b/inc/resource/resource_infrared_obstacle_avoidance_sensor_internal.h
new file mode 100644
index 0000000..f52cdf1
--- /dev/null
+++ b/inc/resource/resource_infrared_obstacle_avoidance_sensor_internal.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jin Yoon <jinny.yoon@samsung.com>
+ * Geunsun Lee <gs86.lee@samsung.com>
+ * Eunyoung Lee <ey928.lee@samsung.com>
+ * Junkyu Han <junkyu.han@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef __POSITION_FINDER_RESOURCE_INFRARED_OBSTACLE_AVOIDANCE_SENSOR_INTERNAL_H__
+#define __POSITION_FINDER_RESOURCE_INFRARED_OBSTACLE_AVOIDANCE_SENSOR_INTERNAL_H__
+
+/**
+ * @brief Releases the gpio handle and changes the gpio pin state to the close(0).
+ * @param[in] pin_num The number of the gpio pin connected to the infrared obstacle avoidance sensor
+ */
+extern void resource_close_infrared_obstacle_avoidance_sensor(int pin_num);
+
+#endif /* __POSITION_FINDER_RESOURCE_INFRARED_OBSTACLE_AVOIDANCE_SENSOR_INTERNAL_H__ */
diff --git a/inc/resource/resource_motor_driver_L298N.h b/inc/resource/resource_motor_driver_L298N.h
new file mode 100644
index 0000000..1cf7bae
--- /dev/null
+++ b/inc/resource/resource_motor_driver_L298N.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jeonghoon Park <jh1979.park@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef __RESOURCE_MOTOR_DRIVER_L298N_H__
+#define __RESOURCE_MOTOR_DRIVER_L298N_H__
+
+/**
+ * This module is sample codes to handling DC motors in Tizen platform.
+ * HW is configured with L298N(motor driver) and PCA9685(PWM controller).
+ * To control motor, we use two GPIO pins of IoT board(e.g. RPi 3) connected
+ * with L298N and a PWM channel of PCA9685 connected with L298N
+ */
+
+/* Default GPIO pins of raspberry pi 3 connected with IN pins of L298N */
+#define DEFAULT_MOTOR1_PIN1 26
+#define DEFAULT_MOTOR1_PIN2 20
+
+#define DEFAULT_MOTOR2_PIN1 19
+#define DEFAULT_MOTOR2_PIN2 16
+
+#define DEFAULT_MOTOR3_PIN1 6
+#define DEFAULT_MOTOR3_PIN2 12
+
+#define DEFAULT_MOTOR4_PIN1 22
+#define DEFAULT_MOTOR4_PIN2 23
+
+/* Default channel numbers of PCA9685 with enable pins of L298N */
+#define DEFAULT_MOTOR1_EN_CH 1
+#define DEFAULT_MOTOR2_EN_CH 2
+#define DEFAULT_MOTOR3_EN_CH 3
+#define DEFAULT_MOTOR4_EN_CH 4
+
+
+/**
+ * @brief Enumeration for motor id.
+ */
+typedef enum {
+ MOTOR_ID_1,
+ MOTOR_ID_2,
+ MOTOR_ID_3,
+ MOTOR_ID_4,
+ MOTOR_ID_MAX
+} motor_id_e;
+
+/**
+ * @param[in] id The motor id
+ * @param[in] pin1 The first pin number to control motor
+ * @param[in] pin2 The second pin number to control motor
+ * @param[in] en_ch The enable channnel number to control PWM signal
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @before resource_set_motor_driver_L298N_speed() : Optional
+ */
+int resource_set_motor_driver_L298N_configuration(motor_id_e id,
+ unsigned int pin1, unsigned int pin2, unsigned en_ch);
+
+/**
+ * @param[in] id The motor id
+ * @param[in] speed The speed to control motor, 0 to stop motor,
+ * positive value to rotate clockwise and higher value to rotate more fast
+ * negative value to rotate couterclockwise and lower value to rotate more fast
+ * @return 0 on success, otherwise a negative error value
+ * @before resource_set_motor_driver_L298N_speed() : Optional
+ */
+int resource_set_motor_driver_L298N_speed(motor_id_e id, int speed);
+
+#endif /* __RESOURCE_MOTOR_DRIVER_L298N_H__ */
diff --git a/inc/resource/resource_motor_driver_L298N_internal.h b/inc/resource/resource_motor_driver_L298N_internal.h
new file mode 100644
index 0000000..2fb63f7
--- /dev/null
+++ b/inc/resource/resource_motor_driver_L298N_internal.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jeonghoon Park <jh1979.park@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef __RESOURCE_MOTOR_DRIVER_L298N_INTERNAL_H__
+#define __RESOURCE_MOTOR_DRIVER_L298N_INTERNAL_H__
+
+#include "resource/resource_motor_driver_L298N.h"
+
+void resource_close_motor_driver_L298N(motor_id_e id);
+void resource_close_motor_driver_L298N_all(void);
+
+#endif /* __RESOURCE_MOTOR_DRIVER_L298N_INTERNAL_H__ */
diff --git a/inc/resource/resource_servo_motor.h b/inc/resource/resource_servo_motor.h
new file mode 100644
index 0000000..924d6cc
--- /dev/null
+++ b/inc/resource/resource_servo_motor.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jeonghoon Park <jh1979.park@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef __RESOURCE_SERVO_MOTOR_H__
+#define __RESOURCE_SERVO_MOTOR_H__
+
+/**
+ * This module is sample codes to handling Servo motors in Tizen platform.
+ * HW is configured with PCA9685(PWM controller).
+ */
+
+/**
+ * @param[in] id The motor id
+ * @param[in] value The value to control servo motor
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @remarks Must adjust servo motor with some value before use to fit your system.
+ */
+int resource_set_servo_motor_value(unsigned int motor_id, int value);
+
+#endif /* __RESOURCE_SERVO_MOTOR_H__ */
diff --git a/inc/resource/resource_servo_motor_internal.h b/inc/resource/resource_servo_motor_internal.h
new file mode 100644
index 0000000..e038390
--- /dev/null
+++ b/inc/resource/resource_servo_motor_internal.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jeonghoon Park <jh1979.park@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef __RESOURCE_SERVO_MOTOR_INTERNAL_H__
+#define __RESOURCE_SERVO_MOTOR_INTERNAL_H__
+
+void resource_close_servo_motor(unsigned int ch);
+void resource_close_servo_motor_all(void);
+
+#endif /* __RESOURCE_SERVO_MOTOR_INTERNAL_H__ */
diff --git a/inc/resource_internal.h b/inc/resource_internal.h
new file mode 100644
index 0000000..fb18904
--- /dev/null
+++ b/inc/resource_internal.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jin Yoon <jinny.yoon@samsung.com>
+ * Geunsun Lee <gs86.lee@samsung.com>
+ * Eunyoung Lee <ey928.lee@samsung.com>
+ * Junkyu Han <junkyu.han@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef __POSITION_FINDER_RESOURCE_INTERNAL_H__
+#define __POSITION_FINDER_RESOURCE_INTERNAL_H__
+
+#include <peripheral_io.h>
+#include "resource_type.h"
+
+#define PIN_MAX 40
+
+typedef struct _resource_read_cb_s {
+ resource_read_cb cb;
+ void *data;
+ int pin_num;
+} resource_read_s;
+
+typedef struct _resource_changed_s {
+ resource_changed_cb cb;
+ void *data;
+ int pin_num;
+} resource_changed_s;
+
+typedef struct _resource_s {
+ int opened;
+ peripheral_gpio_h sensor_h;
+ void (*close) (int);
+ /*FIXME*/
+ resource_changed_s *resource_changed_info;
+} resource_s;
+
+extern resource_s *resource_get_info(int pin_num);
+
+#endif /* __POSITION_FINDER_RESOURCE_INTERNAL_H__ */
diff --git a/inc/resource_type.h b/inc/resource_type.h
new file mode 100644
index 0000000..6853164
--- /dev/null
+++ b/inc/resource_type.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jin Yoon <jinny.yoon@samsung.com>
+ * Geunsun Lee <gs86.lee@samsung.com>
+ * Eunyoung Lee <ey928.lee@samsung.com>
+ * Junkyu Han <junkyu.han@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef __POSITION_FINDER_RESOURCE_TYPE_H__
+#define __POSITION_FINDER_RESOURCE_TYPE_H__
+
+typedef void (*resource_read_cb)(double value, void *data);
+typedef void (*resource_changed_cb)(unsigned int value, void *data);
+
+#endif /* __POSITION_FINDER_RESOURCE_TYPE_H__ */
diff --git a/org.tizen.car-app.manifest b/org.tizen.car-app.manifest
new file mode 100644
index 0000000..af9b883
--- /dev/null
+++ b/org.tizen.car-app.manifest
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+</manifest>
diff --git a/packaging/car-app.spec b/packaging/car-app.spec
new file mode 100644
index 0000000..b957a3e
--- /dev/null
+++ b/packaging/car-app.spec
@@ -0,0 +1,82 @@
+%define P_NAME car-app
+%define ORG_PREFIX org.tizen
+%define APP_LABEL "Car App"
+
+Name: %{ORG_PREFIX}.%{P_NAME}
+%define alias %{name}
+Summary: Car Application
+Version: 0.0.1
+Release: 1
+License: Flora-1.1
+Provides: %{name} = %{version}-%{release}
+Source0: %{name}-%{version}.tar.gz
+
+BuildRequires: cmake
+BuildRequires: hash-signer
+BuildRequires: pkgconfig(capi-appfw-application)
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(libtzplatform-config)
+BuildRequires: pkgconfig(capi-appfw-service-application)
+BuildRequires: pkgconfig(capi-system-peripheral-io)
+BuildRequires: pkgconfig(gio-2.0)
+BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(capi-network-connection)
+
+%description
+Car application
+
+%prep
+%setup -q
+
+%build
+
+%define _pkg_dir %{TZ_SYS_RO_APP}/%{alias}
+%define _pkg_shared_dir %{_pkg_dir}/shared
+%define _pkg_data_dir %{_pkg_dir}/data
+%define _pkg_res_dir %{_pkg_dir}/res
+%define _sys_icons_dir %{_pkg_shared_dir}/res
+%define _sys_packages_dir %{TZ_SYS_RO_PACKAGES}
+%define _sys_license_dir %{TZ_SYS_SHARE}/license
+
+
+%ifarch %{arm}
+export CFLAGS="$CFLAGS -DTIZEN_BUILD_TARGET"
+export CXXFLAGS="$CXXFLAGS -DTIZEN_BUILD_TARGET"
+export FFLAGS="$FFLAGS -DTIZEN_BUILD_TARGET"
+%else
+export CFLAGS="$CFLAGS -DTIZEN_BUILD_EMULATOR"
+export CXXFLAGS="$CXXFLAGS -DTIZEN_BUILD_EMULATOR"
+export FFLAGS="$FFLAGS -DTIZEN_BUILD_EMULATOR"
+%endif
+
+cmake . -DP_NAME=%{P_NAME} \
+ -DORG_PREFIX=%{ORG_PREFIX} \
+ -DAPP_LABEL=%{APP_LABEL} \
+ -DINSTALL_PREFIX=%{_pkg_dir} \
+ -DSYS_ICONS_DIR=%{_sys_icons_dir} \
+ -DSYS_PACKAGES_DIR=%{_sys_packages_dir} \
+
+make %{?jobs:-j%jobs}
+
+%install
+%make_install
+
+%define tizen_sign 1
+%define tizen_sign_base %{_pkg_dir}
+%define tizen_sign_level platform
+%define tizen_author_sign 1
+%define tizen_dist_sign 1
+
+%post
+/sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%manifest %{alias}.manifest
+%defattr(-,root,root,-)
+%{_pkg_dir}/bin/%{P_NAME}
+%{_sys_packages_dir}/%{alias}.xml
+%{_sys_icons_dir}/*.png
+%{_pkg_dir}/author-signature.xml
+%{_pkg_dir}/signature1.xml
diff --git a/shared/res/default_icon.png b/shared/res/default_icon.png
new file mode 100644
index 0000000..9765b1b
--- /dev/null
+++ b/shared/res/default_icon.png
Binary files differ
diff --git a/src/app.c b/src/app.c
new file mode 100644
index 0000000..0a161d3
--- /dev/null
+++ b/src/app.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jeonghoon Park <jh1979.park@samsung.com>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+#include <glib.h>
+#include <service_app.h>
+#include "log.h"
+#include "resource.h"
+#include "receiver.h"
+#include "message.h"
+#include "connection_manager.h"
+
+#define ENABLE_MOTOR 1
+
+enum {
+ DIR_STATE_S,
+ DIR_STATE_F,
+ DIR_STATE_B,
+};
+
+typedef struct app_data_s {
+ unsigned int f_value;
+ unsigned int r_value;
+ unsigned int dir_state;
+ guint idle_h;
+} app_data;
+
+static void service_app_lang_changed(app_event_info_h event_info, void *user_data)
+{
+ return;
+}
+
+static void service_app_region_changed(app_event_info_h event_info, void *user_data)
+{
+ return;
+}
+
+static void service_app_low_battery(app_event_info_h event_info, void *user_data)
+{
+ _E("low battery! exit app");
+ service_app_exit();
+
+ return;
+}
+
+static void service_app_low_memory(app_event_info_h event_info, void *user_data)
+{
+ return;
+}
+
+static inline double __map_round(double val)
+{
+ return floor(val + 0.5);
+}
+
+static int __map_range_val(int d_max, int d_min, int v_max, int v_min, int val)
+{
+ int rval = 0;
+ double slope = 0;
+ slope = 1.0 * (d_max - d_min) / (v_max - v_min);
+
+ rval = d_min + __map_round(slope * (val - v_min));
+
+ return rval;
+}
+
+static int ___map_speed_val(int speed)
+{
+ static const int motor_max = 4095;
+ static const int motor_min = -4095;
+ static const int speed_max = 1000;
+ static const int speed_min = -1000;
+
+ return __map_range_val(motor_max, motor_min,
+ speed_max, speed_min, speed);
+}
+
+static int ___map_servo_val(int servo)
+{
+ static const int motor_max = 500;
+ static const int motor_min = 400;
+ static const int servo_max = 1000;
+ static const int servo_min = -1000;
+
+ return __map_range_val(motor_max, motor_min,
+ servo_max, servo_min, servo);
+}
+
+
+static int __driving_motors(int servo, int speed)
+{
+ int val_speed;
+ int val_servo;
+
+ val_servo = ___map_servo_val(servo);
+ val_speed = ___map_speed_val(speed);
+
+ _D("control motor - servo[%4d : %4d], speed[%4d : %4d]",
+ servo, val_servo, speed, val_speed);
+#if ENABLE_MOTOR
+ resource_set_servo_motor_value(0, val_servo);
+ resource_set_motor_driver_L298N_speed(MOTOR_ID_1, val_speed);
+ resource_set_motor_driver_L298N_speed(MOTOR_ID_2, val_speed);
+#endif
+
+ return 0;
+}
+
+static gboolean __message_dispatcher(gpointer user_data)
+{
+ message_s *msg = NULL;
+
+ do {
+ msg = message_pop_from_inqueue();
+ if (msg) {
+ switch (msg->cmd) {
+ case MESSAGE_CMD_HELLO:
+ /* TODO : say hello to sender */
+ break;
+ case MESSAGE_CMD_CALIBRATION:
+ /* TODO : set calibration mode */
+ break;
+ case MESSAGE_CMD_DRIVE:
+ /* TODO : driving car */
+ __driving_motors(msg->servo, msg->speed);
+ break;
+ case MESSAGE_CMD_BYE:
+ __driving_motors(0, 0);
+ break;
+ }
+ }
+ free(msg);
+ } while (msg);
+
+ return TRUE;
+}
+
+static void __recv_state_change(receiver_type_e type,
+ receiver_state_e state, void* user_data)
+{
+ app_data *ad = user_data;
+ ret_if(!ad);
+
+ _D("receiver type[%d] state changed[%d]", type, state);
+
+ if (state == RECEIVER_STATE_CONNECTED) {
+ if (!ad->idle_h)
+ ad->idle_h = g_idle_add(__message_dispatcher, ad);
+ } else {
+ if (ad->idle_h) {
+ g_source_remove(ad->idle_h);
+ ad->idle_h = 0;
+ }
+ __driving_motors(0, 0);
+ }
+
+ return;
+}
+
+static void __conn_state_changed_cb(connection_state_e state,
+ const char *ip, void* user_data)
+{
+ app_data *ad = user_data;
+
+ _D("connection state changed : %d", state);
+
+ if (state == CONNECTION_STATE_CONNECTED) {
+ receiver_start(RECEIVER_TYPE_UDP);
+
+ } else {
+ receiver_stop(RECEIVER_TYPE_UDP);
+
+ if (ad->idle_h) {
+ g_source_remove(ad->idle_h);
+ ad->idle_h = 0;
+ }
+
+ __driving_motors(0, 0);
+ }
+ return;
+}
+
+static bool service_app_create(void *data)
+{
+ int ret = 0;
+ app_data *ad = data;
+
+ /*
+ * if you want to use default configuration,
+ * Do not need to call resource_set_motor_driver_L298N_configuration(),
+ *
+ */
+#if ENABLE_MOTOR
+ ret = resource_set_motor_driver_L298N_configuration(MOTOR_ID_1, 19, 16, 5);
+ if (ret) {
+ _E("resource_set_motor_driver_L298N_configuration()");
+ service_app_exit();
+ }
+ ret = resource_set_motor_driver_L298N_configuration(MOTOR_ID_2, 26, 20, 4);
+ if (ret) {
+ _E("resource_set_motor_driver_L298N_configuration()");
+ service_app_exit();
+ }
+#endif
+
+ receiver_init(RECEIVER_TYPE_UDP);
+ receiver_set_state_changed_cb(RECEIVER_TYPE_UDP, __recv_state_change, ad);
+
+ connection_manager_init();
+ connection_manager_set_state_changed_cb(__conn_state_changed_cb, ad);
+
+ message_queue_new();
+
+ return true;
+}
+
+static void service_app_control(app_control_h app_control, void *data)
+{
+
+#if ENABLE_MOTOR
+ /* set speed 0, to reduce delay of initializing motor driver */
+ resource_set_motor_driver_L298N_speed(MOTOR_ID_1, 0);
+ resource_set_motor_driver_L298N_speed(MOTOR_ID_2, 0);
+ resource_set_servo_motor_value(0, 450);
+#endif
+
+ return;
+}
+
+static void service_app_terminate(void *data)
+{
+ app_data *ad = data;
+
+ if (ad->idle_h)
+ g_source_remove(ad->idle_h);
+
+
+ connection_manager_fini();
+ receiver_fini(RECEIVER_TYPE_UDP);
+
+ resource_close_all();
+ log_file_close();
+
+ _D("Bye ~");
+
+ return;
+}
+
+int main(int argc, char* argv[])
+{
+ app_data *ad = NULL;
+ int ret = 0;
+ service_app_lifecycle_callback_s event_callback;
+ app_event_handler_h handlers[5] = {NULL, };
+
+ log_type_set(LOG_TYPE_DLOG);
+
+ ad = calloc(1, sizeof(app_data));
+ retv_if(!ad, -1);
+
+ event_callback.create = service_app_create;
+ event_callback.terminate = service_app_terminate;
+ event_callback.app_control = service_app_control;
+
+ service_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY],
+ APP_EVENT_LOW_BATTERY, service_app_low_battery, &ad);
+ service_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY],
+ APP_EVENT_LOW_MEMORY, service_app_low_memory, &ad);
+ service_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED],
+ APP_EVENT_LANGUAGE_CHANGED, service_app_lang_changed, &ad);
+ service_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED],
+ APP_EVENT_REGION_FORMAT_CHANGED, service_app_region_changed, &ad);
+
+ ret = service_app_main(argc, argv, &event_callback, ad);
+ if (ret)
+ _E("failed to start app");
+
+ return 0;
+}
diff --git a/src/connection_manager.c b/src/connection_manager.c
new file mode 100644
index 0000000..2ed6d1b
--- /dev/null
+++ b/src/connection_manager.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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 <net_connection.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+#include "connection_manager.h"
+
+struct conn_mgr_s {
+ connection_h connection;
+ connection_type_e net_state;
+ connection_wifi_state_e wifi_state;
+ char *ip_addr;
+ connection_state_changed_cb state_cb;
+ void *state_cb_data;
+};
+
+struct conn_mgr_s conn_mgr = {
+ NULL,
+ CONNECTION_TYPE_DISCONNECTED,
+ CONNECTION_WIFI_STATE_DEACTIVATED,
+ NULL,
+ NULL,
+ NULL
+};
+
+static const char *__connection_error_to_string(connection_error_e error)
+{
+ switch (error) {
+ case CONNECTION_ERROR_NONE:
+ return "CONNECTION_ERROR_NONE";
+ case CONNECTION_ERROR_INVALID_PARAMETER:
+ return "CONNECTION_ERROR_INVALID_PARAMETER";
+ case CONNECTION_ERROR_OUT_OF_MEMORY:
+ return "CONNECTION_ERROR_OUT_OF_MEMORY";
+ case CONNECTION_ERROR_INVALID_OPERATION:
+ return "CONNECTION_ERROR_INVALID_OPERATION";
+ case CONNECTION_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED:
+ return "CONNECTION_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED";
+ case CONNECTION_ERROR_OPERATION_FAILED:
+ return "CONNECTION_ERROR_OPERATION_FAILED";
+ case CONNECTION_ERROR_ITERATOR_END:
+ return "CONNECTION_ERROR_ITERATOR_END";
+ case CONNECTION_ERROR_NO_CONNECTION:
+ return "CONNECTION_ERROR_NO_CONNECTION";
+ case CONNECTION_ERROR_NOW_IN_PROGRESS:
+ return "CONNECTION_ERROR_NOW_IN_PROGRESS";
+ case CONNECTION_ERROR_ALREADY_EXISTS:
+ return "CONNECTION_ERROR_ALREADY_EXISTS";
+ case CONNECTION_ERROR_OPERATION_ABORTED:
+ return "CONNECTION_ERROR_OPERATION_ABORTED";
+ case CONNECTION_ERROR_DHCP_FAILED:
+ return "CONNECTION_ERROR_DHCP_FAILED";
+ case CONNECTION_ERROR_INVALID_KEY:
+ return "CONNECTION_ERROR_INVALID_KEY";
+ case CONNECTION_ERROR_NO_REPLY:
+ return "CONNECTION_ERROR_NO_REPLY";
+ case CONNECTION_ERROR_PERMISSION_DENIED:
+ return "CONNECTION_ERROR_PERMISSION_DENIED";
+ case CONNECTION_ERROR_NOT_SUPPORTED:
+ return "CONNECTION_ERROR_NOT_SUPPORTED";
+ default:
+ return "CONNECTION_ERROR_UNKNOWN";
+ }
+}
+
+static void __conn_mgr_connection_changed_cb(connection_type_e type,
+ void* user_data)
+{
+ int ret = CONNECTION_ERROR_NONE;
+ connection_state_e state = CONNECTION_STATE_DISCONNECTED;
+ _D("connection changed from[%d] to[%d]", conn_mgr.net_state, type);
+
+ conn_mgr.net_state = type;
+
+ ret = connection_get_wifi_state(conn_mgr.connection,
+ &conn_mgr.wifi_state);
+
+ if (CONNECTION_ERROR_NONE != ret)
+ _E("failed to connection_get_wifi_state - [%s]",
+ __connection_error_to_string(ret));
+
+ free(conn_mgr.ip_addr);
+ conn_mgr.ip_addr = NULL;
+
+ if (conn_mgr.net_state != CONNECTION_TYPE_DISCONNECTED) {
+ state = CONNECTION_STATE_CONNECTED;
+ ret = connection_get_ip_address(conn_mgr.connection,
+ CONNECTION_ADDRESS_FAMILY_IPV4, &conn_mgr.ip_addr);
+
+ if ((CONNECTION_ERROR_NONE != ret) || (conn_mgr.ip_addr == NULL))
+ _E("failed to connection_get_ip_address() - [%s]",
+ __connection_error_to_string(ret));
+ }
+
+ if (conn_mgr.state_cb)
+ conn_mgr.state_cb(state, conn_mgr.ip_addr, conn_mgr.state_cb_data);
+
+ return;
+}
+
+int connection_manager_get_ip(const char **ip)
+{
+ int ret = CONNECTION_ERROR_NONE;
+
+ retv_if(conn_mgr.connection == NULL, -1);
+ retv_if(ip == NULL, -1);
+
+ if (conn_mgr.ip_addr) {
+ *ip = conn_mgr.ip_addr;
+ return 0;
+ }
+
+ if (conn_mgr.net_state == CONNECTION_TYPE_DISCONNECTED) {
+ _W("disconnected now");
+
+ free(conn_mgr.ip_addr);
+ conn_mgr.ip_addr = NULL;
+
+ return -1;
+ }
+
+ ret = connection_get_ip_address(conn_mgr.connection,
+ CONNECTION_ADDRESS_FAMILY_IPV4, &conn_mgr.ip_addr);
+
+ if ((CONNECTION_ERROR_NONE != ret) || (conn_mgr.ip_addr == NULL)) {
+ _E("failed to connection_get_ip_address() - [%s]",
+ __connection_error_to_string(ret));
+ return -1;
+ }
+
+ *ip = conn_mgr.ip_addr;
+
+ return 0;
+}
+
+int connection_manager_init(void)
+{
+ int ret = CONNECTION_ERROR_NONE;
+ if (conn_mgr.connection) {
+ _W("connection manager is already initialized");
+ return 0;
+ }
+
+ ret = connection_create(&conn_mgr.connection);
+ if (CONNECTION_ERROR_NONE != ret) {
+ _E("failed to create connection - [%s]",
+ __connection_error_to_string(ret));
+ return -1;
+ }
+
+ ret = connection_get_type(conn_mgr.connection, &conn_mgr.net_state);
+ if (CONNECTION_ERROR_NONE != ret) {
+ _E("failed to connection_get_type - [%s]",
+ __connection_error_to_string(ret));
+ }
+
+ if (conn_mgr.net_state != CONNECTION_TYPE_DISCONNECTED) {
+ ret = connection_get_ip_address(conn_mgr.connection,
+ CONNECTION_ADDRESS_FAMILY_IPV4, &conn_mgr.ip_addr);
+ if ((CONNECTION_ERROR_NONE != ret) || (conn_mgr.ip_addr == NULL))
+ _E("failed to connection_get_ip_address() - [%s]",
+ __connection_error_to_string(ret));
+ }
+
+ ret = connection_get_wifi_state(conn_mgr.connection, &conn_mgr.wifi_state);
+ if (CONNECTION_ERROR_NONE != ret)
+ _E("failed to connection_get_wifi_state - [%s]",
+ __connection_error_to_string(ret));
+
+ _D("net_state[%d], wifi_state[%d], ip address[%s]",
+ conn_mgr.net_state, conn_mgr.wifi_state, conn_mgr.ip_addr);
+
+ ret = connection_set_type_changed_cb(conn_mgr.connection,
+ __conn_mgr_connection_changed_cb, &conn_mgr);
+ if (CONNECTION_ERROR_NONE != ret)
+ _E("failed to connection_set_type_changed_cb - [%s]",
+ __connection_error_to_string(ret));
+
+ return 0;
+}
+
+int connection_manager_fini(void)
+{
+ if (conn_mgr.connection) {
+ int ret = 0;
+ ret = connection_destroy(conn_mgr.connection);
+ _D("connection_destroy - [%s]", __connection_error_to_string(ret));
+ }
+
+ conn_mgr.net_state = CONNECTION_TYPE_DISCONNECTED;
+ conn_mgr.wifi_state = CONNECTION_WIFI_STATE_DEACTIVATED;
+
+ if (conn_mgr.ip_addr) {
+ free(conn_mgr.ip_addr);
+ conn_mgr.ip_addr = NULL;
+ }
+
+ conn_mgr.state_cb = NULL;
+ conn_mgr.state_cb_data = NULL;
+
+ return 0;
+}
+
+int connection_manager_set_state_changed_cb(
+ connection_state_changed_cb state_cb, void *user_data)
+{
+ conn_mgr.state_cb = state_cb;
+
+ if (state_cb) {
+ connection_state_e state = CONNECTION_STATE_DISCONNECTED;
+
+ conn_mgr.state_cb_data = user_data;
+ if (conn_mgr.net_state != CONNECTION_TYPE_DISCONNECTED)
+ state = CONNECTION_STATE_CONNECTED;
+
+ conn_mgr.state_cb(state, conn_mgr.ip_addr, conn_mgr.state_cb_data);
+ } else
+ conn_mgr.state_cb_data = NULL;
+
+ return 0;
+}
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..b25e8a7
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,138 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <app_common.h>
+#include "log.h"
+
+#define MAX_LOG_SIZE 4096
+#define PATH_MAX 4096
+
+static FILE *log_fp = NULL;
+static log_type ltype = LOG_TYPE_DLOG;
+
+static const char log_prio_name[][DLOG_PRIO_MAX-1] = {
+ "UNKNOWN",
+ "DEFAULT", /**< Default */
+ "VERBOSE", /**< Verbose */
+ "DEBUG", /**< Debug */
+ "INFO", /**< Info */
+ "WARN", /**< Warning */
+ "ERROR", /**< Error */
+ "FATAL", /**< Fatal */
+ "SILENT" /**< Silent */
+};
+
+static inline char* getFormattedTime(void)
+{
+ struct timeval val;
+ struct tm *ptm;
+ static char res_time[40] = {0, };
+
+ gettimeofday(&val, NULL);
+ ptm = localtime(&val.tv_sec);
+
+ // format : YYMMDDhhmmssuuuuuu
+ 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 res_time;
+}
+
+static int __open_log_file(void)
+{
+ char buf[PATH_MAX] = {0,};
+ char *prefix = NULL;
+
+ prefix = app_get_data_path();
+
+ if (!prefix)
+ goto error;
+
+ snprintf(buf, sizeof(buf)-1, "%s%s", prefix, "log.txt");
+ free(prefix);
+
+ log_fp = fopen(buf, "a"); /* append or create new ??? */
+ if (log_fp == NULL) {
+ dlog_print(DLOG_WARN, LOG_TAG, "%s\n", strerror(errno));
+ goto error;
+ }
+
+ return 0;
+
+error:
+ dlog_print(DLOG_WARN, LOG_TAG, "error to use log file, so use dlog as log system\n");
+ ltype = LOG_TYPE_DLOG;
+ return -1;
+}
+
+int log_type_set(log_type type)
+{
+ ltype = type;
+ dlog_print(DLOG_DEBUG, LOG_TAG, "setting log type : [%d]\n", type);
+ switch (type) {
+ case LOG_TYPE_FILE:
+ case LOG_TYPE_ALL:
+ __open_log_file();
+ break;
+ case LOG_TYPE_DLOG: /* nothing to do */
+ default:
+ ltype = LOG_TYPE_DLOG;
+ break;
+ }
+ return 0;
+}
+
+void log_file_close(void)
+{
+ if (log_fp) {
+ fclose(log_fp);
+ log_fp = NULL;
+ dlog_print(DLOG_DEBUG, LOG_TAG, "close log file\n");
+ }
+
+ log_type_set(LOG_TYPE_DLOG);
+
+ return;
+}
+
+int log_print(log_priority prio, const char *tag, const char *fmt, ...)
+{
+ va_list ap;
+
+ switch (ltype) {
+ case LOG_TYPE_FILE:
+ if (log_fp) {
+ va_start(ap, fmt);
+ fprintf(log_fp, "[%s] [%s]", getFormattedTime(), log_prio_name[prio]);
+ vfprintf(log_fp, fmt, ap);
+ va_end(ap);
+ fflush(log_fp);
+ }
+ break;
+ case LOG_TYPE_ALL:
+ va_start(ap, fmt);
+ if (log_fp) {
+ fprintf(log_fp, "[%s] [%s]", getFormattedTime(), log_prio_name[prio]);
+ vfprintf(log_fp, fmt, ap);
+ }
+ dlog_vprint(prio, tag, fmt, ap);
+ va_end(ap);
+
+ if (log_fp)
+ fflush(log_fp);
+ break;
+ case LOG_TYPE_DLOG:
+ default:
+ va_start(ap, fmt);
+ dlog_vprint(prio, tag, fmt, ap);
+ va_end(ap);
+ break;
+ }
+ return 0;
+}
diff --git a/src/message.c b/src/message.c
new file mode 100644
index 0000000..2069f57
--- /dev/null
+++ b/src/message.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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 <time.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <glib.h>
+
+#include "log.h"
+#include "message.h"
+
+static unsigned long long int sequence_number = 0;
+static GQueue inqueue = G_QUEUE_INIT;
+static GQueue outqueue = G_QUEUE_INIT;
+
+static unsigned long long int __message_get_monotonic_time(void)
+{
+ unsigned long long int c_time = 0;
+ struct timespec ts;
+ int ret = 0;
+
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (ret)
+ _E("failed to get monotonic time");
+ else
+ c_time = (((unsigned long long int)ts.tv_sec) * 1000000)
+ + (ts.tv_nsec / 1000);
+
+ return c_time;
+}
+
+int message_new_to_send(message_cmd_e cmd,
+ int servo, int speed, message_s *new_msg)
+{
+ retv_if(!new_msg, -1);
+
+ new_msg->seq_num = sequence_number++;
+ new_msg->cmd = cmd;
+ new_msg->servo = servo;
+ new_msg->speed = speed;
+ new_msg->time = __message_get_monotonic_time();
+
+ if (new_msg->seq_num >= ULLONG_MAX) {
+ /* maybe never reach here */
+ _W("seq number reachs max value, reset it to 0");
+ sequence_number = 0;
+ }
+
+ return 0;
+}
+
+void message_reset_seq_num(void)
+{
+ sequence_number = 0;
+
+ return;
+}
+
+int message_queue_new(void)
+{
+ /* Do nothing because we use static queue
+ * if we use multiple thread to handling messages,
+ * message queue should be changed to thread-safe one.
+ */
+ return 0;
+}
+
+static void __queue_clear_cb(gpointer data, gpointer user_data)
+{
+ free(data);
+ return;
+}
+
+void message_queue_clear(void)
+{
+ g_queue_foreach(&inqueue, __queue_clear_cb, NULL);
+ g_queue_clear(&inqueue);
+
+ g_queue_foreach(&outqueue, __queue_clear_cb, NULL);
+ g_queue_clear(&outqueue);
+
+ return;
+}
+
+void message_push_to_inqueue(message_s *msg)
+{
+ g_queue_push_tail(&inqueue, msg);
+ _D("seq[%llu] is pushed to in-queue", msg->seq_num);
+ return;
+}
+
+void message_push_to_outqueue(message_s *msg)
+{
+ g_queue_push_tail(&outqueue, msg);
+ _D("seq[%llu] is pushed to out-queue", msg->seq_num);
+ return;
+}
+
+message_s *message_pop_from_inqueue(void)
+{
+ return (message_s *)g_queue_pop_head(&inqueue);
+}
+
+message_s *message_pop_from_outqueue(void)
+{
+ return (message_s *)g_queue_pop_head(&outqueue);
+}
diff --git a/src/receiver.c b/src/receiver.c
new file mode 100644
index 0000000..4841afd
--- /dev/null
+++ b/src/receiver.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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 <stdlib.h>
+#include <glib.h>
+#include "log.h"
+#include "receiver_type.h"
+#include "receiver_internal.h"
+#include "receiver_udp.h"
+
+typedef struct __receiver_h {
+ receiver_type_e receiver_type;
+ /* TODO */
+} receiver_h;
+
+struct __receiver_module_h {
+ receiver_type_e receiver_type;
+ void *module_data;
+ receiver_init_func init;
+ receiver_fini_func fini;
+ receiver_start_func start;
+ receiver_stop_func stop;
+ receiver_get_state_func get_state;
+ receiver_state_changed_cb state_change_cb;
+ void *state_change_data;
+};
+
+static GHashTable *receiver_module_hash = NULL;
+
+static void ___module_hash_destroy(gpointer data)
+{
+ receiver_module_h *module_h = data;
+
+ module_h->fini(module_h);
+ free(module_h);
+
+ return;
+}
+
+int receiver_init(receiver_type_e type)
+{
+ int ret = 0;
+ receiver_module_h *handle = NULL;
+
+ if (!receiver_module_hash) {
+ receiver_module_hash = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, NULL, ___module_hash_destroy);
+
+ if (!receiver_module_hash) {
+ _E("failed to create hash table");
+ return -1;
+ }
+ } else {
+ handle = g_hash_table_lookup(receiver_module_hash,
+ GUINT_TO_POINTER(type));
+
+ if (handle) {
+ _D("receiver [%d] type is already initialized", type);
+ return 0;
+ }
+ }
+
+ handle = calloc(1, sizeof(struct __receiver_module_h));
+ if (!handle) {
+ _D("failed to alloc handle memory");
+ return -1;
+ }
+
+ handle->receiver_type = type;
+
+ switch (type) {
+ case RECEIVER_TYPE_UDP:
+ /* TODO */
+ ret = receiver_udp_module_register(handle);
+ if (ret)
+ goto ERROR;
+ break;
+ case RECEIVER_TYPE_BLUETOOTH:
+ /* TODO : for bluetooth module */
+ // ret = receiver_bluetooth_module_register(handle);
+ // if (ret)
+ // goto ERROR;
+ break;
+ }
+
+ if (handle->init) {
+ ret = handle->init(handle);
+ if (ret) {
+ _E("failed to initialized type[%d]", type);
+ goto ERROR;
+ }
+ } else {
+ _W("receiver [%d] type is not implemented init func", type);
+ goto ERROR;
+ }
+
+ g_hash_table_insert(receiver_module_hash, GUINT_TO_POINTER(type), handle);
+
+ return 0;
+
+ERROR:
+ free(handle);
+ return -1;
+}
+
+void receiver_fini(receiver_type_e type)
+{
+ receiver_module_h *handle = NULL;
+ guint hash_size = 0;
+
+ if (!receiver_module_hash)
+ return;
+
+ handle = g_hash_table_lookup(receiver_module_hash,
+ GUINT_TO_POINTER(type));
+
+ if (!handle) {
+ _D("receiver [%d] type is not initialized", type);
+ return;
+ }
+
+ if (!handle->fini)
+ handle->fini(handle);
+
+ g_hash_table_remove(receiver_module_hash, GUINT_TO_POINTER(type));
+
+ hash_size = g_hash_table_size(receiver_module_hash);
+ if (hash_size == 0) {
+ g_hash_table_unref(receiver_module_hash);
+ receiver_module_hash = NULL;
+ }
+
+ return;
+}
+
+int receiver_start(receiver_type_e type)
+{
+ receiver_module_h *handle = NULL;
+
+ if (!receiver_module_hash) {
+ _E("receiver is not initialized");
+ return -1;
+ }
+
+ handle = g_hash_table_lookup(receiver_module_hash,
+ GUINT_TO_POINTER(type));
+
+ if (!handle) {
+ _E("receiver [%d] type is not initialized", type);
+ return -1;
+ }
+
+ if (!handle->start) {
+ _D("receiver [%d] type is not implemented start func", type);
+ return -1;
+ }
+
+ return handle->start(handle);
+}
+
+int receiver_stop(receiver_type_e type)
+{
+ receiver_module_h *handle = NULL;
+
+ if (!receiver_module_hash) {
+ _E("receiver is not initialized");
+ return -1;
+ }
+
+ handle = g_hash_table_lookup(receiver_module_hash,
+ GUINT_TO_POINTER(type));
+
+ if (!handle) {
+ _E("receiver [%d] type is not initialized", type);
+ return -1;
+ }
+
+ if (!handle->stop) {
+ _D("receiver [%d] type is not implemented stop func", type);
+ return -1;
+ }
+
+ return handle->stop(handle);
+}
+
+receiver_state_e receiver_get_state(receiver_type_e type)
+{
+ receiver_module_h *handle = NULL;
+
+ if (!receiver_module_hash) {
+ _E("receiver is not initialized");
+ return RECEIVER_STATE_NONE;
+ }
+
+ handle = g_hash_table_lookup(receiver_module_hash,
+ GUINT_TO_POINTER(type));
+
+ if (!handle) {
+ _E("receiver [%d] type is not initialized", type);
+ return RECEIVER_STATE_NONE;
+ }
+
+ if (!handle->get_state) {
+ _D("receiver [%d] type is not implemented get_state func", type);
+ return RECEIVER_STATE_NONE;
+ }
+
+ return handle->get_state(handle);
+}
+
+int receiver_set_state_changed_cb(receiver_type_e type,
+ receiver_state_changed_cb callback, void *user_data)
+{
+ receiver_module_h *handle = NULL;
+
+ if (!receiver_module_hash) {
+ _E("receiver is not initialized");
+ return -1;
+ }
+
+ handle = g_hash_table_lookup(receiver_module_hash,
+ GUINT_TO_POINTER(type));
+
+ if (!handle) {
+ _E("receiver [%d] type is not initialized", type);
+ return -1;
+ }
+
+ handle->state_change_cb = callback;
+
+ if (callback)
+ handle->state_change_data = user_data;
+ else
+ handle->state_change_data = NULL;
+
+ return 0;
+}
+
+int receiver_set_module_data(receiver_module_h *handle, void *module_data)
+{
+ retv_if(!handle, -1);
+
+ handle->module_data = module_data;
+
+ return 0;
+}
+
+void *receiver_get_module_data(receiver_module_h *handle)
+{
+ retv_if(!handle, NULL);
+
+ return handle->module_data;
+}
+
+int receiver_set_module_init_function(
+ receiver_module_h *handle, receiver_init_func func)
+{
+ retv_if(!handle, -1);
+
+ handle->init = func;
+
+ return 0;
+}
+
+int receiver_set_module_fini_function(
+ receiver_module_h *handle, receiver_fini_func func)
+{
+ retv_if(!handle, -1);
+
+ handle->fini = func;
+
+ return 0;
+}
+
+int receiver_set_module_start_function(
+ receiver_module_h *handle, receiver_start_func func)
+{
+ retv_if(!handle, -1);
+
+ handle->start = func;
+
+ return 0;
+}
+
+int receiver_set_module_stop_function(
+ receiver_module_h *handle, receiver_stop_func func)
+{
+ retv_if(!handle, -1);
+
+ handle->stop = func;
+
+ return 0;
+}
+
+int receiver_set_module_get_state_function(
+ receiver_module_h *handle, receiver_get_state_func func)
+{
+ retv_if(!handle, -1);
+
+ handle->get_state = func;
+
+ return 0;
+}
+
+void receiver_module_state_changed(
+ receiver_module_h *handle, receiver_state_e state)
+{
+ ret_if(!handle);
+
+ if (handle->state_change_cb)
+ handle->state_change_cb(handle->receiver_type,
+ state, handle->state_change_data);
+
+ return;
+}
diff --git a/src/receiver_udp.c b/src/receiver_udp.c
new file mode 100644
index 0000000..07c2028
--- /dev/null
+++ b/src/receiver_udp.c
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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 <stdlib.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "log.h"
+#include "receiver_internal.h"
+#include "message.h"
+
+#define RECEIVER_UDP_PORT 57984
+#define RECEIVER_UDP_WAIT_TIMEOUT 3
+
+typedef enum __receiver_udp_state_e {
+ RECEIVER_UDP_STATE_NONE,
+ RECEIVER_UDP_STATE_INIT,
+ RECEIVER_UDP_STATE_READY,
+ RECEIVER_UDP_STATE_CONNECTED,
+} receiver_udp_state_e;
+
+typedef struct __receiver_udp_h {
+ guint io_watch_id;
+ guint wait_timer_id;
+ receiver_udp_state_e state;
+ GSocket *socket;
+} receiver_udp_h;
+
+// static receiver_udp_h *udp_handle = NULL;
+
+static gchar *__socket_address_to_string(GSocketAddress *address)
+{
+ GInetAddress *inet_address = NULL;
+ char *str, *res;
+ int port;
+
+ inet_address =
+ g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(address));
+
+ str = g_inet_address_to_string(inet_address);
+ port = g_inet_socket_address_get_port(G_INET_SOCKET_ADDRESS(address));
+
+ res = g_strdup_printf("%s:%d", str, port);
+ g_free(str);
+
+ return res;
+}
+
+static receiver_state_e ___state_convert(receiver_udp_state_e state)
+{
+ receiver_state_e r_state = RECEIVER_STATE_NONE;
+
+ switch (state) {
+ case RECEIVER_UDP_STATE_NONE:
+ r_state = RECEIVER_STATE_NONE;
+ break;
+ case RECEIVER_UDP_STATE_INIT:
+ r_state = RECEIVER_STATE_INIT;
+ break;
+ case RECEIVER_UDP_STATE_READY:
+ r_state = RECEIVER_STATE_READY;
+ break;
+ case RECEIVER_UDP_STATE_CONNECTED:
+ r_state = RECEIVER_STATE_CONNECTED;
+ break;
+ }
+ return r_state;
+}
+
+static void __receiver_udp_state_set(
+ receiver_module_h *handle, receiver_udp_state_e state)
+{
+ receiver_udp_h *udp_handle = NULL;
+
+ ret_if(!handle);
+
+ udp_handle = receiver_get_module_data(handle);
+ ret_if(!udp_handle);
+
+ udp_handle->state = state;
+
+ receiver_module_state_changed(handle, ___state_convert(state));
+
+ return;
+}
+
+/* Uses system call, because glib socket API doesn't support unset connect
+ * Please carefully use this function, and after use this function,
+ * DO NOT use g_socket_is_connected().
+ */
+static int __receiver_udp_unset_connection(receiver_module_h *handle)
+{
+ receiver_udp_h *udp_handle = NULL;
+ struct sockaddr addr;
+ int s_fd = 0;
+
+ retv_if(!handle, -1);
+
+ udp_handle = receiver_get_module_data(handle);
+
+ retvm_if(!udp_handle, -1, "handle is not created");
+ retvm_if(!udp_handle->socket, -1, "socket is not created");
+
+ s_fd = g_socket_get_fd(udp_handle->socket);
+ bzero((char *)&addr, sizeof(addr));
+ addr.sa_family = AF_UNSPEC;
+
+ if (connect(s_fd, &addr, sizeof(addr))) {
+ _E("failed to unset connect - %s\n", strerror(errno));
+ /* re-create socket or not ??? */
+ return -1;
+ }
+
+ __receiver_udp_state_set(handle, RECEIVER_UDP_STATE_READY);
+
+ return 0;
+}
+
+static int __receiver_udp_set_connection(
+ receiver_module_h *handle, GSocketAddress *sender_a)
+{
+ GError *error = NULL;
+ receiver_udp_h *udp_handle = NULL;
+
+ retv_if(!handle, -1);
+ retv_if(!sender_a, -1);
+
+ udp_handle = receiver_get_module_data(handle);
+
+ retvm_if(!udp_handle, -1, "handle is not created");
+ retvm_if(!udp_handle->socket, -1, "socket is not created");
+
+ if (udp_handle->state != RECEIVER_UDP_STATE_READY) {
+ _E("check state %d", udp_handle->state);
+ return -1;
+ }
+
+ /* use connect() to specify sender address and reject other sender */
+ if (!g_socket_connect(udp_handle->socket, sender_a, NULL, &error)) {
+ _E("failed to connect - %s", error->message);
+ g_error_free(error);
+ return -1;
+ }
+
+ __receiver_udp_state_set(handle, RECEIVER_UDP_STATE_CONNECTED);
+
+ return 0;
+}
+
+static gboolean __wait_time_out(gpointer user_data)
+{
+ receiver_module_h *handle = user_data;
+
+ retv_if(!handle, FALSE);
+
+ __receiver_udp_unset_connection(handle);
+
+ return FALSE;
+}
+
+static void __receiver_udp_update_wait_timer(receiver_module_h *handle)
+{
+ receiver_udp_h *udp_handle = NULL;
+
+ ret_if(!handle);
+
+ udp_handle = receiver_get_module_data(handle);
+
+ if (udp_handle) {
+ if (udp_handle->wait_timer_id) {
+ g_source_remove(udp_handle->wait_timer_id);
+ udp_handle->wait_timer_id = 0;
+ }
+ udp_handle->wait_timer_id =
+ g_timeout_add_seconds(RECEIVER_UDP_WAIT_TIMEOUT,
+ (GSourceFunc)__wait_time_out, handle);
+ }
+
+ return;
+}
+
+static gboolean __read_socket(GIOChannel *channel,
+ GIOCondition condition,
+ gpointer data)
+{
+ receiver_module_h *handle = data;
+ receiver_udp_h *udp_handle = NULL;
+ GError *error = NULL;
+ message_s *r_msg = NULL;
+ gssize size = 0;
+
+ retv_if(!handle, TRUE);
+
+ udp_handle = receiver_get_module_data(handle);
+
+ retv_if(!udp_handle, TRUE);
+ retv_if(!udp_handle->socket, TRUE);
+
+ if (udp_handle->state < RECEIVER_UDP_STATE_READY) {
+ _E("receiver udp is not ready yet");
+ return TRUE;
+ }
+
+ r_msg = malloc(sizeof(message_s));
+ retv_if(!r_msg, TRUE);
+
+ if (udp_handle->state == RECEIVER_UDP_STATE_READY) {
+ char *s_addr = NULL;
+ GSocketAddress *address = NULL;
+
+ size = g_socket_receive_from(udp_handle->socket, &address,
+ (gchar *)r_msg, sizeof(message_s), NULL, &error);
+
+ if (size < 0) {
+ _D("Error receiving from socket: %s", error->message);
+ g_error_free(error);
+ free(r_msg);
+ r_msg = NULL;
+ }
+
+ s_addr = __socket_address_to_string(address);
+ _D("received first data from [%s]", s_addr);
+
+ message_push_to_inqueue(r_msg);
+
+ if (!__receiver_udp_set_connection(handle, address))
+ __receiver_udp_update_wait_timer(handle);
+ else
+ _E("failed to set connection with [%s]", s_addr);
+
+ free(s_addr);
+ g_object_unref(address);
+ } else { /* state is RECEIVER_UDP_STATE_CONNECTED */
+ size = g_socket_receive(udp_handle->socket,
+ (gchar *)r_msg, sizeof(message_s), NULL, &error);
+
+ if (size < 0) {
+ _D("Error receiving from socket: %s", error->message);
+ g_error_free(error);
+ free(r_msg);
+ r_msg = NULL;
+ }
+ _D("received data");
+ message_push_to_inqueue(r_msg);
+
+ __receiver_udp_update_wait_timer(handle);
+ }
+
+ /* TODO : what should I do after receiveing some data? */
+
+ return TRUE;
+}
+
+static int _receiver_udp_start(void *data)
+{
+ receiver_module_h *handle = data;
+ receiver_udp_h *udp_handle = NULL;
+ int socket_fd = 0;
+ GIOChannel *ch = NULL;
+
+ retv_if(!handle, -1);
+
+ udp_handle = receiver_get_module_data(handle);
+
+ retv_if(!udp_handle, -1);
+ retv_if(!udp_handle->socket, -1);
+
+ if (udp_handle->state != RECEIVER_UDP_STATE_INIT) {
+ if (udp_handle->state == RECEIVER_UDP_STATE_READY) {
+ _E("receiver udp is already started");
+ return 0;
+ } else {
+ _E("receiver udp is invalid state [%d]", udp_handle->state);
+ return -1;
+ }
+ }
+
+ socket_fd = g_socket_get_fd(udp_handle->socket);
+ ch = g_io_channel_unix_new(socket_fd);
+ udp_handle->io_watch_id =
+ g_io_add_watch(ch, G_IO_IN, __read_socket, handle);
+ g_io_channel_unref(ch);
+ ch = NULL;
+
+ __receiver_udp_state_set(handle, RECEIVER_UDP_STATE_READY);
+
+ return 0;
+}
+
+static int _receiver_udp_stop(void *data)
+{
+ receiver_module_h *handle = data;
+ receiver_udp_h *udp_handle = NULL;
+
+ retv_if(!handle, -1);
+
+ udp_handle = receiver_get_module_data(handle);
+
+ retv_if(!udp_handle, -1);
+ retv_if(!udp_handle->socket, -1);
+
+ if (udp_handle->state < RECEIVER_UDP_STATE_READY) {
+ _E("receiver udp is invalid state [%d]", udp_handle->state);
+ return -1;
+ }
+
+ if (udp_handle->wait_timer_id) {
+ g_source_remove(udp_handle->wait_timer_id);
+ udp_handle->wait_timer_id = 0;
+ }
+
+ if (udp_handle->io_watch_id) {
+ g_source_remove(udp_handle->io_watch_id);
+ udp_handle->io_watch_id = 0;
+ }
+
+ __receiver_udp_state_set(handle, RECEIVER_UDP_STATE_INIT);
+
+ return 0;
+}
+
+static int _receiver_udp_init(void *data)
+{
+ receiver_module_h *handle = data;
+ receiver_udp_h *udp_handle = NULL;
+ GError *error = NULL;
+ GSocketAddress *address = NULL;
+ GInetAddress *i_addr = NULL;
+
+ retv_if(!handle, -1);
+
+ udp_handle = receiver_get_module_data(handle);
+ retv_if(!udp_handle, -1);
+
+ if (udp_handle->state != RECEIVER_UDP_STATE_NONE) {
+ _E("receiver udp is invalid state [%d]", udp_handle->state);
+ return -1;
+ }
+
+ udp_handle->socket = g_socket_new(G_SOCKET_FAMILY_IPV4,
+ G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &error);
+
+ if (udp_handle->socket == NULL) {
+ _E("failed to get new socket - %s", error->message);
+ goto ERROR;
+ }
+
+ /* set non-blocking mode */
+ g_socket_set_blocking(udp_handle->socket, FALSE);
+
+ i_addr = g_inet_address_new_any(G_SOCKET_FAMILY_IPV4);
+ if (!i_addr) {
+ _E("failed to get inet any address");
+ goto ERROR;
+ }
+ address = g_inet_socket_address_new(i_addr, RECEIVER_UDP_PORT);
+ g_object_unref(i_addr);
+ i_addr = NULL;
+
+ if (!address) {
+ _E("failed to get socket address");
+ goto ERROR;
+ }
+
+ if (!g_socket_bind(udp_handle->socket, address, TRUE, &error)) {
+ _E("Can't bind socket: %s\n", error->message);
+ goto ERROR;
+ }
+ g_object_unref(address);
+ address = NULL;
+
+ __receiver_udp_state_set(handle, RECEIVER_UDP_STATE_INIT);
+
+ return 0;
+
+ERROR:
+ if (error)
+ g_error_free(error);
+
+ if (address)
+ g_object_unref(address);
+
+ if (i_addr)
+ g_object_unref(i_addr);
+
+ return -1;
+}
+
+static int _receiver_udp_fini(void *data)
+{
+ receiver_module_h *handle = data;
+ receiver_udp_h *udp_handle = NULL;
+
+ retv_if(!handle, -1);
+
+ udp_handle = receiver_get_module_data(handle);
+ retv_if(!udp_handle, -1);
+
+ if (udp_handle) {
+ if (udp_handle->io_watch_id)
+ g_source_remove(udp_handle->io_watch_id);
+
+ if (udp_handle->wait_timer_id)
+ g_source_remove(udp_handle->wait_timer_id);
+
+ if (udp_handle->socket) {
+ g_socket_close(udp_handle->socket, NULL);
+ g_object_unref(udp_handle->socket);
+ }
+
+ __receiver_udp_state_set(handle, RECEIVER_UDP_STATE_NONE);
+
+ free(udp_handle);
+ udp_handle = NULL;
+ }
+
+ return 0;
+}
+
+static receiver_state_e _receiver_udp_get_state(void *data)
+{
+ receiver_module_h *handle = data;
+ receiver_udp_h *udp_handle = NULL;
+
+ retv_if(!handle, RECEIVER_STATE_NONE);
+
+ udp_handle = receiver_get_module_data(handle);
+ retv_if(!udp_handle, RECEIVER_STATE_NONE);
+
+ return ___state_convert(udp_handle->state);
+}
+
+/* Keep it here??? or move to new file??? */
+int receiver_udp_module_register(receiver_module_h *handle)
+{
+ receiver_udp_h *udp_handle = NULL;
+
+ retv_if(!handle, -1);
+
+ udp_handle = malloc(sizeof(receiver_udp_h));
+ if (!udp_handle) {
+ _E("failed to alloc receiver udp handle");
+ return -1;
+ }
+
+ udp_handle->state = RECEIVER_UDP_STATE_NONE;
+ udp_handle->io_watch_id = 0;
+ udp_handle->wait_timer_id = 0;
+ udp_handle->socket = NULL;
+
+ receiver_set_module_data(handle, udp_handle);
+ receiver_set_module_init_function(handle, _receiver_udp_init);
+ receiver_set_module_fini_function(handle, _receiver_udp_fini);
+ receiver_set_module_start_function(handle, _receiver_udp_start);
+ receiver_set_module_stop_function(handle, _receiver_udp_stop);
+ receiver_set_module_get_state_function(handle, _receiver_udp_get_state);
+
+ return 0;
+}
diff --git a/src/resource.c b/src/resource.c
new file mode 100644
index 0000000..a27b0fa
--- /dev/null
+++ b/src/resource.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jin Yoon <jinny.yoon@samsung.com>
+ * Geunsun Lee <gs86.lee@samsung.com>
+ * Eunyoung Lee <ey928.lee@samsung.com>
+ * Junkyu Han <junkyu.han@samsung.com>
+ *
+ * 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 <peripheral_io.h>
+
+#include "log.h"
+#include "resource_internal.h"
+#include "resource/resource_motor_driver_L298N_internal.h"
+#include "resource/resource_servo_motor_internal.h"
+
+static resource_s resource_info[PIN_MAX] = { {0, NULL, NULL}, };
+
+resource_s *resource_get_info(int pin_num)
+{
+ return &resource_info[pin_num];
+}
+
+void resource_close_all(void)
+{
+ int i = 0;
+ for (i = 0; i < PIN_MAX; i++) {
+ if (!resource_info[i].opened) continue;
+ _I("GPIO[%d] is closing...", i);
+
+ if (resource_info[i].close)
+ resource_info[i].close(i);
+ }
+ resource_close_motor_driver_L298N_all();
+ resource_close_servo_motor_all();
+}
diff --git a/src/resource/resource_PCA9685.c b/src/resource/resource_PCA9685.c
new file mode 100644
index 0000000..20a5545
--- /dev/null
+++ b/src/resource/resource_PCA9685.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jeonghoon Park <jh1979.park@samsung.com>
+ *
+ * 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 <stdio.h>
+#include <unistd.h>
+#include <math.h>
+#include <peripheral_io.h>
+#include "log.h"
+#include "resource/resource_PCA9685.h"
+
+#define RPI3_I2C_BUS 1
+
+/* Registers/etc: */
+#define PCA9685_ADDRESS 0x40
+#define MODE1 0x00
+#define MODE2 0x01
+#define SUBADR1 0x02
+#define SUBADR2 0x03
+#define SUBADR3 0x04
+#define PRESCALE 0xFE
+#define LED0_ON_L 0x06
+#define LED0_ON_H 0x07
+#define LED0_OFF_L 0x08
+#define LED0_OFF_H 0x09
+#define ALL_LED_ON_L 0xFA
+#define ALL_LED_ON_H 0xFB
+#define ALL_LED_OFF_L 0xFC
+#define ALL_LED_OFF_H 0xFD
+
+/* Bits: */
+#define RESTART 0x80
+#define SLEEP 0x10
+#define ALLCALL 0x01
+#define INVRT 0x10
+#define OUTDRV 0x04
+
+typedef enum {
+ PCA9685_CH_STATE_NONE,
+ PCA9685_CH_STATE_USED,
+} pca9685_ch_state_e;
+
+static peripheral_i2c_h g_i2c_h = NULL;
+static unsigned int ref_count = 0;
+static pca9685_ch_state_e ch_state[PCA9685_CH_MAX + 1] = {PCA9685_CH_STATE_NONE, };
+
+int resource_pca9685_set_frequency(unsigned int freq_hz)
+{
+ int ret = PERIPHERAL_ERROR_NONE;
+ double prescale_value = 0.0;
+ int prescale = 0;
+ uint8_t oldmode = 0;
+ uint8_t newmode = 0;
+
+ prescale_value = 25000000.0; // 25MHz
+ prescale_value /= 4096.0; // 12-bit
+ prescale_value /= (double)freq_hz;
+ prescale_value -= 1.0;
+
+ prescale = (int)floor(prescale_value + 0.5);
+
+ ret = peripheral_i2c_read_register_byte(g_i2c_h, MODE1, &oldmode);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to read register");
+
+ newmode = (oldmode & 0x7F) | 0x10; // sleep
+ ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, newmode); // go to sleep
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h, PRESCALE, prescale);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, oldmode);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ usleep(500);
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, (oldmode | 0x80));
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ return 0;
+}
+
+int resource_pca9685_set_value_to_channel(unsigned int channel, int on, int off)
+{
+ int ret = PERIPHERAL_ERROR_NONE;
+ retvm_if(g_i2c_h == NULL, -1, "Not initialized yet");
+
+ retvm_if(ch_state[channel] == PCA9685_CH_STATE_NONE, -1,
+ "ch[%u] is not in used state", channel);
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h,
+ LED0_ON_L + 4*channel, on & 0xFF);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h,
+ LED0_ON_H + 4*channel, on >> 8);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h,
+ LED0_OFF_L + 4*channel, off & 0xFF);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h,
+ LED0_OFF_H + 4*channel, off >> 8);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ return 0;
+}
+
+static int resource_pca9685_set_value_to_all(int on, int off)
+{
+ int ret = PERIPHERAL_ERROR_NONE;
+ retvm_if(g_i2c_h == NULL, -1, "Not initialized yet");
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h,
+ ALL_LED_ON_L, on & 0xFF);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h,
+ ALL_LED_ON_H, on >> 8);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h,
+ ALL_LED_OFF_L, off & 0xFF);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h,
+ ALL_LED_OFF_H, off >> 8);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ return 0;
+}
+
+int resource_pca9685_init(unsigned int ch)
+{
+ uint8_t mode1 = 0;
+ int ret = PERIPHERAL_ERROR_NONE;
+
+ if (ch > PCA9685_CH_MAX) {
+ _E("channel[%u] is out of range", ch);
+ return -1;
+ }
+
+ if (ch_state[ch] == PCA9685_CH_STATE_USED) {
+ _E("channel[%u] is already in used state", ch);
+ return -1;
+ }
+
+ if (g_i2c_h)
+ goto PASS_OPEN_HANDLE;
+
+ ret = peripheral_i2c_open(RPI3_I2C_BUS, PCA9685_ADDRESS, &g_i2c_h);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ _E("failed to open pca9685-[bus:%d, addr:%d]",
+ RPI3_I2C_BUS, PCA9685_ADDRESS);
+ return -1;
+ }
+ ret = resource_pca9685_set_value_to_all(0, 0);
+ if (ret) {
+ _E("failed to reset all value to register");
+ goto ERROR;
+ }
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE2, OUTDRV);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ _E("failed to write register");
+ goto ERROR;
+ }
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, ALLCALL);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ _E("failed to write register");
+ goto ERROR;
+ }
+
+ usleep(500); // wait for oscillator
+
+ ret = peripheral_i2c_read_register_byte(g_i2c_h, MODE1, &mode1);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ _E("failed to read register");
+ goto ERROR;
+ }
+
+ mode1 = mode1 & (~SLEEP); // # wake up (reset sleep)
+ ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, mode1);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ _E("failed to write register");
+ goto ERROR;
+ }
+
+ usleep(500); // wait for oscillator
+
+ ret = resource_pca9685_set_frequency(60);
+ if (ret) {
+ _E("failed to set frequency");
+ goto ERROR;
+ }
+
+PASS_OPEN_HANDLE:
+ ref_count++;
+ ch_state[ch] = PCA9685_CH_STATE_USED;
+ _D("pca9685 - ref_count[%u]", ref_count);
+ _D("sets ch[%u] used state", ch);
+
+ return 0;
+
+ERROR:
+ if (g_i2c_h)
+ peripheral_i2c_close(g_i2c_h);
+
+ g_i2c_h = NULL;
+ return -1;
+}
+
+int resource_pca9685_fini(unsigned int ch)
+{
+ if (ch_state[ch] == PCA9685_CH_STATE_NONE) {
+ _E("channel[%u] is not in used state", ch);
+ return -1;
+ }
+ resource_pca9685_set_value_to_channel(ch, 0, 0);
+ ch_state[ch] = PCA9685_CH_STATE_NONE;
+
+ ref_count--;
+ _D("ref count - %u", ref_count);
+
+ if (ref_count == 0 && g_i2c_h) {
+ _D("finalizing pca9685");
+ resource_pca9685_set_value_to_all(0, 0);
+ peripheral_i2c_close(g_i2c_h);
+ g_i2c_h = NULL;
+ }
+
+ return 0;
+}
diff --git a/src/resource/resource_infrared_obstacle_avoidance_sensor.c b/src/resource/resource_infrared_obstacle_avoidance_sensor.c
new file mode 100644
index 0000000..255d3cb
--- /dev/null
+++ b/src/resource/resource_infrared_obstacle_avoidance_sensor.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jin Yoon <jinny.yoon@samsung.com>
+ * Geunsun Lee <gs86.lee@samsung.com>
+ * Eunyoung Lee <ey928.lee@samsung.com>
+ * Junkyu Han <junkyu.han@samsung.com>
+ *
+ * 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 <stdlib.h>
+#include <peripheral_io.h>
+#include "log.h"
+#include "resource_internal.h"
+
+void resource_close_infrared_obstacle_avoidance_sensor(int pin_num)
+{
+ if (!resource_get_info(pin_num)->opened) return;
+
+ _I("Infrared Obstacle Avoidance Sensor is finishing...");
+ if (resource_get_info(pin_num)->resource_changed_info) {
+ free(resource_get_info(pin_num)->resource_changed_info);
+ resource_get_info(pin_num)->resource_changed_info = NULL;
+ }
+ peripheral_gpio_unset_interrupted_cb(resource_get_info(pin_num)->sensor_h);
+ peripheral_gpio_close(resource_get_info(pin_num)->sensor_h);
+ resource_get_info(pin_num)->sensor_h = NULL;
+ resource_get_info(pin_num)->opened = 0;
+
+ return;
+}
+
+static int _init_pin(int pin_num)
+{
+ int ret = PERIPHERAL_ERROR_NONE;
+
+ ret = peripheral_gpio_open(pin_num, &resource_get_info(pin_num)->sensor_h);
+ retv_if(ret != PERIPHERAL_ERROR_NONE, -1);
+
+ ret = peripheral_gpio_set_direction(resource_get_info(pin_num)->sensor_h, PERIPHERAL_GPIO_DIRECTION_IN);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ peripheral_gpio_close(resource_get_info(pin_num)->sensor_h);
+ resource_get_info(pin_num)->sensor_h = NULL;
+ return -1;
+ }
+
+ resource_get_info(pin_num)->opened = 1;
+ resource_get_info(pin_num)->close = resource_close_infrared_obstacle_avoidance_sensor;
+
+ return 0;
+}
+
+int resource_read_infrared_obstacle_avoidance_sensor(int pin_num, unsigned int *out_value)
+{
+ int ret = PERIPHERAL_ERROR_NONE;
+
+ if (!resource_get_info(pin_num)->opened) {
+ ret = _init_pin(pin_num);
+ retv_if(ret < 0, -1);
+ }
+
+ ret = peripheral_gpio_read(resource_get_info(pin_num)->sensor_h, out_value);
+ retv_if(ret != PERIPHERAL_ERROR_NONE, -1);
+
+ *out_value = !*out_value;
+
+ _I("Infrared Obstacle Avoidance Sensor Value : %d", *out_value);
+
+ return 0;
+}
+
+
+static void __ioa_sensor_interrupt_cb(peripheral_gpio_h gpio, peripheral_error_e error, void *user_data)
+{
+ uint32_t value;
+ resource_changed_s *resource_changed_info = (resource_changed_s *)user_data;
+
+ /* Detected : 0, Non-detected : 1 */
+ peripheral_gpio_read(gpio, &value);
+ _D("interrupt value = %d", !value);
+
+ resource_changed_info->cb(!value, resource_changed_info->data);
+
+ return;
+}
+
+int resource_set_infrared_obstacle_avoidance_sensor_interrupted_cb(int pin_num, resource_changed_cb cb, void *data)
+{
+ int ret = PERIPHERAL_ERROR_NONE;
+
+ if (resource_get_info(pin_num)->resource_changed_info == NULL) {
+ resource_get_info(pin_num)->resource_changed_info = calloc(1, sizeof(resource_changed_s));
+ retv_if(!resource_get_info(pin_num)->resource_changed_info, -1);
+ } else {
+ if (resource_get_info(pin_num)->sensor_h)
+ peripheral_gpio_unset_interrupted_cb(resource_get_info(resource_get_info(pin_num)->resource_changed_info->pin_num)->sensor_h);
+ }
+
+ resource_get_info(pin_num)->resource_changed_info->cb = cb;
+ resource_get_info(pin_num)->resource_changed_info->data = data;
+ resource_get_info(pin_num)->resource_changed_info->pin_num = pin_num;
+
+ if (!resource_get_info(pin_num)->opened) {
+ ret = _init_pin(pin_num);
+ goto_if(ret < 0, FREE_RESOURCE);
+ }
+
+ if (resource_get_info(pin_num)->sensor_h) {
+ ret = peripheral_gpio_set_edge_mode(resource_get_info(pin_num)->sensor_h, PERIPHERAL_GPIO_EDGE_BOTH);
+ goto_if(ret != PERIPHERAL_ERROR_NONE, FREE_RESOURCE);
+
+ ret = peripheral_gpio_set_interrupted_cb(resource_get_info(pin_num)->sensor_h, __ioa_sensor_interrupt_cb, resource_get_info(pin_num)->resource_changed_info);
+ goto_if(ret != PERIPHERAL_ERROR_NONE, FREE_RESOURCE);
+ }
+
+ return 0;
+
+FREE_RESOURCE:
+ if (resource_get_info(pin_num)->resource_changed_info) {
+ free(resource_get_info(pin_num)->resource_changed_info);
+ resource_get_info(pin_num)->resource_changed_info = NULL;
+ }
+
+ if (resource_get_info(pin_num)->sensor_h) {
+ peripheral_gpio_unset_interrupted_cb(resource_get_info(pin_num)->sensor_h);
+ peripheral_gpio_close(resource_get_info(pin_num)->sensor_h);
+ resource_get_info(pin_num)->sensor_h = NULL;
+ resource_get_info(pin_num)->opened = 0;
+ }
+
+ return -1;
+}
diff --git a/src/resource/resource_motor_driver_L298N.c b/src/resource/resource_motor_driver_L298N.c
new file mode 100644
index 0000000..291b74b
--- /dev/null
+++ b/src/resource/resource_motor_driver_L298N.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jeonghoon Park <jh1979.park@samsung.com>
+ *
+ * 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 <stdlib.h>
+#include <peripheral_io.h>
+#include "log.h"
+#include "resource/resource_PCA9685.h"
+#include "resource/resource_motor_driver_L298N.h"
+
+typedef enum {
+ MOTOR_STATE_NONE,
+ MOTOR_STATE_CONFIGURED,
+ MOTOR_STATE_STOP,
+ MOTOR_STATE_FORWARD,
+ MOTOR_STATE_BACKWARD,
+} motor_state_e;
+
+typedef struct __motor_driver_s {
+ unsigned int pin_1;
+ unsigned int pin_2;
+ unsigned int en_ch;
+ motor_state_e motor_state;
+ peripheral_gpio_h pin1_h;
+ peripheral_gpio_h pin2_h;
+} motor_driver_s;
+
+static motor_driver_s g_md_h[MOTOR_ID_MAX] = {
+ {0, 0, 0, MOTOR_STATE_NONE, NULL, NULL},
+};
+
+
+/* see Principle section in http://wiki.sunfounder.cc/index.php?title=Motor_Driver_Module-L298N */
+
+static int __motor_brake_n_stop_by_id(motor_id_e id)
+{
+ int ret = PERIPHERAL_ERROR_NONE;
+ int motor1_v = 0;
+ int motor2_v = 0;
+
+ if (g_md_h[id].motor_state <= MOTOR_STATE_CONFIGURED) {
+ _E("motor[%d] are not initialized - state(%d)",
+ id, g_md_h[id].motor_state);
+ return -1;
+ }
+
+ if (g_md_h[id].motor_state == MOTOR_STATE_STOP) {
+ _D("motor[%d] is already stopped", id);
+ return 0;
+ }
+
+ if (g_md_h[id].motor_state == MOTOR_STATE_FORWARD) {
+ motor1_v = 0;
+ motor2_v = 0;
+ } else if (g_md_h[id].motor_state == MOTOR_STATE_BACKWARD) {
+ motor1_v = 1;
+ motor2_v = 1;
+ }
+
+ /* Brake DC motor */
+ ret = peripheral_gpio_write(g_md_h[id].pin1_h, motor1_v);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ _E("Failed to set value[%d] Motor[%d] pin 1", motor1_v, id);
+ return -1;
+ }
+
+ ret = peripheral_gpio_write(g_md_h[id].pin2_h, motor2_v);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ _E("Failed to set value[%d] Motor[%d] pin 2", motor2_v, id);
+ return -1;
+ }
+
+ /* set stop DC motor */
+ // need to stop motor or not?, it may stop motor to free running
+ resource_pca9685_set_value_to_channel(g_md_h[id].en_ch, 0, 0);
+
+ g_md_h[id].motor_state = MOTOR_STATE_STOP;
+
+ return 0;
+}
+
+static int __set_default_configuration_by_id(motor_id_e id)
+{
+ unsigned int pin_1, pin_2, en_ch;
+
+ switch (id) {
+ case MOTOR_ID_1:
+ pin_1 = DEFAULT_MOTOR1_PIN1;
+ pin_2 = DEFAULT_MOTOR1_PIN2;
+ en_ch = DEFAULT_MOTOR1_EN_CH;
+ break;
+ case MOTOR_ID_2:
+ pin_1 = DEFAULT_MOTOR2_PIN1;
+ pin_2 = DEFAULT_MOTOR2_PIN2;
+ en_ch = DEFAULT_MOTOR2_EN_CH;
+ break;
+ case MOTOR_ID_3:
+ pin_1 = DEFAULT_MOTOR3_PIN1;
+ pin_2 = DEFAULT_MOTOR3_PIN2;
+ en_ch = DEFAULT_MOTOR3_EN_CH;
+ break;
+ case MOTOR_ID_4:
+ pin_1 = DEFAULT_MOTOR4_PIN1;
+ pin_2 = DEFAULT_MOTOR4_PIN2;
+ en_ch = DEFAULT_MOTOR4_EN_CH;
+ break;
+ case MOTOR_ID_MAX:
+ default:
+ _E("Unkwon ID[%d]", id);
+ return -1;
+ break;
+ }
+
+ g_md_h[id].pin_1 = pin_1;
+ g_md_h[id].pin_2 = pin_2;
+ g_md_h[id].en_ch = en_ch;
+ g_md_h[id].motor_state = MOTOR_STATE_CONFIGURED;
+
+ return 0;
+}
+
+static int __fini_motor_by_id(motor_id_e id)
+{
+ retv_if(id == MOTOR_ID_MAX, -1);
+
+ if (g_md_h[id].motor_state <= MOTOR_STATE_CONFIGURED)
+ return 0;
+
+ if (g_md_h[id].motor_state > MOTOR_STATE_STOP)
+ __motor_brake_n_stop_by_id(id);
+
+ resource_pca9685_fini(g_md_h[id].en_ch);
+
+ if (g_md_h[id].pin1_h) {
+ peripheral_gpio_close(g_md_h[id].pin1_h);
+ g_md_h[id].pin1_h = NULL;
+ }
+
+ if (g_md_h[id].pin2_h) {
+ peripheral_gpio_close(g_md_h[id].pin2_h);
+ g_md_h[id].pin2_h = NULL;
+ }
+
+ g_md_h[id].motor_state = MOTOR_STATE_CONFIGURED;
+
+ return 0;
+}
+
+static int __init_motor_by_id(motor_id_e id)
+{
+ int ret = 0;
+
+ retv_if(id == MOTOR_ID_MAX, -1);
+
+ if (g_md_h[id].motor_state == MOTOR_STATE_NONE)
+ __set_default_configuration_by_id(id);
+
+ ret = resource_pca9685_init(g_md_h[id].en_ch);
+ if (ret) {
+ _E("failed to init PCA9685");
+ return -1;
+ }
+
+ /* open pins for Motor */
+ ret = peripheral_gpio_open(g_md_h[id].pin_1, &g_md_h[id].pin1_h);
+ if (ret == PERIPHERAL_ERROR_NONE)
+ peripheral_gpio_set_direction(g_md_h[id].pin1_h,
+ PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW);
+ else {
+ _E("failed to open Motor[%d] gpio pin1[%u]", id, g_md_h[id].pin_1);
+ goto ERROR;
+ }
+
+ ret = peripheral_gpio_open(g_md_h[id].pin_2, &g_md_h[id].pin2_h);
+ if (ret == PERIPHERAL_ERROR_NONE)
+ peripheral_gpio_set_direction(g_md_h[id].pin2_h,
+ PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW);
+ else {
+ _E("failed to open Motor[%d] gpio pin2[%u]", id, g_md_h[id].pin_2);
+ goto ERROR;
+ }
+
+ g_md_h[id].motor_state = MOTOR_STATE_STOP;
+
+ return 0;
+
+ERROR:
+ resource_pca9685_fini(g_md_h[id].en_ch);
+
+ if (g_md_h[id].pin1_h) {
+ peripheral_gpio_close(g_md_h[id].pin1_h);
+ g_md_h[id].pin1_h = NULL;
+ }
+
+ if (g_md_h[id].pin2_h) {
+ peripheral_gpio_close(g_md_h[id].pin2_h);
+ g_md_h[id].pin2_h = NULL;
+ }
+
+ return -1;
+}
+
+void resource_close_motor_driver_L298N(motor_id_e id)
+{
+ __fini_motor_by_id(id);
+ return;
+}
+
+void resource_close_motor_driver_L298N_all(void)
+{
+ int i;
+ for (i = MOTOR_ID_1; i < MOTOR_ID_MAX; i++)
+ __fini_motor_by_id(i);
+
+ return;
+}
+
+int resource_set_motor_driver_L298N_configuration(motor_id_e id,
+ unsigned int pin1, unsigned int pin2, unsigned en_ch)
+{
+
+ if (g_md_h[id].motor_state > MOTOR_STATE_CONFIGURED) {
+ _E("cannot set configuration motor[%d] in this state[%d]",
+ id, g_md_h[id].motor_state);
+ return -1;
+ }
+
+ g_md_h[id].pin_1 = pin1;
+ g_md_h[id].pin_2 = pin2;
+ g_md_h[id].en_ch = en_ch;
+ g_md_h[id].motor_state = MOTOR_STATE_CONFIGURED;
+
+ return 0;
+}
+
+int resource_set_motor_driver_L298N_speed(motor_id_e id, int speed)
+{
+ int ret = 0;
+ const int value_max = 4095;
+ int value = 0;
+ int e_state = MOTOR_STATE_NONE;
+ int motor_v_1 = 0;
+ int motor_v_2 = 0;
+
+ if (g_md_h[id].motor_state <= MOTOR_STATE_CONFIGURED) {
+ ret = __init_motor_by_id(id);
+ if (ret) {
+ _E("failed to __init_motor_by_id()");
+ return -1;
+ }
+ }
+
+ value = abs(speed);
+
+ if (value > value_max) {
+ value = value_max;
+ _D("max speed is %d", value_max);
+ }
+ _D("set speed %d", value);
+
+ if (speed == 0) {
+ /* brake and stop */
+ ret = __motor_brake_n_stop_by_id(id);
+ if (ret) {
+ _E("failed to stop motor[%d]", id);
+ return -1;
+ }
+ return 0; /* done */
+ }
+
+ if (speed > 0)
+ e_state = MOTOR_STATE_FORWARD; /* will be set forward */
+ else
+ e_state = MOTOR_STATE_BACKWARD; /* will be set backward */
+
+ if (g_md_h[id].motor_state == e_state)
+ goto SET_SPEED;
+ else {
+ /* brake and stop */
+ ret = __motor_brake_n_stop_by_id(id);
+ if (ret) {
+ _E("failed to stop motor[%d]", id);
+ return -1;
+ }
+ }
+
+ switch (e_state) {
+ case MOTOR_STATE_FORWARD:
+ motor_v_1 = 1;
+ motor_v_2 = 0;
+ break;
+ case MOTOR_STATE_BACKWARD:
+ motor_v_1 = 0;
+ motor_v_2 = 1;
+ break;
+ }
+ ret = peripheral_gpio_write(g_md_h[id].pin1_h, motor_v_1);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ _E("failed to set value[%d] Motor[%d] pin 1", motor_v_1, id);
+ return -1;
+ }
+
+ ret = peripheral_gpio_write(g_md_h[id].pin2_h, motor_v_2);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ _E("failed to set value[%d] Motor[%d] pin 2", motor_v_2, id);
+ return -1;
+ }
+
+SET_SPEED:
+ ret = resource_pca9685_set_value_to_channel(g_md_h[id].en_ch, 0, value);
+ if (ret) {
+ _E("failed to set speed - %d", speed);
+ return -1;
+ }
+
+ g_md_h[id].motor_state = e_state;
+
+ return 0;
+}
diff --git a/src/resource/resource_servo_motor.c b/src/resource/resource_servo_motor.c
new file mode 100644
index 0000000..e16df2e
--- /dev/null
+++ b/src/resource/resource_servo_motor.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jeonghoon Park <jh1979.park@samsung.com>
+ *
+ * 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 "log.h"
+#include "resource/resource_PCA9685.h"
+
+#define SERVO_MOTOR_MAX PCA9685_CH_MAX
+
+static int servo_motor_index[SERVO_MOTOR_MAX + 1] = {0, };
+
+static int resource_servo_motor_init(unsigned int ch)
+{
+ int ret = 0;
+ ret = resource_pca9685_init(ch);
+ if (ret) {
+ _E("failed to init PCA9685 with ch[%u]", ch);
+ return -1;
+ }
+ servo_motor_index[ch] = 1;
+
+ return 0;
+}
+
+void resource_close_servo_motor(unsigned int ch)
+{
+ if (servo_motor_index[ch] == 1) {
+ resource_pca9685_fini(ch);
+ servo_motor_index[ch] = 0;
+ }
+
+ return;
+}
+
+void resource_close_servo_motor_all(void)
+{
+ unsigned int i;
+
+ for (i = 0 ; i <= SERVO_MOTOR_MAX; i++)
+ resource_close_servo_motor(i);
+
+ return;
+}
+
+int resource_set_servo_motor_value(unsigned int motor_id, int value)
+{
+ int ret = 0;
+
+ if (motor_id > SERVO_MOTOR_MAX)
+ return -1;
+
+ if (servo_motor_index[motor_id] == 0) {
+ ret = resource_servo_motor_init(motor_id);
+ if (ret)
+ return -1;
+ }
+
+ ret = resource_pca9685_set_value_to_channel(motor_id, 0, value);
+
+ return ret;
+}
diff --git a/tizen-manifest.xml.in b/tizen-manifest.xml.in
new file mode 100644
index 0000000..c5a61d5
--- /dev/null
+++ b/tizen-manifest.xml.in
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="4.0" package="@ORG_PREFIX@.@PROJECT_NAME@" version="1.0.0">
+ <profile name="mobile"/>
+ <service-application appid="@ORG_PREFIX@.@PROJECT_NAME@" auto-restart="false" exec="@PROJECT_NAME@" multiple="false" nodisplay="true" on-boot="true" taskmanage="false" type="capp">
+ <label>@APP_LABEL@</label>
+ <icon>@PROJECT_NAME@.png</icon>
+ </service-application>
+ <privileges>
+ <privilege>http://tizen.org/privilege/network.get</privilege>
+ <privilege>http://tizen.org/privilege/internet</privilege>
+ <privilege>http://tizen.org/privilege/peripheralio</privilege>
+ </privileges>
+</manifest>