initial version
authorJeonghoon Park <jh1979.park@samsung.com>
Wed, 6 Dec 2017 12:34:31 +0000 (21:34 +0900)
committerJeonghoon Park <jh1979.park@samsung.com>
Wed, 6 Dec 2017 12:34:31 +0000 (21:34 +0900)
12 files changed:
CMakeLists.txt [new file with mode: 0644]
inc/dc_motor.h [new file with mode: 0644]
inc/log.h [new file with mode: 0644]
inc/pca9685.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/dc_motor.c [new file with mode: 0644]
src/log.c [new file with mode: 0644]
src/pca9685.c [new file with mode: 0644]
tizen-manifest.xml.in [new file with mode: 0644]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bc5c2d9
--- /dev/null
@@ -0,0 +1,45 @@
+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
diff --git a/inc/dc_motor.h b/inc/dc_motor.h
new file mode 100644 (file)
index 0000000..e89da69
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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__ */
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/pca9685.h b/inc/pca9685.h
new file mode 100644 (file)
index 0000000..08b041c
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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__ */
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..f23998d
--- /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)
+
+%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
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..e548ca3
--- /dev/null
+++ b/src/app.c
@@ -0,0 +1,153 @@
+/*
+ * 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;
+}
+
diff --git a/src/dc_motor.c b/src/dc_motor.c
new file mode 100644 (file)
index 0000000..8810f01
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * 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
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/pca9685.c b/src/pca9685.c
new file mode 100644 (file)
index 0000000..7fa645c
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * 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;
+}
diff --git a/tizen-manifest.xml.in b/tizen-manifest.xml.in
new file mode 100644 (file)
index 0000000..1acd226
--- /dev/null
@@ -0,0 +1,13 @@
+<?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>