public static ExecuteResult FromError(CommandError error, string reason) => new ExecuteResult(null, error, reason);
public static CommandResult FromError(CommandError error, string reason) { return(new CommandResult(error, reason)); }
protected abstract LazyNotification?PushMessageInternal(CommandError errorStatus, NotificationType ntfyType);
private static void client_OnErrorEvent(object sender, CommandError e) { Console.WriteLine($"[Error] {e.Message}"); }
public static void Throw(this CommandError error) => Throw(error.Error, error.Message);
void OnRead(TcpSocketClient client, byte[] buffers) { ThreadCalls(() => { try { var cmd = new BaseCommand(buffers); switch (cmd.Command) { case Commands.Bind_Resp: var bind_resp = new Bind_Resp(buffers); if (bind_resp.Result != CommandError.Success) { PrintLog("绑定验证失败:" + CommandError.GetMessage(bind_resp.Result)); Thread.Sleep(1000); client.Disconnect(); } break; case Commands.Deliver: var deliver = new Deliver(buffers); //添加接收记录 var sms = new SMS { SPNumber = deliver.SPNumber, UserNumber = deliver.UserNumber, Content = deliver.MessageContent, Time = DateTime.Now, Type = SMSTypes.RECEIVE }; SMSHistory.Add(sms); //绑定会话组 BindGroup(deliver.SPNumber); //绑定会话 if (lbGroup.SelectedItem != null && lbGroup.SelectedItem.ToString() == sms.SPNumber) { BindSession(sms); } else { lbGroup.SelectedItem = deliver.SPNumber; BindSession(deliver.SPNumber); } //新消息提醒 PrintLog("收到一条 " + sms.SPNumber + " 发来的新消息!"); //发送响应 client.Send(new Deliver_Resp { SequenceNumber = deliver.SequenceNumber, Result = CommandError.Success }.GetBytes()); break; case Commands.Deliver_Resp: var deliver_resp = new Deliver_Resp(buffers); if (deliver_resp.Result != CommandError.Success) { PrintLog("传送消息失败:" + CommandError.GetMessage(deliver_resp.Result)); } break; default: break; } PrintLog("接收一条命令:" + Commands.GetString(cmd.Command)); } catch (Exception e) { PrintLog("读取消息出现错误: " + e.Message); } }); }
public void SetAnswer(CommandError commandError, string commandLine = null) { this.commandError = commandError ?? throw new ArgumentNullException(nameof(commandError)); this.commandLine = commandLine; answerWaiter.Set(); }
private static void Client_OnErrorEvent(object sender, CommandError e) { ConsoleHelper.WriteEventLine(e.ErrorFormat(), Color.ForestGreen); }
public CommandResults(bool successful, CommandError error, List <ParsedArgument> arguments) { Successful = successful; Error = error; Arguments = arguments; }
protected virtual void OnCommandError(CommandErrorType errorType, string error) { CommandError?.Invoke(this, new CommandErrorEventArgs(errorType, error)); }
internal PlayerCommandFailedEventArgs(IPlayer player, string input, CommandError error, string errorMessage) : base(player) { Input = input; Error = error; ErrorMessage = errorMessage; }
/// <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> /// <param name="error">An error code in case of failure</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, out CommandError error) { 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"); } error = _lastCommandError; return(_lastResponse.ToArray()); } }
private void ProcessInput() { if (_dataQueue.Count == 0) { FillQueue(); } if (_dataQueue.Count == 0) { // Still no data? (End of stream or stream closed) return; } int data = _dataQueue.Dequeue(); // OnError?.Invoke($"0x{data:X}", null); byte b = (byte)(data & 0x00FF); byte upper_nibble = (byte)(data & 0xF0); byte lower_nibble = (byte)(data & 0x0F); /* * the relevant bits in the command depends on the value of the data byte. If it is less than 0xF0 (start sysex), only the upper nibble identifies the command * while the lower nibble contains additional data */ FirmataCommand command = (FirmataCommand)((data < ((ushort)FirmataCommand.START_SYSEX) ? upper_nibble : b)); // determine the number of bytes remaining in the message int bytes_remaining = 0; bool isMessageSysex = false; switch (command) { default: // command not understood char c = (char)data; _lastRawLine.Append(c); if (c == '\n') { OnError?.Invoke(_lastRawLine.ToString().Trim(), null); OnSysexReply?.Invoke(ReplyType.AsciiData, Encoding.Unicode.GetBytes(_lastRawLine.ToString())); _lastRawLine.Clear(); } return; case FirmataCommand.END_SYSEX: // should never happen return; // commands that require 2 additional bytes case FirmataCommand.DIGITAL_MESSAGE: case FirmataCommand.ANALOG_MESSAGE: case FirmataCommand.SET_PIN_MODE: case FirmataCommand.PROTOCOL_VERSION: bytes_remaining = 2; break; // commands that require 1 additional byte case FirmataCommand.REPORT_ANALOG_PIN: case FirmataCommand.REPORT_DIGITAL_PIN: bytes_remaining = 1; break; // commands that do not require additional bytes case FirmataCommand.SYSTEM_RESET: // do nothing, as there is nothing to reset return; case FirmataCommand.START_SYSEX: // this is a special case with no set number of bytes remaining isMessageSysex = true; _lastRawLine.Clear(); break; } // read the remaining message while keeping track of elapsed time to timeout in case of incomplete message List <byte> message = new List <byte>(); int bytes_read = 0; Stopwatch timeout_start = Stopwatch.StartNew(); while (bytes_remaining > 0 || isMessageSysex) { if (_dataQueue.Count == 0) { int timeout = 10; while (!FillQueue() && timeout-- > 0) { Thread.Sleep(5); } if (timeout == 0) { // Synchronisation problem: The remainder of the expected message is missing _lastCommandError = CommandError.Timeout; return; } } data = _dataQueue.Dequeue(); // OnError?.Invoke($"0x{data:X}", null); // if no data was available, check for timeout if (data == 0xFFFF) { // get elapsed seconds, given as a double with resolution in nanoseconds var elapsed = timeout_start.Elapsed; if (elapsed > DefaultReplyTimeout) { _lastCommandError = CommandError.Timeout; return; } continue; } timeout_start.Restart(); // if we're parsing sysex and we've just read the END_SYSEX command, we're done. if (isMessageSysex && (data == (short)FirmataCommand.END_SYSEX)) { break; } message.Add((byte)(data & 0xFF)); ++bytes_read; --bytes_remaining; } // process the message switch (command) { // ignore these message types (they should not be in a reply) default: case FirmataCommand.REPORT_ANALOG_PIN: case FirmataCommand.REPORT_DIGITAL_PIN: case FirmataCommand.SET_PIN_MODE: case FirmataCommand.END_SYSEX: case FirmataCommand.SYSTEM_RESET: return; case FirmataCommand.PROTOCOL_VERSION: if (_actualFirmataProtocolMajorVersion != 0) { // Firmata sends this message automatically after a device reset (if you press the reset button on the arduino) // If we know the version already, this is unexpected. _lastCommandError = CommandError.DeviceReset; OnError?.Invoke("The device was unexpectedly reset. Please restart the communication.", null); } _actualFirmataProtocolMajorVersion = message[0]; _actualFirmataProtocolMinorVersion = message[1]; _dataReceived.Set(); return; case FirmataCommand.ANALOG_MESSAGE: // report analog commands store the pin number in the lower nibble of the command byte, the value is split over two 7-bit bytes // AnalogValueUpdated(this, // new CallbackEventArgs(lower_nibble, (ushort)(message[0] | (message[1] << 7)))); { int pin = lower_nibble; uint value = (uint)(message[0] | (message[1] << 7)); lock (_lastAnalogValueLock) { _lastAnalogValues[pin] = value; } AnalogPinValueUpdated?.Invoke(pin, value); } break; case FirmataCommand.DIGITAL_MESSAGE: // digital messages store the port number in the lower nibble of the command byte, the port value is split over two 7-bit bytes // Each port corresponds to 8 pins { int offset = lower_nibble * 8; ushort pinValues = (ushort)(message[0] | (message[1] << 7)); lock (_lastPinValueLock) { for (int i = 0; i < 8; i++) { PinValue oldValue = _lastPinValues[i + offset]; int mask = 1 << i; PinValue newValue = (pinValues & mask) == 0 ? PinValue.Low : PinValue.High; if (newValue != oldValue) { PinEventTypes eventTypes = newValue == PinValue.High ? PinEventTypes.Rising : PinEventTypes.Falling; _lastPinValues[i + offset] = newValue; // TODO: The callback should not be within the lock DigitalPortValueUpdated?.Invoke(this, new PinValueChangedEventArgs(eventTypes, i + offset)); } } } } break; case FirmataCommand.START_SYSEX: // a sysex message must include at least one extended-command byte if (bytes_read < 1) { _lastCommandError = CommandError.InvalidArguments; return; } // retrieve the raw data array & extract the extended-command byte var raw_data = message.ToArray(); FirmataSysexCommand sysCommand = (FirmataSysexCommand)(raw_data[0]); int index = 0; ++index; --bytes_read; switch (sysCommand) { case FirmataSysexCommand.REPORT_FIRMWARE: // See https://github.com/firmata/protocol/blob/master/protocol.md // Byte 0 is the command (0x79) and can be skipped here, as we've already interpreted it { _firmwareVersionMajor = raw_data[1]; _firmwareVersionMinor = raw_data[2]; int stringLength = (raw_data.Length - 3) / 2; Span <byte> bytesReceived = stackalloc byte[stringLength]; ReassembleByteString(raw_data, 3, stringLength * 2, bytesReceived); _firmwareName = Encoding.ASCII.GetString(bytesReceived); _dataReceived.Set(); } return; case FirmataSysexCommand.STRING_DATA: { // condense back into 1-byte data int stringLength = (raw_data.Length - 1) / 2; Span <byte> bytesReceived = stackalloc byte[stringLength]; ReassembleByteString(raw_data, 1, stringLength * 2, bytesReceived); string message1 = Encoding.UTF8.GetString(bytesReceived); int idxNull = message1.IndexOf('\0'); if (message1.Contains("%") && idxNull > 0) // C style printf formatters { message1 = message1.Substring(0, idxNull); string message2 = PrintfFromByteStream(message1, bytesReceived, idxNull + 1); OnError?.Invoke(message2, null); } else { OnError?.Invoke(message1, null); } } break; case FirmataSysexCommand.CAPABILITY_RESPONSE: { _supportedPinConfigurations.Clear(); int idx = 1; var currentPin = new SupportedPinConfiguration(0); int pin = 0; while (idx < raw_data.Length) { int mode = raw_data[idx++]; if (mode == 0x7F) { _supportedPinConfigurations.Add(currentPin); currentPin = new SupportedPinConfiguration(++pin); continue; } int resolution = raw_data[idx++]; SupportedMode?sm = SupportedModes.FirstOrDefault(x => x.Value == mode); if (sm == SupportedMode.AnalogInput) { currentPin.PinModes.Add(SupportedMode.AnalogInput); currentPin.AnalogInputResolutionBits = resolution; } else if (sm == SupportedMode.Pwm) { currentPin.PinModes.Add(SupportedMode.Pwm); currentPin.PwmResolutionBits = resolution; } else if (sm == null) { sm = new SupportedMode((byte)mode, $"Unknown mode {mode}"); currentPin.PinModes.Add(sm); } else { currentPin.PinModes.Add(sm); } } // Add 8 entries, so that later we do not need to check whether a port (bank) is complete _lastPinValues = new PinValue[_supportedPinConfigurations.Count + 8].ToList(); _dataReceived.Set(); // Do not add the last instance, should also be terminated by 0xF7 } break; case FirmataSysexCommand.ANALOG_MAPPING_RESPONSE: { // This needs to have been set up previously if (_supportedPinConfigurations.Count == 0) { return; } int idx = 1; int pin = 0; while (idx < raw_data.Length) { if (raw_data[idx] != 127) { _supportedPinConfigurations[pin].AnalogPinNumber = raw_data[idx]; } idx++; pin++; } _dataReceived.Set(); } break; case FirmataSysexCommand.I2C_REPLY: _lastCommandError = CommandError.None; _lastResponse = raw_data; _dataReceived.Set(); break; case FirmataSysexCommand.SPI_DATA: _lastCommandError = CommandError.None; _lastResponse = raw_data; _dataReceived.Set(); break; default: // we pass the data forward as-is for any other type of sysex command _lastCommandError = CommandError.None; _lastResponse = raw_data; // the instance is constant, so we can just remember the pointer OnSysexReply?.Invoke(ReplyType.SysexCommand, raw_data); _dataReceived.Set(); break; } break; } }
public LazyNotification?PushMessage(ReadOnlyMemory <byte> message) { var msgSpan = message.Span; string notifyname; int splitindex = msgSpan.IndexOf(AsciiSpace); if (splitindex < 0) { notifyname = msgSpan.TrimEnd(AsciiSpace).NewUtf8String(); } else { notifyname = msgSpan.Slice(0, splitindex).NewUtf8String(); } bool hasEqual; NotificationType ntfyType; if ((hasEqual = notifyname.IndexOf('=') >= 0) || (ntfyType = findTypeOfNotification(notifyname)) == NotificationType.Unknown) { if (!hasEqual) { Log.Debug("Maybe unknown notification: {0}", notifyname); } cmdLineBuffer = message; return(null); } var lineDataPart = splitindex < 0 ? ReadOnlySpan <byte> .Empty : msgSpan.Slice(splitindex); // if it's not an error it is a notification if (ntfyType != NotificationType.CommandError) { var notification = Deserializer.GenerateNotification(lineDataPart, ntfyType); if (!notification.Ok) { Log.Warn("Got unparsable message. ({0})", msgSpan.NewUtf8String()); return(null); } var lazyNotification = new LazyNotification(notification.Value, ntfyType); lock (waitBlockLock) { var dependantList = dependingBlocks[(int)ntfyType]; if (dependantList != null) { foreach (var item in dependantList) { item.SetNotification(lazyNotification); if (item.DependsOn != null) { foreach (var otherDepType in item.DependsOn) { if (otherDepType == ntfyType) { continue; } dependingBlocks[(int)otherDepType]?.Remove(item); } } } dependantList.Clear(); } } return(lazyNotification); } var result = Deserializer.GenerateSingleNotification(lineDataPart, NotificationType.CommandError); var errorStatus = result.Ok ? (CommandError)result.Value : CommandError.Custom("Invalid Error code"); return(PushMessageInternal(errorStatus, ntfyType)); }