/// <summary> /// This is the main method called by VoxCommando when performing plugin actions. All actions go through here. /// </summary> /// <param name="actionNameArray"> /// An array of strings representing action name. Example action: xbmc.send >>> /// actionNameArray[0] is the plugin name (xbmc), actionNameArray[1] is "send". /// </param> /// <param name="actionParameters">An array of strings representing our action parameters.</param> /// <returns>an actionResult</returns> public actionResult doAction(string[] actionNameArray, string[] actionParameters) { var ar = new actionResult(); const string unknownAction = "Unknown " + nameof(Vision) + " plugin action."; try { Task.Run( delegate { switch (actionNameArray[1].ToUpper()) { case "PHOTO": using (var capture = new VideoCapture()) { Thread.Sleep(PluginOptions.CameraDelayMs); using (Image <Bgr, byte> imageFrame = capture.QueryFrame().ToImage <Bgr, byte>()) { SaveImage(imageFrame.Bitmap); } } ar.setInfo("Capture saved to plugin directory."); break; case "DETECT": ar = FindObjects(actionParameters); break; case "OCR": ar = TeserractOcr(actionParameters); break; case "FACETRAIN": ar = TrainFace(actionParameters); break; case "FACERECO": ar = RecognizeFace(actionParameters); break; case "MOTIONSENSOR": throw new NotImplementedException(); default: ar.setError(unknownAction); break; } } ); } catch (Exception err) { ar.setError(err.ToString()); } return(ar); }
internal static actionResult DestroyPort(SerialPortStream port) { var ar = new actionResult(); if (!port.IsAlive()) { ar.setError("Port already closed."); return(ar); } if (port == Plugin.SelectedPort) { Plugin.MainCtl.Log($"=========== {port.PortName}: log end ===========", false); } string portLongName = Plugin.OpenedPorts.First(kvp => kvp.Value == port).Key; Plugin.OpenedPorts.Remove(portLongName); if (port.IsOpen) { port.Close(); } port.Dispose(); // ReSharper disable once RedundantAssignment port = null; Plugin.MainCtl.UpdatePortsListView(); ar.setInfo("Port closed."); Plugin.HostInstance.log(nameof(Serial) + ": destroyed port: " + portLongName); return(ar); }
internal static actionResult WriteOnPort(string message) { var ar = new actionResult(); if (!Plugin.SelectedPort.IsAlive() || !Plugin.SelectedPort.IsOpen) { ar.setError("Current port isn't open."); return(ar); } bool converted; byte[] parsedBytes = Plugin.ParseHexString(message, out converted); if (converted) { Plugin.SelectedPort.Write(parsedBytes, 0, parsedBytes.Length); string byteMsg = Encoding.UTF8.GetString(parsedBytes); Plugin.MainCtl.Log(byteMsg, true); ar.setInfo("Bytes array sent: " + byteMsg); return(ar); } Plugin.SelectedPort.Write(message); Plugin.MainCtl.Log(message, true); ar.setInfo("Successfully sent: " + message); return(ar); }
internal static actionResult DoDriverAction(string[] actionNameArray, string[] actionParameters) { var ar = new actionResult(); if (!Plugin.SelectedPort.IsAlive()) { ar.setError("Current port isn't open."); return(ar); } if (actionParameters.Length < 1) { ar.setError("Arduino model not specified."); return(ar); } ArduinoModel arduinoModel; if (!Enum.TryParse(actionParameters[0], true, out arduinoModel)) { ar.setError("Invalid Arduino model."); return(ar); } switch (actionNameArray[2].ToUpper()) { case "UPLOAD": { // [Arduino Model], [Path to sketch] // TODO connect avrdude.exe to compile & upload sketches without Arduino IDE. if (actionParameters.Length < 2) { ar.setError("2 parameters expected."); return(ar); } // Uploading sketch from another thread, // Result is returned by Serial.Upload.{Status} event. Task.Run(() => UploadSketch(arduinoModel, actionParameters[1], Plugin.SelectedPort.PortName)); ar.setInfo("Uploading..."); return(ar); } #if DEBUG // BETA ACTIONS, BUT MOST OF THEM ALREADY TESTED ON MY PC W/ ARDUINO UNO. case "MARIO": { // [Arduino model], [Buzzer pin] if (actionParameters.Length < 2) { ar.setError("2 parameters expected."); return(ar); } byte pin; if (!byte.TryParse(actionParameters[1], out pin)) { ar.setError("Invalid buzzer pin."); return(ar); } Task.Run( delegate { using (var driver = new ArduinoDriver(arduinoModel, Plugin.SelectedPort.PortName, true)) { for (var i = 0; i < melody.Length; i++) { int noteDuration = 1000 / tempo[i]; driver.Send(new ToneRequest(pin, (ushort)melody[i], (uint)noteDuration)); Thread.Sleep((int)(noteDuration * 1.40)); driver.Send(new NoToneRequest(pin)); } } Plugin.HostInstance.triggerEvent( "Serial.Micro.Mario.Success", new List <string>() ); } ); ar.setInfo("Uploading..."); break; } case "TONE": { // [Arduino model], [Buzzer pin], [Tone], [Duration in ms] if (actionParameters.Length < 4) { ar.setError("4 parameters expected."); return(ar); } byte pin; if (!byte.TryParse(actionParameters[1], out pin)) { ar.setError("Invalid pin."); return(ar); } ushort tone; if (!ushort.TryParse(actionParameters[2], out tone)) { ar.setError("Invalid tone."); return(ar); } uint duration; if (!uint.TryParse(actionParameters[2], out duration)) { ar.setError("Invalid duration."); return(ar); } Task.Run( delegate { using (var driver = new ArduinoDriver(arduinoModel, Plugin.SelectedPort.PortName, true)) { driver.Send(new ToneRequest(pin, tone, duration)); Thread.Sleep((int)(duration * 1.40)); driver.Send(new NoToneRequest(pin)); } } ); ar.setInfo("OK."); break; } case "ANALOGREAD": { // [Arduino model], [Pin to read] if (actionParameters.Length < 2) { ar.setError("2 parameters expected."); return(ar); } byte pin; if (!byte.TryParse(actionParameters[1], out pin)) { ar.setError("Invalid pin."); return(ar); } using (var driver = new ArduinoDriver(arduinoModel, Plugin.SelectedPort.PortName, true)) { AnalogReadResponse response = driver.Send(new AnalogReadRequest(pin)); ar.setSuccess(response.PinValue.ToString()); } break; } case "DIGITALREAD": { // [Arduino model], [Pin to read] if (actionParameters.Length < 2) { ar.setError("2 parameters expected."); return(ar); } byte pin; if (!byte.TryParse(actionParameters[1], out pin)) { ar.setError("Invalid pin."); return(ar); } using (var driver = new ArduinoDriver(arduinoModel, Plugin.SelectedPort.PortName, true)) { DigitalReadResponse response = driver.Send(new DigitalReadRequest(pin)); ar.setSuccess(response.PinValue.ToString("G").ToUpper()); } break; } // all other actions need at least 3 parameters. default: { if (actionParameters.Length < 3) { ar.setError("3 parameters expected."); return(ar); } byte pin; if (!byte.TryParse(actionParameters[1], out pin)) { ar.setError("Invalid pin."); return(ar); } switch (actionNameArray[2].ToUpper()) { case "ANALOGWRITE": { // [Arduino model], [Pin to write], [Value to write] byte val; if (!byte.TryParse(actionParameters[2], out val)) { ar.setError("Invalid pin value."); return(ar); } using (var driver = new ArduinoDriver(arduinoModel, Plugin.SelectedPort.PortName, true)) { AnalogWriteResponse response = driver.Send(new AnalogWriteRequest(pin, val)); ar.setInfo($"OK. pin {response.PinWritten}, value: {val}"); } break; } case "DIGITALWRITE": { // [Arduino model], [Pin to write], [Value to write] byte val; if (!byte.TryParse(actionParameters[2], out val)) { ar.setError("Invalid pin value."); return(ar); } using (var driver = new ArduinoDriver(arduinoModel, Plugin.SelectedPort.PortName, true)) { DigitalWriteReponse response = driver.Send(new DigitalWriteRequest(pin, (DigitalValue)val)); ar.setInfo($"OK. pin {response.PinWritten}, value: {val}"); } break; } case "PINMODE": { // [Arduino model], [Pin to set], [Pin mode] PinMode pinMode; switch (actionParameters[2].ToUpper()) { case "IN": pinMode = PinMode.Input; break; case "INPULL": pinMode = PinMode.InputPullup; break; case "OUT": pinMode = PinMode.Output; break; default: ar.setError("Invalid pin mode."); return(ar); } using (var driver = new ArduinoDriver(arduinoModel, Plugin.SelectedPort.PortName, true)) { PinModeResponse response = driver.Send(new PinModeRequest(pin, pinMode)); ar.setInfo($"OK. pin {response.Pin}: {response.Mode:G}."); } break; } } break; } #endif } return(ar); }
private actionResult RecognizeFace(string[] parameters) { var ar = new actionResult(); if (MainCtl.TrainedImages.Count == 0) { ar.setError("Database contains no trained faces."); return(ar); } #region Parameters parsing switch (parameters.Length) { case 0: { ar.setError("Path to image not specified."); return(ar); } case 1: { ar.setError("Face name not specified."); return(ar); } } Image <Gray, byte> grayImage; if (string.IsNullOrEmpty(parameters[0])) { using (var capture = new VideoCapture()) { Thread.Sleep(PluginOptions.CameraDelayMs); grayImage = capture.QueryFrame().ToImage <Gray, byte>(); } } else { try { grayImage = new Image <Gray, byte>(parameters[0]); } catch { ar.setError("Invalid path to image."); return(ar); } } if (PluginOptions.UseImageCorrection) { grayImage._EqualizeHist(); } #endregion Rectangle[] faces; using (var classifier = new CascadeClassifier(PluginOptions.CascadesPath + "haarcascade_frontalface_default.xml")) { faces = classifier.DetectMultiScale(grayImage, 1.1, 10); } if (faces.Length == 0) { ar.setError("No trained faces found."); return(ar); } var resultString = ""; foreach (Rectangle face in faces) { using (FaceRecognizer recognizer = new EigenFaceRecognizer()) { recognizer.Read(PluginOptions.PluginPath + "SavedCascade.xml"); FaceRecognizer.PredictionResult recoResult = recognizer.Predict(grayImage.Copy(face).Resize(100, 100, Inter.Cubic)); resultString += $"<{PluginOptions.PeopleFaces.ElementAt(recoResult.Label)}:{recoResult.Distance}>"; } } grayImage.Dispose(); ar.setSuccess(resultString); return(ar); }
private actionResult TrainFace(string[] parameters) { var ar = new actionResult(); #region Parameters parsing switch (parameters.Length) { case 0: { ar.setError("Path to image not specified."); return(ar); } case 1: { ar.setError("Face name not specified."); return(ar); } } Image <Gray, byte> grayImage; if (string.IsNullOrEmpty(parameters[0])) { using (var capture = new VideoCapture()) { Thread.Sleep(PluginOptions.CameraDelayMs); grayImage = capture.QueryFrame().ToImage <Gray, byte>(); } } else { try { grayImage = new Image <Gray, byte>(parameters[0]); } catch { ar.setError("Invalid path to image."); return(ar); } } if (PluginOptions.UseImageCorrection) { grayImage._EqualizeHist(); } #endregion Rectangle[] faces; using (var classifier = new CascadeClassifier($"{PluginOptions.CascadesPath}haarcascade_frontalface_default.xml")) { faces = classifier.DetectMultiScale(grayImage, 1.1, 10); } if (faces.Length == 0) { ar.setError("No face recognized."); return(ar); } using (Image <Gray, byte> faceImage = grayImage.Copy(faces[0]).Resize(100, 100, Inter.Cubic)) { MainCtl.TrainedImages.Add(faceImage); PluginOptions.PeopleFaces.Add(PluginOptions.PeopleFaces.Count + 1, parameters[1]); faceImage.Save($"{PluginOptions.PluginPath}Faces\\face{MainCtl.TrainedImages.Count}.bmp"); } PluginOptions.SaveOptionsToXml(); grayImage.Dispose(); using (FaceRecognizer recognizer = new EigenFaceRecognizer()) { recognizer.Train(MainCtl.TrainedImages.ToArray(), PluginOptions.PeopleFaces.Keys.ToArray()); recognizer.Write($"{PluginOptions.PluginPath}SavedCascade.xml"); } ar.setInfo($"Added face with name: {parameters[0]}."); return(ar); }
private actionResult TeserractOcr(string[] parameters) { var ar = new actionResult(); #region Parameters parsing switch (parameters.Length) { case 0: { ar.setError("Path to image not specified."); return(ar); } case 1: { ar.setError("Symbols culture not specified."); return(ar); } } Image <Gray, byte> grayImage; if (string.IsNullOrEmpty(parameters[0])) { using (var capture = new VideoCapture()) { Thread.Sleep(PluginOptions.CameraDelayMs); grayImage = capture.QueryFrame().ToImage <Gray, byte>(); } } else { try { grayImage = new Image <Gray, byte>(parameters[0]); } catch { ar.setError("Invalid path to image."); return(ar); } } if (PluginOptions.UseImageCorrection) { grayImage._EqualizeHist(); } #endregion using (Tesseract tesseract = parameters.Length == 2 ? new Tesseract($"{PluginOptions.PluginPath}TessData\\", parameters[1], OcrEngineMode.TesseractOnly) : parameters.Length == 3 ? new Tesseract( $"{PluginOptions.PluginPath}TessData\\", parameters[1], OcrEngineMode.TesseractOnly, parameters[2] ) : null) { if (tesseract == null) { ar.setError("Failed to initialize recognizer due to invalid number of parameters."); grayImage.Dispose(); return(ar); } string recognizedText; using (Image <Gray, byte> imgThold = grayImage) { CvInvoke.Threshold(grayImage, imgThold, 140, 255, ThresholdType.Binary); tesseract.SetImage(imgThold); recognizedText = tesseract.GetUTF8Text(); } if (string.IsNullOrWhiteSpace(recognizedText)) { ar.setError("No recognized symbols."); } else { ar.setSuccess(recognizedText); } grayImage.Dispose(); } return(ar); }
/// <param name="parameters"> /// [0] - Path to image, /// [1] - Cascade 1, /// [2] - Cascade 2 ... /// </param> private actionResult FindObjects(string[] parameters) { var ar = new actionResult(); #region Parameters parsing switch (parameters.Length) { case 0: { ar.setError("Path to image not specified."); return(ar); } case 1: { ar.setError("Cascade name not specified."); return(ar); } } Image <Gray, byte> grayImage; if (string.IsNullOrEmpty(parameters[0])) { using (var capture = new VideoCapture()) { Thread.Sleep(PluginOptions.CameraDelayMs); grayImage = capture.QueryFrame().ToImage <Gray, byte>(); } } else { try { grayImage = new Image <Gray, byte>(parameters[0]); } catch { ar.setError("Invalid path to image."); return(ar); } } if (PluginOptions.UseImageCorrection) { grayImage._EqualizeHist(); } #endregion var resultString = ""; for (var i = 1; i < parameters.Length; i++) { if (string.IsNullOrEmpty(parameters[i])) { continue; } using (var classifier = new CascadeClassifier($"{PluginOptions.CascadesPath}haarcascade_{parameters[i].ToLower().Trim()}.xml")) { Rectangle[] objects = classifier.DetectMultiScale(grayImage, 1.1, 10); if (objects.Length != 0) { for (var index = 0; index < objects.Length; index++) { grayImage.Draw(objects[index], new Gray(0), 2); } } resultString += $"<{parameters[i]}:{objects.Length}>\n"; } } SaveImage(grayImage.Bitmap); grayImage.Dispose(); ar.setSuccess(resultString); return(ar); }
private static By CreateElementSelector(ref actionResult ar, string[] parameters) { if (parameters.Length == 0) { ar.setError("'Selector' parameter missing."); return(null); } if (parameters.Length == 1) { ar.setError("'Selector value' parameter missing."); return(null); } // selector parameter By selector; switch (parameters[0].ToUpper()) { case "ID": { selector = By.Id(parameters[1]); break; } case "CLASS": { selector = By.ClassName(parameters[1]); break; } case "CSS": { selector = By.CssSelector(parameters[1]); break; } case "NAME": { selector = By.Name(parameters[1]); break; } case "TAG": { selector = By.TagName(parameters[1]); break; } case "LINKTEXT": { selector = By.LinkText(parameters[1]); break; } case "PARTIALLINKTEXT": { selector = By.PartialLinkText(parameters[1]); break; } case "XPATH": { selector = By.XPath(parameters[1]); break; } default: { ar.setError("Invalid 'Selector' parameter."); return(null); } } return(selector); }
/// <summary> /// This is the main method called by VoxCommando when performing plugin actions. All actions go through here. /// </summary> /// <param name="actionNameArray"> /// An array of strings representing action name. Example action: xbmc.send >>> /// actionNameArray[0] is the plugin name (xbmc), actionNameArray[1] is "send". /// </param> /// <param name="actionParameters">An array of strings representing our action parameters.</param> /// <returns>an actionResult</returns> public actionResult doAction(string[] actionNameArray, string[] actionParameters) { var ar = new actionResult(); const string unknownAction = "Unknown " + nameof(Browser) + " plugin action."; if (actionNameArray.Length < 2) { ar.setError(unknownAction); return(ar); } string actionName1 = actionNameArray[1].ToUpper(); if (webDriver == null && actionName1 != "START") { ar.setError("No web browser opened or selected."); return(ar); } try { switch (actionName1) { // TODO: check for updates for all web driver executables. // ReSharper disable PossibleNullReferenceException case "GOTOURL": { if (actionParameters.Length == 0) { ar.setError("'Url' parameter missing."); } else { if (!actionParameters[0].StartsWith("http://") || !actionParameters[0].StartsWith("https://")) { actionParameters[0] = "https://" + actionParameters[0]; } try { isPageLoaded = false; Task.Run( () => { webDriver.Navigate().GoToUrl(actionParameters[0]); isPageLoaded = true; HostInstance.triggerEvent("Browser.PageLoaded", new List <string>(0)); } ); } catch (Exception ex) { ar.setError("Failed to open specified URL:\n" + ex); break; } ar.setInfo("Page loading started."); } break; } case "WAIT": { while (!isPageLoaded) { Thread.Sleep(10); } ar.setInfo("Page loaded."); break; } case "ELEMENT": { if (actionNameArray.Length < 3) { ar.setError(unknownAction); break; } switch (actionNameArray[2].ToUpper()) { case "FINDROOT": { // selector parameter By selector = CreateElementSelector(ref ar, actionParameters); ReadOnlyCollection <IWebElement> elements = webDriver.FindElements(selector); if (elements.Count == 0) { ar.setError("Cannot find element with specified value. Check your 'Selector value' parameter."); } else { foundWebElements = elements; currentElement = elements[0]; ar.setSuccess(foundWebElements.Count.ToString()); } break; } case "FIND": { if (currentElement == null) { ar.setError("No element selected."); return(ar); } // selector parameter By selector = CreateElementSelector(ref ar, actionParameters); ReadOnlyCollection <IWebElement> elements = currentElement.FindElements(selector); if (elements.Count == 0) { ar.setError("Cannot find element with specified value. Check your 'Selector value' parameter."); } else { foundWebElements = elements; currentElement = elements[0]; ar.setSuccess(foundWebElements.Count.ToString()); } break; } case "SELECT": { // sets currentElement to one from found elements. int selectIndex; if (foundWebElements.Count == 0) { ar.setError("No elements found to select one of them."); } else if (foundWebElements.Count == 1) { ar.setError("First element selected."); } else if (actionParameters.Length == 0) { ar.setError("<Index> of element to select not specified."); } else if (!int.TryParse(actionParameters[0], out selectIndex)) { ar.setError("Invalid <Index> parameter."); } else if (selectIndex < 1 || selectIndex > foundWebElements.Count) { ar.setError("Index parameter is out of range of found elements count."); } else { currentElement = foundWebElements[selectIndex - 1]; ar.setSuccess("Element selected."); } break; } case "INPUT": { if (currentElement == null) { ar.setError("No element selected."); return(ar); } if (actionParameters.Length == 0) { ar.setError("'Text to write' parameter missing."); return(ar); } currentElement.SendKeys(actionParameters[0]); ar.setInfo("OK."); break; } case "CLICK": { if (currentElement == null) { ar.setError("No element selected."); return(ar); } currentElement.Click(); ar.setInfo("OK."); break; } case "GETVISIBLETEXT": { if (currentElement == null) { ar.setError("No element selected."); return(ar); } ar.setSuccess(currentElement.Text); break; } case "GETATTR": { // value of specified attribute for this element. if (currentElement == null) { ar.setError("No element selected."); return(ar); } if (actionParameters.Length == 1) { ar.setError("'Attribute name' parameter missing."); return(ar); } string attrValue; try { attrValue = currentElement.GetAttribute(actionParameters[0]); } catch (StaleElementReferenceException) { ar.setError("Reference to current element is no longer valid.\nRe-find your element."); return(ar); } ar.setSuccess(attrValue); break; } case "GETPROP": { // JavaScript property of the element. if (currentElement == null) { ar.setError("No element selected."); return(ar); } if (actionParameters.Length == 1) { ar.setError("'JS property name' parameter missing."); return(ar); } string attrValue; try { attrValue = currentElement.GetProperty(actionParameters[0]); } catch (StaleElementReferenceException) { ar.setError("Reference to current element is no longer valid.\nRe-find your element."); return(ar); } ar.setSuccess(attrValue); break; } case "GETCSS": { // value of CSS property of current element. if (currentElement == null) { ar.setError("No element selected."); return(ar); } if (actionParameters.Length == 1) { ar.setError("'CSS property name' parameter missing."); return(ar); } string attrValue; try { attrValue = currentElement.GetCssValue(actionParameters[0]); } catch (StaleElementReferenceException) { ar.setError("Reference to current element is no longer valid.\nRe-find your element."); return(ar); } ar.setSuccess(attrValue); break; } case "GETPARENT": { if (currentElement == null) { ar.setError("No element selected."); return(ar); } try { currentElement.FindElement(By.XPath("//span/parent::*")); } catch (NoSuchElementException) { ar.setError("Cannot find parent of current element."); } break; } default: { ar.setError(unknownAction); break; } } break; } #region Browser window case "GETSIZE": { // get if (actionParameters.Length == 0) { Size size = webDriver.Manage().Window.Size; ar.setSuccess($"{size.Width},{size.Height}"); } // set else if (actionParameters.Length == 2) { int width; if (!int.TryParse(actionParameters[0], out width)) { ar.setError("Invalid window width."); } int height; if (!int.TryParse(actionParameters[1], out height)) { ar.setError("Invalid window height."); } webDriver.Manage().Window.Size = new Size(width, height); } else { ar.setError("Invalid parameters count."); } break; } case "GETPOSITION": { // get if (actionParameters.Length == 0) { Point position = webDriver.Manage().Window.Position; ar.setSuccess($"{position.X},{position.Y}"); } // set else if (actionParameters.Length == 2) { int x; if (!int.TryParse(actionParameters[0], out x)) { ar.setError("Invalid X position."); } int y; if (!int.TryParse(actionParameters[1], out y)) { ar.setError("Invalid Y position."); } webDriver.Manage().Window.Position = new Point(x, y); } else { ar.setError("Invalid parameters count."); } break; } // change window state case "NORMALIZE": { webDriver.Manage().Window.Size = savedNormalSize; ar.setInfo("OK."); break; } case "MAXIMIZE": { savedNormalSize = webDriver.Manage().Window.Size; webDriver.Manage().Window.Maximize(); ar.setInfo("OK."); break; } case "MINIMIZE": { savedNormalSize = webDriver.Manage().Window.Size; webDriver.Manage().Window.Minimize(); ar.setInfo("OK."); break; } case "FULLSCREEN": { savedNormalSize = webDriver.Manage().Window.Size; webDriver.Manage().Window.FullScreen(); ar.setInfo("OK."); break; } #endregion #region Working with tabs case "TAB": { if (actionNameArray.Length < 3) { ar.setError(unknownAction); break; } switch (actionNameArray[2].ToUpper()) { case "NEW": { webDriver.ExecuteJavaScript("window.open('','_blank');"); webDriver.SwitchTo().Window(webDriver.WindowHandles.Last()); break; } case "SELECT": { if (actionParameters.Length == 0) { ar.setError("'Tab name' parameter missing."); } else if (SelectWindow(actionParameters[0])) { ar.setInfo("OK."); } else { ar.setError("Cannot find tab with specified name."); } break; } case "SELECTBYNUM": { int tabNumber; if (actionParameters.Length == 0) { ar.setError("'Tab index' parameter missing."); } else if (int.TryParse(actionParameters[0], out tabNumber) || tabNumber - 1 > webDriver.WindowHandles.Count) { webDriver.SwitchTo().Window(webDriver.WindowHandles[tabNumber - 1]); ar.setInfo("OK."); } else { ar.setError("Cannot find tab with specified name."); } break; } case "CLOSE": { webDriver.Close(); webDriver?.SwitchTo().Window(webDriver.WindowHandles.Last()); break; } case "TITLE": { ar.setSuccess(webDriver.Title); break; } case "URL": { ar.setSuccess(webDriver.Url); break; } case "GETTABS": { ar.setSuccess(string.Join("\n", webDriver.WindowHandles)); break; } default: { ar.setError(unknownAction); break; } } break; } #endregion #region Browser start/stop case "START": { bool headless = PluginOptions.LaunchHidden; if (actionParameters.Length > 0 && !bool.TryParse(actionParameters[0], out headless)) { ar.setError("Invalid value for 'hidden' parameter."); break; } try { StartWebDriver(headless); } catch (Exception ex) { ar.setError("Failed to start browser:\n" + ex); break; } ar.setInfo("OK."); break; } case "STOP": { webDriver.Quit(); ar.setInfo("Web driver stopped working."); break; } case "SWITCH": { if (actionParameters.Length == 0) { ar.setError("'Browser type' parameter missing."); } else { BrowserType browserType; if (Enum.TryParse(actionParameters[0], true, out browserType)) { try { webDriver.Quit(); webDriver.Dispose(); PluginOptions.BrowserType = browserType; StartWebDriver(isHidden); } catch (Exception ex) { ar.setError($"Failed to switch to {browserType:G}:\n" + ex); break; } ar.setInfo("OK."); } else { ar.setError("Invalid browser type."); } } break; } #endregion default: { ar.setError(unknownAction); break; } // ReSharper restore PossibleNullReferenceException } } catch (Exception ex) { ar.setError(ex.ToString()); } return(ar); }
/// <summary> /// This is the main method called by VoxCommando when performing plugin actions. All actions go through here. /// </summary> /// <param name="actionNameArray"> /// An array of strings representing action name. Example action: xbmc.send >>> /// actionNameArray[0] is the plugin name (xbmc), actionNameArray[1] is "send". /// </param> /// <param name="actionParameters">An array of strings representing our action parameters.</param> /// <returns>an actionResult</returns> public actionResult doAction(string[] actionNameArray, string[] actionParameters) { var ar = new actionResult(); const string unknownAction = "Unknown " + nameof(Serial) + " plugin action."; if (actionNameArray.Length < 2) { ar.setError(unknownAction); return(ar); } try { switch (actionNameArray[1].ToUpper()) { case "OPEN": { // [PortName pattern], (BaudRate), (DTR), (Parity), (StopBits), (DataBits) #region Parsing action parameters Regex portNameRegex; if (actionParameters.Length < 1 || !IsValidRegex(actionParameters[0], out portNameRegex)) { ar.setError("'Port name pattern' missing or invalid."); return(ar); } var info = ""; // parse baud rate int baudRate; if (actionParameters.Length < 2 || !int.TryParse(actionParameters[1], out baudRate)) { baudRate = 9600; info = "'Baud rate' undefined. Using 9600.\r\n"; } // parse DTR bool dtrEnable; if (actionParameters.Length < 3 || !bool.TryParse(actionParameters[2], out dtrEnable)) { dtrEnable = false; info += "'Use DTR' undefined. Using false.\r\n"; } // parse parity Parity parity; if (actionParameters.Length < 4 || !Enum.TryParse(actionParameters[3], true, out parity)) { parity = Parity.None; info += "'Parity' undefined. Using none.\r\n"; } // parse stop bits StopBits stopBits; if (actionParameters.Length < 5 || !Enum.TryParse(actionParameters[4], true, out stopBits)) { stopBits = StopBits.One; info += "'Stop bits' undefined. Using one.\r\n"; } // parse data bits int dataBits; if (actionParameters.Length < 6 || !int.TryParse(actionParameters[5], out dataBits)) { dataBits = 8; info += "'Data bits' undefined. Using 8.\r\n"; } #endregion // [select] First step - searching it in opened ports foreach (string portLongName in OpenedPorts.Keys) { if (portNameRegex.Match(portLongName).Success) { Match match = ComNameRegex.Match(portLongName); if (!match.Success) { ar.setError("Port must have 'COM' type."); return(ar); } string portComName = match.Value; if (SelectedPort.PortName == portComName) { ar.setError($"{portLongName} already selected."); } else { SerialPortActions.SelectPort(portComName); ar.setInfo($"'{portLongName}' selected."); } return(ar); } } // [open] If not found, look for it through all system ports. string[] portsNames = SerialPortActions.GetPortsList(true, false); foreach (string portLongName in portsNames) { // user pattern match if (portNameRegex.Match(portLongName).Success) { try { SerialPortActions.OpenPort(portLongName, baudRate, dtrEnable, parity, stopBits, dataBits); info += $"'{portLongName}' opened and selected."; ar.setInfo(info); } catch (Exception ex) { ar.setError(ex.Message); } return(ar); } } // failed ar.setError("Matching port not found."); return(ar); } case "GETPORTS": { // (Friendly names), (Show only opened) bool friendlyNames; if (actionParameters.Length < 1 || !bool.TryParse(actionParameters[0], out friendlyNames)) { friendlyNames = false; } bool onlyOpenedPorts; if (actionParameters.Length < 2 || !bool.TryParse(actionParameters[1], out onlyOpenedPorts)) { onlyOpenedPorts = false; } string[] portsNames = SerialPortActions.GetPortsList(friendlyNames, onlyOpenedPorts); if (portsNames.Length == 0) { ar.setError("No open ports."); } else { ar.setSuccess(string.Join("\r\n", portsNames)); } break; } case "WRITE": { // [Message to write on port] if (actionParameters.Length < 1) { ar.setError("1 parameter expected."); return(ar); } ar = SerialPortActions.WriteOnPort(actionParameters[0]); break; } case "CLOSE": { // <No parameters> ar = SerialPortActions.DestroyPort(SelectedPort); break; } case "MICRO": { if (actionNameArray.Length < 3) { ar.setError(unknownAction); return(ar); } // any that action requires port to be closed. SelectedPort.Close(); ar = ArduinoActions.DoDriverAction(actionNameArray, actionParameters); SelectedPort.Open(); break; } default: { ar.setError(unknownAction); break; } } } catch (Exception ex) { ar.setError(ex.ToString()); } return(ar); }