Merge remote-tracking branch 'privategit/master'
authorjunkyu han <junkyu.han@samsung.com>
Mon, 26 Mar 2018 00:43:19 +0000 (09:43 +0900)
committerjunkyu han <junkyu.han@samsung.com>
Mon, 26 Mar 2018 00:43:19 +0000 (09:43 +0900)
35 files changed:
.gitignore [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
README.md [new file with mode: 0644]
inc/connection_manager.h [new file with mode: 0644]
inc/log.h [new file with mode: 0644]
inc/message.h [new file with mode: 0644]
inc/receiver.h [new file with mode: 0644]
inc/receiver_internal.h [new file with mode: 0644]
inc/receiver_type.h [new file with mode: 0644]
inc/receiver_udp.h [new file with mode: 0644]
inc/resource.h [new file with mode: 0644]
inc/resource/resource_PCA9685.h [new file with mode: 0644]
inc/resource/resource_infrared_obstacle_avoidance_sensor.h [new file with mode: 0644]
inc/resource/resource_infrared_obstacle_avoidance_sensor_internal.h [new file with mode: 0644]
inc/resource/resource_motor_driver_L298N.h [new file with mode: 0644]
inc/resource/resource_motor_driver_L298N_internal.h [new file with mode: 0644]
inc/resource/resource_servo_motor.h [new file with mode: 0644]
inc/resource/resource_servo_motor_internal.h [new file with mode: 0644]
inc/resource_internal.h [new file with mode: 0644]
inc/resource_type.h [new file with mode: 0644]
org.tizen.car-app.manifest [new file with mode: 0644]
packaging/car-app.spec [new file with mode: 0644]
shared/res/default_icon.png [new file with mode: 0644]
src/app.c [new file with mode: 0644]
src/connection_manager.c [new file with mode: 0644]
src/log.c [new file with mode: 0644]
src/message.c [new file with mode: 0644]
src/receiver.c [new file with mode: 0644]
src/receiver_udp.c [new file with mode: 0644]
src/resource.c [new file with mode: 0644]
src/resource/resource_PCA9685.c [new file with mode: 0644]
src/resource/resource_infrared_obstacle_avoidance_sensor.c [new file with mode: 0644]
src/resource/resource_motor_driver_L298N.c [new file with mode: 0644]
src/resource/resource_servo_motor.c [new file with mode: 0644]
tizen-manifest.xml.in [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..c6127b3
--- /dev/null
@@ -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 (file)
index 0000000..95c94d6
--- /dev/null
@@ -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 (file)
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 (file)
index 0000000..14a054f
--- /dev/null
@@ -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 (file)
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 (file)
index 0000000..c29f600
--- /dev/null
@@ -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 (file)
index 0000000..e194460
--- /dev/null
@@ -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 (file)
index 0000000..30fb318
--- /dev/null
@@ -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 (file)
index 0000000..81e99d6
--- /dev/null
@@ -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 (file)
index 0000000..ad0a100
--- /dev/null
@@ -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 (file)
index 0000000..5aacc4a
--- /dev/null
@@ -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 (file)
index 0000000..aa45477
--- /dev/null
@@ -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 (file)
index 0000000..20d088e
--- /dev/null
@@ -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 (file)
index 0000000..f52cdf1
--- /dev/null
@@ -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 (file)
index 0000000..1cf7bae
--- /dev/null
@@ -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 (file)
index 0000000..2fb63f7
--- /dev/null
@@ -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 (file)
index 0000000..924d6cc
--- /dev/null
@@ -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 (file)
index 0000000..e038390
--- /dev/null
@@ -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 (file)
index 0000000..fb18904
--- /dev/null
@@ -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 (file)
index 0000000..6853164
--- /dev/null
@@ -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 (file)
index 0000000..af9b883
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>\r
+       <request>\r
+               <domain name="_" />\r
+       </request>\r
+</manifest>\r
diff --git a/packaging/car-app.spec b/packaging/car-app.spec
new file mode 100644 (file)
index 0000000..b957a3e
--- /dev/null
@@ -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 (file)
index 0000000..9765b1b
Binary files /dev/null and b/shared/res/default_icon.png differ
diff --git a/src/app.c b/src/app.c
new file mode 100644 (file)
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 (file)
index 0000000..2ed6d1b
--- /dev/null
@@ -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 (file)
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 (file)
index 0000000..2069f57
--- /dev/null
@@ -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 (file)
index 0000000..4841afd
--- /dev/null
@@ -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 (file)
index 0000000..07c2028
--- /dev/null
@@ -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 (file)
index 0000000..a27b0fa
--- /dev/null
@@ -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 (file)
index 0000000..20a5545
--- /dev/null
@@ -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 (file)
index 0000000..255d3cb
--- /dev/null
@@ -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 (file)
index 0000000..291b74b
--- /dev/null
@@ -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 (file)
index 0000000..e16df2e
--- /dev/null
@@ -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 (file)
index 0000000..c5a61d5
--- /dev/null
@@ -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>