/// <summary> /// Sends a message to the Parrot RF Service. /// </summary> /// <param name="message"></param> /// <returns></returns> public async Task <XElement> SendMessageAsync(ParrotMessage message) { if (!BluetoothClient.Connected) { throw new Exception($"{nameof(ParrotClient)} is not connected."); } _waitingList.WaitOne(); try { // Debug message Console.WriteLine($"=> Sending message '{message.Request}'"); // Send message to Parrot var messageBytes = message.GetRequest(); await BluetoothClient.GetStream().WriteAsync(messageBytes, 0, messageBytes.Length); await BluetoothClient.GetStream().FlushAsync(); // Hold response element XElement answerElement; // Hold notifications var notifyElements = new List <XElement>(); // Receive response(s) do { answerElement = XElement.Parse(await ReceiveResponseAsync()); // Find notificiations if (answerElement.Name == "notify") { notifyElements.Add(answerElement); } else if (answerElement.Name == "answer") { var notifyElement = answerElement.XPathSelectElement("/notify"); if (notifyElement != null) { notifyElements.Add(notifyElement); } } } while (answerElement.Name != "answer"); // Handle notifications foreach (var notifyElement in notifyElements) { var notifyPath = notifyElement?.Attribute("path")?.Value; if (notifyPath == null) { continue; } var resource = ResourceManager.Resources.FirstOrDefault(x => x.Value.Equals(notifyPath)).Key; if (resource == ResourceType.UnknownResource && ZikApi.KnowMessages.Contains(notifyPath)) { Console.WriteLine($"=> Received unhandled notification {resource} ({notifyPath})"); continue; } else if (resource == ResourceType.UnknownResource) { throw new UnknownNotificationException($"Received an unknown notification: {notifyPath}"); } // Debug message Console.WriteLine($"=> Dispatching notification {resource} ({notifyPath})"); NotificationEvent?.AsyncSafeInvoke(this, new NotifyEventArgs(resource, notifyPath)); } // Return return(answerElement); } finally { _waitingList.Release(); } }