public static ExecuteResult FromError(CommandError error, string reason)
 => new ExecuteResult(null, error, reason);
Example #2
0
 public static CommandResult FromError(CommandError error, string reason)
 {
     return(new CommandResult(error, reason));
 }
Example #3
0
 protected abstract LazyNotification?PushMessageInternal(CommandError errorStatus, NotificationType ntfyType);
Example #4
0
 private static void client_OnErrorEvent(object sender, CommandError e)
 {
     Console.WriteLine($"[Error] {e.Message}");
 }
Example #5
0
 public static void Throw(this CommandError error) => Throw(error.Error, error.Message);
Example #6
0
        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);
                }
            });
        }
Example #7
0
 public void SetAnswer(CommandError commandError, string commandLine = null)
 {
     this.commandError = commandError ?? throw new ArgumentNullException(nameof(commandError));
     this.commandLine  = commandLine;
     answerWaiter.Set();
 }
Example #8
0
 private static void Client_OnErrorEvent(object sender, CommandError e)
 {
     ConsoleHelper.WriteEventLine(e.ErrorFormat(), Color.ForestGreen);
 }
Example #9
0
 public CommandResults(bool successful, CommandError error, List <ParsedArgument> arguments)
 {
     Successful = successful;
     Error      = error;
     Arguments  = arguments;
 }
Example #10
0
 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;
 }
Example #12
0
        /// <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());
            }
        }
Example #13
0
        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;
            }
        }
Example #14
0
        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));
        }