ArDrone SDK 1.8 added
[mardrone] / mardrone / ARDrone_SDK_Version_1_8_20110726 / ControlEngine / iPhone / Classes / Menus / HUD.m
1 #import "HUD.h"
2 #import <CoreMotion/CoreMotion.h>
3
4 // Ratio to activate control yaw and gaz
5 #define CONTROL_RATIO   (1.0 / 3.0)
6 #define CONTROL_RATIO_IPAD (1.0 / 6.0)
7
8 #define ACCELERO_THRESHOLD      0.1
9 #define ACCELERO_NORM_THRESHOLD 0.0
10 #define ACCELERO_FASTMOVE_THRESHOLD     1.3
11
12 // Determine if a point within the boundaries of the joystick.
13 static bool_t isPointInCircle(CGPoint point, CGPoint center, float radius) {
14         float dx = (point.x - center.x);
15         float dy = (point.y - center.y);
16         return (radius >= sqrt( (dx * dx) + (dy * dy) ));
17 }
18
19 static float sign(float value)
20 {
21         float result = 1.0;
22         if(value < 0)
23                 result = -1.0;
24         
25         return result;
26 }
27
28 static float Normalize(float x, float y, float z)
29 {
30         return sqrt(x * x + y * y + z * z);
31 }
32
33 static float Clamp(float v, float min, float max)
34 {
35         float result = v;
36         if(v > max)
37                 result = max;
38         else if(v < min)
39                 result = min;
40
41         return result;
42 }
43
44 static CONTROLS controls_table[CONTROL_MODE_MAX] = 
45 {
46         [CONTROL_MODE1] = { {FALSE, inputPitch, inputYaw}, {FALSE, inputGaz, inputRoll} },
47         [CONTROL_MODE2] = { {FALSE, inputGaz, inputYaw}, {TRUE, inputPitch, inputRoll} },
48         [CONTROL_MODE3] = { {TRUE, inputPitch, inputRoll}, {FALSE, inputGaz, inputYaw} },
49         [CONTROL_MODE4] = { {FALSE, inputGaz, inputRoll}, {FALSE, inputPitch, inputYaw} }
50 };
51
52 @interface HUD ()
53 ControlData *controlData;
54 ARDroneHUDConfiguration config;
55 bool_t acceleroEnabled, combinedYawEnabled;
56 CONTROL_MODE controlMode;
57 float accelero[3];
58 float accelero_rotation[3][3];
59 UIAccelerationValue lastX, lastY, lastZ;
60 double lowPassFilterConstant, highPassFilterConstant;
61 BOOL accelerometer_started;
62 CGPoint joystickRightCurrentPosition, joystickLeftCurrentPosition;
63 CGPoint joystickRightInitialPosition, joystickLeftInitialPosition;
64 BOOL buttonRightPressed, buttonLeftPressed;
65 CGPoint rightCenter, leftCenter;
66 float tmp_phi, tmp_theta;
67 BOOL screenOrientationRight;
68 float alpha;
69 SystemSoundID plop_id, batt_id;
70 FILE *mesures_file;
71 BOOL running;
72
73 BOOL compiledForIPad;
74 BOOL usingIPad;
75 BOOL using2xInterface;
76
77
78 #if TARGET_IPHONE_SIMULATOR == 1
79 NSTimer *timer;
80 - (void)simulate_accelerometer:(id)sender;
81 #else
82
83 - (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration;
84 #endif
85 - (void)setAcceleroRotationWithPhi:(float)phi withTheta:(float)theta withPsi:(float)psi;
86 - (void)refreshJoystickRight;
87 - (void)refreshJoystickLeft;
88 - (void)updateVelocity:(CGPoint)point isRight:(BOOL)isRight;
89 - (void)hideInfos;
90 - (void)showInfos;
91 - (void)refreshControlInterface;
92 @end
93
94 @implementation HUD
95 @synthesize firePressed;
96 @synthesize settingsPressed;
97 @synthesize mainMenuPressed;
98
99 - (id)initWithFrame:(CGRect)frame withState:(BOOL)inGame withHUDConfiguration:(ARDroneHUDConfiguration)hudconfiguration withControlData:(ControlData*)data
100 {
101         NSArray *targetArray = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UIDeviceFamily"];
102         compiledForIPad = NO;
103         for (int i = 0; i < [targetArray count]; i++)
104         {
105                 NSNumber* num = (NSNumber*)[targetArray objectAtIndex:i];
106                 int value;
107                 [num getValue:&value];
108                 if (2 == value)
109                 {
110                         compiledForIPad = YES;
111                         break;
112                 }
113         }
114         
115         usingIPad = NO;
116         if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
117         {
118                 usingIPad = YES;
119         }
120         
121         using2xInterface = NO;
122         if ([UIScreen instancesRespondToSelector:@selector(scale)]) {
123                 CGFloat scale = [[UIScreen mainScreen] scale];
124                 if (scale > 1.0) {
125                         using2xInterface = YES;
126                 }
127         }       
128         
129         if (usingIPad && compiledForIPad)
130         {
131                 self = [super initWithNibName:@"HUD-iPad" bundle:nil];
132         }
133         else
134         {
135                 self = [super initWithNibName:@"HUD" bundle:nil];
136         }
137         NSLog(@"HUD frame => w : %f, h : %f", data, frame.size.width, frame.size.height);
138         if(self)
139         {
140                 controlData = data;
141                 running = inGame;
142                 firePressed = NO;
143                 settingsPressed = NO;
144                 mainMenuPressed = NO;
145                 
146                 vp_os_memcpy(&config, &hudconfiguration, sizeof(ARDroneHUDConfiguration));
147                 
148                 acceleroEnabled = TRUE;
149                 combinedYawEnabled = FALSE;
150                 controlMode = CONTROL_MODE3;
151                 buttonRightPressed = buttonLeftPressed = NO;
152                 
153                 rightCenter = CGPointZero;      
154                 leftCenter = CGPointZero;
155                 lowPassFilterConstant = 0.2;
156                 highPassFilterConstant = (1.0 / 5.0) / ((1.0 / kAPS) + (1.0 / 5.0));
157                 
158                 joystickRightInitialPosition = CGPointZero;
159                 joystickRightCurrentPosition = CGPointZero;
160                 joystickLeftInitialPosition = CGPointZero;
161                 joystickLeftCurrentPosition = CGPointZero;
162                 
163                 accelero[0] = 0.0;
164                 accelero[1] = 0.0;
165                 accelero[2] = 0.0;
166                 
167                 tmp_phi = 0.0;
168                 tmp_theta = 0.0;
169                 
170                 [self setAcceleroRotationWithPhi:0.0 withTheta:0.0 withPsi:0.0];
171                 
172                 accelerometer_started = NO;
173
174 #if TARGET_IPHONE_SIMULATOR == 1
175                 [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)(1.0 / kAPS) target:self selector:@selector(simulate_accelerometer:) userInfo:nil repeats:YES];
176 #else
177                 [[UIAccelerometer sharedAccelerometer] setUpdateInterval: (NSTimeInterval)(1.0 / kAPS)];
178                 [[UIAccelerometer sharedAccelerometer] setDelegate:self];
179 #endif          
180
181 #ifdef WRITE_DEBUG_ACCELERO     
182                 char filename[128];
183                 NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0];
184                 sprintf(filename, "%s/accelero_iphones_mesures.txt",
185                                 [documentsDirectory cStringUsingEncoding:NSUTF8StringEncoding]);
186                 mesures_file = fopen(filename, "wb");
187                 fprintf(mesures_file, "ARDrone\nNumSamples;AccEnable;AccXbrut;AccYbrut;AccZbrut;AccX;AccY;AccZ;PhiAngle;ThetaAngle;AlphaAngle\n");
188 #endif
189         }
190
191         return self;
192 }
193
194 - (void) setAcceleroRotationWithPhi:(float)phi withTheta:(float)theta withPsi:(float)psi
195 {       
196         accelero_rotation[0][0] = cosf(psi)*cosf(theta);
197         accelero_rotation[0][1] = -sinf(psi)*cosf(phi) + cosf(psi)*sinf(theta)*sinf(phi);
198         accelero_rotation[0][2] = sinf(psi)*sinf(phi) + cosf(psi)*sinf(theta)*cosf(phi);
199         accelero_rotation[1][0] = sinf(psi)*cosf(theta);
200         accelero_rotation[1][1] = cosf(psi)*cosf(phi) + sinf(psi)*sinf(theta)*sinf(phi);
201         accelero_rotation[1][2] = -cosf(psi)*sinf(phi) + sinf(psi)*sinf(theta)*cosf(phi);
202         accelero_rotation[2][0] = -sinf(theta);
203         accelero_rotation[2][1] = cosf(theta)*sinf(phi);
204         accelero_rotation[2][2] = cosf(theta)*cosf(phi);
205
206 #ifdef WRITE_DEBUG_ACCELERO     
207         NSLog(@"Accelero rotation matrix changed :"); 
208         NSLog(@"%0.1f %0.1f %0.1f", accelero_rotation[0][0], accelero_rotation[0][1], accelero_rotation[0][2]);
209         NSLog(@"%0.1f %0.1f %0.1f", accelero_rotation[1][0], accelero_rotation[1][1], accelero_rotation[1][2]);
210         NSLog(@"%0.1f %0.1f %0.1f", accelero_rotation[2][0], accelero_rotation[2][1], accelero_rotation[2][2]); 
211 #endif
212 }
213
214 #if TARGET_IPHONE_SIMULATOR == 1
215 - (void)simulate_accelerometer:(id)sender
216 {
217         UIAcceleration *acceleration = [[UIAcceleration alloc] init];
218 #else
219 - (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
220 {               
221 #endif
222         static double highPassFilterX = 0.0, highPassFilterY = 0.0, highPassFilterZ = 0.0;
223         static bool_t prev_accelero_enabled = TRUE;
224         float norm, alpha;
225         float accelerox, acceleroy, acceleroz;
226         highPassFilterX = highPassFilterConstant * (highPassFilterX + acceleration.x - lastX);
227         highPassFilterY = highPassFilterConstant * (highPassFilterY + acceleration.y - lastY);
228         highPassFilterZ = highPassFilterConstant * (highPassFilterZ + acceleration.z - lastZ);
229         lastX = acceleration.x;
230         lastY = acceleration.y;
231         lastZ = acceleration.z;
232         
233         if(running)
234         {
235                 if(fabs(highPassFilterX) > ACCELERO_FASTMOVE_THRESHOLD || 
236                    fabs(highPassFilterY) > ACCELERO_FASTMOVE_THRESHOLD || 
237                    fabs(highPassFilterZ) > ACCELERO_FASTMOVE_THRESHOLD)
238                 {
239                         firePressed = YES;
240                 }
241                 else
242                 {
243                         firePressed = NO;
244                                         
245                         if(acceleroEnabled)
246                         {
247                                 if(screenOrientationRight)
248                                 {
249                                         accelerox = acceleration.x;
250                                         acceleroy = -acceleration.y;
251                                 }
252                                 else
253                                 {
254                                         accelerox = -acceleration.x;
255                                         acceleroy = acceleration.y;
256                                 }
257                                 acceleroz = -acceleration.z;
258                                 
259                                 // Initialize previous values of acceleros
260                                 if(accelerometer_started == NO)
261                                 {
262                                         accelerometer_started = YES;
263                                         accelero[0] = accelerox;
264                                         accelero[1] = acceleroy;
265                                         accelero[2] = acceleroz;
266                                 }               
267
268                                 // Apply low pass filter on acceleros
269                                 accelero[0] = accelerox * lowPassFilterConstant + accelero[0] * (1.0 - lowPassFilterConstant);
270                                 accelero[1] = acceleroy * lowPassFilterConstant + accelero[1] * (1.0 - lowPassFilterConstant);
271                                 accelero[2] = acceleroz * lowPassFilterConstant + accelero[2] * (1.0 - lowPassFilterConstant);
272
273                                 // Apply rotation matrix and Clamp
274                                 accelerox = Clamp((accelero_rotation[0][0] * accelero[0]) + (accelero_rotation[0][1] * accelero[1]) + (accelero_rotation[0][2] * accelero[2]), -1.0, 1.0);
275                                 acceleroy = Clamp((accelero_rotation[1][0] * accelero[0]) + (accelero_rotation[1][1] * accelero[1]) + (accelero_rotation[1][2] * accelero[2]), -1.0, 1.0);
276                                 acceleroz = Clamp((accelero_rotation[2][0] * accelero[0]) + (accelero_rotation[2][1] * accelero[1]) + (accelero_rotation[2][2] * accelero[2]), -1.0, 1.0);
277                                 
278                                 // compute
279                                 if(fabs(acceleroy) < ACCELERO_THRESHOLD)
280                                 {
281                                         if(accelerox >= 0.0)
282                                                 alpha = M_PI_2;
283                                         else    
284                                                 alpha = -M_PI_2;
285                                 }
286                                 else
287                                 {
288                                         alpha = atan2(accelerox, acceleroy);
289                                 }
290                                 
291                                 norm = Normalize(accelerox, acceleroy, 0.0);
292                                 if(norm > ACCELERO_NORM_THRESHOLD)
293                                 {
294                                         float tmp = (norm - ACCELERO_NORM_THRESHOLD) * (norm - ACCELERO_NORM_THRESHOLD);
295                                         controlData->accelero_phi = tmp * cosf(alpha);
296                                         controlData->accelero_theta = -tmp * sinf(alpha);
297                                 }
298                                 else
299                                 {
300                                         controlData->accelero_phi = 0.0;
301                                         controlData->accelero_theta = 0.0;
302                                 }
303                         }
304                         else if(prev_accelero_enabled != acceleroEnabled)
305                         {
306                                 controlData->accelero_phi = 0.0;
307                                 controlData->accelero_theta = 0.0;
308                         }
309                         
310                         prev_accelero_enabled = acceleroEnabled;
311                         sendControls();
312                 }
313         }       
314 }
315
316 - (void)refreshJoystickRight
317 {
318         CGRect frame = joystickRightBackgroundImageView.frame;
319         frame.origin = joystickRightCurrentPosition;
320         joystickRightBackgroundImageView.frame = frame;
321 }    
322
323 - (void)refreshJoystickLeft
324 {
325         CGRect frame = joystickLeftBackgroundImageView.frame;
326         frame.origin = joystickLeftCurrentPosition;
327         joystickLeftBackgroundImageView.frame = frame;
328 }    
329
330 - (void)refreshControlInterface
331 {
332         if(acceleroEnabled)
333         {
334                 switch (controlMode) {
335                         case CONTROL_MODE2:
336                                 joystickLeftBackgroundImageView.hidden = NO;
337                                 joystickRightBackgroundImageView.hidden = YES;
338                                 break;
339                                 
340                         case CONTROL_MODE3:
341                         default:
342                                 joystickLeftBackgroundImageView.hidden = YES;
343                                 joystickRightBackgroundImageView.hidden = NO;
344                                 break;
345                 }
346         }
347         else
348         {
349                 joystickLeftBackgroundImageView.hidden = NO;
350                 joystickRightBackgroundImageView.hidden = NO;
351         }
352
353         [self refreshJoystickRight];
354         [self refreshJoystickLeft];
355 }
356         
357 - (void)changeState:(BOOL)inGame
358 {
359         printf("%s - running : %d, inGame : %d\n", __FUNCTION__, running, inGame);
360         running = inGame;
361         if(!inGame)
362         {
363                 if(buttonRightPressed)
364                         [joystickRightButton sendActionsForControlEvents:UIControlEventTouchCancel];
365                 
366                 if(buttonLeftPressed)
367                         [joystickLeftButton sendActionsForControlEvents:UIControlEventTouchCancel];
368         }
369 }
370
371 - (void)acceleroValueChanged:(bool_t)enabled
372 {
373         acceleroEnabled = enabled;
374         [self performSelectorOnMainThread:@selector(refreshControlInterface) withObject:nil waitUntilDone:YES];
375 }
376
377 - (void)combinedYawValueChanged:(bool_t)enabled
378 {
379         combinedYawEnabled = enabled;
380         [self performSelectorOnMainThread:@selector(refreshControlInterface) withObject:nil waitUntilDone:YES];
381 }
382         
383 - (void)interfaceAlphaValueChanged:(CGFloat)value
384 {
385         joystickRightThumbImageView.alpha = value;
386         joystickRightBackgroundImageView.alpha = value;
387         joystickLeftThumbImageView.alpha = value;
388         joystickLeftBackgroundImageView.alpha = value;
389         alpha = value;
390 }
391         
392 - (void)controlModeChanged:(CONTROL_MODE)mode
393 {
394         controlMode = mode;
395         [self performSelectorOnMainThread:@selector(refreshControlInterface) withObject:nil waitUntilDone:YES];
396 }
397
398 - (void)updateVelocity:(CGPoint)point isRight:(BOOL)isRight
399 {
400         CGPoint nextpoint = CGPointMake(point.x, point.y);
401         CGPoint center = (isRight ? rightCenter : leftCenter);
402         UIImageView *backgroundImage = (isRight ? joystickRightBackgroundImageView : joystickLeftBackgroundImageView);
403         UIImageView *thumbImage = (isRight ? joystickRightThumbImageView : joystickLeftThumbImageView);
404         
405         // Calculate distance and angle from the center.
406         float dx = nextpoint.x - center.x;
407         float dy = nextpoint.y - center.y;
408         
409         float distance = sqrt(dx * dx + dy * dy);
410         float angle = atan2(dy, dx); // in radians
411         
412         // NOTE: Velocity goes from -1.0 to 1.0.
413         // BE CAREFUL: don't just cap each direction at 1.0 since that
414         // doesn't preserve the proportions.
415         float joystick_radius = backgroundImage.frame.size.width / 2;
416         if (distance > joystick_radius) {
417                 dx = cos(angle) * joystick_radius;
418                 dy = sin(angle) * joystick_radius;
419         }
420         
421         // Constrain the thumb so that it stays within the joystick
422         // boundaries.  This is smaller than the joystick radius in
423         // order to account for the size of the thumb.
424         float thumb_radius = thumbImage.frame.size.width / 2;
425         if (distance > thumb_radius) {
426                 nextpoint.x = center.x + (cos(angle) * thumb_radius);
427                 nextpoint.y = center.y + (sin(angle) * thumb_radius);
428         }
429         
430         // Update the thumb's position
431         CGRect frame = thumbImage.frame;
432         frame.origin.x = nextpoint.x - (thumbImage.frame.size.width / 2);
433         frame.origin.y = nextpoint.y - (thumbImage.frame.size.height / 2);      
434         thumbImage.frame = frame;
435 }
436         
437 - (void)setMessageBox:(NSString*)str
438 {
439         static int prevSound = 0;
440         [messageBoxLabel performSelectorOnMainThread:@selector(setText:) withObject:str waitUntilDone:YES];
441         
442         struct timeval nowSound;
443         gettimeofday(&nowSound, NULL);
444         if (([str compare:ARDroneEngineLocalizeString(@"BATTERY LOW ALERT")] == NSOrderedSame) &&
445                 2 < (nowSound.tv_sec - prevSound))
446         {
447                 AudioServicesPlaySystemSound(batt_id);
448                 prevSound = nowSound.tv_sec;
449         }
450 }
451
452 - (void)setTakeOff:(NSString*)str
453 {
454         UIImage *image = [UIImage imageNamed:[str stringByAppendingString:@".png"]];
455         [takeOffButton setImage:image forState:UIControlStateNormal];
456 }
457
458 - (void)setEmergency:(NSString*)str
459 {
460         if([str length] != 0)
461         {
462                 UIImage *image = [UIImage imageNamed:[str stringByAppendingString:@".png"]];
463                 emergencyButton.enabled = TRUE;
464                 emergencyButton.alpha = 1.0;
465                 [emergencyButton setImage:image forState:UIControlStateNormal];
466         }
467         else
468         {
469                 emergencyButton.enabled = FALSE;
470                 emergencyButton.alpha = 0.5;
471         }
472 }
473
474 - (void)hideInfos
475 {
476         batteryLevelLabel.hidden = YES;
477         batteryImageView.hidden = YES;  
478 }
479
480 - (void)showInfos
481 {
482         batteryLevelLabel.hidden = (config.enableBatteryPercentage == NO);
483         batteryImageView.hidden = NO;
484 }
485         
486         
487 - (void)enableBackToMainMenu
488 {
489         backToMainMenuButton.enabled = YES;
490         backToMainMenuButton.alpha = 1.0;
491 }
492
493 - (void)disableBackToMainMenu
494 {
495         backToMainMenuButton.enabled = NO;
496         backToMainMenuButton.alpha = 0.0;
497 }
498         
499 - (void)showBackToMainMenu:(BOOL)show
500 {
501         if(show)
502                 [self performSelectorOnMainThread:@selector(enableBackToMainMenu) withObject:nil waitUntilDone:YES];
503         else
504                 [self performSelectorOnMainThread:@selector(disableBackToMainMenu) withObject:nil waitUntilDone:YES];
505 }
506
507 - (void)setBattery:(int)percent
508 {
509         if(percent < 0)
510         {
511                 [self performSelectorOnMainThread:@selector(hideInfos) withObject:nil waitUntilDone:YES];               
512         }
513         else
514         {
515                 UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"battery%d.png", ((percent < 10) ? 0 : (int)((percent / 33.4) + 1))]];
516                 [batteryImageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
517                 
518                 [self performSelectorOnMainThread:@selector(showInfos) withObject:nil waitUntilDone:YES];               
519                 
520                 [batteryLevelLabel performSelectorOnMainThread:@selector(setTextColor:) withObject:((percent < 10) ? [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.7] : [UIColor colorWithRed:0.0 green:0.65 blue:0.0 alpha:0.7]) waitUntilDone:YES];            
521                 [batteryLevelLabel performSelectorOnMainThread:@selector(setText:) withObject:[NSString stringWithFormat:@"%d %%", percent] waitUntilDone:YES];
522         }
523 }
524
525 - (IBAction)buttonPress:(id)sender forEvent:(UIEvent *)event 
526 {
527         UITouch *touch = [[event touchesForView:sender] anyObject];
528         CGPoint point = [touch locationInView:self.view];
529         bool_t acceleroModeOk = NO;
530
531         if(sender == joystickRightButton)
532         {
533                 buttonRightPressed = YES;
534                 // Start only if the first touch is within the pad's boundaries.
535                 // Allow touches to be tracked outside of the pad as long as the
536                 // screen continues to be pressed.
537                 BOOL joystickIsOutside =  ((point.x + (joystickRightBackgroundImageView.frame.size.width / 2) > (joystickRightButton.frame.origin.x + joystickRightButton.frame.size.width)) ||
538                                                                    (point.x - (joystickRightBackgroundImageView.frame.size.width / 2) < joystickRightButton.frame.origin.x) ||
539                                                                    (point.y + (joystickRightBackgroundImageView.frame.size.height / 2) > (joystickRightButton.frame.origin.y + joystickRightButton.frame.size.height)) ||
540                                                                    (point.y - (joystickRightBackgroundImageView.frame.size.height / 2) < joystickRightButton.frame.origin.y));
541                 
542                 if(joystickIsOutside)
543                 {
544                         AudioServicesPlaySystemSound(plop_id);
545                 }
546                 
547                 joystickRightCurrentPosition.x = point.x - (joystickRightBackgroundImageView.frame.size.width / 2);
548                 joystickRightCurrentPosition.y = point.y - (joystickRightBackgroundImageView.frame.size.height / 2);
549                 
550                 joystickRightBackgroundImageView.alpha = joystickRightThumbImageView.alpha = 1.0;
551
552                 // Refresh Joystick
553                 [self refreshJoystickRight];
554                 
555                 // Update center
556                 rightCenter = CGPointMake(joystickRightBackgroundImageView.frame.origin.x + (joystickRightBackgroundImageView.frame.size.width / 2), joystickRightBackgroundImageView.frame.origin.y + (joystickRightBackgroundImageView.frame.size.height / 2));
557         
558                 // Update velocity
559                 [self updateVelocity:rightCenter isRight:YES];
560                 
561                 acceleroModeOk = controls_table[controlMode].Right.can_use_accelero;
562                 
563                 if(combinedYawEnabled && buttonLeftPressed)
564                         controlData->accelero_flag |= (1 << ARDRONE_PROGRESSIVE_CMD_COMBINED_YAW_ACTIVE);
565         }
566         else if(sender == joystickLeftButton)
567         {
568                 buttonLeftPressed = YES;
569                 
570                 joystickLeftCurrentPosition.x = point.x - (joystickLeftBackgroundImageView.frame.size.width / 2);
571                 joystickLeftCurrentPosition.y = point.y - (joystickLeftBackgroundImageView.frame.size.height / 2);
572                 
573                 joystickLeftBackgroundImageView.alpha = joystickLeftThumbImageView.alpha = 1.0;
574                 
575                 // Refresh Joystick
576                 [self refreshJoystickLeft];
577                 
578                 // Update center
579                 leftCenter = CGPointMake(joystickLeftBackgroundImageView.frame.origin.x + (joystickLeftBackgroundImageView.frame.size.width / 2), joystickLeftBackgroundImageView.frame.origin.y + (joystickLeftBackgroundImageView.frame.size.height / 2));
580                 
581                 // Update velocity
582                 [self updateVelocity:leftCenter isRight:NO];
583
584                 acceleroModeOk = controls_table[controlMode].Left.can_use_accelero;
585                 if(combinedYawEnabled && buttonRightPressed)
586                         controlData->accelero_flag |= (1 << ARDRONE_PROGRESSIVE_CMD_COMBINED_YAW_ACTIVE);
587         }
588         
589         if(acceleroModeOk)
590         {
591                 controlData->accelero_flag |= (1 << ARDRONE_PROGRESSIVE_CMD_ENABLE);
592                 if(acceleroEnabled)
593                 {
594                         // Start only if the first touch is within the pad's boundaries.
595                         // Allow touches to be tracked outside of the pad as long as the
596                         // screen continues to be pressed.                      
597                         float phi, theta;
598                         phi = (float)atan2f(accelero[1], accelero[2]);
599                         theta = -(float)atan2f(accelero[0] * cosf(phi), accelero[2]);
600                         [self setAcceleroRotationWithPhi:phi withTheta:theta withPsi:0.0];
601                 }
602         }                       
603 }
604
605 - (IBAction)buttonRelease:(id)sender forEvent:(UIEvent *)event 
606 {
607         bool_t acceleroModeOk = NO;
608         if(sender == joystickRightButton)
609         {
610                 buttonRightPressed = NO;
611                 
612                 // Reinitialize joystick position
613                 joystickRightCurrentPosition = joystickRightInitialPosition;
614                 joystickRightBackgroundImageView.alpha = joystickRightThumbImageView.alpha = alpha;
615                 
616                 // Refresh joystick
617                 [self refreshJoystickRight];
618                 
619                 // Update center
620                 rightCenter = CGPointMake(joystickRightBackgroundImageView.frame.origin.x + (joystickRightBackgroundImageView.frame.size.width / 2), joystickRightBackgroundImageView.frame.origin.y + (joystickRightBackgroundImageView.frame.size.height / 2));
621                 
622                 // reset joystick
623                 [self updateVelocity:rightCenter isRight:YES];
624                 
625                 controls_table[controlMode].Right.up_down(0.0);
626                 controls_table[controlMode].Right.left_right(0.0);
627
628                 acceleroModeOk = controls_table[controlMode].Right.can_use_accelero;
629                 
630                 if(combinedYawEnabled)
631                         controlData->accelero_flag &= ~(1 << ARDRONE_PROGRESSIVE_CMD_COMBINED_YAW_ACTIVE);
632         }
633         else if(sender == joystickLeftButton)
634         {
635                 //printf("button left released\n");
636                 buttonLeftPressed = NO;
637                 // Reinitialize joystick position
638                 joystickLeftCurrentPosition = joystickLeftInitialPosition;
639                 joystickLeftBackgroundImageView.alpha = joystickLeftThumbImageView.alpha = alpha;
640                 
641                 // Refresh joystick
642                 [self refreshJoystickLeft];
643                 
644                 // Update center
645                 leftCenter = CGPointMake(joystickLeftBackgroundImageView.frame.origin.x + (joystickLeftBackgroundImageView.frame.size.width / 2), joystickLeftBackgroundImageView.frame.origin.y + (joystickLeftBackgroundImageView.frame.size.height / 2));
646                 
647                 // reset joystick
648                 [self updateVelocity:leftCenter isRight:NO];
649
650                 controls_table[controlMode].Left.up_down(0.0);
651                 controls_table[controlMode].Left.left_right(0.0);
652
653                 acceleroModeOk = controls_table[controlMode].Left.can_use_accelero;
654
655                 if(combinedYawEnabled)
656                         controlData->accelero_flag &= ~(1 << ARDRONE_PROGRESSIVE_CMD_COMBINED_YAW_ACTIVE);
657         }
658         
659         if(acceleroModeOk)
660         {
661                 controlData->accelero_flag &= ~(1 << ARDRONE_PROGRESSIVE_CMD_ENABLE);
662                 if(acceleroEnabled)
663                 {
664                         [self setAcceleroRotationWithPhi:0.0 withTheta:0.0 withPsi:0.0];
665                 }
666         }
667 }
668
669 - (IBAction)buttonDrag:(id)sender forEvent:(UIEvent *)event 
670 {
671         UITouch *touch = [[event touchesForView:sender] anyObject];
672         CGPoint point = [touch locationInView:self.view];
673         bool_t acceleroModeOk = NO;
674         
675         
676         float controlRatio = 0.5 - (CONTROL_RATIO / 2.0);
677         if (usingIPad && compiledForIPad)
678         {
679                 controlRatio = 0.5 - (CONTROL_RATIO_IPAD / 2.0);
680         }
681         
682         
683         
684         if(sender == joystickRightButton)
685         {
686                 if((rightCenter.x - point.x) > ((joystickRightBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.width)))
687                 {
688                         float percent = ((rightCenter.x - point.x) - ((joystickRightBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.width))) / ((controlRatio * joystickRightBackgroundImageView.frame.size.width));
689                         //NSLog(@"Percent (left)  : %f\n", percent);
690                         if(percent > 1.0)
691                                 percent = 1.0;
692                         controls_table[controlMode].Right.left_right(-percent);
693                 }
694                 else if((point.x - rightCenter.x) > ((joystickRightBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.width)))
695                 {
696                         float percent = ((point.x - rightCenter.x) - ((joystickRightBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.width))) / ((controlRatio * joystickRightBackgroundImageView.frame.size.width));
697                         //NSLog(@"Percent (right) : %f\n", percent);
698                         if(percent > 1.0)
699                                 percent = 1.0;
700                         controls_table[controlMode].Right.left_right(percent);
701                 }
702                 else
703                 {
704                         controls_table[controlMode].Right.left_right(0.0);
705                 }
706
707                 if((point.y - rightCenter.y) > ((joystickRightBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.height)))
708                 {
709                         float percent = ((point.y - rightCenter.y) - ((joystickRightBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.height))) / ((controlRatio * joystickRightBackgroundImageView.frame.size.height));
710                         //NSLog(@"Percent (down)  : %f\n", percent);
711                         if(percent > 1.0)
712                                 percent = 1.0;
713                         controls_table[controlMode].Right.up_down(-percent);
714                 }
715                 else if((rightCenter.y - point.y) > ((joystickRightBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.height)))
716                 {
717                         float percent = ((rightCenter.y - point.y) - ((joystickRightBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.height))) / ((controlRatio * joystickRightBackgroundImageView.frame.size.height));
718                         //NSLog(@"Percent (top)   : %f\n", percent);
719                         if(percent > 1.0)
720                                 percent = 1.0;
721                         controls_table[controlMode].Right.up_down(percent);
722                 }
723                 else
724                 {
725                         controls_table[controlMode].Right.up_down(0.0);
726                 }
727
728                 acceleroModeOk = controls_table[controlMode].Right.can_use_accelero;
729         }
730         else if(sender == joystickLeftButton)
731         {
732                 if((leftCenter.x - point.x) > ((joystickLeftBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.width)))
733                 {
734                         float percent = ((leftCenter.x - point.x) - ((joystickLeftBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.width))) / ((controlRatio * joystickLeftBackgroundImageView.frame.size.width));
735                         if(percent > 1.0)
736                                 percent = 1.0;
737                         controls_table[controlMode].Left.left_right(-percent);
738                 }
739                 else if((point.x - leftCenter.x) > ((joystickLeftBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.width)))
740                 {
741                         float percent = ((point.x - leftCenter.x) - ((joystickLeftBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.width))) / ((controlRatio * joystickLeftBackgroundImageView.frame.size.width));
742                         if(percent > 1.0)
743                                 percent = 1.0;
744                         controls_table[controlMode].Left.left_right(percent);
745                 }
746                 else
747                 {
748                         controls_table[controlMode].Left.left_right(0.0);
749                 }       
750                 
751                 if((point.y - leftCenter.y) > ((joystickLeftBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.height)))
752                 {
753                         float percent = ((point.y - leftCenter.y) - ((joystickLeftBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.height))) / ((controlRatio * joystickLeftBackgroundImageView.frame.size.height));
754                         if(percent > 1.0)
755                                 percent = 1.0;
756                         controls_table[controlMode].Left.up_down(-percent);
757                 }
758                 else if((leftCenter.y - point.y) > ((joystickLeftBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.height)))
759                 {
760                         float percent = ((leftCenter.y - point.y) - ((joystickLeftBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.height))) / ((controlRatio * joystickLeftBackgroundImageView.frame.size.height));
761                         if(percent > 1.0)
762                                 percent = 1.0;
763                         controls_table[controlMode].Left.up_down(percent);
764                 }
765                 else
766                 {
767                         controls_table[controlMode].Left.up_down(0.0);
768                 }               
769
770                 acceleroModeOk = controls_table[controlMode].Left.can_use_accelero;
771         }
772                 
773         if(acceleroModeOk)
774         {
775                 if(!acceleroEnabled)
776                 {
777                         // Update joystick velocity
778                         [self updateVelocity:point isRight:(sender == joystickRightButton)];
779                 }
780         }
781         else
782         {
783                 // Update joystick velocity
784                 [self updateVelocity:point isRight:(sender == joystickRightButton)];
785         }
786
787 }
788
789 - (IBAction)buttonClick:(id)sender forEvent:(UIEvent *)event 
790 {
791         static ARDRONE_VIDEO_CHANNEL channel = ARDRONE_VIDEO_CHANNEL_FIRST;
792         if(sender == settingsButton)
793                 settingsPressed = YES;
794         else if(sender == backToMainMenuButton)
795                 mainMenuPressed = YES;
796         else if(sender == switchScreenButton)
797         {
798                 if(channel++ == ARDRONE_VIDEO_CHANNEL_LAST)
799                         channel = ARDRONE_VIDEO_CHANNEL_FIRST;
800                 
801                 ARDRONE_TOOL_CONFIGURATION_ADDEVENT(video_channel, (int32_t*)&channel, NULL);
802         }
803         else if(sender == takeOffButton)
804         {
805                 switchTakeOff();
806         }
807         else if(sender == emergencyButton)
808         {
809                 emergency();
810         }
811 }
812
813 - (void)viewDidLoad
814 {
815         switchScreenButton.hidden = (config.enableSwitchScreen == NO);
816         backToMainMenuButton.hidden = (config.enableBackToMainMenu == NO);
817         batteryLevelLabel.hidden = (config.enableBatteryPercentage == NO);
818         
819         rightCenter = CGPointMake(joystickRightThumbImageView.frame.origin.x + (joystickRightThumbImageView.frame.size.width / 2), joystickRightThumbImageView.frame.origin.y + (joystickRightThumbImageView.frame.size.height / 2));
820         joystickRightInitialPosition = CGPointMake(rightCenter.x - (joystickRightBackgroundImageView.frame.size.width / 2), rightCenter.y - (joystickRightBackgroundImageView.frame.size.height / 2));
821         leftCenter = CGPointMake(joystickLeftThumbImageView.frame.origin.x + (joystickLeftThumbImageView.frame.size.width / 2), joystickLeftThumbImageView.frame.origin.y + (joystickLeftThumbImageView.frame.size.height / 2));
822         joystickLeftInitialPosition = CGPointMake(leftCenter.x - (joystickLeftBackgroundImageView.frame.size.width / 2), leftCenter.y - (joystickLeftBackgroundImageView.frame.size.height / 2));
823
824         joystickLeftCurrentPosition = joystickLeftInitialPosition;
825         joystickRightCurrentPosition = joystickRightInitialPosition;
826         
827         alpha = MIN(joystickRightBackgroundImageView.alpha, joystickRightThumbImageView.alpha);
828         joystickRightBackgroundImageView.alpha = joystickRightThumbImageView.alpha = alpha;
829         joystickLeftBackgroundImageView.alpha = joystickLeftThumbImageView.alpha = alpha;
830
831     // Get the URL to the sound file to play
832         CFURLRef batt_url  = CFBundleCopyResourceURL (CFBundleGetMainBundle(),
833                                                                                                    CFSTR ("battery"),
834                                                                                                    CFSTR ("wav"),
835                                                                                                   NULL);
836     CFURLRef plop_url  = CFBundleCopyResourceURL (CFBundleGetMainBundle(),
837                                                                                                    CFSTR ("plop"),
838                                                                                                    CFSTR ("wav"),
839                                                                                                    NULL);
840         
841     // Create a system sound object representing the sound file
842     AudioServicesCreateSystemSoundID (plop_url, &plop_id);
843     AudioServicesCreateSystemSoundID (batt_url, &batt_id);
844         CFRelease(plop_url);
845         CFRelease(batt_url);
846         
847         [self setBattery:-1];
848 }
849
850 - (void) dealloc 
851 {
852 #ifdef WRITE_DEBUG_ACCELERO
853         fclose(mesures_file);
854 #endif
855         AudioServicesDisposeSystemSoundID (plop_id);
856         AudioServicesDisposeSystemSoundID (batt_id);
857         [super dealloc];
858 }
859
860 @end