From 69fbcb9d131c90918d4dd9995350409b45327a9f Mon Sep 17 00:00:00 2001 From: Jeonghoon Park Date: Thu, 4 Jan 2018 17:23:33 +0900 Subject: [PATCH] add pilot version of receiver udp module --- CMakeLists.txt | 1 + inc/receiver_udp.h | 23 ++++ src/receiver_udp.c | 323 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 347 insertions(+) create mode 100644 inc/receiver_udp.h create mode 100644 src/receiver_udp.c diff --git a/CMakeLists.txt b/CMakeLists.txt index f2024a5..1b0196a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ ADD_EXECUTABLE(${PROJECT_NAME} ${PROJECT_ROOT_DIR}/src/log.c ${PROJECT_ROOT_DIR}/src/resource.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 diff --git a/inc/receiver_udp.h b/inc/receiver_udp.h new file mode 100644 index 0000000..7c1ae23 --- /dev/null +++ b/inc/receiver_udp.h @@ -0,0 +1,23 @@ +/* + * 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__ + +int receiver_udp_start(void); +int receiver_udp_stop(void); + +#endif /* __CAR_APP_RECEIVER_UDP_H__ */ diff --git a/src/receiver_udp.c b/src/receiver_udp.c new file mode 100644 index 0000000..1b429a9 --- /dev/null +++ b/src/receiver_udp.c @@ -0,0 +1,323 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "receiver_internal.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_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; +} + +int __receiver_udp_init(void) +{ + if (udp_handle) { + _E("receiver udp is already initialized"); + return -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; + + return 0; +} + +int __receiver_udp_fini(void) +{ + 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); + } + + free(udp_handle); + udp_handle = NULL; + } + + return 0; +} + +/* 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(void) +{ + struct sockaddr addr; + int s_fd = 0; + + 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; + } + udp_handle->state = RECEIVER_UDP_STATE_READY; + _D("unset connection"); + + return 0; +} + +static int __receiver_udp_set_connection(GSocketAddress *sender_a) +{ + GError *error = NULL; + + retv_if(!sender_a, -1); + 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; + } + udp_handle->state = RECEIVER_UDP_STATE_CONNECTED; + _D("set connection"); + + return 0; +} + +static gboolean __wait_time_out(gpointer user_data) +{ + __receiver_udp_unset_connection(); + + return FALSE; +} + +static void __receiver_udp_update_wait_timer(void) +{ + 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, NULL); + } + return; +} + +static gboolean __read_socket(GIOChannel *channel, + GIOCondition condition, + gpointer data) +{ + gssize size = 0; + receiver_udp_h *handle = (receiver_udp_h *)data; + GError *error = NULL; + + char buf[1024] = {0, }; /* temp */ + + retv_if(!handle, TRUE); + retv_if(!handle->socket, TRUE); + + if (handle->state == RECEIVER_UDP_STATE_NONE) { + _E("receiver udp is not ready yet"); + return TRUE; + } + + if (handle->state == RECEIVER_UDP_STATE_READY) { + char *s_addr = NULL; + GSocketAddress *address = NULL; + + size = g_socket_receive_from(handle->socket, &address, + buf, sizeof(buf), NULL, &error); + + if (size < 0) { + _D("Error receiving from socket: %s", error->message); + g_error_free(error); + } + + s_addr = __socket_address_to_string(address); + _D("received first data from [%s]", s_addr); + + + if (!__receiver_udp_set_connection(address)) + __receiver_udp_update_wait_timer(); + 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(handle->socket, + buf, sizeof(buf), NULL, &error); + + if (size < 0) { + _D("Error receiving from socket: %s", error->message); + g_error_free(error); + } + _D("received data"); + __receiver_udp_update_wait_timer(); + } + + /* TODO : what should I do after receiveing some data? */ + + return TRUE; +} + +int receiver_udp_start(void) +{ + GError *error = NULL; + GSocketAddress *address = NULL; + GInetAddress *i_addr = NULL; + int socket_fd = 0; + GIOChannel *ch = NULL; + int ret = 0; + + if (!udp_handle) { + ret = __receiver_udp_init(); + if (ret) + return -1; + } + + if (udp_handle->state >= RECEIVER_UDP_STATE_READY) { + _W("receivet udp is already started"); + return 0; + } + + 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; + + 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, udp_handle); + g_io_channel_unref(ch); + ch = NULL; + + udp_handle->state = RECEIVER_UDP_STATE_READY; + _D("receiver udp started"); + + return 0; + +ERROR: + if (error) + g_error_free(error); + + if (address) + g_object_unref(address); + + if (i_addr) + g_object_unref(i_addr); + + __receiver_udp_fini(); + + return -1; +} + +int receiver_udp_stop(void) +{ + __receiver_udp_fini(); + _D("receiver udp stopped"); + + return 0; +} -- 2.7.4