ArDrone SDK 1.8 added
[mardrone] / mardrone / ARDrone_SDK_Version_1_8_20110726 / Examples / Linux / Protocol / at_cmds.c
diff --git a/mardrone/ARDrone_SDK_Version_1_8_20110726/Examples/Linux/Protocol/at_cmds.c b/mardrone/ARDrone_SDK_Version_1_8_20110726/Examples/Linux/Protocol/at_cmds.c
new file mode 100644 (file)
index 0000000..aeb619f
--- /dev/null
@@ -0,0 +1,350 @@
+/**
+ * @file my_client.c
+ * @author karl leplat
+ * @date 2009/07/01
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/time.h>
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+#include "app.h"
+
+static pthread_mutex_t at_cmd_lock;
+static pthread_t at_thread = 0;
+static int32_t at_thread_alive = 1;
+
+uint32_t mykonos_state = 0;
+
+/* AT constant */
+#define AT_PORT                   5556
+#define AT_BUFFER_SIZE            1024
+
+typedef enum {
+    MYKONOS_UI_BIT_AG             = 0, /* Button turn to left */
+    MYKONOS_UI_BIT_AB             = 1, /* Button altitude down (ah - ab)*/
+    MYKONOS_UI_BIT_AD             = 2, /* Button turn to right */
+    MYKONOS_UI_BIT_AH             = 3, /* Button altitude up (ah - ab)*/
+    MYKONOS_UI_BIT_L1             = 4, /* Button - z-axis (r1 - l1) */
+    MYKONOS_UI_BIT_R1             = 5, /* Not used */
+    MYKONOS_UI_BIT_L2             = 6, /* Button + z-axis (r1 - l1) */ 
+    MYKONOS_UI_BIT_R2             = 7, /* Not used */
+    MYKONOS_UI_BIT_SELECT         = 8, /* Button emergency reset all */
+    MYKONOS_UI_BIT_START          = 9, /* Button Takeoff / Landing */
+    MYKONOS_UI_BIT_TRIM_THETA     = 18, /* y-axis trim +1 (Trim increase at +/- 1??/s) */
+    MYKONOS_UI_BIT_TRIM_PHI       = 20, /* x-axis trim +1 (Trim increase at +/- 1??/s) */
+    MYKONOS_UI_BIT_TRIM_YAW       = 22, /* z-axis trim +1 (Trim increase at +/- 1??/s) */
+    MYKONOS_UI_BIT_X              = 24, /* x-axis +1 */
+    MYKONOS_UI_BIT_Y              = 28, /* y-axis +1 */
+} mykonos_ui_bitfield_t;
+
+typedef struct _radiogp_cmd_t {
+  int32_t pitch; 
+  int32_t roll;
+  int32_t gaz; 
+  int32_t yaw;
+} radiogp_cmd_t;
+static radiogp_cmd_t radiogp_cmd = {0};
+
+#define MYKONOS_NO_TRIM                                                        \
+    ((1 << MYKONOS_UI_BIT_TRIM_THETA) |                        \
+        (1 << MYKONOS_UI_BIT_TRIM_PHI) |                       \
+        (1 << MYKONOS_UI_BIT_TRIM_YAW) |                       \
+        (1 << MYKONOS_UI_BIT_X) |                                      \
+        (1 << MYKONOS_UI_BIT_Y))
+
+static uint32_t user_input = MYKONOS_NO_TRIM;
+
+static int at_udp_socket  = -1;
+static int overflow = 0;
+static unsigned long ocurrent = 0;
+
+static void send_command(int nb_sequence);
+static void* at_cmds_loop(void *arg);
+static void boot_drone(void);
+static unsigned long get_time_ms(void);
+
+static inline int get_mask_from_state( uint32_t state, uint32_t mask )
+{
+    return state & mask ? TRUE : FALSE;
+}
+
+
+static unsigned long get_time_ms(void)
+{
+       struct timeval tv;
+       gettimeofday(&tv, NULL);
+       return (tv.tv_sec*1000 + tv.tv_usec/1000);
+}
+
+static void boot_drone(void)
+{
+       const char cmds[] = "AT*CONFIG=\"general:navdata_demo\",\"TRUE\"\r";
+
+       if ( get_mask_from_state( mykonos_state,
+                                                         MYKONOS_NAVDATA_BOOTSTRAP )) {
+               at_write ((int8_t*)cmds, strlen (cmds));
+
+               int retry = 20;
+               int bcontinue = TRUE;
+               int next = 0;
+               while (bcontinue && retry) {
+                               if (next == 0) {
+                                       if ( get_mask_from_state( mykonos_state, MYKONOS_COMMAND_MASK )) {
+                                               INFO ("[CONTROL] Processing the current command ... \n");
+                                               next++;
+                                       }
+                               }
+                               else {
+                                       char str[AT_BUFFER_SIZE];
+                                       memset (str, 0, AT_BUFFER_SIZE); 
+                                       sprintf (str, "AT*CTRL=%d,%d\r", ACK_CONTROL_MODE, 0);
+                                       at_write ((int8_t*)str, strlen (str));
+
+                                       if ( !get_mask_from_state( mykonos_state, MYKONOS_COMMAND_MASK )) {
+                                               INFO ("[CONTROL] Ack control event OK, send navdata demo\n");
+                                               bcontinue = FALSE;
+                                       }
+                               }
+                               sleep (1);
+                               retry--;
+               }
+       }
+}
+
+static void* at_cmds_loop(void *arg)
+{
+       unsigned long current, deadline;
+       unsigned int nb_sequence = 0;
+
+       INFO("AT commands thread starting (thread=%d)...\n", (int)pthread_self());
+
+       user_input = MYKONOS_NO_TRIM;
+       ocurrent = get_time_ms();
+
+    while (at_thread_alive) {
+
+               if (get_mask_from_state(mykonos_state, MYKONOS_NAVDATA_BOOTSTRAP)) {
+                       INFO("attempting to boot drone...\n");
+                       boot_drone();
+                       nb_sequence = 0;
+                       continue;
+               }
+
+               // compute next loop iteration deadline
+               deadline = get_time_ms() + MYKONOS_REFRESH_MS;
+
+               // send pilot command
+               send_command( nb_sequence++ );
+
+               // sleep until deadline
+               current = get_time_ms();
+               if (current < deadline) {
+                       usleep(1000*(deadline-current));
+               }
+       }
+
+       INFO("AT commands thread stopping\n");
+    return NULL;
+}
+
+static void send_command(int nb_sequence)
+{
+       unsigned long current;
+       char str[AT_BUFFER_SIZE];
+
+       
+   // send command to drone
+       current = get_time_ms();
+
+       pthread_mutex_lock( &at_cmd_lock );
+       snprintf(str, AT_BUFFER_SIZE, "AT*SEQ=%d\rAT*RADGP=%d,%d,%d,%d\rAT*REF=%d\r",
+                       nb_sequence, radiogp_cmd.pitch, radiogp_cmd.roll, radiogp_cmd.gaz, radiogp_cmd.yaw, user_input);
+   pthread_mutex_unlock( &at_cmd_lock );
+   
+   //Send AT command   
+   at_write((int8_t*)str, strlen (str));
+
+       // check 30 ms overflow
+       if (current > ocurrent + 30) {
+               overflow += current - ocurrent - MYKONOS_REFRESH_MS;
+       }
+       ocurrent = current;
+
+       /* dump command every 2s */
+       if ((nb_sequence & 63) == 0) {
+          pthread_mutex_lock( &at_cmd_lock );
+               INFO("seq=%d radgp(%d,%d,%d,%d) ui=0x%08x over=%d\n", nb_sequence,
+                        radiogp_cmd.pitch, radiogp_cmd.roll, radiogp_cmd.gaz, radiogp_cmd.yaw, user_input, overflow);
+      pthread_mutex_unlock( &at_cmd_lock );
+               overflow = 0;
+       }
+}
+
+void at_write (int8_t *buffer, int32_t len)
+{
+       struct sockaddr_in to;
+       int32_t flags;
+
+       pthread_mutex_lock( &at_cmd_lock );
+       if( at_udp_socket < 0 ) {
+               struct sockaddr_in at_udp_addr;
+
+               memset( (char*)&at_udp_addr, 0, sizeof(at_udp_addr) );
+
+               at_udp_addr.sin_family      = AF_INET;
+               at_udp_addr.sin_addr.s_addr = INADDR_ANY;
+               at_udp_addr.sin_port        = htons( AT_PORT + 100 );
+
+               at_udp_socket = socket( AF_INET, SOCK_DGRAM, 0 );
+
+               if( at_udp_socket >= 0 )
+               {
+                       flags = fcntl(at_udp_socket, F_GETFL, 0);
+                       if( flags >= 0 )
+                       {
+                               flags |= O_NONBLOCK;
+
+                               flags = fcntl(at_udp_socket, F_SETFL, flags );
+                       }
+                       else
+                       {
+                               INFO("Get Socket Options failed\n");
+                       }
+
+                       if (bind(at_udp_socket, (struct sockaddr*)&at_udp_addr, sizeof(struct sockaddr)) < 0) {
+                               INFO ("at_write:bind: %s\n", strerror(errno));
+                       }
+               }
+       }
+
+       if( at_udp_socket >= 0 )
+       {
+               int res;
+
+               memset( (char*)&to, 0, sizeof(to) );
+               to.sin_family       = AF_INET;
+               to.sin_addr.s_addr  = inet_addr(WIFI_MYKONOS_IP); // BROADCAST address for subnet 192.168.1.xxx
+               to.sin_port         = htons (AT_PORT);
+
+               res = sendto( at_udp_socket, (char*)buffer, len, 0, (struct sockaddr*)&to, sizeof(to) );
+       }
+   pthread_mutex_unlock( &at_cmd_lock );
+}
+
+/* Public functions */
+void at_stop( void )
+{
+       if ( !at_thread )
+               return;
+   
+   at_thread_alive = 0;
+       pthread_join(at_thread, NULL);
+       at_thread = 0;
+       pthread_mutex_destroy( &at_cmd_lock );
+
+       if (at_udp_socket >= 0){
+               close(at_udp_socket);
+               at_udp_socket = -1;
+       }
+}
+
+/************* at_init ****************
+* Description : Initialize AT process.    
+*/
+void at_run( void )
+{
+       if (at_thread)
+               return;
+
+       /* Initialize mutex */
+       if ( pthread_mutex_init( &at_cmd_lock, NULL ) != 0)
+   {
+          INFO("AT mutex init failed: %s\n", strerror(errno));
+      return;
+   }
+
+       // AT cmds loop
+   at_thread_alive = 1;
+       if ( pthread_create( &at_thread, NULL, at_cmds_loop, NULL ) )
+   {
+               INFO("pthread_create: %s\n", strerror(errno));
+       }
+}
+
+/************* at_set_flat_trim ****************
+* Description : Calibration of the ARDrone.   
+*/
+void at_set_flat_trim( void )
+{
+       const char cmd[] = "AT*FTRIM\r";
+       at_write ((int8_t*)cmd, strlen (cmd));
+}
+
+/************* at_ui_pad_start_pressed ****************
+* Description : Takeoff/Landing, used with at_cmds_loop function.  
+*/
+void at_ui_pad_start_pressed( void )
+{
+       if (!at_thread)
+               return;
+
+   pthread_mutex_lock( &at_cmd_lock );
+   user_input ^= 1 << MYKONOS_UI_BIT_START;
+   pthread_mutex_unlock( &at_cmd_lock );
+}
+
+/************* at_set_radiogp_input ****************
+* Description : Fill struct radiogp_cmd, 
+* used with at_cmds_loop function.
+* pitch : y-axis (rad) (-25000, +25000)  
+* roll : x-axis (rad) (-25000, +25000) 
+* gaz :  altitude (mm/s) (-25000, +25000)
+* yaw : z-axis (rad/s) (-25000, +25000)
+*/
+void at_set_radiogp_input( int32_t pitch, int32_t roll, int32_t gaz, int32_t yaw )
+{
+       if (!at_thread)
+               return;
+       
+   pthread_mutex_lock( &at_cmd_lock );
+       radiogp_cmd.pitch = pitch;
+       radiogp_cmd.roll = roll;
+       radiogp_cmd.gaz = gaz;
+       radiogp_cmd.yaw = yaw;
+       pthread_mutex_unlock( &at_cmd_lock );
+}
+
+/************* at_set_iphone_acceleros ****************
+* Description : Send directly accelero values. 
+* enable : Apply values parameters on the ARDrone (only if iphone is used for computation).   
+* fax : x-axis (-0.5, +0.5)
+* fay : y-axis (-0.5, +0.5)
+* faz : z-axis (-0.5, +0.5)
+*/
+void at_set_iphone_acceleros( int enable, float32_t fax, float32_t fay, float32_t faz )
+{
+       char cmd[AT_BUFFER_SIZE];
+       memset (cmd, 0, AT_BUFFER_SIZE); 
+       sprintf (cmd, "AT*ACCS=%d,%d,%d,%d\r", (int32_t)enable, (int32_t)fax, (int32_t)fay, (int32_t)faz);
+       at_write ((int8_t*)cmd, strlen (cmd));
+}
+
+
+