/// <summary> /// Called by a timer /// </summary> /// <param name="sender"></param> /// <param name="eventArgs"></param> protected virtual void MonitorADM(Object sender, ElapsedEventArgs eventArgs) { _admtimer.Stop(); try { lock (_lockMonitorADM) { //get all current ports that have boards connected List <String> ports = ArduinoDeviceManager.GetBoardPorts(SupportedBoards, AllowedPorts, DeniedPorts); //build a list of any ADMs that are no longer connected to one of these ports (e.g. USB has been yanked out) List <ArduinoDeviceManager> adms = ADMS.Values.ToList(); foreach (ArduinoDeviceManager adm in adms) { if (adm == null) { continue; } if (!ports.Contains(adm.Port)) { //if for some reason (config change?) the port for the ADM is not a possible board port DisconnectADM(adm.Port); } } //now we try and connect all the boards that we have not just disconnected but have not yet been connected if (ports.Count > 0 && ADMS.Count < RequiredBoardsCount) { _noPortsFoundWarning = false; foreach (String port in ports) { try { ConnectADM(port); } catch (System.IO.IOException e) { switch (e.HResult) { case Win32.ERROR_ATTACHED_DEVICE_NOT_FUNCTIONING: ResetPort(port, e); break; } Tracing?.TraceEvent(TraceEventType.Error, 100, "ADMService::MonitorADM: Connecting ADM to port {0} produced IOException {1} ({2}): {3}", port, e.GetType().ToString(), e.HResult, e.Message); } catch (Exception e) { Tracing?.TraceEvent(TraceEventType.Error, 100, "ADMService::MonitorADM: Connecting ADM to port {0} produced Exception {1} ({2}): {3}", port, e.GetType().ToString(), e.HResult, e.Message); } } } else if (ADMS.Count < RequiredBoardsCount) { if (!_noPortsFoundWarning) { Tracing?.TraceEvent(TraceEventType.Warning, 100, "ADMService::MonitorADM: No boards connected to any port"); _noPortsFoundWarning = true; } } //Finally we check on the state of the ADM foreach (ArduinoDeviceManager adm in adms) { if (adm == null) { continue; } if (!adm.IsConnected) { //TODO: how do we handle this? Tracing?.TraceEvent(TraceEventType.Warning, 100, "ADM (BDID={0}) @ {1} is of state", adm.State); } else if (ADMInactivityTimeout > 0) { //if there has been a suspicioius lack of activity... long msQuiet = (DateTime.Now.Ticks - adm.LastMessageReceivedOn.Ticks) / TimeSpan.TicksPerMillisecond; if (msQuiet > ADMInactivityTimeout) { OnADMInactivityTimeout(adm, msQuiet); } } } } //end of monitor lock } catch (Exception e) { Tracing?.TraceEvent(TraceEventType.Error, 100, "Unknown exception in MonitorADM: {0}, {1}", e.GetType().ToString(), e.Message); } _admtimer.Start(); }
override public bool HandleCommand(Connection cnn, Message message, String cmd, List <Object> args, Message response) { bool respond = true; MessageSchema schema = new ADMService.MessageSchema(response); DeviceManager devMgr; ArduinoDeviceManager adm; switch (cmd) { case "status": schema.AddADMS(ADMS); List <String> ports = ArduinoDeviceManager.GetBoardPorts(SupportedBoards, AllowedPorts, DeniedPorts); schema.AddPorts(ports); schema.AddRequiredBoards(RequiredBoards); devMgr = DeviceManager.GetInstance(); List <String> portDevices = new List <String>(); foreach (String port in ports) { List <DeviceManager.DeviceInfo> devs = devMgr.GetDevices("(" + port + ")"); foreach (DeviceManager.DeviceInfo devInfo in devs) { String s = String.Format("{0} ({1}): {2}", devInfo.Description, devInfo.InstanceID, devInfo.Status); portDevices.Add(s); } } response.AddValue("PortDevices", portDevices); break; case "disable-port": case "enable-port": case "reset-port": if (args.Count != 1 || args[0] == null || args[0].ToString() == String.Empty) { throw new Exception("No port specified"); } String devicePort = args[0].ToString().ToUpper(); devMgr = DeviceManager.GetInstance(); List <DeviceManager.DeviceInfo> ar = devMgr.GetDevices("(" + devicePort + ")"); if (ar.Count != 1) { throw new Exception("Cannot find device on port " + devicePort); } DeviceManager.DeviceInfo di = ar[0]; //first we check if there is an ADM on this port String output = ""; lock (_lockMonitorADM) { if (ADMS.ContainsKey(devicePort)) { output += String.Format("Found ADM on port {0} so disconnecting first", devicePort) + Environment.NewLine; DisconnectADM(devicePort); System.Threading.Thread.Sleep(500); if (SerialPorts.IsOpen(devicePort)) { throw new Exception("Serial port is open on " + devicePort); } } Process proc = null; if (cmd == "disable-port") { proc = devMgr.DisableDevice(di.InstanceID); } else if (cmd == "enable-port") { proc = devMgr.EnableDevice(di.InstanceID); } else { proc = devMgr.ResetDevice(di.InstanceID); } output += proc.StandardOutput.ReadToEnd(); } response.Value = output; break; default: var tgtcmd = cmd.Split(':'); if (tgtcmd.Length < 2) { throw new Exception(String.Format("ADM: Unrecognised command {0}", cmd)); } //Check that there are any boards connected if (ADMS.Count == 0) { throw new Exception("ADM: No boards connected"); } //so this is an ADM command, find the board first adm = GetADM(tgtcmd[0]); if (adm == null) { throw new Exception(String.Format("ADM: Cannot find ADM {0}", tgtcmd[0])); } if (!adm.IsConnected) { throw new Exception(String.Format("ADM: {0} is not conntected", adm.BoardID)); } //handle commands related to the board (i.e. not to a specific added device) if (tgtcmd.Length == 2) { int repeat; //frequently used var name int delay; //frequently used var name switch (tgtcmd[1].ToLower()) { case "status": AddADMRequest(adm, adm.RequestStatus(), response.Target); respond = false; break; case "ping": AddADMRequest(adm, adm.Ping(), response.Target); respond = false; break; case "pingloadtest": repeat = args != null && args.Count > 0 ? System.Convert.ToInt16(args[0]) : 10; delay = args != null && args.Count > 1 ? System.Convert.ToInt16(args[1]) : 500; Task.Run(() => { for (int i = 0; i < repeat; i++) { adm.Ping(); System.Threading.Thread.Sleep(delay); } }); respond = false; break; case "capability": var lbc = adm.ListBoardCapability(); response.AddValue("PinCount: ", lbc.Count); response.AddValue("Pins", lbc); break; case "disconnect": DisconnectADM(adm.Port); break; case "setdigitalpin": if (args.Count < 2) { throw new Exception("Insufficient arguments ... must supply a pin number and value"); } int pin = System.Convert.ToInt16(args[0]); bool val = Chetch.Utilities.Convert.ToBoolean(args[1]); if (!adm.IsPinCapable(pin, Solid.Arduino.Firmata.PinMode.DigitalOutput)) { throw new Exception(String.Format("Pin {0} is not capabale of digital output", pin)); } if (adm.GetDevicesByPin(pin) != null) { throw new Exception(String.Format("Pin {0} is being used by a device", pin)); } adm.SetDigitalPinMode(pin, Solid.Arduino.Firmata.PinMode.DigitalOutput); adm.SetDigitalPin(pin, val); break; case "setdigitalport": if (args.Count < 2) { throw new Exception("Insufficient arguments ... must supply a port number and value"); } int port = System.Convert.ToInt16(args[0]); bool enable = Chetch.Utilities.Convert.ToBoolean(args[1]); adm.SetDigitalReportMode(port, enable); //adm.G break; case "list-devices": schema.AddDevices(adm.GetDevices()); break; case "list-pins": break; default: throw new Exception(String.Format("No ADM direct command {0}", tgtcmd[1])); } } else { //handle command specific to device try { respond = HandleADMDeviceCommand(adm, tgtcmd[1], tgtcmd[2], args, response); } catch (Exception e) { Tracing?.TraceEvent(TraceEventType.Error, 0, "Exception: {0}", e.Message); throw e; } } if (response.Value == null || response.Value == String.Empty) { response.Value = "Handled " + cmd; } break; } return(respond); }