/// <summary> /// Send a command and wait for a reply /// </summary> /// <param name="sequence">The command sequence, typically starting with <see cref="FirmataCommand.START_SYSEX"/> and ending with <see cref="FirmataCommand.END_SYSEX"/></param> /// <param name="timeout">A non-default timeout</param> /// <returns>The raw sequence of sysex reply bytes. The reply does not include the START_SYSEX byte, but it does include the terminating END_SYSEX byte. The first byte is the /// <see cref="FirmataSysexCommand"/> command number of the corresponding request</returns> public List <byte> SendCommandAndWait(FirmataCommandSequence sequence, TimeSpan timeout) { if (!sequence.Validate()) { throw new ArgumentException("The command sequence is invalid", nameof(sequence)); } lock (_synchronisationLock) { if (_firmataStream == null) { throw new ObjectDisposedException(nameof(FirmataDevice)); } _dataReceived.Reset(); // Use an explicit iteration, avoids a memory allocation here for (int i = 0; i < sequence.Sequence.Count; i++) { _firmataStream.WriteByte(sequence.Sequence[i]); } _firmataStream.Flush(); bool result = _dataReceived.WaitOne(timeout); if (result == false) { throw new TimeoutException("Timeout waiting for command answer"); } return(new List <byte>(_lastResponse)); } }
/// <summary> /// Send a command to the device, expecting a reply. /// </summary> /// <param name="commandSequence">Command to send. This /// should normally be a sysex command.</param> /// <param name="timeout">Command timeout</param> /// <exception cref="TimeoutException">The timeout elapsed before a reply was received.</exception> /// <returns>The reply packet</returns> protected byte[] SendCommandAndWait(FirmataCommandSequence commandSequence, TimeSpan timeout) { if (_firmata == null) { throw new InvalidOperationException("Command handler not registered"); } return(_firmata.SendCommandAndWait(commandSequence, timeout)); }
/// <summary> /// Sends a command to the device, not expecting an answer. /// </summary> /// <param name="commandSequence">A command sequence. This /// should normally be a sysex command.</param> protected void SendCommand(FirmataCommandSequence commandSequence) { if (_firmata == null) { throw new InvalidOperationException("Command handler not registered"); } _firmata.SendCommand(commandSequence); }
private (int TimeStamp, int NewTicks, bool Success) DecodeFrequencyReport(Span <byte> reply) { if (reply.Length < 13 || reply[0] != (byte)FirmataSysexCommand.FREQUENCY_COMMAND) { // Logger.LogError("Frequency sensor extension: Incorrect answer received"); return(0, 0, false); } int timestamp = (int)FirmataCommandSequence.DecodeUInt32(reply, 3); int ticks = (int)FirmataCommandSequence.DecodeUInt32(reply, 8); return(timestamp, ticks, true); }
/// <summary> /// Send a command that does not generate a reply. /// This method must only be used for commands that do not generate a reply. It must not be used if only the caller is not /// interested in the answer. /// </summary> /// <param name="sequence">The command sequence to send</param> /// <param name="timeout">A non-default timeout</param> public void SendCommand(FirmataCommandSequence sequence, TimeSpan timeout) { if (!sequence.Validate()) { throw new ArgumentException("The command sequence is invalid", nameof(sequence)); } lock (_synchronisationLock) { if (_firmataStream == null) { throw new ObjectDisposedException(nameof(FirmataDevice)); } // Use an explicit iteration, avoids a memory allocation here for (int i = 0; i < sequence.Sequence.Count; i++) { _firmataStream.WriteByte(sequence.Sequence[i]); } _firmataStream.Flush(); } }
/// <summary> /// Send a command to the device, expecting a reply. This uses a default timeout. /// </summary> /// <param name="commandSequence">Command to send. This /// should normally be a sysex command.</param> /// <exception cref="TimeoutException">The timeout elapsed before a reply was received.</exception> /// <returns>The reply packet</returns> protected byte[] SendCommandAndWait(FirmataCommandSequence commandSequence) { return(SendCommandAndWait(commandSequence, FirmataDevice.DefaultReplyTimeout)); }
/// <summary> /// Callback function that returns whether the given reply indicates an error /// </summary> /// <param name="sequence">The original sequence</param> /// <param name="reply">The reply. <see cref="IsMatchingAck"/> is already tested to be true for this reply</param> /// <returns>A command error code, in case this reply indicates a no-acknowledge</returns> protected virtual CommandError HasCommandError(FirmataCommandSequence sequence, byte[] reply) => CommandError.None;
/// <summary> /// This method is called to check whether the reply is a valid ACK/NOACK for the given command sequence. /// Can be used to avoid accepting something as command reply that is completely unrelated (such as an asynchronous callback). /// In different words, this should return false if the given reply is not something that is an answer to a synchronous command. /// </summary> /// <param name="sequence">The sequence that was sent</param> /// <param name="reply">The reply</param> /// <returns>True if this reply matches the sequence. True is the default, for backwards compatibility</returns> protected virtual bool IsMatchingAck(FirmataCommandSequence sequence, byte[] reply) => true;
/// <summary> /// Send a command to the device, expecting a reply. /// </summary> /// <param name="commandSequence">Command to send. This /// should normally be a sysex command.</param> /// <param name="timeout">Command timeout</param> /// <exception cref="TimeoutException">The timeout elapsed before a reply was received.</exception> /// <returns>The reply packet</returns> protected byte[] SendCommandAndWait(FirmataCommandSequence commandSequence, TimeSpan timeout) { return(SendCommandAndWait(commandSequence, timeout, out _)); }
/// <summary> /// Send a command and wait for a reply /// </summary> /// <param name="sequence">The command sequence, typically starting with <see cref="FirmataCommand.START_SYSEX"/> and ending with <see cref="FirmataCommand.END_SYSEX"/></param> /// <returns>The raw sequence of sysex reply bytes. The reply does not include the START_SYSEX byte, but it does include the terminating END_SYSEX byte. The first byte is the /// <see cref="FirmataSysexCommand"/> command number of the corresponding request</returns> public List <byte> SendCommandAndWait(FirmataCommandSequence sequence) { return(SendCommandAndWait(sequence, DefaultReplyTimeout)); }
/// <summary> /// Send a command that does not generate a reply. /// This method must only be used for commands that do not generate a reply. It must not be used if only the caller is not /// interested in the answer. /// </summary> /// <param name="sequence">The command sequence to send</param> public void SendCommand(FirmataCommandSequence sequence) { SendCommand(sequence, DefaultReplyTimeout); }
/// <summary> /// Send a command and wait for a reply /// </summary> /// <param name="sequence">The command sequence, typically starting with <see cref="FirmataCommand.START_SYSEX"/> and ending with <see cref="FirmataCommand.END_SYSEX"/></param> /// <param name="timeout">A non-default timeout</param> /// <returns>The raw sequence of sysex reply bytes. The reply does not include the START_SYSEX byte, but it does include the terminating END_SYSEX byte. The first byte is the /// <see cref="FirmataSysexCommand"/> command number of the corresponding request</returns> public byte[] SendCommandAndWait(FirmataCommandSequence sequence, TimeSpan timeout) { return(SendCommandAndWait(sequence, timeout, out _)); }