7 #include <sys/socket.h>
9 #include <netinet/in.h>
12 #include <arpa/inet.h>
24 #include <sys/ioctl.h>
29 static pthread_mutex_t at_cmd_lock;
30 static pthread_t at_thread = 0;
31 static int32_t at_thread_alive = 1;
33 uint32_t mykonos_state = 0;
37 #define AT_BUFFER_SIZE 1024
40 MYKONOS_UI_BIT_AG = 0, /* Button turn to left */
41 MYKONOS_UI_BIT_AB = 1, /* Button altitude down (ah - ab)*/
42 MYKONOS_UI_BIT_AD = 2, /* Button turn to right */
43 MYKONOS_UI_BIT_AH = 3, /* Button altitude up (ah - ab)*/
44 MYKONOS_UI_BIT_L1 = 4, /* Button - z-axis (r1 - l1) */
45 MYKONOS_UI_BIT_R1 = 5, /* Not used */
46 MYKONOS_UI_BIT_L2 = 6, /* Button + z-axis (r1 - l1) */
47 MYKONOS_UI_BIT_R2 = 7, /* Not used */
48 MYKONOS_UI_BIT_SELECT = 8, /* Button emergency reset all */
49 MYKONOS_UI_BIT_START = 9, /* Button Takeoff / Landing */
50 MYKONOS_UI_BIT_TRIM_THETA = 18, /* y-axis trim +1 (Trim increase at +/- 1??/s) */
51 MYKONOS_UI_BIT_TRIM_PHI = 20, /* x-axis trim +1 (Trim increase at +/- 1??/s) */
52 MYKONOS_UI_BIT_TRIM_YAW = 22, /* z-axis trim +1 (Trim increase at +/- 1??/s) */
53 MYKONOS_UI_BIT_X = 24, /* x-axis +1 */
54 MYKONOS_UI_BIT_Y = 28, /* y-axis +1 */
55 } mykonos_ui_bitfield_t;
57 typedef struct _radiogp_cmd_t {
63 static radiogp_cmd_t radiogp_cmd = {0};
65 #define MYKONOS_NO_TRIM \
66 ((1 << MYKONOS_UI_BIT_TRIM_THETA) | \
67 (1 << MYKONOS_UI_BIT_TRIM_PHI) | \
68 (1 << MYKONOS_UI_BIT_TRIM_YAW) | \
69 (1 << MYKONOS_UI_BIT_X) | \
70 (1 << MYKONOS_UI_BIT_Y))
72 static uint32_t user_input = MYKONOS_NO_TRIM;
74 static int at_udp_socket = -1;
75 static int overflow = 0;
76 static unsigned long ocurrent = 0;
78 static void send_command(int nb_sequence);
79 static void* at_cmds_loop(void *arg);
80 static void boot_drone(void);
81 static unsigned long get_time_ms(void);
83 static inline int get_mask_from_state( uint32_t state, uint32_t mask )
85 return state & mask ? TRUE : FALSE;
89 static unsigned long get_time_ms(void)
92 gettimeofday(&tv, NULL);
93 return (tv.tv_sec*1000 + tv.tv_usec/1000);
96 static void boot_drone(void)
98 const char cmds[] = "AT*CONFIG=\"general:navdata_demo\",\"TRUE\"\r";
100 if ( get_mask_from_state( mykonos_state,
101 MYKONOS_NAVDATA_BOOTSTRAP )) {
102 at_write ((int8_t*)cmds, strlen (cmds));
105 int bcontinue = TRUE;
107 while (bcontinue && retry) {
109 if ( get_mask_from_state( mykonos_state, MYKONOS_COMMAND_MASK )) {
110 INFO ("[CONTROL] Processing the current command ... \n");
115 char str[AT_BUFFER_SIZE];
116 memset (str, 0, AT_BUFFER_SIZE);
117 sprintf (str, "AT*CTRL=%d,%d\r", ACK_CONTROL_MODE, 0);
118 at_write ((int8_t*)str, strlen (str));
120 if ( !get_mask_from_state( mykonos_state, MYKONOS_COMMAND_MASK )) {
121 INFO ("[CONTROL] Ack control event OK, send navdata demo\n");
131 static void* at_cmds_loop(void *arg)
133 unsigned long current, deadline;
134 unsigned int nb_sequence = 0;
136 INFO("AT commands thread starting (thread=%d)...\n", (int)pthread_self());
138 user_input = MYKONOS_NO_TRIM;
139 ocurrent = get_time_ms();
141 while (at_thread_alive) {
143 if (get_mask_from_state(mykonos_state, MYKONOS_NAVDATA_BOOTSTRAP)) {
144 INFO("attempting to boot drone...\n");
150 // compute next loop iteration deadline
151 deadline = get_time_ms() + MYKONOS_REFRESH_MS;
153 // send pilot command
154 send_command( nb_sequence++ );
156 // sleep until deadline
157 current = get_time_ms();
158 if (current < deadline) {
159 usleep(1000*(deadline-current));
163 INFO("AT commands thread stopping\n");
167 static void send_command(int nb_sequence)
169 unsigned long current;
170 char str[AT_BUFFER_SIZE];
173 // send command to drone
174 current = get_time_ms();
176 pthread_mutex_lock( &at_cmd_lock );
177 snprintf(str, AT_BUFFER_SIZE, "AT*SEQ=%d\rAT*RADGP=%d,%d,%d,%d\rAT*REF=%d\r",
178 nb_sequence, radiogp_cmd.pitch, radiogp_cmd.roll, radiogp_cmd.gaz, radiogp_cmd.yaw, user_input);
179 pthread_mutex_unlock( &at_cmd_lock );
182 at_write((int8_t*)str, strlen (str));
184 // check 30 ms overflow
185 if (current > ocurrent + 30) {
186 overflow += current - ocurrent - MYKONOS_REFRESH_MS;
190 /* dump command every 2s */
191 if ((nb_sequence & 63) == 0) {
192 pthread_mutex_lock( &at_cmd_lock );
193 INFO("seq=%d radgp(%d,%d,%d,%d) ui=0x%08x over=%d\n", nb_sequence,
194 radiogp_cmd.pitch, radiogp_cmd.roll, radiogp_cmd.gaz, radiogp_cmd.yaw, user_input, overflow);
195 pthread_mutex_unlock( &at_cmd_lock );
200 void at_write (int8_t *buffer, int32_t len)
202 struct sockaddr_in to;
205 pthread_mutex_lock( &at_cmd_lock );
206 if( at_udp_socket < 0 ) {
207 struct sockaddr_in at_udp_addr;
209 memset( (char*)&at_udp_addr, 0, sizeof(at_udp_addr) );
211 at_udp_addr.sin_family = AF_INET;
212 at_udp_addr.sin_addr.s_addr = INADDR_ANY;
213 at_udp_addr.sin_port = htons( AT_PORT + 100 );
215 at_udp_socket = socket( AF_INET, SOCK_DGRAM, 0 );
217 if( at_udp_socket >= 0 )
219 flags = fcntl(at_udp_socket, F_GETFL, 0);
224 flags = fcntl(at_udp_socket, F_SETFL, flags );
228 INFO("Get Socket Options failed\n");
231 if (bind(at_udp_socket, (struct sockaddr*)&at_udp_addr, sizeof(struct sockaddr)) < 0) {
232 INFO ("at_write:bind: %s\n", strerror(errno));
237 if( at_udp_socket >= 0 )
241 memset( (char*)&to, 0, sizeof(to) );
242 to.sin_family = AF_INET;
243 to.sin_addr.s_addr = inet_addr(WIFI_MYKONOS_IP); // BROADCAST address for subnet 192.168.1.xxx
244 to.sin_port = htons (AT_PORT);
246 res = sendto( at_udp_socket, (char*)buffer, len, 0, (struct sockaddr*)&to, sizeof(to) );
248 pthread_mutex_unlock( &at_cmd_lock );
251 /* Public functions */
258 pthread_join(at_thread, NULL);
260 pthread_mutex_destroy( &at_cmd_lock );
262 if (at_udp_socket >= 0){
263 close(at_udp_socket);
268 /************* at_init ****************
269 * Description : Initialize AT process.
276 /* Initialize mutex */
277 if ( pthread_mutex_init( &at_cmd_lock, NULL ) != 0)
279 INFO("AT mutex init failed: %s\n", strerror(errno));
285 if ( pthread_create( &at_thread, NULL, at_cmds_loop, NULL ) )
287 INFO("pthread_create: %s\n", strerror(errno));
291 /************* at_set_flat_trim ****************
292 * Description : Calibration of the ARDrone.
294 void at_set_flat_trim( void )
296 const char cmd[] = "AT*FTRIM\r";
297 at_write ((int8_t*)cmd, strlen (cmd));
300 /************* at_ui_pad_start_pressed ****************
301 * Description : Takeoff/Landing, used with at_cmds_loop function.
303 void at_ui_pad_start_pressed( void )
308 pthread_mutex_lock( &at_cmd_lock );
309 user_input ^= 1 << MYKONOS_UI_BIT_START;
310 pthread_mutex_unlock( &at_cmd_lock );
313 /************* at_set_radiogp_input ****************
314 * Description : Fill struct radiogp_cmd,
315 * used with at_cmds_loop function.
316 * pitch : y-axis (rad) (-25000, +25000)
317 * roll : x-axis (rad) (-25000, +25000)
318 * gaz : altitude (mm/s) (-25000, +25000)
319 * yaw : z-axis (rad/s) (-25000, +25000)
321 void at_set_radiogp_input( int32_t pitch, int32_t roll, int32_t gaz, int32_t yaw )
326 pthread_mutex_lock( &at_cmd_lock );
327 radiogp_cmd.pitch = pitch;
328 radiogp_cmd.roll = roll;
329 radiogp_cmd.gaz = gaz;
330 radiogp_cmd.yaw = yaw;
331 pthread_mutex_unlock( &at_cmd_lock );
334 /************* at_set_iphone_acceleros ****************
335 * Description : Send directly accelero values.
336 * enable : Apply values parameters on the ARDrone (only if iphone is used for computation).
337 * fax : x-axis (-0.5, +0.5)
338 * fay : y-axis (-0.5, +0.5)
339 * faz : z-axis (-0.5, +0.5)
341 void at_set_iphone_acceleros( int enable, float32_t fax, float32_t fay, float32_t faz )
343 char cmd[AT_BUFFER_SIZE];
344 memset (cmd, 0, AT_BUFFER_SIZE);
345 sprintf (cmd, "AT*ACCS=%d,%d,%d,%d\r", (int32_t)enable, (int32_t)fax, (int32_t)fay, (int32_t)faz);
346 at_write ((int8_t*)cmd, strlen (cmd));