--- /dev/null
+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
+)
+
+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/dc_motor.c
+ ${PROJECT_ROOT_DIR}/src/pca9685.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
--- /dev/null
+/*
+ * 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_DC_MOTOR_H__
+#define __CAR_APP_DC_MOTOR_H__
+
+typedef enum {
+ DC_MOTOR_ID_L,
+ DC_MOTOR_ID_R,
+} dc_motor_id_e;
+
+int dc_motor_init(void);
+int dc_motor_fini(void);
+int dc_motor_speed_set(dc_motor_id_e id, int speed);
+
+#endif /* __CAR_APP_DC_MOTOR_H__ */
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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_PCA9685_H__
+#define __CAR_APP_PCA9685_H__
+
+int pca9685_init(void);
+int pca9685_fini(void);
+int pca9685_set_frequency(unsigned int freq_hz);
+int pca9685_set_value_to_channel(unsigned int channel, int on, int off);
+int pca9685_set_value_to_all(int on, int off);
+
+#endif /* __CAR_APP_PCA9685_H__ */
--- /dev/null
+<manifest>\r
+ <request>\r
+ <domain name="_" />\r
+ </request>\r
+</manifest>\r
--- /dev/null
+%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)
+
+%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} \
+ -DINSTALL_RESDIR=%{_pkg_res_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
--- /dev/null
+/*
+ * 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 <glib.h>
+#include <service_app.h>
+#include "log.h"
+#include "dc_motor.h"
+
+typedef struct app_data_s {
+ guint timer_id;
+} app_data;
+
+static void service_app_control(app_control_h app_control, void *data)
+{
+ return;
+}
+
+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)
+{
+ return;
+}
+
+static void service_app_low_memory(app_event_info_h event_info, void *user_data)
+{
+ return;
+}
+
+static inline int __get_r_val(int val)
+{
+ if (val > 0)
+ return 0 - val;
+ else
+ return ABS(val);
+}
+
+static gboolean __control_dcmotor_cb(gpointer user_data)
+{
+ static int value = -2000;
+ int value2 = 0;
+
+ value = __get_r_val(value);
+
+ dc_motor_speed_set(DC_MOTOR_ID_L, 0);
+ dc_motor_speed_set(DC_MOTOR_ID_R, 0);
+
+ sleep(1);
+
+ dc_motor_speed_set(DC_MOTOR_ID_L, value);
+ dc_motor_speed_set(DC_MOTOR_ID_R, value);
+
+ sleep(5);
+ if (value > 0)
+ value2 = value + 1000;
+ else
+ value2 = value - 1000;
+
+ dc_motor_speed_set(DC_MOTOR_ID_L, value2);
+ dc_motor_speed_set(DC_MOTOR_ID_R, value2);
+
+ return G_SOURCE_CONTINUE;
+}
+
+static bool service_app_create(void *data)
+{
+ app_data *ad = data;
+ int ret = 0;
+ ret = dc_motor_init();
+ if (ret) {
+ _E("failed init motor, terminating this application");
+ service_app_exit();
+ }
+
+ ad->timer_id = g_timeout_add_seconds(10, __control_dcmotor_cb, ad);
+
+ return true;
+}
+
+static void service_app_terminate(void *data)
+{
+ app_data *ad = data;
+
+ if (ad->timer_id) {
+ g_source_remove(ad->timer_id);
+ ad->timer_id = 0;
+ }
+
+ dc_motor_fini();
+ 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;
+}
+
--- /dev/null
+/*
+ * 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 "pca9685.h"
+#include "dc_motor.h"
+
+/* connected GPIO pin numbers of raspberry pi 3 with IN pins of L298N */
+#define MotorA_1 19
+#define MotorA_2 16
+#define MotorB_1 26
+#define MotorB_2 20
+
+/* connected channel numbers of PCA9685 with enable pins of L298N */
+#define EnableA_CH 5
+#define EnableB_CH 4
+
+typedef enum {
+ MOTOR_STATE_NONE,
+ MOTOR_STATE_STOP,
+ MOTOR_STATE_FORWARD,
+ MOTOR_STATE_BACKWARD,
+} motor_state_e;
+
+peripheral_gpio_h motorA_1_h = NULL;
+peripheral_gpio_h motorA_2_h = NULL;
+peripheral_gpio_h motorB_1_h = NULL;
+peripheral_gpio_h motorB_2_h = NULL;
+
+static int MotorState[2] = {MOTOR_STATE_NONE, };
+
+/* see Principle section in http://wiki.sunfounder.cc/index.php?title=Motor_Driver_Module-L298N */
+
+static int dc_motor_stop(dc_motor_id_e id)
+{
+ int ret = PERIPHERAL_ERROR_NONE;
+ int motor1_v = 0;
+ int motor2_v = 0;
+ peripheral_gpio_h motor_1_h = NULL;
+ peripheral_gpio_h motor_2_h = NULL;
+ int channel = 0;
+
+ if (MotorState[id] == MOTOR_STATE_NONE) {
+ _E("motor[%d] are not initialized - state(%d)", id, MotorState[id]);
+ return -1;
+ }
+
+ if (MotorState[id] == MOTOR_STATE_STOP) {
+ _D("motor[%d] is already stopped", id);
+ return 0;
+ }
+
+ switch (id) {
+ case DC_MOTOR_ID_L:
+ channel = EnableA_CH;
+ motor_1_h = motorA_1_h;
+ motor_2_h = motorA_2_h;
+ break;
+ case DC_MOTOR_ID_R:
+ channel = EnableB_CH;
+ motor_1_h = motorB_1_h;
+ motor_2_h = motorB_2_h;
+ break;
+ }
+
+ switch (MotorState[id]) {
+ case MOTOR_STATE_FORWARD:
+ motor1_v = 0;
+ motor2_v = 0;
+ break;
+ case MOTOR_STATE_BACKWARD:
+ motor1_v = 1;
+ motor2_v = 1;
+ break;
+ }
+
+ /* Brake DC motor */
+ ret = peripheral_gpio_write(motor_1_h, motor1_v);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ _E("Failed to set value[%d] Motor_1[%d]", motor1_v, id);
+ return -1;
+ }
+
+ ret = peripheral_gpio_write(motor_2_h, motor2_v);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ _E("Failed to set value[%d] Motor_1[%d]", motor2_v, id);
+ return -1;
+ }
+
+ /* set stop DC motor */
+ pca9685_set_value_to_channel(channel, 0, 0);
+
+ MotorState[id] = MOTOR_STATE_STOP;
+
+ return 0;
+}
+
+static void pins_fini(void)
+{
+ MotorState[DC_MOTOR_ID_L] = MOTOR_STATE_NONE;
+ MotorState[DC_MOTOR_ID_R] = MOTOR_STATE_NONE;
+
+ pca9685_fini();
+
+ if (motorA_1_h) {
+ peripheral_gpio_close(motorA_1_h);
+ motorA_1_h = NULL;
+ }
+
+ if (motorA_2_h) {
+ peripheral_gpio_close(motorA_2_h);
+ motorA_2_h = NULL;
+ }
+
+
+ if (motorB_1_h) {
+ peripheral_gpio_close(motorB_1_h);
+ motorB_1_h = NULL;
+ }
+
+ if (motorB_2_h) {
+ peripheral_gpio_close(motorB_2_h);
+ motorB_2_h = NULL;
+ }
+
+ return;
+}
+
+static int pins_init(void)
+{
+ int ret = 0;
+
+ if ((MotorState[DC_MOTOR_ID_L] > MOTOR_STATE_NONE) ||
+ (MotorState[DC_MOTOR_ID_R] > MOTOR_STATE_NONE)) {
+ _E("current state = %d, %d",
+ MotorState[DC_MOTOR_ID_L], MotorState[DC_MOTOR_ID_R]);
+ return -1;
+ }
+
+ ret = pca9685_init();
+ if (ret) {
+ _E("failed to init PCA9685");
+ return -1;
+ }
+
+ ret = pca9685_set_frequency(60);
+ if (ret) {
+ _E("failed to set frequency to PCA9685");
+ goto ERROR;
+ }
+
+ /* open pins for Motor A */
+ ret = peripheral_gpio_open(MotorA_1, &motorA_1_h);
+ if (ret == PERIPHERAL_ERROR_NONE)
+ peripheral_gpio_set_direction(motorA_1_h,
+ PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW);
+ else {
+ _E("failed to open MotorA_1 gpio pin(%d)", MotorA_1);
+ goto ERROR;
+ }
+
+ ret = peripheral_gpio_open(MotorA_2, &motorA_2_h);
+ if (ret == PERIPHERAL_ERROR_NONE)
+ peripheral_gpio_set_direction(motorA_2_h,
+ PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW);
+ else {
+ _E("failed to open MotorA_2 gpio pin(%d)", MotorA_2);
+ goto ERROR;
+ }
+
+ MotorState[DC_MOTOR_ID_L] = MOTOR_STATE_STOP;
+
+ /* open pins for Motor B */
+ ret = peripheral_gpio_open(MotorB_1, &motorB_1_h);
+ if (ret == PERIPHERAL_ERROR_NONE)
+ peripheral_gpio_set_direction(motorB_1_h,
+ PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW);
+ else {
+ _E("failed to open MotorB_1 gpio pin(%d)", MotorB_1);
+ goto ERROR;
+ }
+
+ ret = peripheral_gpio_open(MotorB_2, &motorB_2_h);
+ if (ret == PERIPHERAL_ERROR_NONE)
+ peripheral_gpio_set_direction(motorB_2_h,
+ PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW);
+ else {
+ _E("failed to open MotorB_2 gpio pin(%d)", MotorB_2);
+ goto ERROR;
+ }
+
+ MotorState[DC_MOTOR_ID_R] = MOTOR_STATE_STOP;
+
+ return 0;
+
+ERROR:
+ pca9685_fini();
+ pins_fini();
+ return -1;
+}
+
+int dc_motor_init(void)
+{
+ int ret = 0;
+
+ ret = pins_init();
+
+ return ret;
+}
+
+int dc_motor_fini(void)
+{
+ int ret = 0;
+
+ pins_fini();
+
+ return ret;
+}
+
+int dc_motor_speed_set(dc_motor_id_e id, int speed)
+{
+ int ret = 0;
+ const int value_max = 4095;
+ int value = 0;
+ int channel = 0;
+ peripheral_gpio_h motor_1_h = NULL;
+ peripheral_gpio_h motor_2_h = NULL;
+ int motor_v_1 = 0;
+ int motor_v_2 = 0;
+ int e_state = MOTOR_STATE_NONE;
+
+ 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 = dc_motor_stop(id);
+ if (ret) {
+ _E("failed to stop motor[%d]", id);
+ return -1;
+ }
+ return 0; /* done */
+ }
+
+ switch (id) {
+ case DC_MOTOR_ID_L:
+ channel = EnableA_CH;
+ motor_1_h = motorA_1_h;
+ motor_2_h = motorA_2_h;
+ break;
+ case DC_MOTOR_ID_R:
+ channel = EnableB_CH;
+ motor_1_h = motorB_1_h;
+ motor_2_h = motorB_2_h;
+ break;
+ }
+
+ if (speed > 0)
+ e_state = MOTOR_STATE_FORWARD; /* will be set forward */
+ else
+ e_state = MOTOR_STATE_BACKWARD; /* will be set backward */
+
+ if (MotorState[id] == e_state)
+ goto SET_SPEED;
+ else {
+ /* brake and stop */
+ ret = dc_motor_stop(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(motor_1_h, motor_v_1);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ _E("failed to set value[%d] Motor_1[%d]", motor_v_1, id);
+ return -1;
+ }
+
+ ret = peripheral_gpio_write(motor_2_h, motor_v_2);
+ if (ret != PERIPHERAL_ERROR_NONE) {
+ _E("failed to set value[%d] Motor_2[%d]", motor_v_2, id);
+ return -1;
+ }
+
+SET_SPEED:
+ ret = pca9685_set_value_to_channel(channel, 0, value);
+ if (ret) {
+ _E("failed to set speed - %d", speed);
+ return -1;
+ }
+
+ MotorState[id] = e_state;
+
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+#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;
+}
--- /dev/null
+/*
+ * 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"
+
+#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
+
+static peripheral_i2c_h g_i2c_h = NULL;
+
+int 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 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");
+
+ 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;
+}
+
+int 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 pca9685_init(void)
+{
+ uint8_t mode1 = 0;
+
+ int ret = PERIPHERAL_ERROR_NONE;
+ 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 = pca9685_set_value_to_all(0, 0);
+ retvm_if(ret, -1, "failed to set value to register");
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE2, OUTDRV);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, ALLCALL);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ usleep(500); // wait for oscillator
+
+ ret = peripheral_i2c_read_register_byte(g_i2c_h, MODE1, &mode1);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to read register");
+
+ mode1 = mode1 & (~SLEEP); // # wake up (reset sleep)
+ ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, mode1);
+ retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+ usleep(500); // wait for oscillator
+
+ return 0;
+}
+
+int pca9685_fini(void)
+{
+ if (g_i2c_h) {
+ peripheral_i2c_close(g_i2c_h);
+ g_i2c_h = NULL;
+ }
+
+ return 0;
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="3.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>