private void Tello_onConnection(Tello.ConnectionState newState) { if (newState == Tello.ConnectionState.Connected) { Debug.Log("Connected to Tello, please wait for camera feed"); Tello.setPicVidMode(1); // 0: picture, 1: video Tello.setVideoBitRate((int)TelloController.VideoBitRate.VideoBitRateAuto); Tello.requestIframe(); } }
private void Tello_onConnection(Tello.ConnectionState newState) { //throw new System.NotImplementedException(); //Debug.Log("Tello_onConnection : " + newState); if (newState == Tello.ConnectionState.Connected) { Tello.setPicVidMode(1); // 0: picture, 1: video Tello.setVideoBitRate((int)Tello.VideoBitRate.VideoBitRateAuto); //Tello.setEV(0); Tello.requestIframe(); } }
protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); this.RequestWindowFeature(WindowFeatures.NoTitle); this.Window.AddFlags(WindowManagerFlags.Fullscreen | WindowManagerFlags.TurnScreenOn); SetContentView(Resource.Layout.Settings); var items = new List <int>() { 0, 1, 2, 3, 4, 5, 6 }; var axisAdapter = new ArrayAdapter <int>(this, Android.Resource.Layout.SimpleSpinnerItem, items); var spinner = FindViewById <Spinner>(Resource.Id.lxSpinner); spinner.Adapter = axisAdapter; spinner.SetSelection(Preferences.lxAxis); spinner.ItemSelected += (sender, args) => { Preferences.lxAxis = args.Position; Preferences.save(); }; spinner = FindViewById <Spinner>(Resource.Id.lySpinner); spinner.Adapter = axisAdapter; spinner.SetSelection(Preferences.lyAxis); spinner.ItemSelected += (sender, args) => { Preferences.lyAxis = args.Position; Preferences.save(); }; spinner = FindViewById <Spinner>(Resource.Id.rxSpinner); spinner.Adapter = axisAdapter; spinner.SetSelection(Preferences.rxAxis); spinner.ItemSelected += (sender, args) => { Preferences.rxAxis = args.Position; Preferences.save(); }; spinner = FindViewById <Spinner>(Resource.Id.rySpinner); spinner.Adapter = axisAdapter; spinner.SetSelection(Preferences.ryAxis); spinner.ItemSelected += (sender, args) => { Preferences.ryAxis = args.Position; Preferences.save(); }; var joyItems = new List <string>() { "Generic", "PS3/PS4" }; var joyAdapter = new ArrayAdapter <string>(this, Android.Resource.Layout.SimpleSpinnerItem, joyItems); var joyTypeSpinner = FindViewById <Spinner>(Resource.Id.joystickTypeSpinner); joyTypeSpinner.Adapter = joyAdapter; joyTypeSpinner.SetSelection(Preferences.joyType); joyTypeSpinner.ItemSelected += (sender, args) => { Preferences.setJoyType(args.Position); Preferences.save(); }; var evItems = new List <double>() { -3.0, -2.7, -2.3, -2.0, -1.7, -1.3, -1.0, -0.7, -0.3, 0, 0.3, 0.7, 1.0, 1.3, 1.7, 2.0, 2.3, 2.7, 3.0 }; var evAdapter = new ArrayAdapter <double>(this, Android.Resource.Layout.SimpleSpinnerItem, evItems); var evSpinner = FindViewById <Spinner>(Resource.Id.exposureSpinner); evSpinner.Adapter = evAdapter; evSpinner.SetSelection(Preferences.exposure); evSpinner.ItemSelected += (sender, args) => { Preferences.exposure = args.Position; Tello.setEV(Preferences.exposure); Preferences.save(); }; var vbrItems = new List <string>() { "Auto", "1M", "1.5M", "2M", "3M", "4M", "5", "6" }; var vbrAdapter = new ArrayAdapter <string>(this, Android.Resource.Layout.SimpleSpinnerItem, vbrItems); var vbrSpinner = FindViewById <Spinner>(Resource.Id.vbrSpinner); vbrSpinner.Adapter = vbrAdapter; vbrSpinner.SetSelection(Preferences.videoBitRate); vbrSpinner.ItemSelected += (sender, args) => { Preferences.videoBitRate = args.Position; Tello.setVideoBitRate(Preferences.videoBitRate); Preferences.save(); }; //2,5,10,20,40 var iframeRateItems = new List <string>() { "10/s", "4/s", "2/s", "1/s", "0.5/s" }; var iframeRateAdapter = new ArrayAdapter <string>(this, Android.Resource.Layout.SimpleSpinnerItem, iframeRateItems); var iframeRateSpinner = FindViewById <Spinner>(Resource.Id.iframeRateSpinner); iframeRateSpinner.Adapter = iframeRateAdapter; switch (Preferences.iFrameRate) { case 2: iframeRateSpinner.SetSelection(0); break; case 5: iframeRateSpinner.SetSelection(1); break; case 10: iframeRateSpinner.SetSelection(2); break; case 20: iframeRateSpinner.SetSelection(3); break; case 40: iframeRateSpinner.SetSelection(4); break; } iframeRateSpinner.ItemSelected += (sender, args) => { switch (args.Position) { case 0: Preferences.iFrameRate = 2; break; case 1: Preferences.iFrameRate = 5; break; case 2: Preferences.iFrameRate = 10; break; case 3: Preferences.iFrameRate = 20; break; case 4: Preferences.iFrameRate = 40; break; } Tello.iFrameRate = Preferences.iFrameRate; Preferences.save(); }; var cacheVideoSwitch = FindViewById <Switch>(Resource.Id.cacheVideoSwitch); cacheVideoSwitch.Checked = Preferences.cacheVideo; cacheVideoSwitch.CheckedChange += (sender, args) => { Preferences.cacheVideo = args.IsChecked; Preferences.save(); }; var photoQualitySwitch = FindViewById <Switch>(Resource.Id.photoQualitySwitch); photoQualitySwitch.Checked = Preferences.jpgQuality > 0; photoQualitySwitch.CheckedChange += (sender, args) => { Preferences.jpgQuality = args.IsChecked ? 1 : 0; Preferences.save(); Tello.setJpgQuality(Preferences.jpgQuality); }; //Settings button Button convertVideoButton = FindViewById <Button>(Resource.Id.convertVideoButton); convertVideoButton.Click += async delegate { if (true) { try { FileData fileData = await CrossFilePicker.Current.PickFile(); if (fileData == null) { return; // user canceled file picking } string fileName = fileData.FileName; //string contents = System.Text.Encoding.UTF8.GetString(fileData.DataArray); Console.WriteLine(fileData.FilePath); System.Console.WriteLine("File name chosen: " + fileName); //System.Console.WriteLine("File data: " + contents); RunOnUiThread(async() => { var videoConverter = new aTello.VideoConverter(); var result = await videoConverter.ConvertFileAsync(this, new Java.IO.File(fileData.FilePath)); Toast.MakeText(Application.Context, "Video Converted. Result:" + result, ToastLength.Long).Show(); }); } catch (Exception ex) { System.Console.WriteLine("Exception choosing file: " + ex.ToString()); } return; } }; Button convertAllVideoButton = FindViewById <Button>(Resource.Id.convertAllVideoButton); convertAllVideoButton.Click += async delegate { var path = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, "aTello/video/"); Java.IO.File f = new Java.IO.File(path); var files = f.ListFiles().ToList(); //append cache files to list. path = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, "aTello/video/cache"); f = new Java.IO.File(path); files.AddRange(f.ListFiles()); foreach (Java.IO.File inFile in files) { if (!inFile.IsDirectory && inFile.Name.EndsWith(".h264")) { RunOnUiThread(async() => { var videoConverter = new aTello.VideoConverter(); var inF = new Java.IO.File(inFile.Path); var result = await videoConverter.ConvertFileAsync(this, inF); Toast.MakeText(Application.Context, "Video Converted. Result:" + result, ToastLength.Long).Show(); if (result != null) { inF.Delete(); } }); } } }; //EditText text = FindViewById<EditText>(Resource.Id.maxHeightText); //text.AfterTextChanged += delegate { // Tello.setMaxHeight(int.Parse(text.Text)); //}; //text = FindViewById<EditText>(Resource.Id.exposureText); //text.AfterTextChanged += delegate { // Tello.setEV(int.Parse(text.Text)); //}; //text = FindViewById<EditText>(Resource.Id.attAngleText); //text.AfterTextChanged += delegate { // Tello.setAttAngle(int.Parse(text.Text)); //}; //text = FindViewById<EditText>(Resource.Id.eisText); //text.AfterTextChanged += delegate { // Tello.setEIS(int.Parse(text.Text)); //}; }
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(); }