public static ISCPMessage Parse(string raw) { if (raw[0] == '!') { raw = raw.Substring(2); // skip !1 } raw = raw.TrimEnd((char)0x0a, (char)0x0d, (char)0x1a); var m = new ISCPMessage() { Command = raw.Length >= 3 ? raw.Substring(0, 3) : "" }; if (raw.Length > 3) { var i = raw.IndexOf("<?xml"); if (i > 0) { m.RawData = raw.Substring(3, i - 3); m.Xml = XDocument.Parse(raw.Substring(i)).Root; } else { m.RawData = raw.Substring(3); } } return(m); }
public virtual void ParseFrom(ISCPMessage source) { // just copy Command = source.Command; RawData = source.RawData; Xml = source.Xml; }
protected bool DefaultResponseAcceptFunc(ISCPMessage originalMessage, ISCPMessage receivedMessage) { if (originalMessage.Command == receivedMessage.Command) { return(true); } return(false); }
public async Task <TResponse> SendCommandAsync <TResponse>(ISCPMessage message, int millisecondsTimeout = 2000, Func <ISCPMessage, ISCPMessage, bool> acceptedResponseFunc = null) where TResponse : ISCPMessage, new() { var response = await SendCommandAsync(message, millisecondsTimeout, acceptedResponseFunc); if (response != null) { var newReponse = new TResponse(); newReponse.ParseFrom(response); return(newReponse); } return(null); }
public static ISCPMessage Parse(byte[] buf) { if (buf.Take(4).SequenceEqual(Magic)) { // ISCP var messageSize = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buf, 8)); var msg = Encoding.ASCII.GetString(buf, 16, messageSize); var end = msg.IndexOfAny(new[] { (char)0x0a, (char)0x0d, (char)0x1a }); msg = msg.Substring(2, end - 2); // remove !1 and EOF return(ISCPMessage.Parse(msg)); } return(null); }
public async Task <ISCPMessage> SendCommandAsync(ISCPMessage message, int millisecondsTimeout = 2000, Func <ISCPMessage, ISCPMessage, bool> acceptedResponseFunc = null) { var wait = new ManualResetEventSlim(false); ISCPMessage response = null; // handle to check if command matches. this methods seems more efective then observeable events with Rx. var messsageHandler = new EventHandler <ISCPMessageEventArgs>((sender, args) => { // check if response is accepted. default behavior ist just verifing if command is the same if ((acceptedResponseFunc != null && acceptedResponseFunc(message, args.Message)) || DefaultResponseAcceptFunc(message, args.Message)) { response = args.Message; wait.Set(); } }); try { MessageReceived += messsageHandler; System.Diagnostics.Trace.WriteLine($"{DateTime.Now:O} Send:{message.ToString()}"); var bytes = message.GetBytes(); await _networkStream.WriteAsync(bytes, 0, bytes.Length); var timeout = !wait.Wait(millisecondsTimeout); } catch (Exception exp) { System.Diagnostics.Trace.WriteLine($"{DateTime.Now:O} Error ({message.ToString()}):{exp.ToString()}"); throw exp; } finally { MessageReceived -= messsageHandler; // detach! } if (response != null) { System.Diagnostics.Trace.WriteLine($"{DateTime.Now:O} Response({message.Command}):{response.ToString()}"); } else { System.Diagnostics.Trace.WriteLine($"{DateTime.Now:O} Response timeout ({message.Command}, {millisecondsTimeout} ms)."); throw new TimeoutException("Response timeout ({message.Command}, {millisecondsTimeout} ms)."); } return(response); }
public async Task <ISCPMessage> SendCommandWithRetryAsync(ISCPMessage message, int nbrOfRetries = 3, int millisecondsTimeout = 2000, Func <ISCPMessage, ISCPMessage, bool> acceptedResponseFunc = null) { int i = 0; ISCPMessage response = null; while (i < nbrOfRetries) { try { response = await SendCommandAsync(message, millisecondsTimeout, acceptedResponseFunc); break; } catch (TimeoutException) { i++; } } return(response); }
private void MessageReceiveListener(object obj) { var readBuf = new byte[2048]; int startIndex = 0; while (_listenerCancellationToken.IsCancellationRequested == false) { try { _messageProcessingResetEvent.Set(); var readTask = _networkStream.ReadAsync(readBuf, startIndex, readBuf.Length - startIndex, _listenerCancellationToken.Token); int read = readTask.Result; _messageProcessingResetEvent.Reset(); // detect ISCP blocks int endIndex = 0; for (int i = 0; i < read - 4; i++) { try { // message start with ISCP if (readBuf.Skip(i).Take(4).SequenceEqual(ISCPMessage.Magic)) { startIndex = i; var messageSize = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(readBuf, startIndex + 8)); endIndex = startIndex + 16 + messageSize; var msgString = Encoding.ASCII.GetString(readBuf, startIndex + 16, messageSize); i = endIndex - 1; var msg = ISCPMessage.Parse(msgString); if (msg != null) { System.Diagnostics.Trace.WriteLine($"{DateTime.Now:O} Received {msg.ToString()}"); MessageReceived?.Invoke(this, new ISCPMessageEventArgs() { Message = msg }); } } } catch (Exception exp) { System.Diagnostics.Trace.Fail("Failed extracting ISCP message", exp.ToString()); // just try next byte } } if (endIndex < read) { // still some uncompleted messages in remaining buffer startIndex = read - endIndex; readBuf.Skip(endIndex).Take(startIndex).ToArray().CopyTo(readBuf, 0); // copy to start of buf } else { startIndex = 0; } } catch (AggregateException exp) { if (!(exp.InnerException is OperationCanceledException)) { System.Diagnostics.Trace.Fail($"Error reading message.", exp.ToString()); } } catch (Exception exp) { System.Diagnostics.Trace.Fail($"Error parsing message.", exp.ToString()); } } }
/// <summary> /// Try to find ISCP devices on network. /// </summary> public static Task <List <ReceiverInfo> > DiscoverAsync(int millisecondsTimeout = 5000) { return(Task.Run(() => { int onkyoPort = 60128; byte[] onkyoMagic = new ISCPMessage("ECNQSTN").GetBytes("!x"); var foundReceivers = new List <ReceiverInfo>(); IEnumerable <string> ips = GetInterfaceAddresses(); // Broadcast magic Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); using (socket) { socket.Blocking = false; // So we can use Poll socket.EnableBroadcast = true; socket.Bind(new IPEndPoint(IPAddress.Any, 0)); foreach (var i in ips) { try { var ip = IPAddress.Parse(i); socket.SendTo(onkyoMagic, new IPEndPoint(ip, onkyoPort)); } catch (SocketException) { } } EndPoint addr = new IPEndPoint(IPAddress.Broadcast, onkyoPort); byte[] data = new byte[1024]; int read = 0; while (true) { int microsecondTimeout = (int)(millisecondsTimeout * 1000); if (!socket.Poll(microsecondTimeout, SelectMode.SelectRead)) { break; } read = socket.ReceiveFrom(data, ref addr); var msg = ISCPMessage.Parse(data); // Return string looks something like this: // !1ECNTX-NR609/60128/DX GroupCollection info = Regex.Match(msg.ToString(), //@"!" + //@"(?<device_category>\d)" + @"ECN" + @"(?<model_name>[^/]*)/" + @"(?<iscp_port>\d{5})/" + @"(?<area_code>\w{2})/" + @"(?<identifier>.*)" ).Groups; IPAddress adr = (addr as IPEndPoint).Address; if (!foundReceivers.Any(p => p.IPAddress == adr)) { var ri = new ReceiverInfo { Port = Int32.Parse(info["iscp_port"].Value), Model = info["model_name"].Value, IPAddress = adr }; foundReceivers.Add(ri); } } } return foundReceivers; })); }
public async Task <ISCPMessage> SendCommandAsync(string message) { var m = ISCPMessage.Parse(message); return(await SendCommandAsync(m)); }