ArDrone SDK 1.8 added
[mardrone] / mardrone / ARDrone_SDK_Version_1_8_20110726 / Examples / Multiplatform / Protocol / at_cmds.c
diff --git a/mardrone/ARDrone_SDK_Version_1_8_20110726/Examples/Multiplatform/Protocol/at_cmds.c b/mardrone/ARDrone_SDK_Version_1_8_20110726/Examples/Multiplatform/Protocol/at_cmds.c
new file mode 100644 (file)
index 0000000..e8ff4c7
--- /dev/null
@@ -0,0 +1,318 @@
+/**
+ * @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 <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"
+
+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;
+
+static int at_udp_socket  = -1;
+
+static inline int get_mask_from_state( uint32_t state, uint32_t mask )
+{
+    return state & mask ? TRUE : FALSE;
+}
+
+void at_write (int8_t *buffer, int32_t len)
+{
+    struct sockaddr_in to;
+    int32_t flags;
+
+    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) );
+        }
+}
+
+void set_radiogp_input( int32_t pitch, int32_t roll, int32_t gaz, int32_t yaw )
+{
+    /*pitch, roll, yaw : values between -32767 and +32767 */
+    /*gaz : GAZ_REF_MAX = 20 */
+       char cmd[AT_BUFFER_SIZE];
+       memset (cmd, 0, AT_BUFFER_SIZE); 
+       sprintf (cmd, "AT*RADGP=%d,%d,%d,%d\r", pitch, roll, gaz, yaw);
+       at_write ((int8_t*)cmd, strlen (cmd));
+}
+void set_ui_input( uint32_t value )
+{
+       char cmd[AT_BUFFER_SIZE];
+       memset (cmd, 0, AT_BUFFER_SIZE); 
+       sprintf (cmd, "AT*REF=%d\r", value);
+       at_write ((int8_t*)cmd, strlen (cmd));
+}
+
+void 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));
+}
+
+void set_flat_trim( void )
+{
+       const char cmd[] = "AT*FTRIM\r";
+       at_write ((int8_t*)cmd, strlen (cmd));
+}
+
+struct event_info motion_info;
+struct event_info trackball_info;
+struct orientation_info orientation;
+
+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--;
+               }
+       }
+}
+
+#define BUFSIZE  256
+
+#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 ui_mask = MYKONOS_NO_TRIM;
+
+static int start_button = 0;
+static int overflow = 0;
+static unsigned long ocurrent = 0;
+
+static void send_command(int nb_sequence)
+{
+       unsigned long current;
+       char str[BUFSIZE];
+       int32_t pitch = 0, roll = 0, yaw = 0, gaz = 0, sw, sh;
+
+       //FIXME: access to motion/trackball/orientation is not thread-safe
+       // this should not really matter for this demo
+       if (motion_info.state) {
+
+               get_screen_dimensions(&sw, &sh);
+
+               // up/down zone => gaz +/- 500 mm/s
+               if (motion_info.x <= sw/3) {
+                       gaz = (motion_info.y > sh/2)? 10000 : -10000;
+               }
+
+               // take off/landing zone (toggle start bit)
+               if (!start_button && (motion_info.x >= 2*sw/3) &&
+                       (motion_info.y <= sh/3)) {
+                       ui_mask ^= (1 << MYKONOS_UI_BIT_START);
+                       start_button = 1;
+               }
+               //INFO("touch @ (%d,%d)\n", motion_info.x, motion_info.y);
+       }
+       else {
+               start_button = 0;
+       }
+
+       if (trackball_info.state) {
+               pitch = -(orientation.values[2]+20)*1000;
+               if (pitch >= 25000) {
+                       pitch = 25000;
+               }
+               if (pitch <= -25000) {
+                       pitch = -25000;
+               }
+               roll = orientation.values[1]*1000;
+               if (roll >= 25000) {
+                       roll = 25000;
+               }
+               if (roll <= -25000) {
+                       roll = -25000;
+               }
+               yaw = (trackball_info.x-1)*4000;
+               /*
+               INFO("yaw %c orientation: %d %d\n", yaw[trackball_info.x],
+                        orientation.values[1], orientation.values[2]);
+               */
+       }
+       // send command to drone
+       current = get_time_ms();
+
+       //FIXME: are allowed to concatenate AT commands this way ?
+       snprintf(str, BUFSIZE, "AT*SEQ=%d\rAT*RADGP=%d,%d,%d,%d\rAT*REF=%d\r",
+                        nb_sequence, pitch, roll, gaz, yaw, ui_mask);
+       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) {
+               INFO("seq=%d radgp(%d,%d,%d,%d) ui=0x%08x over=%d\n", nb_sequence,
+                        pitch, roll, gaz, yaw, ui_mask, overflow);
+               overflow = 0;
+       }
+}
+
+DEFINE_THREAD_ROUTINE( at_cmds_loop, data )
+{
+       unsigned long current, deadline;
+       unsigned int nb_sequence = 0;
+
+       INFO("AT commands thread starting (thread=%d)...\n", (int)pthread_self());
+
+       ui_mask = MYKONOS_NO_TRIM;
+       start_button = 0;
+       motion_info.state = 0;
+       trackball_info.state = 0;
+       trackball_info.x = 1;
+       orientation.values[0] = 0;
+       orientation.values[1] = 0;
+       orientation.values[2] = 0;
+       ocurrent = get_time_ms();
+
+    while (gAppAlive) {
+
+               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));
+               }
+       }
+
+    if (at_udp_socket >= 0){
+        close(at_udp_socket);
+        at_udp_socket = -1;
+    }
+
+       INFO("AT commands thread stopping\n");
+    return NULL;
+}