add pilot version of receiver udp module
authorJeonghoon Park <jh1979.park@samsung.com>
Thu, 4 Jan 2018 08:23:33 +0000 (17:23 +0900)
committerJeonghoon Park <jh1979.park@samsung.com>
Thu, 4 Jan 2018 08:23:33 +0000 (17:23 +0900)
CMakeLists.txt
inc/receiver_udp.h [new file with mode: 0644]
src/receiver_udp.c [new file with mode: 0644]

index f2024a5..1b0196a 100644 (file)
@@ -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 (file)
index 0000000..7c1ae23
--- /dev/null
@@ -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 (file)
index 0000000..1b429a9
--- /dev/null
@@ -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 <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"
+
+#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;
+}