From: Jeonghoon Park Date: Wed, 6 Dec 2017 12:34:31 +0000 (+0900) Subject: initial version X-Git-Url: http://review.tizen.org/git/?p=apps%2Fnative%2Fgear-racing-car.git;a=commitdiff_plain;h=c3a51261d55562d0b0f6075bce0a2c94d78a8033 initial version --- diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..bc5c2d9 --- /dev/null +++ b/CMakeLists.txt @@ -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 index 0000000..e89da69 --- /dev/null +++ b/inc/dc_motor.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Contact: Jeonghoon Park + * + * 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 index 0000000..ba19887 --- /dev/null +++ b/inc/log.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Contact: Jeonghoon Park + * + * 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 + +#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 index 0000000..08b041c --- /dev/null +++ b/inc/pca9685.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Contact: Jeonghoon Park + * + * 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 index 0000000..af9b883 --- /dev/null +++ b/org.tizen.car-app.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/car-app.spec b/packaging/car-app.spec new file mode 100644 index 0000000..f23998d --- /dev/null +++ b/packaging/car-app.spec @@ -0,0 +1,82 @@ +%define P_NAME car-app +%define ORG_PREFIX org.tizen +%define APP_LABEL "Car App" + +Name: %{ORG_PREFIX}.%{P_NAME} +%define alias %{name} +Summary: Car Application +Version: 0.0.1 +Release: 1 +License: Flora-1.1 +Provides: %{name} = %{version}-%{release} +Source0: %{name}-%{version}.tar.gz + +BuildRequires: cmake +BuildRequires: hash-signer +BuildRequires: pkgconfig(capi-appfw-application) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(libtzplatform-config) +BuildRequires: pkgconfig(capi-appfw-service-application) +BuildRequires: pkgconfig(capi-system-peripheral-io) +BuildRequires: pkgconfig(gio-2.0) +BuildRequires: pkgconfig(glib-2.0) + +%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 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 index 0000000..e548ca3 --- /dev/null +++ b/src/app.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Contact: Jeonghoon Park + * + * Licensed under the Flora License, Version 1.1 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "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 index 0000000..8810f01 --- /dev/null +++ b/src/dc_motor.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Contact: Jeonghoon Park + * + * Licensed under the Flora License, Version 1.1 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "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 index 0000000..b25e8a7 --- /dev/null +++ b/src/log.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 0000000..7fa645c --- /dev/null +++ b/src/pca9685.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Contact: Jeonghoon Park + * + * Licensed under the Flora License, Version 1.1 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "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 index 0000000..1acd226 --- /dev/null +++ b/tizen-manifest.xml.in @@ -0,0 +1,13 @@ + + + + + + @PROJECT_NAME@.png + + + http://tizen.org/privilege/network.get + http://tizen.org/privilege/internet + http://tizen.org/privilege/peripheralio + +