protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.Main); //force max brightness on screen. Window.Attributes.ScreenBrightness = 1f; //Full screen and hide nav bar. View decorView = Window.DecorView; var uiOptions = (int)decorView.SystemUiVisibility; var newUiOptions = (int)uiOptions; newUiOptions |= (int)SystemUiFlags.LowProfile; newUiOptions |= (int)SystemUiFlags.Fullscreen; newUiOptions |= (int)SystemUiFlags.HideNavigation; newUiOptions |= (int)SystemUiFlags.Immersive; // This option will make bars disappear by themselves newUiOptions |= (int)SystemUiFlags.ImmersiveSticky; decorView.SystemUiVisibility = (StatusBarVisibility)newUiOptions; //Keep screen from dimming. this.Window.SetFlags(WindowManagerFlags.KeepScreenOn, WindowManagerFlags.KeepScreenOn); onScreenJoyL = FindViewById <JoystickView>(Resource.Id.joystickViewL); onScreenJoyR = FindViewById <JoystickView>(Resource.Id.joystickViewR); takeoffButton = FindViewById <ImageButton>(Resource.Id.takeoffButton); throwTakeoffButton = FindViewById <ImageButton>(Resource.Id.throwTakeoffButton); rthButton = FindViewById <ImageButton>(Resource.Id.rthButton); //subscribe to Tello connection events Tello.onConnection += (Tello.ConnectionState newState) => { //Update state on screen Button cbutton = FindViewById <Button>(Resource.Id.connectButton); //If not connected check to see if connected to tello network. if (newState != Tello.ConnectionState.Connected && newState != Tello.ConnectionState.Paused) { WifiManager wifiManager = (WifiManager)Application.Context.GetSystemService(Context.WifiService); string ip = Formatter.FormatIpAddress(wifiManager.ConnectionInfo.IpAddress); if (!ip.StartsWith("192.168.10.")) { //CrossTextToSpeech.Current.Speak("No network found."); //Not connected to network. RunOnUiThread(() => { cbutton.Text = "Not Connected. Touch Here."; cbutton.SetBackgroundColor(Android.Graphics.Color.ParseColor("#55ff3333")); }); return; } } if (newState == Tello.ConnectionState.Paused) { } if (newState == Tello.ConnectionState.UnPausing) { } if (newState == Tello.ConnectionState.Connected) { //Tello.queryMaxHeight(); //Override max hei on connect. Tello.setMaxHeight(30);//meters Tello.queryMaxHeight(); //Tello.queryAttAngle(); Tello.setAttAngle(25); //Tello.queryAttAngle(); Tello.setJpgQuality(Preferences.jpgQuality); CrossTextToSpeech.Current.Speak("Connected"); Tello.setPicVidMode(picMode);//0=picture(960x720) //updateVideoSize(); Tello.setEV(Preferences.exposure); Tello.setVideoBitRate(Preferences.videoBitRate); Tello.setVideoDynRate(1); if (forceSpeedMode) { Tello.controllerState.setSpeedMode(1); } else { Tello.controllerState.setSpeedMode(0); } } if (newState == Tello.ConnectionState.Disconnected) { //if was connected then warn. if (Tello.connectionState == Tello.ConnectionState.Connected) { CrossTextToSpeech.Current.Speak("Disconnected"); } } //update connection state button. RunOnUiThread(() => { if (newState == Tello.ConnectionState.UnPausing)//Fix. Don't show "unpausing" string. { cbutton.Text = Tello.ConnectionState.Connected.ToString(); } else { cbutton.Text = newState.ToString(); } if (newState == Tello.ConnectionState.Connected || newState == Tello.ConnectionState.UnPausing) { cbutton.SetBackgroundColor(Android.Graphics.Color.ParseColor("#6090ee90"));//transparent light green. } else { cbutton.SetBackgroundColor(Android.Graphics.Color.ParseColor("#ffff00"));//yellow } }); }; var modeTextView = FindViewById <TextView>(Resource.Id.modeTextView); var hSpeedTextView = FindViewById <TextView>(Resource.Id.hSpeedTextView); var vSpeedTextView = FindViewById <TextView>(Resource.Id.vSpeedTextView); var heiTextView = FindViewById <TextView>(Resource.Id.heiTextView); var batTextView = FindViewById <TextView>(Resource.Id.batTextView); var wifiTextView = FindViewById <TextView>(Resource.Id.wifiTextView); //Log file setup. var logPath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, "aTello/logs/");; var logStartTime = DateTime.Now; var logFilePath = logPath + logStartTime.ToString("yyyy-dd-M--HH-mm-ss") + ".csv"; if (doStateLogging) { //write header for cols in log. System.IO.Directory.CreateDirectory(logPath); File.WriteAllText(logFilePath, "time," + Tello.state.getLogHeader()); } //Long click vert speed to force fast mode. hSpeedTextView.LongClick += delegate { forceSpeedMode = !forceSpeedMode; if (forceSpeedMode) { Tello.controllerState.setSpeedMode(1); } else { Tello.controllerState.setSpeedMode(0); } }; cameraShutterSound.Load("cameraShutterClick.mp3"); //subscribe to Tello update events Tello.onUpdate += (int cmdId) => { if (doStateLogging) { //write update to log. var elapsed = DateTime.Now - logStartTime; File.AppendAllText(logFilePath, elapsed.ToString(@"mm\:ss\:ff\,") + Tello.state.getLogLine()); } RunOnUiThread(() => { if (cmdId == 86)//ac status update. { //Update state on screen modeTextView.Text = "FM:" + Tello.state.flyMode; hSpeedTextView.Text = string.Format("HS:{0: 0.0;-0.0}m/s", (float)Tello.state.flySpeed / 10); vSpeedTextView.Text = string.Format("VS:{0: 0.0;-0.0}m/s", -(float)Tello.state.verticalSpeed / 10);//Note invert so negative means moving down. heiTextView.Text = string.Format("Hei:{0: 0.0;-0.0}m", (float)Tello.state.height / 10); if (Tello.controllerState.speed > 0) { hSpeedTextView.SetBackgroundColor(Android.Graphics.Color.IndianRed); } else { hSpeedTextView.SetBackgroundColor(Android.Graphics.Color.DarkGreen); } batTextView.Text = "Bat:" + Tello.state.batteryPercentage; wifiTextView.Text = "Wifi:" + Tello.state.wifiStrength; //Autopilot debugging. if (/*!bAutopilot &&*/ Tello.state.flying) { RunOnUiThread(() => { var eular = Tello.state.toEuler(); var yaw = eular[2]; var deltaPosX = autopilotTarget.X - Tello.state.posX; var deltaPosY = autopilotTarget.Y - Tello.state.posY; var dist = Math.Sqrt(deltaPosX * deltaPosX + deltaPosY * deltaPosY); var normalizedX = deltaPosX / dist; var normalizedY = deltaPosY / dist; var targetYaw = Math.Atan2(normalizedY, normalizedX); var deltaYaw = targetYaw - yaw; var str = string.Format("x {0:0.00; -0.00} y {1:0.00; -0.00} yaw {2:0.00; -0.00} targetYaw {3:0.00; -0.00} targetDist {4:0.00; -0.00} On:{5}", Tello.state.posX, Tello.state.posY, (((yaw * (180.0 / Math.PI)) + 360.0) % 360.0), (((targetYaw * (180.0 / Math.PI)) + 360.0) % 360.0), dist, bAutopilot.ToString()); TextView joystat = FindViewById <TextView>(Resource.Id.joystick_state); joystat.Text = str; }); } //acstat.Text = str; if (Tello.state.flying) { takeoffButton.SetImageResource(Resource.Drawable.land); } else if (!Tello.state.flying) { takeoffButton.SetImageResource(Resource.Drawable.takeoff_white); } } if (cmdId == 48)//ack picture start. { cameraShutterSound.Play(); } if (cmdId == 98)//start picture download. { } if (cmdId == 100) //picture piece downloaded. { if (Tello.picDownloading == false) //if done downloading. { if (remainingExposures >= 0) { var exposureSet = new int[] { 0, -2, 8 }; Tello.setEV(Preferences.exposure + exposureSet[remainingExposures]); remainingExposures--; Tello.takePicture(); } if (remainingExposures == -1)//restore exposure. { Tello.setEV(Preferences.exposure); } } } }); //Do autopilot input. handleAutopilot(); }; var videoFrame = new byte[100 * 1024]; var videoOffset = 0; updateVideoSize(); Video.Decoder.surface = FindViewById <SurfaceView>(Resource.Id.surfaceView).Holder.Surface; /* * var textureView = FindViewById<TextureView>(Resource.Id.textureView); * mSurfaceTextureListener = new SurfaceTextureListener(this); * textureView.SurfaceTextureListener = mSurfaceTextureListener; * * //var st = new Surface(textureView.SurfaceTexture); * //Video.Decoder.surface = st; * */ var path = "aTello/video/"; System.IO.Directory.CreateDirectory(Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, path + "cache/")); videoFilePath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, path + "cache/" + DateTime.Now.ToString("MMMM dd yyyy HH-mm-ss") + ".h264"); FileStream videoStream = null; startUIUpdateThread(); //updateUI();//hide record light etc. //subscribe to Tello video data var vidCount = 0; Tello.onVideoData += (byte[] data) => { totalVideoBytesReceived += data.Length; //Handle recording. if (true) //videoFilePath != null) { if (data[2] == 0 && data[3] == 0 && data[4] == 0 && data[5] == 1) //if nal { var nalType = data[6] & 0x1f; // if (nalType == 7 || nalType == 8) { if (toggleRecording) { if (videoStream != null) { videoStream.Close(); } videoStream = null; isRecording = !isRecording; toggleRecording = false; if (isRecording) { videoFilePath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, path + DateTime.Now.ToString("MMMM dd yyyy HH-mm-ss") + ".h264"); startRecordingTime = DateTime.Now; // Tello.setVideoRecord(vidCount++); CrossTextToSpeech.Current.Speak("Recording"); updateUI(); } else { videoFilePath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, path + "cache/" + DateTime.Now.ToString("MMMM dd yyyy HH-mm-ss") + ".h264"); CrossTextToSpeech.Current.Speak("Recording stopped"); updateUI(); } } } } if ((isRecording || Preferences.cacheVideo)) { if (videoStream == null) { videoStream = new FileStream(videoFilePath, FileMode.Append); } if (videoStream != null) { //Save raw data minus sequence. videoStream.Write(data, 2, data.Length - 2);//Note remove 2 byte seq when saving. } } } //Handle video display. if (true)//video decoder tests. { //Console.WriteLine("1"); if (data[2] == 0 && data[3] == 0 && data[4] == 0 && data[5] == 1)//if nal { var nalType = data[6] & 0x1f; if (nalType == 7 || nalType == 8) { } if (videoOffset > 0) { aTello.Video.Decoder.decode(videoFrame.Take(videoOffset).ToArray()); videoOffset = 0; } //var nal = (received.bytes[6] & 0x1f); //if (nal != 0x01 && nal != 0x07 && nal != 0x08 && nal != 0x05) // Console.WriteLine("NAL type:" + nal); } //todo. resquence frames. Array.Copy(data, 2, videoFrame, videoOffset, data.Length - 2); videoOffset += (data.Length - 2); } }; onScreenJoyL.onUpdate += OnTouchJoystickMoved; onScreenJoyR.onUpdate += OnTouchJoystickMoved; Tello.startConnecting();//Start trying to connect. //Clicking on network state button will show wifi connection page. Button button = FindViewById <Button>(Resource.Id.connectButton); button.Click += delegate { WifiManager wifiManager = (WifiManager)Application.Context.GetSystemService(Context.WifiService); string ip = Formatter.FormatIpAddress(wifiManager.ConnectionInfo.IpAddress); if (!ip.StartsWith("192.168.10."))//Already connected to network? { StartActivity(new Intent(Android.Net.Wifi.WifiManager.ActionPickWifiNetwork)); } }; rthButton.LongClick += delegate { bAutopilot = !bAutopilot;//Toggle autopilot }; rthButton.Click += delegate { bAutopilot = false;//Stop if going. Tello.controllerState.setAxis(0, 0, 0, 0); Tello.sendControllerUpdate(); //set new home point setAutopilotTarget(new PointF(Tello.state.posX, Tello.state.posY)); }; takeoffButton.LongClick += delegate { if (Tello.connected && !Tello.state.flying) { Tello.takeOff(); } else if (Tello.connected && Tello.state.flying) { Tello.land(); } }; throwTakeoffButton.LongClick += delegate { if (Tello.connected && !Tello.state.flying) { Tello.throwTakeOff(); } else if (Tello.connected && Tello.state.flying) { //Tello.land(); } }; var pictureButton = FindViewById <ImageButton>(Resource.Id.pictureButton); Tello.picPath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, "aTello/pics/"); System.IO.Directory.CreateDirectory(Tello.picPath); pictureButton.Click += delegate { remainingExposures = -1; Tello.takePicture(); }; /* * Multiple exposure. Not working yet. * pictureButton.LongClick += delegate * { * remainingExposures = 2; * Tello.takePicture(); * }; */ var recordButton = FindViewById <ImageButton>(Resource.Id.recordButton); recordButton.Click += delegate { toggleRecording = true; }; recordButton.LongClick += delegate { //Toggle picMode = picMode == 1 ? 0 : 1; Tello.setPicVidMode(picMode); updateVideoSize(); aTello.Video.Decoder.reconfig(); }; var galleryButton = FindViewById <ImageButton>(Resource.Id.galleryButton); galleryButton.Click += async delegate { //var uri = Android.Net.Uri.FromFile(new Java.IO.File(Tello.picPath)); //shareImage(uri); //return; Intent intent = new Intent(); intent.PutExtra(Intent.ActionView, Tello.picPath); intent.SetType("image/*"); intent.SetAction(Intent.ActionGetContent); StartActivityForResult(Intent.CreateChooser(intent, "Select Picture"), 1); }; //Settings button ImageButton settingsButton = FindViewById <ImageButton>(Resource.Id.settingsButton); settingsButton.Click += delegate { StartActivity(typeof(SettingsActivity)); }; //Init joysticks. input_manager = (InputManager)GetSystemService(Context.InputService); CheckGameControllers(); }