ArDrone SDK 1.8 added
[mardrone] / mardrone / ARDrone_SDK_Version_1_8_20110726 / ARDroneLib / Soft / Lib / ardrone_tool / Navdata / ardrone_navdata_client.c
diff --git a/mardrone/ARDrone_SDK_Version_1_8_20110726/ARDroneLib/Soft/Lib/ardrone_tool/Navdata/ardrone_navdata_client.c b/mardrone/ARDrone_SDK_Version_1_8_20110726/ARDroneLib/Soft/Lib/ardrone_tool/Navdata/ardrone_navdata_client.c
new file mode 100644 (file)
index 0000000..2b7dae9
--- /dev/null
@@ -0,0 +1,257 @@
+#include <errno.h>
+#include <string.h>
+
+#include <config.h>
+
+#include <VP_Os/vp_os_print.h>
+#include <VP_Com/vp_com.h>
+
+#include <ardrone_api.h>
+#include <ardrone_tool/ardrone_tool.h>
+#include <ardrone_tool/Navdata/ardrone_navdata_client.h>
+#include <ardrone_tool/Com/config_com.h>
+
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <unistd.h>
+#endif
+
+// PROTO_THREAD_ROUTINE( navdata_update , nomParams );
+
+static bool_t navdata_thread_in_pause = TRUE;
+static bool_t bContinue = TRUE;
+static uint32_t num_retries = 0; 
+static vp_os_cond_t navdata_client_condition;
+static vp_os_mutex_t navdata_client_mutex;
+
+static vp_com_socket_t navdata_socket;
+static Read navdata_read      = NULL;
+static Write navdata_write    = NULL;
+
+static uint8_t navdata_buffer[NAVDATA_MAX_SIZE];
+navdata_unpacked_t navdata_unpacked;
+
+C_RESULT ardrone_navdata_client_init(void)
+{
+  C_RESULT res;
+
+  COM_CONFIG_SOCKET_NAVDATA(&navdata_socket, VP_COM_CLIENT, NAVDATA_PORT, wifi_ardrone_ip);
+  navdata_socket.protocol = VP_COM_UDP;
+  navdata_socket.is_multicast = 1;      // enable multicast for Navdata
+  navdata_socket.multicast_base_addr = MULTICAST_BASE_ADDR;
+
+  vp_os_mutex_init(&navdata_client_mutex);
+  vp_os_cond_init(&navdata_client_condition, &navdata_client_mutex);
+       
+  res = C_OK;
+
+  return res;
+}
+
+C_RESULT ardrone_navdata_client_suspend(void)
+{
+       vp_os_mutex_lock(&navdata_client_mutex);
+       navdata_thread_in_pause = TRUE;
+       vp_os_mutex_unlock(&navdata_client_mutex);      
+       
+       return C_OK;
+}
+
+C_RESULT ardrone_navdata_client_resume(void)
+{
+       vp_os_mutex_lock(&navdata_client_mutex);
+       vp_os_cond_signal(&navdata_client_condition);
+       navdata_thread_in_pause = FALSE;
+       vp_os_mutex_unlock(&navdata_client_mutex);      
+
+       return C_OK;
+}
+
+C_RESULT ardrone_navdata_open_server(void)
+{
+  // Flag value :
+  // 1 -> Unicast
+  // 2 -> Multicast
+  int32_t flag = 1, len = sizeof(flag);
+
+  if( navdata_write != NULL )
+  {
+    if (navdata_socket.is_multicast == 1)
+      flag = 2;
+
+    navdata_write(&navdata_socket, (const int8_t*) &flag, &len);
+  }
+
+  return C_OK;
+}
+
+DEFINE_THREAD_ROUTINE( navdata_update, nomParams )
+{
+  C_RESULT res;
+  int32_t  i, size;
+  uint32_t cks, navdata_cks, sequence = NAVDATA_SEQUENCE_DEFAULT-1;
+  struct timeval tv;
+#ifdef _WIN32
+  int timeout_for_windows=1000/*milliseconds*/;
+#endif
+
+
+  navdata_t* navdata = (navdata_t*) &navdata_buffer[0];
+
+  tv.tv_sec   = 1/*second*/;
+  tv.tv_usec  = 0;
+
+  res = C_OK;
+
+  if( VP_FAILED(vp_com_open(COM_NAVDATA(), &navdata_socket, &navdata_read, &navdata_write)) )
+  {
+    printf("VP_Com : Failed to open socket for navdata\n");
+    res = C_FAIL;
+  }
+
+  if( VP_SUCCEEDED(res) )
+  {
+    PRINT("Thread navdata_update in progress...\n");
+
+#ifdef _WIN32
+       setsockopt((int32_t)navdata_socket.priv, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout_for_windows, sizeof(timeout_for_windows));
+       /* Added by Stephane to force the drone start sending data. */
+       if(navdata_write)
+       {       int sizeinit = 5; navdata_write( (void*)&navdata_socket, (int8_t*)"Init", &sizeinit ); }
+#else
+       setsockopt((int32_t)navdata_socket.priv, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
+#endif
+
+
+    i = 0;
+    while( ardrone_navdata_handler_table[i].init != NULL )
+    {
+      // if init failed for an handler we set its process function to null
+      // We keep its release function for cleanup
+      if( VP_FAILED( ardrone_navdata_handler_table[i].init(ardrone_navdata_handler_table[i].data) ) )
+        ardrone_navdata_handler_table[i].process = NULL;
+
+      i ++;
+    }
+
+   navdata_thread_in_pause = FALSE;
+    while( VP_SUCCEEDED(res) 
+           && !ardrone_tool_exit() 
+           && bContinue )
+    {
+         if(navdata_thread_in_pause)
+         {
+               vp_os_mutex_lock(&navdata_client_mutex);
+               num_retries = NAVDATA_MAX_RETRIES + 1;
+               vp_os_cond_wait(&navdata_client_condition);
+               vp_os_mutex_unlock(&navdata_client_mutex);
+         }
+       
+               if( navdata_read == NULL )
+      {
+        res = C_FAIL;
+        continue;
+      }
+
+      size = NAVDATA_MAX_SIZE;
+      navdata->header = 0; // Soft reset
+      res = navdata_read( (void*)&navdata_socket, (int8_t*)&navdata_buffer[0], &size );
+
+#ifdef _WIN32  
+         if( size <= 0 )
+#else
+         if( size == 0 )
+#endif
+               {
+                       // timeout
+                       PRINT("Timeout when reading navdatas - resending a navdata request on port %i\n",NAVDATA_PORT);
+                       /* Resend a request to the drone to get navdatas */
+                       ardrone_navdata_open_server();
+                       sequence = NAVDATA_SEQUENCE_DEFAULT-1;
+                       num_retries++;
+               } 
+               else
+         num_retries = 0;
+
+      if( VP_SUCCEEDED( res ) )
+      {
+        if( navdata->header == NAVDATA_HEADER )
+        {
+          if( ardrone_get_mask_from_state(navdata->ardrone_state, ARDRONE_COM_WATCHDOG_MASK) )
+          {
+            // reset sequence number because of com watchdog
+            // This code is mandatory because we can have a com watchdog without detecting it on mobile side :
+            //        Reconnection is fast enough (less than one second)
+            sequence = NAVDATA_SEQUENCE_DEFAULT-1;
+
+            if( ardrone_get_mask_from_state(navdata->ardrone_state, ARDRONE_NAVDATA_BOOTSTRAP) == FALSE )
+              ardrone_tool_send_com_watchdog(); // acknowledge
+          }
+
+          if( navdata->sequence > sequence )
+          {
+            i = 0;
+
+            ardrone_navdata_unpack_all(&navdata_unpacked, navdata, &navdata_cks);
+            cks = ardrone_navdata_compute_cks( &navdata_buffer[0], size - sizeof(navdata_cks_t) );
+
+            if( cks == navdata_cks )
+            {
+              while( ardrone_navdata_handler_table[i].init != NULL )
+              {
+                if( ardrone_navdata_handler_table[i].process != NULL )
+                  ardrone_navdata_handler_table[i].process( &navdata_unpacked );
+
+                i++;
+              }
+            }
+            else
+            {
+              PRINT("[Navdata] Checksum failed : %d (distant) / %d (local)\n", navdata_cks, cks);
+            }
+          }
+          else
+          {
+            PRINT("[Navdata] Sequence pb : %d (distant) / %d (local)\n", navdata->sequence, sequence);
+          }
+
+          // remaining = sizeof(navdata);
+
+          sequence = navdata->sequence;
+        }
+      }
+    }
+
+    // Release resources alllocated by handlers
+    i = 0;
+    while( ardrone_navdata_handler_table[i].init != NULL )
+    {
+      ardrone_navdata_handler_table[i].release();
+
+      i ++;
+    }
+  }
+
+  vp_com_close(COM_NAVDATA(), &navdata_socket);
+
+  DEBUG_PRINT_SDK("Thread navdata_update ended\n");
+
+  return (THREAD_RET)res;
+}
+
+uint32_t ardrone_navdata_client_get_num_retries(void)
+{
+  return num_retries;
+}
+
+C_RESULT ardrone_navdata_client_shutdown(void)
+{
+   bContinue = FALSE;
+
+   return C_OK;
+}
+
+