using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using Tango.PMR; using Tango.PMR.Common; using Tango.PMR.Stubs; using Tango.Transport.Adapters; using Google.Protobuf; using System.Threading; using Newtonsoft.Json; using Google.Protobuf.Collections; using System.Collections; namespace Tango.Stubs.CLI { class Program { static void Main(string[] args) { Run(args); } private static void Run(string[] args) { if (args == null || args.Length < 3 || args[0] == "?") { PrintHelp(); } String comPort = args[0].ToUpper(); String baudRate = args[1]; String stubName = args[2]; var stubType = GetAvailableRequestResponseStubs().SingleOrDefault(x => x.Name.ToLower() == stubName.ToLower() || x.Name.Replace("Request", "").ToLower() == stubName.ToLower()); if (stubType == null) { PrintError("Invalid stub '" + stubName + "'."); } var stubProps = stubType.GetProperties(BindingFlags.Public | BindingFlags.Instance); if (stubProps.Length > args.Length - 3) { PrintError("Not enough arguments for " + stubType.Name + "."); } try { MessageContainer container = new MessageContainer(); container.Token = Guid.NewGuid().ToString(); container.Type = ParseMessageType(stubType.Name); Object request = Activator.CreateInstance(stubType); int argIndex = 3; foreach (var prop in stubProps) { String arg = args[argIndex++].ToString(); if (prop.PropertyType == typeof(UInt32)) { prop.SetValue(request, UInt32.Parse(arg)); } else if (prop.PropertyType == typeof(bool)) { prop.SetValue(request, bool.Parse(arg)); } else if (typeof(IList).IsAssignableFrom(prop.PropertyType)) { IList arr = prop.GetValue(request) as IList; foreach (var item in arg.Split(',')) { object converted = Convert.ChangeType(item, prop.PropertyType.GetGenericArguments()[0]); arr.Add(converted); } } else { object converted = Convert.ChangeType(arg, prop.PropertyType); prop.SetValue(request, converted); } } container.Data = typeof(IMessage).GetExtensionMethod(typeof(ByteString).Assembly, "ToByteString").Invoke(request, new object[] { request }) as ByteString; byte[] requestData = container.ToByteArray(); UsbSerialBaudRates rate = UsbSerialBaudRates.BR_115200; if (!Enum.TryParse("BR_" + baudRate, out rate)) { throw new ArgumentException("Invalid baud rate specified."); } using (UsbTransportAdapter adapter = new UsbTransportAdapter(comPort, rate)) { Console.WriteLine("Connecting to machine on " + comPort + "..."); adapter.Connect().Wait(); bool done = false; Task.Factory.StartNew(() => { Console.WriteLine("Sending " + stubType.Name + "..."); adapter.Write(requestData); DateTime startTime = DateTime.Now; MessageContainer responseContainer = null; adapter.DataAvailable += (sender, data) => { responseContainer = ParseContainer(data); }; while (responseContainer == null) { Thread.Sleep(10); if (DateTime.Now > startTime.AddSeconds(5)) { PrintError("Response has failed to arrive after 5 seconds."); } } Console.WriteLine("Response Received:"); var type = typeof(MessageFactory).Assembly.GetType("Tango.PMR.Stubs." + responseContainer.Type.ToOriginalName()); MessageParser parser = type.GetProperty("Parser").GetValue(container) as MessageParser; IMessage message = parser.ParseFrom(responseContainer.Data); Console.WriteLine(JsonConvert.SerializeObject(message, Formatting.Indented)); done = true; }); while (!done) { Thread.Sleep(10); } } } catch (Exception ex) { PrintError(ex.FlattenMessage()); } } private static void PrintHelp() { Console.WriteLine("Twine - Tango stubs execution utility v" + typeof(Program).Assembly.GetName().Version.ToString()); Console.WriteLine(); Console.WriteLine("Usage:"); Console.WriteLine( String.Format("{0} [Embedded device COM port] [stub name] [param1..] [param2..] [param3..]", Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().MainModule.FileName))); Console.WriteLine(); Console.WriteLine("Example:"); Console.WriteLine(); Console.WriteLine( String.Format("{0} COM4 CalculateRequest 10 5", Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().MainModule.FileName))); Console.WriteLine(); Console.WriteLine("Available Stubs:"); int stubCount = 1; foreach (var stub in GetAvailableRequestResponseStubs()) { Console.WriteLine(); if ((stubCount++) % 2 != 0) { Console.WriteLine("-----------------------------------------------------------------------------------"); } Console.WriteLine(stub.Name + ":"); int paramCount = 1; foreach (var prop in stub.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { Console.WriteLine(String.Format("Param {0}: {1}, {2}", paramCount++, prop.Name, Path.GetExtension(prop.PropertyType.ToString()).Replace(".", "").ToLower())); } } ExitSuccess(); } private static void PrintError(String error) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(error); Console.ForegroundColor = ConsoleColor.Gray; ExitError(); } private static void ExitError() { Environment.Exit(-1); } private static void ExitSuccess() { Environment.Exit(0); } private static List GetAvailableRequestResponseStubs() { return typeof(MessageFactory).Assembly.GetTypes().Where(x => x.Namespace != null && x.Namespace.Contains("Stubs") && (x.Name.Contains("Request") || x.Name.Contains("Response")) && !x.Name.Contains("Reflection")).ToList(); } public static MessageType ParseMessageType(String text) { MessageType t; if (Enum.TryParse(text, true, out t)) { return t; } else { throw new InvalidCastException("Message type " + text + " was not found on PMR MessageType enumeration!"); } } /// /// Parses a message container from the specified byte array. /// /// The data. /// public static MessageContainer ParseContainer(byte[] data) { MessageContainer container = MessageContainer.Parser.ParseFrom(data); return container; } } }