/// <summary> /// Sends a message to the Pebble and awaits the response. /// </summary> /// <typeparam name="T">The type of message</typeparam> /// <param name="message">The message content.</param> /// <param name="millisecondsTimeout">The milliseconds timeout.</param> /// <returns>A message response</returns> /// <exception cref="System.InvalidOperationException">A message is being waited for already</exception> /// <remarks>Beware when debugging that setting a breakpoint in Protocol.Run or ProtocolMessageReceived will cause the ResetEvent to time out</remarks> private Task <T> SendMessageAndAwaitResponseAsync <T>(P3bbleMessage message, int millisecondsTimeout = 10000) where T : P3bbleMessage { if (this._pendingMessageSignal != null || this.IsBusy) { throw new InvalidOperationException("A message is being waited for already"); } return(Task.Run <T>(async() => { this.IsBusy = true; int startTicks = Environment.TickCount; this._pendingMessageSignal = new ManualResetEventSlim(false); this._pendingMessage = message; // Send the message... await this._protocol.WriteMessage(message); // Wait for the response... this._pendingMessageSignal.Wait(millisecondsTimeout); T pendingMessage = null; if (this._pendingMessageSignal.IsSet) { // Store any response will be null if timed out... pendingMessage = this._pendingMessage as T; } // See if we have a protocol error LogsMessage logMessage = this._pendingMessage as LogsMessage; Type pendingMessageType = this._pendingMessage.GetType(); // Clear the pending variables... this._pendingMessageSignal = null; this._pendingMessage = null; int timeTaken = Environment.TickCount - startTicks; this.IsBusy = false; if (pendingMessage != null) { ServiceLocator.Logger.WriteLine(pendingMessage.GetType().Name + " message received back in " + timeTaken.ToString() + "ms"); } else { ServiceLocator.Logger.WriteLine(message.GetType().Name + " message timed out in " + timeTaken.ToString() + "ms - type received was " + pendingMessageType.ToString()); } return pendingMessage; })); }
/// <summary> /// Creates an incoming message. /// </summary> /// <param name="endpoint">The endpoint.</param> /// <param name="payload">The payload.</param> /// <returns>A specific message type</returns> public static P3bbleMessage CreateMessage(Endpoint endpoint, List <byte> payload) { P3bbleMessage frame = null; switch (endpoint) { case Endpoint.Ping: frame = new PingMessage(); break; case Endpoint.Version: frame = new VersionMessage(); break; case Endpoint.Time: frame = new TimeMessage(); break; case Endpoint.Logs: frame = new LogsMessage(); break; case Endpoint.AppManager: frame = new AppManagerMessage(); break; case Endpoint.MusicControl: frame = new MusicMessage(); break; case Endpoint.ApplicationMessage: frame = new AppMessage(endpoint); break; case Endpoint.PutBytes: frame = new PutBytesMessage(); break; } if (frame != null) { frame.GetContentFromMessage(payload); } return(frame); }
/// <summary> /// Handles protocol messages /// </summary> /// <param name="message">The message.</param> private async void ProtocolMessageReceived(P3bbleMessage message) { ServiceLocator.Logger.WriteLine("ProtocolMessageReceived: " + message.Endpoint.ToString()); switch (message.Endpoint) { case Endpoint.PhoneVersion: // We need to tell the Pebble what we are... await this._protocol.WriteMessage(new PhoneVersionMessage(IsMusicControlEnabled)); break; case Endpoint.Version: // Store version info we got from the Pebble... VersionMessage version = message as VersionMessage; this.FirmwareVersion = version.Firmware; this.RecoveryFirmwareVersion = version.RecoveryFirmware; break; case Endpoint.Logs: if (message as LogsMessage != null) { ServiceLocator.Logger.WriteLine("LOG: '" + (message as LogsMessage).Message + "'"); } break; case Endpoint.MusicControl: var musicMessage = message as MusicMessage; if (this.MusicControlReceived != null && musicMessage != null && musicMessage.ControlAction != MusicControlAction.Unknown) { this.MusicControlReceived(musicMessage.ControlAction); } break; default: break; } // Check if we're waiting for a message... if (this._pendingMessageSignal != null && this._pendingMessage != null) { if (this._pendingMessage.Endpoint == message.Endpoint) { ServiceLocator.Logger.WriteLine("ProtocolMessageReceived: we were waiting for this type of message"); // PutBytes messages are state machines, so need special treatment... if (message.Endpoint == Endpoint.PutBytes) { var putMessage = this._pendingMessage as PutBytesMessage; if (putMessage.HandleStateMessage(message as PutBytesMessage)) { this._pendingMessageSignal.Set(); } else { await this._protocol.WriteMessage(putMessage); } } else { this._pendingMessage = message; this._pendingMessageSignal.Set(); } } else { // We've received a Log message when we were expecting something else, // this means the protocol comms got messed up somehow, we should abort... if (message.Endpoint == Endpoint.Logs) { this._pendingMessage = message; this._pendingMessageSignal.Set(); } } } }