Things used in this project

Hardware components:
Microsoft Lumia 950XL
You can use also other windows 10 devices
×1
Microsoft Xbox One Controller (bluetooth)
×1
Pi 3 02
Raspberry Pi 3 Model B
Also a raspberry pi 2 is compatible with this project
×1
Drone Frame
This frame has the power distribution board built in
×1
AfroFlight Naze32 Rev6 Flight Controller
×1
Hobby King 30A ESC 3A UBEC
×4
Turnigy D3530/14 1100KV Brushless Outrunner Motor
×4
Hobbyking Slowfly Propeller 10x4.5 Blue (CW/CCW) (4pcs)
×1
Turnigy 3300mAh 3S 30C Lipo Pack
×1
Gold Plated Spring Connector 3.5mm
You need only 12 female connector to connect ESCs to Motor
×2
HXT 4mm Gold Connector
You need just one of this to connect the battery to the power distribution board
×1
Mini Ublox NEO-M8N GPS for Naze32 / Flip32
GPS module for Naze 32 flight controller
×1
51gzz5eu9pl. sx425
HC-SR04
×1
Microsoft Lifecam HD-3000
×1
Vodafone K5150 4G/LTE USB
4G/LTE modem for web socket connection - Compatible with Windows 10 IoT core
×1
Wireless 300N USB 2.0 Dongle
This wifi dongle is compatible with Windows 10 IoT core, i choose this one because it has the removible external antenna
×1
Micro USB data cable
This short cable is required to connect RPi to the flight controller
×1
Software apps and online services:
10
Microsoft Windows 10 IoT Core
W9gt7hzo
Microsoft Azure
Hand tools and fabrication machines:
09507 01
Soldering iron (generic)

Schematics

The Idea 1.0
2 3hu0kfwvpc
The Idea 2.0
3 frtu7xziz3
RPi and fligh controller connection
1 kixi4u4imk

Code

App.csC#
using System;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Networking.Connectivity;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace Drone
{
	public enum Mode
	{
		Wifi = 1,
		LTE = 2
	}

	sealed partial class App : Application
    {
        public static bool isRPi;
        public static bool internetAvailable;
        public static Mode Mode;
		internal static string MapServiceToken = "yourmapservicetokenhere";

        public App()
        {
            this.InitializeComponent();
            this.Suspending += OnSuspending;

            NetworkInformation.NetworkStatusChanged += NetworkStatusChanged;

            isRPi = true;
			Mode = Mode.LTE;
        }

        public static bool IsInternetAvailable()
        {
            ConnectionProfile connections = NetworkInformation.GetInternetConnectionProfile();
            return connections != null && connections.GetNetworkConnectivityLevel() == NetworkConnectivityLevel.InternetAccess;
        }

        private void NetworkStatusChanged(object sender)
        {
            if (IsInternetAvailable())
            {
                internetAvailable = true;

                // Handle network reconnection
            }
            else
            {
                internetAvailable = false;

                // Handle network disconnection
            }
        }

        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {
            // Check the internet connection OnLaunched application event
            NetworkStatusChanged(null);

            Frame rootFrame = Window.Current.Content as Frame;

            if (rootFrame == null)
            {
                rootFrame = new Frame();

                rootFrame.NavigationFailed += OnNavigationFailed;

                if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    //TODO: Load state from previously suspended application
                }

                Window.Current.Content = rootFrame;
            }

            if (e.PrelaunchActivated == false)
            {
                if (rootFrame.Content == null)
                {
                    rootFrame.Navigate(typeof(MainPage), e.Arguments);
                }

                Window.Current.Activate();
            }
        }

        void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
        }

        private void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            //TODO: Save application state and stop any background activity
            deferral.Complete();
        }
    }
}
MainPage.csC#
using System;
using System.Diagnostics;
using Windows.Devices.Gpio;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.Gaming.Input;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Input;
using Windows.Devices.Geolocation;
using Windows.UI.Xaml.Controls.Maps;
using Windows.Foundation;
using Drone.Helpers;
using Windows.System.Threading;
using System.Threading;

namespace Drone
{
    public sealed partial class MainPage : Page
    {
        //private static string defaultHostName = "minwinpc";
        private static string defaultHostName = "192.168.137.1";
		    public static string hostName = defaultHostName;
        private static DispatcherTimer timer;
		    public static Stopwatch stopwatch;
		    private static IAsyncAction workItemThread;
	    	private static long lastCheckTime;
		    private static Gamepad controller;
        public static bool isGamepadConnected;
        public static bool isLandCompleted;
        public static bool isSignalLost;
        public static bool isTakeOffCompleted;
        private static Geopoint dronePosition;
        private static Image droneIcon;

        private const int LED_PIN = 26;
        private static GpioPin ledPin;
        private static GpioPinValue ledPinValue;

        private static ushort aux1, aux2, aux3, aux4;
        private static double throttle, yaw, roll, pitch;
        private static int throttleTakeOffRange;
        private const int MAX_THROTTLE_TAKEOFF_FACTOR = 400;
        private const int THROTTLE_TAKEOFF_FACTOR = 250;
        private const int LANDING_DISTANCE = 50;
        private const double THUMBSTICK_FACTOR = 0.1;
        private static int countButton, flightModeCount, gpsDataCount;

        public MainPage()
        {
            this.InitializeComponent();

            isGamepadConnected = false;
            isTakeOffCompleted = false;
            isLandCompleted = false;
            isSignalLost = false;

            throttle = 0;
            roll = 1500;
            pitch = 1500;
            yaw = 1500;
            aux1 = 1500;
            aux2 = 1500;
            aux3 = 1500;
            aux4 = 1500;
            throttleTakeOffRange = 0;
            countButton = 0;
            flightModeCount = 0;
            gpsDataCount = 0;

            armToggle.IsEnabled = false;
            armToggle.IsTabStop = false;
            horizonToggle.IsEnabled = false;
            horizonToggle.IsTabStop = false;
            takeOffLandToggle.IsEnabled = false;
            takeOffLandToggle.IsTabStop = false;
            plusButton.IsEnabled = false;
            plusButton.IsTabStop = false;
            minusButton.IsEnabled = false;
            minusButton.IsTabStop = false;
		      	gpsHoldToggle.IsEnabled = false;
			      gpsHoldToggle.IsTabStop = false;
            returnToHomeToggle.IsEnabled = false;
            returnToHomeToggle.IsTabStop = false;

            droneIcon = new Image();
            droneIcon.Source = new Windows.UI.Xaml.Media.Imaging.BitmapImage(new Uri("ms-appx:///Assets/Icons/drone_pin.png"));
            droneIcon.Width = 30;
            droneIcon.Height = 33;
            map.ZoomLevel = 17;
            map.Children.Add(droneIcon);
            map.MapServiceToken = App.MapServiceToken;

            InitGPIO();

			if(App.Mode == Mode.Wifi)
				InitNetwork();
			if (App.Mode == Mode.LTE)
				InitWebSocket();

            if (App.isRPi)
            {    
                InitNaze32();
                InitTelemetry();
                TurnOnLED();
			}

            Gamepad.GamepadAdded += Gamepad_GamepadAdded;
            Gamepad.GamepadRemoved += Gamepad_GamepadRemoved;

			stopwatch = new Stopwatch();
			stopwatch.Start();

			timer = new DispatcherTimer();
			timer.Interval = TimeSpan.FromMilliseconds(20);
			timer.Tick += timer_Tick;
			timer.Start();
		}

		private async void Gamepad_GamepadRemoved(object sender, Gamepad e)
        {
            Debug.WriteLine("--------- CONTROLLER DISCONNECTED ---------");
            controller = null;
            isGamepadConnected = false;
            
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
			{
                gamepadStatus.Opacity = 0.2;
                armToggle.IsEnabled = false;
                horizonToggle.IsEnabled = false;
                takeOffLandToggle.IsEnabled = false;
            });
        }

        private async void Gamepad_GamepadAdded(object sender, Gamepad e)
        {
            Debug.WriteLine("--------- CONTROLLER CONNECTED ---------");
            controller = e;
            isGamepadConnected = true;

			await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
			{
				gamepadStatus.Opacity = 1;
                armToggle.IsEnabled = true;
                horizonToggle.IsEnabled = true;
			});
        }

        private void droneStatus_Tapped(object sender, TappedRoutedEventArgs e)
        {
            if (droneStatus.Opacity < 0.3)
                FlyoutBase.ShowAttachedFlyout(sender as FrameworkElement);
        }

        private void connectButton_Click(object sender, RoutedEventArgs e)
        {
            StartupFlyout.Hide();

            if (!string.IsNullOrWhiteSpace(deviceName.Text))
                hostName = deviceName.Text;
            NetworkCmd.NetworkInit(hostName);
        }

        private void InitGPIO()
        {
            var gpio = GpioController.GetDefault();

            if (gpio == null)
            {
                App.isRPi = false;
                return;
            }

            //Set led
            ledPin = gpio.OpenPin(LED_PIN);
            ledPinValue = GpioPinValue.High;
            ledPin.Write(ledPinValue);
            ledPin.SetDriveMode(GpioPinDriveMode.Output);
        }

        public void InitNetwork()
        {
            if (App.isRPi)      
                hostName = "";

            NetworkCmd.NetworkInit(hostName);
        }

		public async void InitWebSocket()
		{
			if (App.isRPi)
				await WebSocketCmd.OpenSocket("drone", "controller");
			else
				await WebSocketCmd.OpenSocket("controller", "drone");
		}

		public async void InitNaze32()
        {
            await MultiWii.Init();
        }

        public void InitTelemetry()
        {
            Telemetry.Init();         
        }

        private void timer_Tick(object sender, object e)
        {
			var socketIsConnected = false;

			if (App.Mode == Mode.Wifi)
				socketIsConnected = NetworkCmd.socketIsConnected;
			if (App.Mode == Mode.LTE)
				socketIsConnected = WebSocketCmd.socketIsConnected;

			if (!App.isRPi && isGamepadConnected && socketIsConnected)
			{
				// Read data from controller
				var reading = controller.GetCurrentReading();

				// Set RC data
				SetThrottle(reading.RightTrigger, reading.LeftTrigger);
				SetYaw(reading.LeftThumbstickX);
				SetPitch(reading.RightThumbstickY);
				SetRoll(reading.RightThumbstickX);
				CheckButtons(reading.Buttons);

				pitchLabel.Text = $"PITCH: {(ushort)pitch}";
				rollLabel.Text = $"ROLL: {(ushort)roll}";
				yawLabel.Text = $"YAW: {(ushort)yaw}";
				throttleLabel.Text = $"THROTTLE: {(ushort)throttle}";
				takeOffRangeLabel.Text = $"TAKE OFF RANGE: {throttleTakeOffRange}";

				//Send data to RPI
				var bytes = MultiWii.Calculate_MSP_SET_RAW_RC((ushort)throttle, (ushort)roll, (ushort)pitch, (ushort)yaw, aux1, aux2, aux3, aux4); //Cleanflight - TAER1234

				if (App.Mode == Mode.Wifi)
					NetworkCmd.SendDataToHost(bytes);
				if (App.Mode == Mode.LTE)
					WebSocketCmd.SendDataToHost(bytes);

				if (countButton < 5)
					countButton++;
			}

			if (gpsDataCount == 20)
			{
				if (App.isRPi)
				{
					MultiWii.GetGPSData();
					MultiWii.GetAttitude();
				}

				SetGPSInfo();
				SetAttitudeInfo();
				SetSignalStrengthInfo();
				gpsDataCount = 0;
			}

			gpsDataCount++;
		}

        private void SetThrottle(double rightTrigger, double leftTrigger)
        {
            // Incremental split of throttle on left and right trigger
            if (isTakeOffCompleted)
            {
                if (rightTrigger == 1)
                {
                    throttle = throttleTakeOffRange + THROTTLE_TAKEOFF_FACTOR + (rightTrigger * (500 - THROTTLE_TAKEOFF_FACTOR - throttleTakeOffRange)) + (leftTrigger * 500) + 1000;
                }
                else
                {
                    throttle = throttleTakeOffRange + THROTTLE_TAKEOFF_FACTOR + (rightTrigger * (500 - THROTTLE_TAKEOFF_FACTOR - throttleTakeOffRange)) + 1000;
                }
            }
        }

        private void SetYaw(double leftThumbstickX)
        {
            if (leftThumbstickX > THUMBSTICK_FACTOR || leftThumbstickX < -THUMBSTICK_FACTOR)
            {
                yaw = (leftThumbstickX * 500) + 1500;
            }
            else
            {
                yaw = 1500;
            }
        }

        private void SetPitch(double rightThumbstickY)
        {
            if(rightThumbstickY > THUMBSTICK_FACTOR || rightThumbstickY < -THUMBSTICK_FACTOR)
            {
                pitch = (rightThumbstickY * 500) + 1500;
            }
            else
            {
                pitch = 1500;
            }
        }

        private void SetRoll(double rightThumbstickX)
        {
            if (rightThumbstickX > THUMBSTICK_FACTOR || rightThumbstickX < -THUMBSTICK_FACTOR)
            {
                roll = (rightThumbstickX * 500) + 1500;
            }
            else
            {
                roll = 1500;
            }
        }

        private void CheckButtons(GamepadButtons buttons)
        {
            if (countButton == 5 && buttons == GamepadButtons.View)
            {
                if (armToggle.IsChecked == true)
                    armToggle.IsChecked = false;
                else
                    armToggle.IsChecked = true;

                countButton = 0;
            }
            else if (countButton == 5 && buttons == GamepadButtons.Menu)
            {
                if (horizonToggle.IsChecked == true)
                {
                    switch (flightModeCount)
                    {
                        case 0:
                            horizonToggle.Content = "Angle";
                            aux2 = 1000;
                            flightModeCount++;
                            break;
                        //case 1:
                        //    horizonToggle.Content = "Air";
                        //    aux2 = 2000;
                        //    flightModeCount++;
                        //    break;
                        case 1:
                            flightModeCount = 0;
                            horizonToggle.IsChecked = false;
                            break;
                    }
                }
                else
                    horizonToggle.IsChecked = true;

                countButton = 0;
            }
            else if (armToggle.IsChecked == true && countButton == 5 && buttons == GamepadButtons.DPadDown)
            {
                if (takeOffLandToggle.IsChecked == true)
                    takeOffLandToggle.IsChecked = false;

                countButton = 0;
            }
            else if (armToggle.IsChecked == true && countButton == 5 && buttons == GamepadButtons.DPadUp)
            {
                if (takeOffLandToggle.IsChecked == false)
                    takeOffLandToggle.IsChecked = true;

                countButton = 0;
            }
			else if (armToggle.IsChecked == true && countButton == 5 && buttons == GamepadButtons.DPadRight)
			{
				if (gpsHoldToggle.IsChecked == false && MultiWii.gpsFix == 2)
					gpsHoldToggle.IsChecked = true;
				else
					gpsHoldToggle.IsChecked = false;

				countButton = 0;
			}
            else if (armToggle.IsChecked == true && countButton == 5 && buttons == GamepadButtons.DPadLeft)
            {
                if (returnToHomeToggle.IsChecked == false && MultiWii.gpsFix == 2)
                    returnToHomeToggle.IsChecked = true;
                else
                    returnToHomeToggle.IsChecked = false;

                countButton = 0;
            }
            else if (armToggle.IsChecked == true && countButton == 5 && buttons == GamepadButtons.LeftShoulder)
            {
                if (isTakeOffCompleted && (THROTTLE_TAKEOFF_FACTOR + throttleTakeOffRange) > THROTTLE_TAKEOFF_FACTOR)
                    throttleTakeOffRange -= 5;

                countButton = 0;
            }
            else if (armToggle.IsChecked == true && countButton == 5 && buttons == GamepadButtons.RightShoulder)
            {
                if (isTakeOffCompleted && (THROTTLE_TAKEOFF_FACTOR + throttleTakeOffRange) < MAX_THROTTLE_TAKEOFF_FACTOR)
                    throttleTakeOffRange += 5;

                countButton = 0;
            }
        }

        private void arm_Checked(object sender, RoutedEventArgs e)
        {
            aux1 = 2000;
            Debug.WriteLine("--------- ARMED ---------");

            takeOffLandToggle.IsEnabled = true;
        }

        private void arm_Unchecked(object sender, RoutedEventArgs e)
        {
            aux1 = 1000;
            Debug.WriteLine("--------- DISARMED ---------");

            takeOffLandToggle.IsChecked = false;
            takeOffLandToggle.IsEnabled = false;
        }

        private void horizonToggle_Checked(object sender, RoutedEventArgs e)
        {
            flightModeCount = 0;
            aux2 = 1200;
            Debug.WriteLine("--------- HORIZON: ON ---------");
        }

        private void horizonToggle_Unchecked(object sender, RoutedEventArgs e)
        {
            horizonToggle.Content = "Horizon";
            aux2 = 1500;
            Debug.WriteLine("--------- HORIZON: OFF ---------");
        }

        private void takeOffLandToggle_Checked(object sender, RoutedEventArgs e)
        {
            TakeOff();
            plusButton.IsEnabled = true;
            minusButton.IsEnabled = true;
        }

        private void takeOffLandToggle_Unchecked(object sender, RoutedEventArgs e)
        {
            Land();
            plusButton.IsEnabled = false;
            minusButton.IsEnabled = false;
        }

        private void plusButton_Click(object sender, RoutedEventArgs e)
        {
            if (isTakeOffCompleted && (THROTTLE_TAKEOFF_FACTOR + throttleTakeOffRange) < MAX_THROTTLE_TAKEOFF_FACTOR)
                throttleTakeOffRange += 5;
        }

        private void minusButton_Click(object sender, RoutedEventArgs e)
        {
            if (isTakeOffCompleted && (THROTTLE_TAKEOFF_FACTOR + throttleTakeOffRange) > THROTTLE_TAKEOFF_FACTOR)
                throttleTakeOffRange -= 5;
        }

		private void gpsHoldToggle_Checked(object sender, RoutedEventArgs e)
		{
            if(returnToHomeToggle.IsChecked == true)
                returnToHomeToggle.IsChecked = false;
			aux3 = 2000;
			Debug.WriteLine("--------- GPS HOLD: ON ---------");
		}

		private void gpsHoldToggle_Unchecked(object sender, RoutedEventArgs e)
		{
			aux3 = 1500;
			Debug.WriteLine("--------- GPS HOLD: OFF ---------");
		}

        private void returnToHomeToggle_Checked(object sender, RoutedEventArgs e)
        {
            if(gpsHoldToggle.IsChecked == true)
                gpsHoldToggle.IsChecked = false;
            aux3 = 1000;
            Debug.WriteLine("--------- RETURN TO HOME: ON ---------");
        }

        private void returnToHomeToggle_Unchecked(object sender, RoutedEventArgs e)
        {
            aux3 = 1500;
            Debug.WriteLine("--------- RETURN TO HOME: OFF ---------");
        }

        public async void SetGPSInfo()
        {
			if (App.isRPi)
			{
				var speed = MultiWii.gpsSpeed * 0.036; // convert cm/s to km/h
				await Telemetry.SendMessagesAsync(new GpsTelemetryMessage(MultiWii.gpsFix, MultiWii.gpsNumSat, MultiWii.gpsLatitude, MultiWii.gpsLongitude, MultiWii.gpsAltitude, speed));
			}
			else
			{
				if (MultiWii.gpsFix == 2)
				{
					gpsStatus.Opacity = 1;
					gpsHoldToggle.IsEnabled = true;
					returnToHomeToggle.IsEnabled = true;
				}
				else
				{
					gpsStatus.Opacity = 0.2;
					gpsHoldToggle.IsEnabled = false;
					returnToHomeToggle.IsEnabled = false;
				}

				var speed = MultiWii.gpsSpeed * 0.036; // convert cm/s to km/h
				speedLabel.Text = $"SPEED: {speed} KM/H";
				altitudeLabel.Text = "ALTITUDE: " + MultiWii.gpsAltitude;
				numSatLabel.Text = "NUM SAT: " + MultiWii.gpsNumSat;

				dronePosition = new Geopoint(new BasicGeoposition() { Latitude = MultiWii.gpsLatitude, Longitude = MultiWii.gpsLongitude, Altitude = MultiWii.gpsAltitude });
				map.Center = dronePosition;

				MapControl.SetLocation(droneIcon, dronePosition);
				MapControl.SetNormalizedAnchorPoint(droneIcon, new Point(0.5, 1));
			}
        }

		public async void SetAttitudeInfo() 
		{
			if(App.isRPi) 
			{
				await Telemetry.SendMessagesAsync(new AttitudeTelemetryMessage(MultiWii.angx, MultiWii.angy, MultiWii.head, MultiWii.headfree));
			}
			else 
			{
				// UI update
			}
		}

		public async void SetSignalStrengthInfo() 
		{
			if (App.isRPi)
			{
				await Telemetry.SendMessagesAsync(new SignalTelemetryMessage(Telemetry.GetSignalStrength()));
			}
			else
			{
				// UI update
			}
		}

        public static void TurnOnLED()
        {
            if (!App.isRPi)
                return;

            if (ledPinValue == GpioPinValue.High)
            {
                ledPinValue = GpioPinValue.Low;
                ledPin.Write(ledPinValue);
            }
        }

        public static void TurnOffLED()
        {
            if (!App.isRPi)
                return;

            if (ledPinValue == GpioPinValue.Low)
            {
                ledPinValue = GpioPinValue.High;
                ledPin.Write(ledPinValue);
            }
        }

        public static void FlipLED()
        {
            if (!App.isRPi)
                return;

            if (ledPinValue == GpioPinValue.High)
            {
                ledPinValue = GpioPinValue.Low;
                ledPin.Write(ledPinValue);
            }
            else
            {
                ledPinValue = GpioPinValue.High;
                ledPin.Write(ledPinValue);
            }
        }

        public static async void BlinkLED(int ms, int times)
        {
            if (!App.isRPi)
                return;

            times = times * 2;

            if (ledPinValue == GpioPinValue.High)
            {
                while (times != 0)
                {
                    FlipLED();
                    await Task.Delay(ms);
                    times--;
                }

                TurnOffLED();
            }
            else
            {
                while (times != 0)
                {
                    FlipLED();
                    await Task.Delay(ms);
                    times--;
                }

                TurnOnLED();
            }
        }

        private void TakeOff()
        {
			// TODO: Auto take off (about 1,5 meters from ground)
			// Auto take off logic here

            takeOffLandToggle.Content = "Land";
            isTakeOffCompleted = true;
            isLandCompleted = false;
        }

        private void Land()
        {
			// TODO: Auto land (about 1,5 meters from ground)
			// Auto land logic here

			takeOffLandToggle.Content = "Take Off";
            throttle = 0;
            throttleTakeOffRange = 0;
            isTakeOffCompleted = false;
            isLandCompleted = true;

			// Update UI
        }

        public static void Safe()
        {
			// TODO: Call auto land function
			// Land();

			// Set values to default
            throttle = 1000 + THROTTLE_TAKEOFF_FACTOR;
            roll = 1500;
            pitch = 1500;
            yaw = 1500;
            throttleTakeOffRange = 0;
            MultiWii.MSP_SET_RAW_RC((ushort)throttle, (ushort)roll, (ushort)pitch, (ushort)yaw, aux1, aux2, aux3, aux4); //Cleanflight - TAER1234
        }
    }
}
NetworkCmd.csC#
using System;
using System.Diagnostics;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using Windows.Networking;
using Windows.UI.Popups;
using System.Collections.Generic;
using Windows.Foundation;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml;
using System.IO;

namespace Drone
{
	public static class NetworkCmd
	{
		private static string hostName = "";
		private const string hostPort = "8027";
        private static StreamSocketListener listener;
        private static DataReader readPacket;
        private static int readBuff = 64;

        public static bool socketIsConnected = false;

		public static long lastCmdSent;
		public static long lastCmdReceived;

		public static async void NetworkInit(string host)
		{
			ClearPrevious();

			hostName = host;
			Debug.WriteLine("NetworkInit() host = " + hostName + " port = " + hostPort);

            // if no host, be client, otherwise be a host
            if (!string.IsNullOrWhiteSpace(hostName))
            {
                await InitConnectionToHost(hostName, hostPort);
            }
            else
            {
                if (listener == null) await StartListener(hostPort);
            }
		}

        #region ----- helpers -----	
        public static void SendDataToHost(string stringToSend)
        {
            if (socketIsConnected) PostSocketWrite(stringToSend);
        }

        static async void PostSocketWrite(string writeStr)
        {
            if (socket == null || !socketIsConnected)
            {
                Debug.WriteLine("Wr: Socket not connected yet.");
                return;
            }

            try
            {
                DataWriter writer = new DataWriter(socket.OutputStream);
                writer.WriteString(writeStr);
                await writer.StoreAsync();
                await writer.FlushAsync();
                writer.DetachStream();
                writer = null;
			}
            catch (Exception ex)
            {
                Debug.WriteLine("Failed to Write - " + ex.Message);
            }
        }

        public static void SendDataToHost(byte[] bytes)
        {
            if (socketIsConnected) PostSocketWrite(bytes);
        }

        static async void PostSocketWrite(byte[] bytes)
        {
            if (socket == null || !socketIsConnected)
            {
                Debug.WriteLine("Wr: Socket not connected yet.");
                return;
            }

            try
            {
                DataWriter writer = new DataWriter(socket.OutputStream);
                writer.WriteBytes(bytes);
                await writer.StoreAsync();
                await writer.FlushAsync();
                writer.DetachStream();
                writer = null;
				lastCmdSent = MainPage.stopwatch.ElapsedMilliseconds;
			}
            catch (Exception ex)
            {
                Debug.WriteLine("Failed to Write - " + ex.Message);
                socketIsConnected = false;

                if (App.isRPi)
                {
                    Debug.WriteLine("Controller signal lost!");
                    MainPage.isSignalLost = true;
                    //MainPage.Safe();
                }

                if (!App.isRPi)
                {
                    Debug.WriteLine("Drone signal lost!");
                    MainPage.isSignalLost = true;

                    await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                    {
                        var currentPage = ((ContentControl)Window.Current.Content).Content as Page;
                        var droneStatus = currentPage.FindName("droneStatus") as Image;
                        droneStatus.Opacity = 0.2;
                    });
                }
            }
        }

        static void PostSocketRead(int length)
        {
            if (socket == null || !socketIsConnected)
            {
                Debug.WriteLine("Rd: Socket not connected yet.");
                return;
            }

            try
            {
                var readBuf = new Windows.Storage.Streams.Buffer((uint)length);
                var readOp = socket.InputStream.ReadAsync(readBuf, (uint)length, InputStreamOptions.Partial);
                readOp.Completed = (IAsyncOperationWithProgress<IBuffer, uint> asyncAction, AsyncStatus asyncStatus) =>
                {
                    switch (asyncStatus)
                    {
                        case AsyncStatus.Completed:
                        case AsyncStatus.Error:
                            try
                            {
                                IBuffer localBuf = asyncAction.GetResults();
                                uint bytesRead = localBuf.Length;
                                readPacket = DataReader.FromBuffer(localBuf);
                                OnDataReadCompletion(bytesRead, readPacket);
                            }
                            catch (Exception ex)
                            {
                                Debug.WriteLine("Read operation failed:  " + ex.Message);
                            }
                            break;
                        case AsyncStatus.Canceled:
                            Debug.WriteLine("Read operation cancelled");
                            break;
                    }
                };
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Failed to post a Read - " + ex.Message);
            }
        }

        public static void OnDataReadCompletion(uint bytesRead, DataReader readPacket)
        {
            try
            {
                if (readPacket == null)
                {
                    Debug.WriteLine("DataReader is null");
                    return;
                }

                uint buffLen = readPacket.UnconsumedBufferLength;

                if (buffLen == 0)
                {
                    Debug.WriteLine("Buffer is empty");          
                    return;
                }

                Debug.WriteLine($"Network Received (b={bytesRead},l={buffLen})");

                List<byte> bytes = new List<byte>();
                while (buffLen > 0)
                {
                    byte b = readPacket.ReadByte();
                    bytes.Add(b);
                    buffLen--;
                }

				lastCmdReceived = MainPage.stopwatch.ElapsedMilliseconds;

				if (App.isRPi)
                {
                    MultiWii.sendRequestMSP(bytes);
                    PostSocketRead(readBuff);
                }
                else
                {
                    MultiWii.evaluateResponseMSP(bytes);
                    PostSocketRead(readBuff);
                }
			}
            catch(Exception ex)
            {
                Debug.WriteLine("OnDataReadCompletion() - " + ex.Message);
            }
        }

        private static void ClearPrevious()
		{
			if (socket != null)
			{
				socket.Dispose();
				socket = null;
				socketIsConnected = false;
			}
		}
		#endregion

		#region ----- host connection ----
		public static bool listenerHasStarted;
		private static async Task StartListener(string port)
		{
			try
			{
				listener = new StreamSocketListener();
				listener.ConnectionReceived += OnConnection;
				await listener.BindServiceNameAsync(port).AsTask();
				Debug.WriteLine("Listening on port " + port);
				listenerHasStarted = true;
			}
			catch (Exception e)
			{
				Debug.WriteLine("StartListener() - Unable to bind listener. " + e.Message);
                MainPage.BlinkLED(250, 2);
            }
		}

		private static void OnConnection(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
		{
			try
			{
				if (App.isRPi)
				{
                    MainPage.BlinkLED(250, 1);
                    
                    socket = args.Socket;
                    if (socket != null)
                    {
                        socketIsConnected = true;

						// Start reading controller commands
						PostSocketRead(readBuff);
                    }
                }
            }
            catch (Exception ex)
			{
				Debug.WriteLine("OnConnection() - " + ex.Message);
			}
		}
		#endregion

		#region ----- client connection -----
		static StreamSocket socket;
		private static async Task InitConnectionToHost(string host, string port)
		{
			try
			{
                ClearPrevious();
                socket = new StreamSocket();

                HostName hostNameObj = new HostName(host);
				await socket.ConnectAsync(hostNameObj, port).AsTask();
				Debug.WriteLine("Connected to " + hostNameObj + ":" + port);
				socketIsConnected = true;

                // Start listening feedback from drone
                if (!App.isRPi)
                    PostSocketRead(readBuff);

                if (!App.isRPi)
                {
                    await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                    {
                        var currentPage = ((ContentControl)Window.Current.Content).Content as Page;
                        var droneStatus = currentPage.FindName("droneStatus") as Image;
                        droneStatus.Opacity = 1;
                    });
                }
            }
			catch (Exception ex)
			{
				Debug.WriteLine("InitConnectionToHost() - " + ex.Message);
				if (!App.isRPi)
					await new MessageDialog("InitConnectionToHost() - " + ex.Message).ShowAsync();
			}
		}		
		#endregion		
	}
}
WebSocketCmd.csC#
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Drone
{
	public static class WebSocketCmd
	{
		private static MessageWebSocket socket;
		public static bool socketIsConnected = false;

		public static long lastCmdSent;
		public static long lastCmdReceived;

		private static string from;
		private static string to;

		private static void Init()
		{
			try
			{
				socket = new MessageWebSocket();
				socket.MessageReceived += MessageWebSocket_MessageReceived;
				socket.Closed += MessageWebSocket_Closed;
				socket.Control.MessageType = SocketMessageType.Binary;
			}
			catch (Exception ex)
			{
				Debug.WriteLine("Error initializing web socket: " + ex.Message);
			}
		}

		private static void MessageWebSocket_Closed(IWebSocket sender, WebSocketClosedEventArgs args)
		{
			CloseSocket();
		}

		private static void MessageWebSocket_MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
		{
			try
			{
				var readPacket = args.GetDataReader();

				if (readPacket == null)
				{
					Debug.WriteLine("DataReader is null");
					return;
				}

				uint buffLen = readPacket.UnconsumedBufferLength;

				if (buffLen == 0)
				{
					Debug.WriteLine("Buffer is empty");
					return;
				}

				if (args.MessageType == SocketMessageType.Utf8)
				{
					var error = readPacket.ReadString(buffLen);
					HandleError(error);
					return;
				}

				if (MainPage.isSignalLost)
					MainPage.isSignalLost = false;

				List<byte> bytes = new List<byte>();
				while (buffLen > 0)
				{
					byte b = readPacket.ReadByte();
					bytes.Add(b);
					buffLen--;
				}

				lastCmdReceived = MainPage.stopwatch.ElapsedMilliseconds;

				if (App.isRPi)
					MultiWii.sendRequestMSP(bytes);
				else
					MultiWii.evaluateResponseMSP(bytes);
			}
			catch (Exception ex)
			{
				Debug.WriteLine("MessageWebSocket_MessageReceived() - " + ex.Message);
			}
		}

		public static async Task OpenSocket(string f, string t)
		{
			if (socket != null)
			{
				CloseSocket();
			}

			Init();

			from = f;
			to = t;

			try
			{
				await socket.ConnectAsync(new Uri($"ws://yoursite.azurewebsites.net/"));
				socketIsConnected = true;

				if (!App.isRPi)
				{
					await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
					{
						var currentPage = ((ContentControl)Window.Current.Content).Content as Page;
						var droneStatus = currentPage.FindName("droneStatus") as Image;
						droneStatus.Opacity = 1;
					});
				}
				else
					Debug.WriteLine("Web socket connected!");

			}
			catch (Exception ex)
			{
				socket.Dispose();
				socket = null;
				socketIsConnected = false;
				Debug.WriteLine("Error connecting to web socket: " + ex.Message);
			}
		}

		public static void SendDataToHost(byte[] bytes)
		{
			if (socketIsConnected) PostSocketWrite(bytes);
		}

		private static async void PostSocketWrite(byte[] bytes)
		{
			if (!socketIsConnected)
			{
				Debug.WriteLine("Socket is not connected!");
				return;
			}

			try
			{
				DataWriter writer = new DataWriter(socket.OutputStream);
				writer.WriteBytes(bytes);
				await writer.StoreAsync();
				await writer.FlushAsync();
				writer.DetachStream();
				writer = null;
				lastCmdSent = MainPage.stopwatch.ElapsedMilliseconds;
			}
			catch (ObjectDisposedException ex)
			{
				Debug.WriteLine($"Error sending data: {ex.Message} Restarting connection...");
				await RestartSocket();
				Debug.WriteLine("Connection restarted successfully");
			}
			catch (Exception ex)
			{
				Debug.WriteLine("Failed to Write - " + ex.Message);
				socketIsConnected = false;
			}
		}

		private static async Task RestartSocket()
		{
			Init();

			try
			{
				await socket.ConnectAsync(new Uri($"ws://yoursite.azurewebsites.net/"));
				socketIsConnected = true;
			}
			catch (Exception ex)
			{
				Debug.WriteLine("Error restarting web socket: " + ex.Message);
				socketIsConnected = false;
			}
		}

		public static async void CloseSocket()
		{
			if (!socketIsConnected)
			{
				Debug.WriteLine("Socket is not connected!");
				return;
			}

			try
			{
				socket.Close(1000, "Closed due to user request.");
				socket.Dispose();
				socket = null;
				socketIsConnected = false;

				if (!App.isRPi)
				{
					await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
					{
						var currentPage = ((ContentControl)Window.Current.Content).Content as Page;
						var droneStatus = currentPage.FindName("droneStatus") as Image;
						droneStatus.Opacity = 0.2;
					});
				}
				else
					Debug.WriteLine("Web socket closed!");
			}
			catch (Exception ex)
			{
				Debug.WriteLine("Error closing socket: " + ex.Message);
			}
		}

		private static void HandleError(string error) 
		{ 
			//Debug.WriteLine("Failed to write to remote client - " + error);
			MainPage.isSignalLost = true;

			if (App.isRPi)
			{
				// ERROR - Controller is no longer connected to the web app
				Debug.WriteLine("Controller is no longer connected to the web app: {error}");
			}
			else
			{
				// ERROR - Drone is no longer connected to the web app
				Debug.WriteLine("Drone is no longer connected to the web app: {error}");
			}
		}
	}
}
MultiWii.csC#
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
using Windows.Storage.Streams;

namespace Drone
{
    public static class MultiWii
    { 
        private static SerialDevice serialPort = null;
        private static List<DeviceInformation> listOfDevices = new List<DeviceInformation>();
		public static bool deviceIsConnected = false;

		public static long lastCmdSent;
		public static long lastCmdReceived;

		private const string MSP_HEADER = "$M<";

        public static int version, multiType, mspVersion, capability;
        public static int roll, pitch, yaw, throttle, aux1, aux2, aux3, aux4;
        public static int gpsFix, gpsNumSat, gpsSpeed, gpsGroundCourse;
        public static double gpsLatitude, gpsLongitude, gpsAltitude;
        public static float angx, angy, head, headfree, alt;

        private enum MSPConst
        {
            MSP_IDENT = 100,
            MSP_STATUS = 101,
            MSP_RAW_IMU = 102,
            MSP_SERVO = 103,
            MSP_MOTOR = 104,
            MSP_RC = 105,
            MSP_RAW_GPS = 106,
            MSP_COMP_GPS = 107,
            MSP_ATTITUDE = 108,
            MSP_ALTITUDE = 109,
            MSP_BAT = 110,
            MSP_RC_TUNING = 111,
            MSP_PID = 112,
            MSP_BOX = 113,
            MSP_MISC = 114,
            MSP_MOTOR_PINS = 115,
            MSP_BOXNAMES = 116,
            MSP_PIDNAMES = 117,
            MSP_SUPERRAW_IMU = 119,

            MSP_SET_RAW_SENSORS = 199,
            MSP_SET_RAW_RC = 200,
            MSP_SET_RAW_GPS = 201,
            MSP_SET_PID = 202,
            MSP_SET_BOX = 203,
            MSP_SET_RC_TUNING = 204,
            MSP_ACC_CALIBRATION = 205,
            MSP_MAG_CALIBRATION = 206,
            MSP_SET_MISC = 207,
            MSP_RESET_CONF = 208,

            MSP_EEPROM_WRITE = 250,

            MSP_DEBUG = 254
        }

        private const int
          IDLE = 0,
          HEADER_START = 1,
          HEADER_M = 2,
          HEADER_ARROW = 3,
          HEADER_SIZE = 4,
          HEADER_CMD = 5,
          HEADER_ERR = 6;

        private static byte[] inBuf = new byte[256];
        private static int c_state = IDLE;
        private static bool err_rcvd = false;

        private static byte checksum = 0;
        private static byte cmd;
        private static int offset = 0, dataSize = 0;

        public static async Task Init()
        {
            try
            {
                ListAvailablePorts();
                var deviceName = "CP2104 USB to UART Bridge Controller";
                //var deviceName = "Silicon Labs CP210x USB to UART Bridge (COM3)";
                var device = listOfDevices.Where(x => x.Name == deviceName).FirstOrDefault();
				if (device != null)
				{
					await OpenConnection(device.Id).AsAsyncAction();
					deviceIsConnected = true;
				}
				else
				{
					deviceIsConnected = false;
					throw new Exception($"Device {deviceName} not found!");
				}

                Listen();
            }
            catch(Exception ex)
            {
                MainPage.BlinkLED(250, 4);
                Debug.WriteLine(ex.Message);
            }
        }

        private static async void ListAvailablePorts()
        {
            try
            {
                string aqs = SerialDevice.GetDeviceSelector();

                var dis = await DeviceInformation.FindAllAsync(aqs);

                for (int i = 0; i < dis.Count; i++)
                {
                    listOfDevices.Add(dis[i]);
                }

				if (listOfDevices.Count < 1)
					throw new Exception("Error finding usb connected devices");
            }
            catch (Exception ex)
            {
                MainPage.BlinkLED(250, 3);
                Debug.WriteLine(ex.Message);
			}
        }

        private static async Task OpenConnection(string deviceID)
        {
            CloseConnection();
            serialPort = await SerialDevice.FromIdAsync(deviceID).AsTask();
            serialPort.BaudRate = 115200;
            serialPort.WriteTimeout = TimeSpan.FromMilliseconds(10);
            serialPort.ReadTimeout = TimeSpan.FromMilliseconds(10);
            serialPort.Parity = SerialParity.None;
            serialPort.StopBits = SerialStopBitCount.One;
            serialPort.DataBits = 8;
            serialPort.IsRequestToSendEnabled = false;
            serialPort.IsDataTerminalReadyEnabled = false;
        }

        private static void CloseConnection()
        {
            if (serialPort != null)
            {
                serialPort.Dispose();
            }

            serialPort = null;
        }

        private static int p;

        private static int read32() { return (Int32)((inBuf[p++] & 0xff) + ((inBuf[p++] & 0xff) << 8) + ((inBuf[p++] & 0xff) << 16) + ((inBuf[p++] & 0xff) << 24)); }
        private static int read16() { return (Int16)((inBuf[p++] & 0xff) + ((inBuf[p++]) << 8)); }
        private static int read8() { return inBuf[p++] & 0xff; }

        //send msp without payload
        private static List<Byte> requestMSP(int msp)
        {
            return requestMSP(msp, null);
        }

        //send multiple msp without payload
        private static List<Byte> requestMSP(int[] msps)
        {
            List<Byte> s = new List<Byte>();
            foreach (int m in msps)
            {
                s.AddRange(requestMSP(m, null));
            }
            return s;
        }

        //send msp with payload
        private static List<Byte> requestMSP(int msp, byte[] payload)
        {
            if (msp < 0)
            {
                return null;
            }
            List<Byte> bf = new List<Byte>();
            foreach (byte c in MSP_HEADER.ToCharArray())
            {
                bf.Add(c);
            }

            byte checksum = 0;
            byte pl_size = (byte)((payload != null ? (int)(payload.Length) : 0) & 0xFF);
            bf.Add(pl_size);
            checksum ^= (byte)(pl_size & 0xFF);

            bf.Add((byte)(msp & 0xFF));
            checksum ^= (byte)(msp & 0xFF);

            if (payload != null)
            {
                foreach (byte b in payload)
                {
                    bf.Add((byte)(b & 0xFF));
                    checksum ^= (byte)(b & 0xFF);
                }
            }
            bf.Add(checksum);
            return (bf);
        }

        public static void sendRequestMSP(List<Byte> msp)
        {
            byte[] arr = new byte[msp.Count];
            int i = 0;
            foreach (byte b in msp)
            {
                arr[i++] = b;
            }

            Write(arr); // send the complete byte sequence in one go
        }

        public static void parseByte(byte c) {
            if (c_state == IDLE)
            {
                c_state = (c == '$') ? HEADER_START : IDLE;
            }
            else if (c_state == HEADER_START)
            {
                c_state = (c == 'M') ? HEADER_M : IDLE;
            }
            else if (c_state == HEADER_M)
            {
                if (c == '>')
                {
                    c_state = HEADER_ARROW;
                }
                else if (c == '!')
                {
                    c_state = HEADER_ERR;
                }
                else
                {
                    c_state = IDLE;
                }
            }
            else if (c_state == HEADER_ARROW || c_state == HEADER_ERR)
            {
                /* is this an error message? */
                err_rcvd = (c_state == HEADER_ERR);        /* now we are expecting the payload size */
                dataSize = (c & 0xFF);
                /* reset index variables */
                p = 0;
                offset = 0;
                checksum = 0;
                checksum ^= (byte)(c & 0xFF);
                /* the command is to follow */
                c_state = HEADER_SIZE;
            }
            else if (c_state == HEADER_SIZE)
            {
                cmd = (byte)(c & 0xFF);
                checksum ^= (byte)(c & 0xFF);
                c_state = HEADER_CMD;
            }
            else if (c_state == HEADER_CMD && offset < dataSize)
            {
                checksum ^= (byte)(c & 0xFF);
                inBuf[offset++] = (byte)(c & 0xFF);
            }
            else if (c_state == HEADER_CMD && offset >= dataSize)
            {
                /* compare calculated and transferred checksum */
                if ((checksum & 0xFF) == (c & 0xFF))
                {
                    if (err_rcvd)
                    {
                        //System.err.println("Copter did not understand request type "+c);
                        Debug.WriteLine("Copter did not understand request type " + c);
                    }
                    else
                    {
                        /* we got a valid response packet, evaluate it */
                        evaluateCommand(cmd, dataSize);
                    }
                }
                else
                {
                    Debug.WriteLine("invalid checksum for command " + ((int)(cmd & 0xFF)) + ": " + (checksum & 0xFF) + " expected, got " + (int)(c & 0xFF));
                }
                c_state = IDLE;
            }
        }

        private static async void Listen()
        {
            try
            {
                if (serialPort != null)
                {
                    // Create the DataReader object and attach to InputStream 
                    DataReader reader = new DataReader(serialPort.InputStream);

                    while (true)
                    {
                        //Launch the ReadBytesAsync task to perform the read
                        await ReadBytesAsync(reader);
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }

        private static async void Read()
        {
            try
            {
                if (serialPort != null)
                {
                    DataReader reader = new DataReader(serialPort.InputStream);
                    await ReadBytesAsync(reader);
                    reader.DetachStream();
                    reader = null;
				}
            }
            catch (Exception ex)
            {              
                Debug.WriteLine(ex.Message);
            }
        }

        private static async Task ReadBytesAsync(DataReader reader)
        {
            uint ReadBufferLength = (uint)inBuf.Length;

            // Set InputStreamOptions to complete the asynchronous read operation when one or more bytes is available
            reader.InputStreamOptions = InputStreamOptions.Partial;

            var data = new List<byte>();

            // Launch the task and wait
            var bytesRead = await reader.LoadAsync(ReadBufferLength);         
            while (bytesRead > 0)
            {
                var b = reader.ReadByte();
                data.Add(b);
                parseByte(b);
                bytesRead--;
            }

			lastCmdReceived = MainPage.stopwatch.ElapsedMilliseconds;

			if (App.isRPi && App.Mode == Mode.Wifi)
				NetworkCmd.SendDataToHost(data.ToArray());
			if (App.isRPi && App.Mode == Mode.LTE)
				WebSocketCmd.SendDataToHost(data.ToArray());
		}

        private static async void Write(byte[] value)
        {
            try
            {
                if (serialPort != null)
                {
                    DataWriter writer = new DataWriter(serialPort.OutputStream);
                    await WriteBytesAsync(writer, value);
                    writer.DetachStream();
                    writer = null;
				}
            }
            catch(Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }

        private static async Task WriteBytesAsync(DataWriter writer, byte[] value)
        {
            writer.WriteBytes(value);
            await writer.StoreAsync();
			lastCmdSent = MainPage.stopwatch.ElapsedMilliseconds;
		}

        public static void evaluateResponseMSP(List<byte> data)
        {
            foreach (byte b in data)
            {
                parseByte(b);
            }
        }

        private static void evaluateCommand(byte cmd, int dataSize)
        {
            int icmd = (int)(cmd & 0xFF);
            switch (icmd)
            {
                case (int)MSPConst.MSP_IDENT:
                    version = read8();
                    multiType = read8();
                    mspVersion = read8();
                    capability = read32();
                    Debug.WriteLine($"Version: {version} Type: {multiType} MspVersion: {mspVersion} Capability: {capability}");
                    break;

                case (int)MSPConst.MSP_ATTITUDE:
                    angx = read16() / 10f;
                    angy = read16() / 10f;
                    head = read16();
                    headfree = read16();
                    Debug.WriteLine($"angx: {angx} angy: {angy} head: {head} headfree: {headfree}");
                    break;

                case (int)MSPConst.MSP_ALTITUDE:
                    alt = read32();
                    Debug.WriteLine($"altitude: {alt}");
                    break;

                case (int)MSPConst.MSP_RC:
                    roll = read16();
                    pitch = read16();
                    yaw = read16();
                    throttle = read16();
                    aux1 = read16();
                    aux2 = read16();
                    aux3 = read16();
                    aux4 = read16();
                    Debug.WriteLine($"MSP_RC: [{roll},{pitch},{yaw},{throttle},{aux1},{aux2},{aux3},{aux4}]");
                    break;

                case (int)MSPConst.MSP_SET_RAW_RC:
					//if (App.isRPi)
					//GetRC();
					//Debug.WriteLine("MSP_RC: Received!");
					break;

                case (int)MSPConst.MSP_RAW_GPS:
                    gpsFix = read8();
                    gpsNumSat = read8();
                    gpsLatitude = read32() / 10000000d;
                    gpsLongitude = read32() / 10000000d;
                    gpsAltitude = read16();
                    gpsSpeed = read16();
                    gpsGroundCourse = read16();
                    Debug.WriteLine($"GPS Signal: {gpsFix} GPS num sat: {gpsNumSat} Latitude: {gpsLatitude} Longitude: {gpsLongitude} Altitude: {gpsAltitude} Speed: {gpsSpeed}");
                    break;

                default:
                    Debug.WriteLine("Command not implemented: " + icmd);
                    break;
            }
        }

        // ROLL/PITCH/YAW/THROTTLE/AUX1/AUX2/AUX3/AUX4
        // Range [1000;2000]
        // This request is used to inject RC channel via MSP. Each chan overrides legacy RX as long as it is refreshed at least every second. See UART radio projects for more details.
        // Command Code = 200
        public static void MSP_SET_RAW_RC(UInt16 ch1, UInt16 ch2, UInt16 ch3, UInt16 ch4, UInt16 ch5, UInt16 ch6, UInt16 ch7, UInt16 ch8)
        {
			if (!deviceIsConnected)
				return;

            // Send
            List<byte> data = new List<byte>();
            data.AddRange(BitConverter.GetBytes(ch1));
            data.AddRange(BitConverter.GetBytes(ch2));
            data.AddRange(BitConverter.GetBytes(ch3));
            data.AddRange(BitConverter.GetBytes(ch4));
            data.AddRange(BitConverter.GetBytes(ch5));
            data.AddRange(BitConverter.GetBytes(ch6));
            data.AddRange(BitConverter.GetBytes(ch7));
            data.AddRange(BitConverter.GetBytes(ch8));

            sendRequestMSP(requestMSP((int)MSPConst.MSP_SET_RAW_RC, data.ToArray()));
        }

        public static byte[] Calculate_MSP_SET_RAW_RC(UInt16 ch1, UInt16 ch2, UInt16 ch3, UInt16 ch4, UInt16 ch5, UInt16 ch6, UInt16 ch7, UInt16 ch8)
        {
            // Send
            List<byte> data = new List<byte>();
            data.AddRange(BitConverter.GetBytes(ch1));
            data.AddRange(BitConverter.GetBytes(ch2));
            data.AddRange(BitConverter.GetBytes(ch3));
            data.AddRange(BitConverter.GetBytes(ch4));
            data.AddRange(BitConverter.GetBytes(ch5));
            data.AddRange(BitConverter.GetBytes(ch6));
            data.AddRange(BitConverter.GetBytes(ch7));
            data.AddRange(BitConverter.GetBytes(ch8));

            return requestMSP((int)MSPConst.MSP_SET_RAW_RC, data.ToArray()).ToArray();
        }

        public static void GetRC()
        {
			if (!deviceIsConnected)
				return;

			sendRequestMSP(requestMSP((int)MSPConst.MSP_RC));
        }

        public static void GetGPSData()
        {
			if (!deviceIsConnected)
				return;

			sendRequestMSP(requestMSP((int)MSPConst.MSP_RAW_GPS));
        }

        public static void GetBoardVersion()
        {
			if (!deviceIsConnected)
				return;

			sendRequestMSP(requestMSP((int)MSPConst.MSP_IDENT));
        }

        public static void GetAltitude()
        {
			if (!deviceIsConnected)
				return;

			sendRequestMSP(requestMSP((int)MSPConst.MSP_ALTITUDE));
        }

        public static void GetAttitude()
        {
			if (!deviceIsConnected)
				return;

			sendRequestMSP(requestMSP((int)MSPConst.MSP_ATTITUDE));
        }
    }
}
Telemetry.csC#
using Drone.Helpers;
using Microsoft.Azure.Devices.Client;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using Windows.Networking.Connectivity;

namespace Drone
{
    public class Telemetry
    {
        private static DeviceClient deviceClient;
        private static string iotHubUri = "yourservice.azure-devices.net";
        private static string deviceKey = "yourkeyhere";
        private static string deviceId = "yourdeviceidhere";
		private static bool iotHubIsConnected = false;

		public static void Init()
        {
            try
            {
                deviceClient = DeviceClient.Create(iotHubUri, new DeviceAuthenticationWithRegistrySymmetricKey(deviceId, deviceKey));
				Debug.WriteLine("Connected to IoTHub");
				iotHubIsConnected = true;
			}
            catch (Exception ex)
            {
                Debug.WriteLine("Error during telemetry init: " + ex.Message);
            }
        }

        public static async Task SendMessagesAsync(ITelemetryMessage message)
        {
			if (!iotHubIsConnected)
				return;

            var data = new Message(Encoding.ASCII.GetBytes(message.GetJSON()));

            try
            {
                await deviceClient.SendEventAsync(data);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error sending telemetry message to Azure: " + ex.Message);
            }
        }

		public static int GetSignalStrength() 
		{
			var connectionProfile = NetworkInformation.GetInternetConnectionProfile();
			var signal = connectionProfile.GetSignalBars();

			if (signal.HasValue)
				return (int)signal;
			else
				return 0;
		}
	}
}

Credits

Replications

Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Similar projects you might like

Wildlife Detector
Advanced
  • 766
  • 13

Device detects motion, then takes a picture of triggering wildlife. Uses a neural net to identify the wildlife species and does something.

Living Space web APP
Advanced
  • 307
  • 5

Work in progress

Moving Somewhere New? Want to know the climate of a location with amenities nearby ? Use LIVING SPACE APP to find that perfect location.

Detecting Older Irrigation Lines
Advanced
  • 479
  • 6

Work in progress

Irrigation pipelines are everywhere and some irrigation lines are 30-40 old.People have no idea where the line is?so we can use this device.

Tracking TV Stand
Advanced
  • 627
  • 8

Full instructions

The Tracking TV Stand uses a Walabot to angle a monitor in the optimal angle for viewing depending on the audience in the field of view.

Baby Room Watcher
Advanced
  • 527
  • 7

Full instructions

Monitor what happening in the baby room when we are not present there and send an SMS to the parent when motion is Detected.

Anti-Snoozer
Advanced
  • 75
  • 1

Work in progress

Anti-Snoozer is a project powered by Intel Edison and Intel RealSense that is geared to prevent accidents that occur as a result of falling

Anti-Snoozer

Team Safe Drivers

ProjectsCommunitiesTopicsContestsLiveAppsBetaFree StoreBlogAdd projectSign up / Login
Feedback