using System; using System.Collections.Generic; using System.ComponentModel; using System.Configuration; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO; using System.Xml; using System.Collections; using System.Net; using System.Text.RegularExpressions; using System.Diagnostics; using System.Runtime.InteropServices; using System.Speech.Synthesis; using System.Globalization; using System.Threading; using System.Net.Sockets; using ArdupilotMega.Utilities; using IronPython.Hosting; using log4net; using ArdupilotMega.Controls; using System.Security.Cryptography; using ArdupilotMega.Comms; using ArdupilotMega.Arduino; using System.IO.Ports; using Transitions; namespace ArdupilotMega { public partial class MainV2 : Form { private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); // used to hide/show console window [DllImport("user32.dll")] public static extern int FindWindow(string szClass, string szTitle); [DllImport("user32.dll")] public static extern int ShowWindow(int Handle, int showState); const int SW_SHOWNORMAL = 1; const int SW_HIDE = 0; /// /// Main Comport interface /// public static MAVLink comPort = new MAVLink(); /// /// Comport name /// public static string comPortName = ""; /// /// use to store all internal config /// public static Hashtable config = new Hashtable(); /// /// used to prevent comport access for exclusive use /// public static bool giveComport = false; /// /// mono detection /// public static bool MONO = false; /// /// speech engein enable /// public static bool speechEnable = false; /// /// spech engine static class /// public static Speech speechEngine = null; /// /// joystick static class /// public static Joystick joystick = null; /// /// track last joystick packet sent. used to track timming /// DateTime lastjoystick = DateTime.Now; /// /// hud background image grabber from a video stream - not realy that efficent. ie no hardware overlays etc. /// public static WebCamService.Capture cam = null; /// /// the static global state of the currently connected MAV /// public static CurrentState cs = new CurrentState(); /// /// controls the main serial reader thread /// bool serialThread = false; /// /// used for mini https server for websockets/mjpeg video stream, and network link kmls /// private TcpListener listener; /// /// track the last heartbeat sent /// private DateTime heatbeatSend = DateTime.Now; /// /// used to call anything as needed. /// public static MainV2 instance = null; public static MainSwitcher View; /// /// used to feed in a network link kml to the http server /// public string georefkml = ""; /// /// store the time we first connect /// DateTime connecttime = DateTime.Now; /// /// enum of firmwares /// public enum Firmwares { ArduPlane, ArduCopter2, ArduRover } DateTime connectButtonUpdate = DateTime.Now; /// /// declared here if i want a "single" instance of the form /// ie configuration gets reloaded on every click /// GCSViews.FlightData FlightData; GCSViews.FlightPlanner FlightPlanner; //GCSViews.ConfigurationView.Setup Configuration; GCSViews.Simulation Simulation; //GCSViews.Firmware Firmware; //GCSViews.Terminal Terminal; private Form connectionStatsForm; private ConnectionStats _connectionStats; /// /// This 'Control' is the toolstrip control that holds the comport combo, baudrate combo etc /// Otiginally seperate controls, each hosted in a toolstip sqaure, combined into this custom /// control for layout reasons. /// static internal ConnectionControl _connectionControl; public MainV2() { log.Info("Mainv2 ctor"); Form splash = new Splash(); splash.Show(); string strVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); strVersion = "mav " + MAVLink.MAVLINK_WIRE_PROTOCOL_VERSION; splash.Text = "Mission Planner " + Application.ProductVersion + " " + strVersion; splash.Refresh(); Application.DoEvents(); instance = this; InitializeComponent(); View = MyView; _connectionControl = toolStripConnectionControl.ConnectionControl; _connectionControl.CMB_baudrate.TextChanged += this.CMB_baudrate_TextChanged; _connectionControl.CMB_baudrate.SelectedIndexChanged += this.CMB_baudrate_SelectedIndexChanged; _connectionControl.CMB_serialport.SelectedIndexChanged += this.CMB_serialport_SelectedIndexChanged; _connectionControl.CMB_serialport.Enter += this.CMB_serialport_Enter; _connectionControl.CMB_serialport.Click += this.CMB_serialport_Click; _connectionControl.TOOL_APMFirmware.SelectedIndexChanged += this.TOOL_APMFirmware_SelectedIndexChanged; _connectionControl.ShowLinkStats += (sender, e) => ShowConnectionStatsForm(); srtm.datadirectory = Path.GetDirectoryName(Application.ExecutablePath) + Path.DirectorySeparatorChar + "srtm"; var t = Type.GetType("Mono.Runtime"); MONO = (t != null); speechEngine = new Speech(); // proxy loader - dll load now instead of on config form load new Transition(new TransitionType_EaseInEaseOut(2000)); MyRenderer.currentpressed = MenuFlightData; MainMenu.Renderer = new MyRenderer(); foreach (object obj in Enum.GetValues(typeof(Firmwares))) { _connectionControl.TOOL_APMFirmware.Items.Add(obj); } if (_connectionControl.TOOL_APMFirmware.Items.Count > 0) _connectionControl.TOOL_APMFirmware.SelectedIndex = 0; this.Text = splash.Text; comPort.BaseStream.BaudRate = 115200; // ** Old // CMB_serialport.Items.AddRange(SerialPort.GetPortNames()); // CMB_serialport.Items.Add("TCP"); // CMB_serialport.Items.Add("UDP"); // if (CMB_serialport.Items.Count > 0) // { // CMB_baudrate.SelectedIndex = 7; // CMB_serialport.SelectedIndex = 0; // } // ** new _connectionControl.CMB_serialport.Items.AddRange(ArdupilotMega.Comms.SerialPort.GetPortNames()); _connectionControl.CMB_serialport.Items.Add("TCP"); _connectionControl.CMB_serialport.Items.Add("UDP"); if (_connectionControl.CMB_serialport.Items.Count > 0) { _connectionControl.CMB_baudrate.SelectedIndex = 7; _connectionControl.CMB_serialport.SelectedIndex = 0; } // ** Done splash.Refresh(); Application.DoEvents(); // set this before we reset it MainV2.config["NUM_tracklength"] = "200"; xmlconfig(false); if (config.ContainsKey("language") && !string.IsNullOrEmpty((string)config["language"])) changelanguage(CultureInfoEx.GetCultureInfo((string)config["language"])); if (!MONO) // windows only { if (MainV2.config["showconsole"] != null && MainV2.config["showconsole"].ToString() == "True") { } else { int win = FindWindow("ConsoleWindowClass", null); ShowWindow(win, SW_HIDE); // hide window } } try { FlightData = new GCSViews.FlightData(); FlightPlanner = new GCSViews.FlightPlanner(); //Configuration = new GCSViews.ConfigurationView.Setup(); Simulation = new GCSViews.Simulation(); //Firmware = new GCSViews.Firmware(); //Terminal = new GCSViews.Terminal(); // preload Python.CreateEngine(); } catch (ArgumentException e) { //http://www.microsoft.com/en-us/download/details.aspx?id=16083 //System.ArgumentException: Font 'Arial' does not support style 'Regular'. log.Fatal(e); CustomMessageBox.Show(e.ToString() + "\n\n Please install this http://www.microsoft.com/en-us/download/details.aspx?id=16083"); this.Close(); } catch (Exception e) { log.Fatal(e); CustomMessageBox.Show("A Major error has occured : " + e.ToString()); this.Close(); } if (MainV2.config["CHK_GDIPlus"] != null) GCSViews.FlightData.myhud.UseOpenGL = !bool.Parse(MainV2.config["CHK_GDIPlus"].ToString()); ChangeUnits(); try { if (config["MainLocX"] != null && config["MainLocY"] != null) { this.StartPosition = FormStartPosition.Manual; Point startpos = new Point(int.Parse(config["MainLocX"].ToString()), int.Parse(config["MainLocY"].ToString())); this.Location = startpos; } if (config["MainMaximised"] != null) { this.WindowState = (FormWindowState)Enum.Parse(typeof(FormWindowState), config["MainMaximised"].ToString()); // dont allow minimised start state if (this.WindowState == FormWindowState.Minimized) { this.WindowState = FormWindowState.Normal; this.Location = new Point(100, 100); } } if (config["MainHeight"] != null) this.Height = int.Parse(config["MainHeight"].ToString()); if (config["MainWidth"] != null) this.Width = int.Parse(config["MainWidth"].ToString()); if (config["CMB_rateattitude"] != null) MainV2.cs.rateattitude = byte.Parse(config["CMB_rateattitude"].ToString()); if (config["CMB_rateposition"] != null) MainV2.cs.rateposition = byte.Parse(config["CMB_rateposition"].ToString()); if (config["CMB_ratestatus"] != null) MainV2.cs.ratestatus = byte.Parse(config["CMB_ratestatus"].ToString()); if (config["CMB_raterc"] != null) MainV2.cs.raterc = byte.Parse(config["CMB_raterc"].ToString()); if (config["CMB_ratesensors"] != null) MainV2.cs.ratesensors = byte.Parse(config["CMB_ratesensors"].ToString()); if (config["speechenable"] != null) MainV2.speechEnable = bool.Parse(config["speechenable"].ToString()); //int fixme; /* MainV2.cs.rateattitude = 50; MainV2.cs.rateposition = 50; MainV2.cs.ratestatus = 50; MainV2.cs.raterc = 50; MainV2.cs.ratesensors = 50; */ try { if (config["TXT_homelat"] != null) cs.HomeLocation.Lat = double.Parse(config["TXT_homelat"].ToString()); if (config["TXT_homelng"] != null) cs.HomeLocation.Lng = double.Parse(config["TXT_homelng"].ToString()); if (config["TXT_homealt"] != null) cs.HomeLocation.Alt = double.Parse(config["TXT_homealt"].ToString()); } catch { } } catch { } if (cs.rateattitude == 0) // initilised to 10, configured above from save { CustomMessageBox.Show("NOTE: your attitude rate is 0, the hud will not work\nChange in Configuration > Planner > Telemetry Rates"); } //System.Threading.Thread.Sleep(2000); // make sure new enough .net framework is installed if (!MONO) { Microsoft.Win32.RegistryKey installed_versions = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP"); string[] version_names = installed_versions.GetSubKeyNames(); //version names start with 'v', eg, 'v3.5' which needs to be trimmed off before conversion double Framework = Convert.ToDouble(version_names[version_names.Length - 1].Remove(0, 1), CultureInfo.InvariantCulture); int SP = Convert.ToInt32(installed_versions.OpenSubKey(version_names[version_names.Length - 1]).GetValue("SP", 0)); if (Framework < 3.5) { CustomMessageBox.Show("This program requires .NET Framework 3.5. You currently have " + Framework); } } Application.DoEvents(); splash.Close(); } private void ResetConnectionStats() { // If the form has been closed, or never shown before, we need do nothing, as // connection stats will be reset when shown if (this.connectionStatsForm != null && connectionStatsForm.Visible) { // else the form is already showing. reset the stats this.connectionStatsForm.Controls.Clear(); _connectionStats = new ConnectionStats(comPort); this.connectionStatsForm.Controls.Add(_connectionStats); ThemeManager.ApplyThemeTo(this.connectionStatsForm); } } private void ShowConnectionStatsForm() { if (this.connectionStatsForm == null || this.connectionStatsForm.IsDisposed) { // If the form has been closed, or never shown before, we need all new stuff this.connectionStatsForm = new Form { Width = 430, Height = 180, MaximizeBox = false, MinimizeBox = false, FormBorderStyle = FormBorderStyle.FixedDialog, Text = "Link Stats" }; // Change the connection stats control, so that when/if the connection stats form is showing, // there will be something to see this.connectionStatsForm.Controls.Clear(); _connectionStats = new ConnectionStats(comPort); this.connectionStatsForm.Controls.Add(_connectionStats); this.connectionStatsForm.Width = _connectionStats.Width; } this.connectionStatsForm.Show(); ThemeManager.ApplyThemeTo(this.connectionStatsForm); } /// /// used to create planner screenshots - access by control-s /// internal void ScreenShot() { Rectangle bounds = Screen.GetBounds(Point.Empty); using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height)) { using (Graphics g = Graphics.FromImage(bitmap)) { g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size); } string name = "ss" + DateTime.Now.ToString("HHmmss") + ".jpg"; bitmap.Save(Path.GetDirectoryName(Application.ExecutablePath) + Path.DirectorySeparatorChar + name, System.Drawing.Imaging.ImageFormat.Jpeg); CustomMessageBox.Show("Screenshot saved to " + name); } } private void CMB_serialport_Click(object sender, EventArgs e) { string oldport = _connectionControl.CMB_serialport.Text; _connectionControl.CMB_serialport.Items.Clear(); _connectionControl.CMB_serialport.Items.AddRange(ArdupilotMega.Comms.SerialPort.GetPortNames()); _connectionControl.CMB_serialport.Items.Add("TCP"); _connectionControl.CMB_serialport.Items.Add("UDP"); if (_connectionControl.CMB_serialport.Items.Contains(oldport)) _connectionControl.CMB_serialport.Text = oldport; } private void MenuFlightData_Click(object sender, EventArgs e) { MyView.ShowScreen("FlightData"); } private void MenuFlightPlanner_Click(object sender, EventArgs e) { // refresh ap/ac specific items FlightPlanner.updateCMDParams(); MyView.ShowScreen("FlightPlanner"); } private void MenuConfiguration_Click(object sender, EventArgs e) { MyView.ShowScreen("Config"); } private void MenuSimulation_Click(object sender, EventArgs e) { MyView.ShowScreen("Simulation"); } private void MenuFirmware_Click(object sender, EventArgs e) { MyView.ShowScreen("Firmware"); } private void MenuTerminal_Click(object sender, EventArgs e) { if (comPort.BaseStream.IsOpen) { MenuConnect_Click(sender, e); } MyView.ShowScreen("Terminal"); } private void MenuConnect_Click(object sender, EventArgs e) { giveComport = false; // sanity check if (comPort.BaseStream.IsOpen && cs.groundspeed > 4) { if (DialogResult.No == CustomMessageBox.Show("Your model is still moving are you sure you want to disconnect?", "Disconnect", MessageBoxButtons.YesNo)) { return; } } // cleanup from any previous sessions if (comPort.logfile != null) comPort.logfile.Close(); if (comPort.rawlogfile != null) comPort.rawlogfile.Close(); comPort.logfile = null; comPort.rawlogfile = null; // decide if this is a connect or disconnect if (comPort.BaseStream.IsOpen) { try { if (speechEngine != null) // cancel all pending speech speechEngine.SpeakAsyncCancelAll(); comPort.BaseStream.DtrEnable = false; comPort.Close(); } catch (Exception ex) { log.Error(ex); } // now that we have closed the connection, cancel the connection stats // so that the 'time connected' etc does not grow, but the user can still // look at the now frozen stats on the still open form try { // if terminal is used, then closed using this button.... exception ((ConnectionStats)this.connectionStatsForm.Controls[0]).StopUpdates(); } catch { } this.MenuConnect.BackgroundImage = global::ArdupilotMega.Properties.Resources.connect; } else { switch (_connectionControl.CMB_serialport.Text) { case "TCP": comPort.BaseStream = new TcpSerial(); break; case "UDP": comPort.BaseStream = new UdpSerial(); break; default: comPort.BaseStream = new Comms.SerialPort(); break; } // Tell the connection UI that we are now connected. _connectionControl.IsConnected(true); // Here we want to reset the connection stats counter etc. this.ResetConnectionStats(); //cleanup any log being played comPort.logreadmode = false; if (comPort.logplaybackfile != null) comPort.logplaybackfile.Close(); comPort.logplaybackfile = null; try { // set port, then options comPort.BaseStream.PortName = _connectionControl.CMB_serialport.Text; comPort.BaseStream.DataBits = 8; comPort.BaseStream.StopBits = (StopBits)Enum.Parse(typeof(StopBits), "1"); comPort.BaseStream.Parity = (Parity)Enum.Parse(typeof(Parity), "None"); try { comPort.BaseStream.BaudRate = int.Parse(_connectionControl.CMB_baudrate.Text); } catch (Exception exp) { log.Error(exp); } // false here comPort.BaseStream.DtrEnable = false; comPort.BaseStream.RtsEnable = false; // prevent serialreader from doing anything giveComport = true; // reset on connect logic. if (config["CHK_resetapmonconnect"] == null || bool.Parse(config["CHK_resetapmonconnect"].ToString()) == true) comPort.BaseStream.toggleDTR(); giveComport = false; // setup to record new logs try { Directory.CreateDirectory(Path.GetDirectoryName(Application.ExecutablePath) + Path.DirectorySeparatorChar + @"logs"); comPort.logfile = new BinaryWriter(File.Open(Path.GetDirectoryName(Application.ExecutablePath) + Path.DirectorySeparatorChar + @"logs" + Path.DirectorySeparatorChar + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss") + ".tlog", FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None)); comPort.rawlogfile = new BinaryWriter(File.Open(Path.GetDirectoryName(Application.ExecutablePath) + Path.DirectorySeparatorChar + @"logs" + Path.DirectorySeparatorChar + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss") + ".rlog", FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None)); } catch (Exception exp2) { log.Error(exp2); CustomMessageBox.Show("Failed to create log - wont log this session"); } // soft fail // reset connect time - for timeout functions connecttime = DateTime.Now; // do the connect comPort.Open(true); // detect firmware we are conected to. if (comPort.param["SYSID_SW_TYPE"] != null) { if (float.Parse(comPort.param["SYSID_SW_TYPE"].ToString()) == 10) { _connectionControl.TOOL_APMFirmware.SelectedIndex = _connectionControl.TOOL_APMFirmware.Items.IndexOf(Firmwares.ArduCopter2); } else if (float.Parse(comPort.param["SYSID_SW_TYPE"].ToString()) == 20) { _connectionControl.TOOL_APMFirmware.SelectedIndex = _connectionControl.TOOL_APMFirmware.Items.IndexOf(Firmwares.ArduRover); } else if (float.Parse(comPort.param["SYSID_SW_TYPE"].ToString()) == 0) { _connectionControl.TOOL_APMFirmware.SelectedIndex = _connectionControl.TOOL_APMFirmware.Items.IndexOf(Firmwares.ArduPlane); } } // save the baudrate for this port config[_connectionControl.CMB_serialport.Text + "_BAUD"] = _connectionControl.CMB_baudrate.Text; // refresh config window if needed if (MyView.current != null && MyView.current.Name == "Config") { MyView.ShowScreen("Config"); } // load wps on connect option. if (config["loadwpsonconnect"] != null && bool.Parse(config["loadwpsonconnect"].ToString()) == true) { MenuFlightPlanner_Click(null, null); FlightPlanner.BUT_read_Click(null, null); } // set connected icon this.MenuConnect.BackgroundImage = global::ArdupilotMega.Properties.Resources.disconnect; } catch (Exception ex) { log.Warn(ex); try { _connectionControl.IsConnected(false); UpdateConnectIcon(); comPort.Close(); } catch { } // detect firmware -> scan eeprom contents -> error if no valid ap param/apvar header detected. try { string version = ArduinoDetect.DetectVersion(comPort.BaseStream.PortName); ArduinoComms port = new ArduinoSTK(); if (version == "1280") { port = new ArduinoSTK(); port.BaudRate = 57600; } else if (version == "2560") { port = new ArduinoSTKv2(); port.BaudRate = 115200; } else { throw new Exception("Can not determine APM board type"); } port.PortName = comPort.BaseStream.PortName; port.DtrEnable = true; port.Open(); if (port.connectAP()) { byte[] buffer = port.download(20); port.Close(); if ((buffer[0] == 'A' || buffer[0] == 'P') && (buffer[1] == 'A' || buffer[1] == 'P')) // this is the apvar header { log.Info("Valid eeprom contents"); } else { CustomMessageBox.Show("You dont appear to have uploaded a firmware yet,\n\nPlease goto the firmware page and upload one."); return; } } else { log.Error("Could not download eeprom contents"); } } catch (Exception exp3) { log.Error(exp3); } CustomMessageBox.Show("Can not establish a connection\n\n" + ex.Message); return; } } } private void CMB_serialport_SelectedIndexChanged(object sender, EventArgs e) { comPortName = _connectionControl.CMB_serialport.Text; if (comPortName == "UDP" || comPortName == "TCP") { _connectionControl.CMB_baudrate.Enabled = false; if (comPortName == "TCP") MainV2.comPort.BaseStream = new TcpSerial(); if (comPortName == "UDP") MainV2.comPort.BaseStream = new UdpSerial(); } else { _connectionControl.CMB_baudrate.Enabled = true; MainV2.comPort.BaseStream = new ArdupilotMega.Comms.SerialPort(); } try { comPort.BaseStream.PortName = _connectionControl.CMB_serialport.Text; MainV2.comPort.BaseStream.BaudRate = int.Parse(_connectionControl.CMB_baudrate.Text); // check for saved baud rate and restore if (config[_connectionControl.CMB_serialport.Text + "_BAUD"] != null) { _connectionControl.CMB_baudrate.Text = config[_connectionControl.CMB_serialport.Text + "_BAUD"].ToString(); } } catch { } } private void MainV2_FormClosed(object sender, FormClosedEventArgs e) { // shutdown threads GCSViews.FlightData.threadrun = 0; GCSViews.Simulation.threadrun = 0; // shutdown local thread serialThread = false; try { if (comPort.BaseStream.IsOpen) comPort.Close(); } catch { } // i get alot of these errors, the port is still open, but not valid - user has unpluged usb try { FlightData.Dispose(); } catch { } try { FlightPlanner.Dispose(); } catch { } try { Simulation.Dispose(); } catch { } // save config xmlconfig(true); } private void xmlconfig(bool write) { if (write || !File.Exists(Path.GetDirectoryName(Application.ExecutablePath) + Path.DirectorySeparatorChar + @"config.xml")) { try { XmlTextWriter xmlwriter = new XmlTextWriter(Path.GetDirectoryName(Application.ExecutablePath) + Path.DirectorySeparatorChar + @"config.xml", Encoding.ASCII); xmlwriter.Formatting = Formatting.Indented; xmlwriter.WriteStartDocument(); xmlwriter.WriteStartElement("Config"); xmlwriter.WriteElementString("comport", comPortName); xmlwriter.WriteElementString("baudrate", _connectionControl.CMB_baudrate.Text); xmlwriter.WriteElementString("APMFirmware", MainV2.cs.firmware.ToString()); foreach (string key in config.Keys) { try { if (key == "" || key.Contains("/")) // "/dev/blah" continue; xmlwriter.WriteElementString(key, config[key].ToString()); } catch { } } xmlwriter.WriteEndElement(); xmlwriter.WriteEndDocument(); xmlwriter.Close(); } catch (Exception ex) { CustomMessageBox.Show(ex.ToString()); } } else { try { using (XmlTextReader xmlreader = new XmlTextReader(Path.GetDirectoryName(Application.ExecutablePath) + Path.DirectorySeparatorChar + @"config.xml")) { while (xmlreader.Read()) { xmlreader.MoveToElement(); try { switch (xmlreader.Name) { case "comport": string temp = xmlreader.ReadString(); _connectionControl.CMB_serialport.SelectedIndex = _connectionControl.CMB_serialport.FindString(temp); if (_connectionControl.CMB_serialport.SelectedIndex == -1) { _connectionControl.CMB_serialport.Text = temp; // allows ports that dont exist - yet } comPort.BaseStream.PortName = temp; comPortName = temp; break; case "baudrate": string temp2 = xmlreader.ReadString(); _connectionControl.CMB_baudrate.SelectedIndex = _connectionControl.CMB_baudrate.FindString(temp2); if (_connectionControl.CMB_baudrate.SelectedIndex == -1) { _connectionControl.CMB_baudrate.Text = temp2; //CMB_baudrate.SelectedIndex = CMB_baudrate.FindString("57600"); ; // must exist } //bau = int.Parse(CMB_baudrate.Text); break; case "APMFirmware": string temp3 = xmlreader.ReadString(); _connectionControl.TOOL_APMFirmware.SelectedIndex = _connectionControl.TOOL_APMFirmware.FindStringExact(temp3); if (_connectionControl.TOOL_APMFirmware.SelectedIndex == -1) _connectionControl.TOOL_APMFirmware.SelectedIndex = 0; MainV2.cs.firmware = (MainV2.Firmwares)Enum.Parse(typeof(MainV2.Firmwares), _connectionControl.TOOL_APMFirmware.Text); break; case "Config": break; case "xml": break; default: if (xmlreader.Name == "") // line feeds break; config[xmlreader.Name] = xmlreader.ReadString(); break; } } // silent fail on bad entry catch (Exception ee) { log.Error(ee); } } } } catch (Exception ex) { log.Error("Bad Config File", ex); } } } private void CMB_baudrate_SelectedIndexChanged(object sender, EventArgs e) { try { comPort.BaseStream.BaudRate = int.Parse(_connectionControl.CMB_baudrate.Text); } catch { } } /// /// thread used to send joystick packets to the MAV /// private void joysticksend() { float rate = 50; int count = 0; DateTime lastratechange = DateTime.Now; while (true) { try { if (MONO) { log.Error("Mono: closing joystick thread"); break; } if (!MONO) { //joystick stuff if (joystick != null && joystick.enabled) { MAVLink.mavlink_rc_channels_override_t rc = new MAVLink.mavlink_rc_channels_override_t(); rc.target_component = comPort.compid; rc.target_system = comPort.sysid; if (joystick.getJoystickAxis(1) != Joystick.joystickaxis.None) rc.chan1_raw = cs.rcoverridech1;//(ushort)(((int)state.Rz / 65.535) + 1000); if (joystick.getJoystickAxis(2) != Joystick.joystickaxis.None) rc.chan2_raw = cs.rcoverridech2;//(ushort)(((int)state.Y / 65.535) + 1000); if (joystick.getJoystickAxis(3) != Joystick.joystickaxis.None) rc.chan3_raw = cs.rcoverridech3;//(ushort)(1000 - ((int)slider[0] / 65.535 ) + 1000); if (joystick.getJoystickAxis(4) != Joystick.joystickaxis.None) rc.chan4_raw = cs.rcoverridech4;//(ushort)(((int)state.X / 65.535) + 1000); if (joystick.getJoystickAxis(5) != Joystick.joystickaxis.None) rc.chan5_raw = cs.rcoverridech5; if (joystick.getJoystickAxis(6) != Joystick.joystickaxis.None) rc.chan6_raw = cs.rcoverridech6; if (joystick.getJoystickAxis(7) != Joystick.joystickaxis.None) rc.chan7_raw = cs.rcoverridech7; if (joystick.getJoystickAxis(8) != Joystick.joystickaxis.None) rc.chan8_raw = cs.rcoverridech8; if (lastjoystick.AddMilliseconds(rate) < DateTime.Now) { /* if (cs.rssi > 0 && cs.remrssi > 0) { if (lastratechange.Second != DateTime.Now.Second) { if (cs.txbuffer > 90) { if (rate < 20) rate = 21; rate--; if (cs.linkqualitygcs < 70) rate = 50; } else { if (rate > 100) rate = 100; rate++; } lastratechange = DateTime.Now; } } */ // Console.WriteLine(DateTime.Now.Millisecond + " {0} {1} {2} {3} {4}", rc.chan1_raw, rc.chan2_raw, rc.chan3_raw, rc.chan4_raw,rate); comPort.sendPacket(rc); count++; lastjoystick = DateTime.Now; } } } Thread.Sleep(20); } catch { } // cant fall out } } /// /// Used to fix the icon status for unexpected unplugs etc... /// private void UpdateConnectIcon() { if ((DateTime.Now - connectButtonUpdate).Milliseconds > 500) { // Console.WriteLine(DateTime.Now.Millisecond); if (comPort.BaseStream.IsOpen) { if ((string)this.MenuConnect.BackgroundImage.Tag != "Disconnect") { this.BeginInvoke((MethodInvoker)delegate { this.MenuConnect.BackgroundImage = global::ArdupilotMega.Properties.Resources.disconnect; this.MenuConnect.BackgroundImage.Tag = "Disconnect"; _connectionControl.IsConnected(true); }); } } else { if ((string)this.MenuConnect.BackgroundImage.Tag != "Connect") { this.BeginInvoke((MethodInvoker)delegate { this.MenuConnect.BackgroundImage = global::ArdupilotMega.Properties.Resources.connect; this.MenuConnect.BackgroundImage.Tag = "Connect"; _connectionControl.IsConnected(false); if (_connectionStats != null) { _connectionStats.StopUpdates(); } }); } if (comPort.logreadmode) { this.BeginInvoke((MethodInvoker)delegate { _connectionControl.IsConnected(true); }); } } connectButtonUpdate = DateTime.Now; } } /// /// main serial reader thread /// controls /// serial reading /// link quality stats /// speech voltage - custom - alt warning - data lost /// heartbeat packet sending /// /// and can't fall out /// private void SerialReader() { if (serialThread == true) return; serialThread = true; int minbytes = 0; DateTime speechcustomtime = DateTime.Now; DateTime linkqualitytime = DateTime.Now; while (serialThread) { try { Thread.Sleep(5); // update connect/disconnect button and info stats UpdateConnectIcon(); // 30 seconds interval speech options if (speechEnable && speechEngine != null && (DateTime.Now - speechcustomtime).TotalSeconds > 30 && MainV2.cs.lat != 0 && (MainV2.comPort.logreadmode || comPort.BaseStream.IsOpen)) { //speechbatteryvolt float warnvolt = 0; float.TryParse(MainV2.getConfig("speechbatteryvolt"), out warnvolt); if (MainV2.getConfig("speechbatteryenabled") == "True" && MainV2.cs.battery_voltage <= warnvolt) { MainV2.speechEngine.SpeakAsync(Common.speechConversion(MainV2.getConfig("speechbattery"))); } if (MainV2.getConfig("speechcustomenabled") == "True") { MainV2.speechEngine.SpeakAsync(Common.speechConversion(MainV2.getConfig("speechcustom"))); } speechcustomtime = DateTime.Now; } // speech altitude warning. if (speechEnable && speechEngine != null && (MainV2.comPort.logreadmode || comPort.BaseStream.IsOpen)) { float warnalt = float.MaxValue; float.TryParse(MainV2.getConfig("speechaltheight"), out warnalt); try { if (MainV2.getConfig("speechaltenabled") == "True" && (MainV2.cs.alt - (int)double.Parse(MainV2.getConfig("TXT_homealt"))) <= warnalt) { if (MainV2.speechEngine.State == SynthesizerState.Ready) MainV2.speechEngine.SpeakAsync(Common.speechConversion(MainV2.getConfig("speechalt"))); } } catch { } // silent fail } // if not connected or busy, sleep and loop if (!comPort.BaseStream.IsOpen || giveComport == true) { System.Threading.Thread.Sleep(100); continue; } // make sure we attenuate the link quality if we dont see any valid packets if ((DateTime.Now - comPort.lastvalidpacket).TotalSeconds > 10) { MainV2.cs.linkqualitygcs = 0; } // attenuate the link qualty over time if ((DateTime.Now - comPort.lastvalidpacket).TotalSeconds >= 1) { if (linkqualitytime.Second != DateTime.Now.Second) { MainV2.cs.linkqualitygcs = (ushort)(MainV2.cs.linkqualitygcs * 0.8f); linkqualitytime = DateTime.Now; GCSViews.FlightData.myhud.Invalidate(); } } // send a hb every seconds from gcs to ap if (heatbeatSend.Second != DateTime.Now.Second) { MAVLink.mavlink_heartbeat_t htb = new MAVLink.mavlink_heartbeat_t() { type = (byte)MAVLink.MAV_TYPE.GCS, autopilot = (byte)MAVLink.MAV_AUTOPILOT.ARDUPILOTMEGA, mavlink_version = 3, }; comPort.sendPacket(htb); heatbeatSend = DateTime.Now; } // data loss warning - ignore first 30 seconds of connect if ((DateTime.Now - comPort.lastvalidpacket).TotalSeconds > 10 && (DateTime.Now - connecttime).TotalSeconds > 30) { if (speechEnable && speechEngine != null) { if (MainV2.speechEngine.State == SynthesizerState.Ready) MainV2.speechEngine.SpeakAsync("WARNING No Data for " + (int)(DateTime.Now - comPort.lastvalidpacket).TotalSeconds + " Seconds"); } } // actauly read the packets while (comPort.BaseStream.BytesToRead > minbytes && giveComport == false) { try { comPort.readPacket(); } catch { } } } catch (Exception e) { log.Error("Serial Reader fail :" + e.ToString()); try { comPort.Close(); } catch { } } } } /// /// Override the stock ToolStripProfessionalRenderer to implement 'highlighting' of the /// currently selected GCS view. /// private class MyRenderer : ToolStripProfessionalRenderer { public static ToolStripItem currentpressed; protected override void OnRenderButtonBackground(ToolStripItemRenderEventArgs e) { //BackgroundImage if (e.Item.BackgroundImage == null) base.OnRenderButtonBackground(e); else { Rectangle bounds = new Rectangle(Point.Empty, e.Item.Size); e.Graphics.DrawImage(e.Item.BackgroundImage, bounds); if (e.Item.Pressed || e.Item == currentpressed) { SolidBrush brush = new SolidBrush(Color.FromArgb(73, 0x2b, 0x3a, 0x03)); e.Graphics.FillRectangle(brush, bounds); if (e.Item.Name != "MenuConnect") { //Console.WriteLine("new " + e.Item.Name + " old " + currentpressed.Name ); //e.Item.GetCurrentParent().Invalidate(); if (currentpressed != e.Item) currentpressed.Invalidate(); currentpressed = e.Item; } // Something... } else if (e.Item.Selected) // mouse over { SolidBrush brush = new SolidBrush(Color.FromArgb(73, 0x2b, 0x3a, 0x03)); e.Graphics.FillRectangle(brush, bounds); // Something... } using (Pen pen = new Pen(Color.Black)) { //e.Graphics.DrawRectangle(pen, bounds.X, bounds.Y, bounds.Width - 1, bounds.Height - 1); } } } protected override void OnRenderItemImage(ToolStripItemImageRenderEventArgs e) { //base.OnRenderItemImage(e); } } private void MainV2_Load(object sender, EventArgs e) { MyView.AddScreen(new MainSwitcher.Screen("FlightData", FlightData, true)); MyView.AddScreen(new MainSwitcher.Screen("FlightPlanner", FlightPlanner, true)); MyView.AddScreen(new MainSwitcher.Screen("Config", new GCSViews.ConfigurationView.Setup(), false)); MyView.AddScreen(new MainSwitcher.Screen("Simulation", Simulation, true)); MyView.AddScreen(new MainSwitcher.Screen("Firmware", new GCSViews.Firmware(), false)); MyView.AddScreen(new MainSwitcher.Screen("Terminal", new GCSViews.Terminal(), false)); MyView.AddScreen(new MainSwitcher.Screen("Help", new GCSViews.Help(), false)); // init button depressed - ensures correct action //int fixme; MenuFlightData_Click(sender, e); // for long running tasks using own threads. // for short use threadpool // setup http server try { listener = new TcpListener(IPAddress.Any, 56781); new Thread(listernforclients) { Name = "motion jpg stream-network kml", IsBackground = true }.Start(); } catch (Exception ex) { log.Error("Error starting TCP listener thread: ", ex); CustomMessageBox.Show(ex.ToString()); } /// setup joystick packet sender new Thread(new ThreadStart(joysticksend)) { IsBackground = true, Priority = ThreadPriority.AboveNormal, Name = "Main joystick sender" }.Start(); // setup main serial reader new Thread(SerialReader) { IsBackground = true, Name = "Main Serial reader", Priority = ThreadPriority.AboveNormal }.Start(); try { if (!System.Diagnostics.Debugger.IsAttached) { // single update check per day if (getConfig("update_check") != DateTime.Now.ToShortDateString()) { CheckForUpdate(); config["update_check"] = DateTime.Now.ToShortDateString(); } } } catch (Exception ex) { log.Error("Update check failed", ex); } } public static String ComputeWebSocketHandshakeSecurityHash09(String secWebSocketKey) { const String MagicKEY = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; String secWebSocketAccept = String.Empty; // 1. Combine the request Sec-WebSocket-Key with magic key. String ret = secWebSocketKey + MagicKEY; // 2. Compute the SHA1 hash System.Security.Cryptography.SHA1 sha = new System.Security.Cryptography.SHA1CryptoServiceProvider(); byte[] sha1Hash = sha.ComputeHash(Encoding.UTF8.GetBytes(ret)); // 3. Base64 encode the hash secWebSocketAccept = Convert.ToBase64String(sha1Hash); return secWebSocketAccept; } /// /// little web server for sending network link kml's /// void listernforclients() { try { listener.Start(); } catch (Exception e) { log.Error("Exception starting lister. Possible multiple instances of planner?", e); return; } // in use // Enter the listening loop. while (true) { // Perform a blocking call to accept requests. // You could also user server.AcceptSocket() here. try { log.Info("Listening for client - 1 client at a time"); TcpClient client = listener.AcceptTcpClient(); // Get a stream object for reading and writing log.Info("Accepted Client " + client.Client.RemoteEndPoint.ToString()); //client.SendBufferSize = 100 * 1024; // 100kb //client.LingerState.Enabled = true; //client.NoDelay = true; // makesure we have valid image GCSViews.FlightData.mymap.streamjpgenable = true; GCSViews.FlightData.myhud.streamjpgenable = true; MethodInvoker m = delegate() { GCSViews.FlightData.mymap.Refresh(); }; this.Invoke(m); NetworkStream stream = client.GetStream(); var asciiEncoding = new ASCIIEncoding(); var request = new byte[1024]; int len = stream.Read(request, 0, request.Length); string head = System.Text.Encoding.ASCII.GetString(request, 0, len); log.Info(head); int index = head.IndexOf('\n'); string url = head.Substring(0, index - 1); //url = url.Replace("\r", ""); //url = url.Replace("GET ",""); //url = url.Replace(" HTTP/1.0", ""); //url = url.Replace(" HTTP/1.1", ""); if (url.Contains("websocket")) { using (var writer = new StreamWriter(stream, Encoding.Default)) { writer.WriteLine("HTTP/1.1 101 WebSocket Protocol Handshake"); writer.WriteLine("Upgrade: WebSocket"); writer.WriteLine("Connection: Upgrade"); writer.WriteLine("WebSocket-Location: ws://localhost:56781/websocket/server"); int start = head.IndexOf("Sec-WebSocket-Key:") + 19; int end = head.IndexOf('\r', start); if (end == -1) end = head.IndexOf('\n', start); string accept = ComputeWebSocketHandshakeSecurityHash09(head.Substring(start, end - start)); writer.WriteLine("Sec-WebSocket-Accept: " + accept); writer.WriteLine("Server: APM Planner"); writer.WriteLine(""); writer.Flush(); while (client.Connected) { Thread.Sleep(200); log.Debug(stream.DataAvailable + " " + client.Available); while (client.Available > 0) { Console.Write(stream.ReadByte()); } byte[] packet = new byte[256]; string sendme = cs.roll + "," + cs.pitch + "," + cs.yaw; packet[0] = 0x81; // fin - binary packet[1] = (byte)sendme.Length; int i = 2; foreach (char ch in sendme) { packet[i++] = (byte)ch; } stream.Write(packet, 0, i); //break; } } } else if (url.Contains("georefnetwork.kml")) { string header = "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.google-earth.kml+xml\r\n\r\n"; byte[] temp = asciiEncoding.GetBytes(header); stream.Write(temp, 0, temp.Length); byte[] buffer = Encoding.ASCII.GetBytes(georefkml); stream.Write(buffer, 0, buffer.Length); stream.Close(); } else if (url.Contains("network.kml")) { string header = "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.google-earth.kml+xml\r\n\r\n"; byte[] temp = asciiEncoding.GetBytes(header); stream.Write(temp, 0, temp.Length); SharpKml.Dom.Document kml = new SharpKml.Dom.Document(); SharpKml.Dom.Placemark pmplane = new SharpKml.Dom.Placemark(); pmplane.Name = "P/Q "; pmplane.Visibility = true; SharpKml.Dom.Location loc = new SharpKml.Dom.Location(); loc.Latitude = cs.lat; loc.Longitude = cs.lng; loc.Altitude = cs.alt; if (loc.Altitude < 0) loc.Altitude = 0.01; SharpKml.Dom.Orientation ori = new SharpKml.Dom.Orientation(); ori.Heading = cs.yaw; ori.Roll = -cs.roll; ori.Tilt = -cs.pitch; SharpKml.Dom.Scale sca = new SharpKml.Dom.Scale(); sca.X = 2; sca.Y = 2; sca.Z = 2; SharpKml.Dom.Model model = new SharpKml.Dom.Model(); model.Location = loc; model.Orientation = ori; model.AltitudeMode = SharpKml.Dom.AltitudeMode.Absolute; model.Scale = sca; SharpKml.Dom.Link link = new SharpKml.Dom.Link(); link.Href = new Uri("block_plane_0.dae", UriKind.Relative); model.Link = link; pmplane.Geometry = model; SharpKml.Dom.LookAt la = new SharpKml.Dom.LookAt() { Altitude = loc.Altitude.Value, Latitude = loc.Latitude.Value, Longitude = loc.Longitude.Value, Tilt = 80, Heading = cs.yaw, AltitudeMode = SharpKml.Dom.AltitudeMode.Absolute, Range = 50 }; kml.Viewpoint = la; kml.AddFeature(pmplane); SharpKml.Dom.CoordinateCollection coords = new SharpKml.Dom.CoordinateCollection(); foreach (var point in MainV2.comPort.wps.Values) { coords.Add(new SharpKml.Base.Vector(point.x, point.y, point.z)); } SharpKml.Dom.LineString ls = new SharpKml.Dom.LineString(); ls.AltitudeMode = SharpKml.Dom.AltitudeMode.RelativeToGround; ls.Coordinates = coords; SharpKml.Dom.Placemark pm = new SharpKml.Dom.Placemark() { Geometry = ls }; kml.AddFeature(pm); SharpKml.Base.Serializer serializer = new SharpKml.Base.Serializer(); serializer.Serialize(kml); byte[] buffer = Encoding.ASCII.GetBytes(serializer.Xml); stream.Write(buffer, 0, buffer.Length); stream.Close(); } else if (url.Contains("block_plane_0.dae")) { string header = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n"; byte[] temp = asciiEncoding.GetBytes(header); stream.Write(temp, 0, temp.Length); BinaryReader file = new BinaryReader(File.Open("block_plane_0.dae", FileMode.Open, FileAccess.Read, FileShare.Read)); byte[] buffer = new byte[1024]; while (file.PeekChar() != -1) { int leng = file.Read(buffer, 0, buffer.Length); stream.Write(buffer, 0, leng); } file.Close(); stream.Close(); } else if (url.Contains("hud.html")) { string header = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"; byte[] temp = asciiEncoding.GetBytes(header); stream.Write(temp, 0, temp.Length); BinaryReader file = new BinaryReader(File.Open("hud.html", FileMode.Open, FileAccess.Read, FileShare.Read)); byte[] buffer = new byte[1024]; while (file.PeekChar() != -1) { int leng = file.Read(buffer, 0, buffer.Length); stream.Write(buffer, 0, leng); } file.Close(); stream.Close(); } else if (url.ToLower().Contains("hud.jpg") || url.ToLower().Contains("map.jpg") || url.ToLower().Contains("both.jpg")) { string header = "HTTP/1.1 200 OK\r\nContent-Type: multipart/x-mixed-replace;boundary=APMPLANNER\r\n\r\n--APMPLANNER\r\n"; byte[] temp = asciiEncoding.GetBytes(header); stream.Write(temp, 0, temp.Length); while (client.Connected) { System.Threading.Thread.Sleep(200); // 5hz byte[] data = null; if (url.ToLower().Contains("hud")) { GCSViews.FlightData.myhud.streamjpgenable = true; data = GCSViews.FlightData.myhud.streamjpg.ToArray(); } else if (url.ToLower().Contains("map")) { GCSViews.FlightData.mymap.streamjpgenable = true; data = GCSViews.FlightData.mymap.streamjpg.ToArray(); } else { GCSViews.FlightData.mymap.streamjpgenable = true; GCSViews.FlightData.myhud.streamjpgenable = true; Image img1 = Image.FromStream(GCSViews.FlightData.myhud.streamjpg); Image img2 = Image.FromStream(GCSViews.FlightData.mymap.streamjpg); int bigger = img1.Height > img2.Height ? img1.Height : img2.Height; Image imgout = new Bitmap(img1.Width + img2.Width, bigger); Graphics grap = Graphics.FromImage(imgout); grap.DrawImageUnscaled(img1, 0, 0); grap.DrawImageUnscaled(img2, img1.Width, 0); MemoryStream streamjpg = new MemoryStream(); imgout.Save(streamjpg, System.Drawing.Imaging.ImageFormat.Jpeg); data = streamjpg.ToArray(); } header = "Content-Type: image/jpeg\r\nContent-Length: " + data.Length + "\r\n\r\n"; temp = asciiEncoding.GetBytes(header); stream.Write(temp, 0, temp.Length); stream.Write(data, 0, data.Length); header = "\r\n--APMPLANNER\r\n"; temp = asciiEncoding.GetBytes(header); stream.Write(temp, 0, temp.Length); } GCSViews.FlightData.mymap.streamjpgenable = false; GCSViews.FlightData.myhud.streamjpgenable = false; stream.Close(); } stream.Close(); } catch (Exception ee) { log.Error("Failed mjpg ", ee); } } } private void TOOL_APMFirmware_SelectedIndexChanged(object sender, EventArgs e) { MainV2.cs.firmware = (MainV2.Firmwares)Enum.Parse(typeof(MainV2.Firmwares), _connectionControl.TOOL_APMFirmware.Text); } private void MainV2_Resize(object sender, EventArgs e) { log.Info("myview width " + MyView.Width + " height " + MyView.Height); log.Info("this width " + this.Width + " height " + this.Height); } private void MenuHelp_Click(object sender, EventArgs e) { MyView.ShowScreen("Help"); } public static void updateCheckMain(ProgressReporterDialogue frmProgressReporter) { var baseurl = ConfigurationManager.AppSettings["UpdateLocation"]; try { bool update = updateCheck(frmProgressReporter, baseurl, ""); var process = new Process(); string exePath = Path.GetDirectoryName(Application.ExecutablePath); if (MONO) { process.StartInfo.FileName = "mono"; process.StartInfo.Arguments = " \"" + exePath + Path.DirectorySeparatorChar + "Updater.exe\"" + " \"" + Application.ExecutablePath + "\""; } else { process.StartInfo.FileName = exePath + Path.DirectorySeparatorChar + "Updater.exe"; process.StartInfo.Arguments = Application.ExecutablePath; } try { foreach (string newupdater in Directory.GetFiles(exePath, "Updater.exe*.new")) { File.Copy(newupdater, newupdater.Remove(newupdater.Length - 4), true); File.Delete(newupdater); } } catch (Exception ex) { log.Error("Exception during update", ex); } if (frmProgressReporter != null) frmProgressReporter.UpdateProgressAndStatus(-1, "Starting Updater"); log.Info("Starting new process: " + process.StartInfo.FileName + " with " + process.StartInfo.Arguments); process.Start(); log.Info("Quitting existing process"); try { // clean close MainV2.instance.BeginInvoke((MethodInvoker)delegate() { MainV2.instance.Close(); }); } catch (Exception ex) { log.Error(ex); Application.Exit(); } } catch (Exception ex) { log.Error("Update Failed", ex); CustomMessageBox.Show("Update Failed " + ex.Message); } } private static void UpdateLabel(Label loadinglabel, string text) { MainV2.instance.Invoke((MethodInvoker)delegate { loadinglabel.Text = text; Application.DoEvents(); }); } private static void CheckForUpdate() { var baseurl = ConfigurationManager.AppSettings["UpdateLocation"]; string path = Path.GetDirectoryName(Application.ExecutablePath); path = path + Path.DirectorySeparatorChar + "version.txt"; log.Debug(path); // Create a request using a URL that can receive a post. string requestUriString = baseurl + Path.GetFileName(path); log.Debug("Checking for update at: " + requestUriString); var webRequest = WebRequest.Create(requestUriString); webRequest.Timeout = 5000; // Set the Method property of the request to POST. webRequest.Method = "GET"; ((HttpWebRequest)webRequest).IfModifiedSince = File.GetLastWriteTimeUtc(path); // Get the response. var response = webRequest.GetResponse(); // Display the status. log.Debug("Response status: " + ((HttpWebResponse)response).StatusDescription); // Get the stream containing content returned by the server. //dataStream = response.GetResponseStream(); // Open the stream using a StreamReader for easy access. bool updateFound = false; if (File.Exists(path)) { var fi = new FileInfo(path); Version LocalVersion = new Version(); Version WebVersion = new Version(); if (File.Exists(path)) { using (Stream fs = File.OpenRead(path)) { using (StreamReader sr = new StreamReader(fs)) { LocalVersion = new Version(sr.ReadLine()); sr.Close(); } fs.Close(); } } using (StreamReader sr = new StreamReader(response.GetResponseStream())) { WebVersion = new Version(sr.ReadLine()); sr.Close(); } log.Info("New file Check: local " + LocalVersion + " vs Remote " + WebVersion); if (LocalVersion < WebVersion) { updateFound = true; } } else { updateFound = true; log.Info("File does not exist: Getting " + path); // get it } response.Close(); if (updateFound) { var dr = CustomMessageBox.Show("Update Found\n\nDo you wish to update now?", "Update Now", MessageBoxButtons.YesNo); if (dr == DialogResult.Yes) { DoUpdate(); } else { return; } } } public static void DoUpdate() { ProgressReporterDialogue frmProgressReporter = new ProgressReporterDialogue() { Text = "Check for Updates", StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen }; ThemeManager.ApplyThemeTo(frmProgressReporter); frmProgressReporter.DoWork += new Controls.ProgressReporterDialogue.DoWorkEventHandler(DoUpdateWorker_DoWork); frmProgressReporter.UpdateProgressAndStatus(-1, "Checking for Updates"); frmProgressReporter.RunBackgroundOperationAsync(); } static void DoUpdateWorker_DoWork(object sender, Controls.ProgressWorkerEventArgs e) { // TODO: Is this the right place? #region Fetch Parameter Meta Data var progressReporterDialogue = ((ProgressReporterDialogue)sender); progressReporterDialogue.UpdateProgressAndStatus(-1, "Getting Updated Parameters"); try { ParameterMetaDataParser.GetParameterInformation(); } catch (Exception ex) { log.Error(ex.ToString()); CustomMessageBox.Show("Error getting Parameter Information"); } #endregion Fetch Parameter Meta Data progressReporterDialogue.UpdateProgressAndStatus(-1, "Getting Base URL"); // check for updates if (Debugger.IsAttached) { log.Info("Skipping update test as it appears we are debugging"); } else { MainV2.updateCheckMain(progressReporterDialogue); } } private static bool updateCheck(ProgressReporterDialogue frmProgressReporter, string baseurl, string subdir) { bool update = false; List files = new List(); // Create a request using a URL that can receive a post. log.Info(baseurl); WebRequest request = WebRequest.Create(baseurl); request.Timeout = 10000; // Set the Method property of the request to POST. request.Method = "GET"; // Get the request stream. Stream dataStream; //= request.GetRequestStream(); // Get the response. WebResponse response = request.GetResponse(); // Display the status. log.Info(((HttpWebResponse)response).StatusDescription); // Get the stream containing content returned by the server. dataStream = response.GetResponseStream(); // Open the stream using a StreamReader for easy access. StreamReader reader = new StreamReader(dataStream); // Read the content. string responseFromServer = reader.ReadToEnd(); // Display the content. Regex regex = new Regex("href=\"([^\"]+)\"", RegexOptions.IgnoreCase); if (regex.IsMatch(responseFromServer)) { MatchCollection matchs = regex.Matches(responseFromServer); for (int i = 0; i < matchs.Count; i++) { if (matchs[i].Groups[1].Value.ToString().Contains("..")) continue; if (matchs[i].Groups[1].Value.ToString().Contains("http")) continue; files.Add(System.Web.HttpUtility.UrlDecode(matchs[i].Groups[1].Value.ToString())); } } //Console.WriteLine(responseFromServer); // Clean up the streams. reader.Close(); dataStream.Close(); response.Close(); string dir = Path.GetDirectoryName(Application.ExecutablePath) + Path.DirectorySeparatorChar + subdir; if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); foreach (string file in files) { if (frmProgressReporter.doWorkArgs.CancelRequested) { frmProgressReporter.doWorkArgs.CancelAcknowledged = true; throw new Exception("Cancel"); } if (file.Equals("/")) { continue; } if (file.EndsWith("/")) { update = updateCheck(frmProgressReporter, baseurl + file, subdir.Replace('/', Path.DirectorySeparatorChar) + file) && update; continue; } if (frmProgressReporter != null) frmProgressReporter.UpdateProgressAndStatus(-1, "Checking " + file); string path = Path.GetDirectoryName(Application.ExecutablePath) + Path.DirectorySeparatorChar + subdir + file; // Create a request using a URL that can receive a post. request = WebRequest.Create(baseurl + file); log.Info(baseurl + file + " "); // Set the Method property of the request to POST. request.Method = "HEAD"; ((HttpWebRequest)request).IfModifiedSince = File.GetLastWriteTimeUtc(path); // Get the response. response = request.GetResponse(); // Display the status. log.Info(((HttpWebResponse)response).StatusDescription); // Get the stream containing content returned by the server. //dataStream = response.GetResponseStream(); // Open the stream using a StreamReader for easy access. bool updateThisFile = false; if (File.Exists(path)) { FileInfo fi = new FileInfo(path); //log.Info(response.Headers[HttpResponseHeader.ETag]); string CurrentEtag = ""; if (File.Exists(path + ".etag")) { using (Stream fs = File.OpenRead(path + ".etag")) { using (StreamReader sr = new StreamReader(fs)) { CurrentEtag = sr.ReadLine(); sr.Close(); } fs.Close(); } } log.Debug("New file Check: " + fi.Length + " vs " + response.ContentLength + " " + response.Headers[HttpResponseHeader.ETag] + " vs " + CurrentEtag); if (fi.Length != response.ContentLength || response.Headers[HttpResponseHeader.ETag] != CurrentEtag) { using (StreamWriter sw = new StreamWriter(path + ".etag.new")) { sw.WriteLine(response.Headers[HttpResponseHeader.ETag]); sw.Close(); } updateThisFile = true; log.Info("NEW FILE " + file); } } else { updateThisFile = true; log.Info("NEW FILE " + file); // get it } reader.Close(); //dataStream.Close(); response.Close(); if (updateThisFile) { if (!update) { //DialogResult dr = MessageBox.Show("Update Found\n\nDo you wish to update now?", "Update Now", MessageBoxButtons.YesNo); //if (dr == DialogResult.Yes) { update = true; } //else { // return; } } if (frmProgressReporter != null) frmProgressReporter.UpdateProgressAndStatus(-1, "Getting " + file); // from head long bytes = response.ContentLength; // Create a request using a URL that can receive a post. request = HttpWebRequest.Create(baseurl + file); // Set the Method property of the request to POST. request.Method = "GET"; ((HttpWebRequest)request).AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; request.Headers.Add("Accept-Encoding", "gzip,deflate"); // Get the response. response = request.GetResponse(); // Display the status. log.Debug(((HttpWebResponse)response).StatusDescription); // Get the stream containing content returned by the server. dataStream = response.GetResponseStream(); long contlen = bytes; byte[] buf1 = new byte[1024]; FileStream fs = new FileStream(path + ".new", FileMode.Create); // DateTime dt = DateTime.Now; dataStream.ReadTimeout = 30000; while (dataStream.CanRead) { try { if (dt.Second != DateTime.Now.Second) { if (frmProgressReporter != null) frmProgressReporter.UpdateProgressAndStatus((int)(((double)(contlen - bytes) / (double)contlen) * 100), "Getting " + file + ": " + (((double)(contlen - bytes) / (double)contlen) * 100).ToString("0.0") + "%"); //+ Math.Abs(bytes) + " bytes"); dt = DateTime.Now; } } catch { } // log.Debug(file + " " + bytes); int len = dataStream.Read(buf1, 0, 1024); if (len == 0) break; bytes -= len; fs.Write(buf1, 0, len); } fs.Close(); dataStream.Close(); response.Close(); } } //P.StartInfo.CreateNoWindow = true; //P.StartInfo.RedirectStandardOutput = true; return update; } /// /// trying to replicate google code etags....... this doesnt work. /// /// /// /// private string GetFileETag(string fileName, DateTime modifyDate) { string FileString; System.Text.Encoder StringEncoder; byte[] StringBytes; MD5CryptoServiceProvider MD5Enc; //use file name and modify date as the unique identifier FileString = fileName + modifyDate.ToString("d", CultureInfo.InvariantCulture); //get string bytes StringEncoder = Encoding.UTF8.GetEncoder(); StringBytes = new byte[StringEncoder.GetByteCount(FileString.ToCharArray(), 0, FileString.Length, true)]; StringEncoder.GetBytes(FileString.ToCharArray(), 0, FileString.Length, StringBytes, 0, true); //hash string using MD5 and return the hex-encoded hash MD5Enc = new MD5CryptoServiceProvider(); byte[] hash = MD5Enc.ComputeHash((Stream)File.OpenRead(fileName)); return "\"" + BitConverter.ToString(hash).Replace("-", string.Empty) + "\""; } /// /// keyboard shortcuts override /// /// /// /// protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { if (keyData == Keys.F12) { MenuConnect_Click(null, null); return true; } if (keyData == (Keys.Control | Keys.F)) // temp { Form frm = new temp(); ThemeManager.ApplyThemeTo(frm); frm.Show(); return true; } /*if (keyData == (Keys.Control | Keys.S)) // screenshot { ScreenShot(); return true; }*/ if (keyData == (Keys.Control | Keys.G)) // nmea out { Form frm = new SerialOutput(); ThemeManager.ApplyThemeTo(frm); frm.Show(); return true; } if (keyData == (Keys.Control | Keys.A)) // 3dr radio { Form temp = new Form(); Control frm = new _3DRradio(); temp.Controls.Add(frm); temp.Size = frm.Size; frm.Dock = DockStyle.Fill; ThemeManager.ApplyThemeTo(temp); temp.Show(); return true; } if (keyData == (Keys.Control | Keys.W)) // test ac config { Controls.ConfigPanel cfg = new Controls.ConfigPanel(Application.StartupPath + System.IO.Path.DirectorySeparatorChar + "ArduCopterConfig.xml"); //cfg.Show(); return true; } if (keyData == (Keys.Control | Keys.T)) // for override connect { try { MainV2.comPort.Open(false); } catch (Exception ex) { CustomMessageBox.Show(ex.ToString()); } return true; } if (keyData == (Keys.Control | Keys.Y)) // for ryan beall { #if MAVLINK10 // write MainV2.comPort.doCommand(MAVLink.MAV_CMD.PREFLIGHT_STORAGE, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); //read ///////MainV2.comPort.doCommand(MAVLink09.MAV_CMD.PREFLIGHT_STORAGE, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); #else MainV2.comPort.doAction(MAVLink.MAV_ACTION.MAV_ACTION_STORAGE_WRITE); #endif CustomMessageBox.Show("Done MAV_ACTION_STORAGE_WRITE"); return true; } if (keyData == (Keys.Control | Keys.J)) // for jani { string data = "!!"; Common.InputBox("inject", "enter data to be written", ref data); MainV2.comPort.Write(data + "\r"); return true; } return base.ProcessCmdKey(ref msg, keyData); } public void changelanguage(CultureInfo ci) { if (ci != null && !Thread.CurrentThread.CurrentUICulture.Equals(ci)) { Thread.CurrentThread.CurrentUICulture = ci; config["language"] = ci.Name; //System.Threading.Thread.CurrentThread.CurrentCulture = ci; HashSet views = new HashSet { FlightData, FlightPlanner, Simulation }; foreach (Control view in MyView.Controls) views.Add(view); foreach (Control view in views) { if (view != null) { ComponentResourceManager rm = new ComponentResourceManager(view.GetType()); foreach (Control ctrl in view.Controls) rm.ApplyResource(ctrl); rm.ApplyResources(view, "$this"); } } } } private void MainV2_FormClosing(object sender, FormClosingEventArgs e) { config["MainHeight"] = this.Height; config["MainWidth"] = this.Width; config["MainMaximised"] = this.WindowState.ToString(); config["MainLocX"] = this.Location.X.ToString(); config["MainLocY"] = this.Location.Y.ToString(); try { comPort.logreadmode = false; if (comPort.logfile != null) comPort.logfile.Close(); if (comPort.rawlogfile != null) comPort.rawlogfile.Close(); comPort.logfile = null; comPort.rawlogfile = null; } catch { } } public static string getConfig(string paramname) { if (config[paramname] != null) return config[paramname].ToString(); return ""; } public void ChangeUnits() { try { // dist if (MainV2.config["distunits"] != null) { switch ((Common.distances)Enum.Parse(typeof(Common.distances), MainV2.config["distunits"].ToString())) { case Common.distances.Meters: MainV2.cs.multiplierdist = 1; break; case Common.distances.Feet: MainV2.cs.multiplierdist = 3.2808399f; break; } } // speed if (MainV2.config["speedunits"] != null) { switch ((Common.speeds)Enum.Parse(typeof(Common.speeds), MainV2.config["speedunits"].ToString())) { case Common.speeds.ms: MainV2.cs.multiplierspeed = 1; break; case Common.speeds.fps: MainV2.cs.multiplierdist = 3.2808399f; break; case Common.speeds.kph: MainV2.cs.multiplierspeed = 3.6f; break; case Common.speeds.mph: MainV2.cs.multiplierspeed = 2.23693629f; break; case Common.speeds.knots: MainV2.cs.multiplierspeed = 1.94384449f; break; } } } catch { } } private void CMB_baudrate_TextChanged(object sender, EventArgs e) { var sb = new StringBuilder(); int baud = 0; for (int i = 0; i < _connectionControl.CMB_baudrate.Text.Length; i++) if (char.IsDigit(_connectionControl.CMB_baudrate.Text[i])) { sb.Append(_connectionControl.CMB_baudrate.Text[i]); baud = baud * 10 + _connectionControl.CMB_baudrate.Text[i] - '0'; } if (_connectionControl.CMB_baudrate.Text != sb.ToString()) { _connectionControl.CMB_baudrate.Text = sb.ToString(); } try { if (baud > 0 && comPort.BaseStream.BaudRate != baud) comPort.BaseStream.BaudRate = baud; } catch (Exception) { } } private void CMB_serialport_Enter(object sender, EventArgs e) { CMB_serialport_Click(sender, e); } private void MainMenu_MouseLeave(object sender, EventArgs e) { //MainMenu.Visible = false; } private void MainV2_MouseMove(object sender, MouseEventArgs e) { // if (e.Y < 50) // MainMenu.Visible = true; } } }