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