Beispiel #1
0
        /// <summary>
        /// Decoder step 1: get message header 10 bytes
        /// </summary>
        /// <param name="length"></param>
        /// <param name="need"></param>
        /// <returns>The decoder step to execute next.</returns>
        private int DecoderStep1GetMessageHeader(ref int length, out int need)
        {
            if (!StreamDecoder.CheckAvailable(length, 10, out need))
            {
                return(1);
            }

            this.messageHeader      = MessageHeader.Decode(new ReadOnlySpan <byte>(this.Buffer, this.decodeIndex, 10));
            this.decodeIndex       += 10;
            this.messageDataLength -= 10;
            length -= 10;
            if (this.messageDataLength == 0)
            {
                if (this.messageHeader.MessageType == MessageType.DataMessage)
                {
                    this.dataMessageHandler(this.messageHeader, new SecsMessage(this.messageHeader.S, this.messageHeader.F, string.Empty, replyExpected: this.messageHeader.ReplyExpected));
                }
                else
                {
                    this.controlMessageHandler(this.messageHeader);
                }

                return(0);
            }

            if (length >= this.messageDataLength)
            {
                Trace.WriteLine("Get Complete Data Message with total data");
                this.dataMessageHandler(this.messageHeader, new SecsMessage(this.messageHeader.S, this.messageHeader.F, string.Empty, StreamDecoder.BufferedDecodeItem(this.Buffer, ref this.decodeIndex), this.messageHeader.ReplyExpected));
                length -= (int)this.messageDataLength;
                this.messageDataLength = 0;
                return(0);                //completeWith message received
            }
            return(this.DecoderStep2GetItemHeader(ref length, out need));
        }
Beispiel #2
0
        private static Item BufferedDecodeItem(byte[] bytes, ref int index)
        {
            byte formatCodeValue = bytes[index];
            var  format          = (SecsFormat)(formatCodeValue & 0b_111111_00);
            byte lengthBits      = (byte)(formatCodeValue & 0b_000000_11);

            index++;

            byte[] itemLengthBytes = new byte[4];
            Array.Copy(bytes, index, itemLengthBytes, 0, lengthBits);
            Array.Reverse(itemLengthBytes, 0, lengthBits);
            int dataLength = BitConverter.ToInt32(itemLengthBytes, 0);             // max to 3 byte dataLength

            index += lengthBits;

            if (format == SecsFormat.List)
            {
                if (dataLength == 0)
                {
                    return(Item.L());
                }

                var list = new List <Item>(dataLength);
                for (int i = 0; i < dataLength; i++)
                {
                    list.Add(StreamDecoder.BufferedDecodeItem(bytes, ref index));
                }

                return(Item.L(list));
            }
            var item = Item.BytesDecode(format, bytes, index, dataLength);

            index += dataLength;
            return(item);
        }
Beispiel #3
0
        /// <summary>
        /// Decoder step 2: get _format + lengthBits(2bit) 1 byte
        /// </summary>
        /// <param name="length"></param>
        /// <param name="need"></param>
        /// <returns>The decoder step to execute next.</returns>
        private int DecoderStep2GetItemHeader(ref int length, out int need)
        {
            if (!StreamDecoder.CheckAvailable(length, 1, out need))
            {
                return(2);
            }

            this.format     = (SecsFormat)(this.Buffer[this.decodeIndex] & 0xFC);
            this.lengthBits = (byte)(this.Buffer[this.decodeIndex] & 3);
            this.decodeIndex++;
            this.messageDataLength--;
            length--;
            return(this.DecoderStep3GetItemLength(ref length, out need));
        }
Beispiel #4
0
        /// <summary>
        /// Decoder step 0: get total message length 4 bytes
        /// </summary>
        /// <param name="length"></param>
        /// <param name="need"></param>
        /// <returns>The decoder step to execute next.</returns>
        private int DecoderStep0GetTotalMessageLength(ref int length, out int need)
        {
            if (!StreamDecoder.CheckAvailable(length, 4, out need))
            {
                return(0);
            }

            Array.Reverse(this.Buffer, this.decodeIndex, 4);
            this.messageDataLength = BitConverter.ToUInt32(this.Buffer, this.decodeIndex);
            Trace.WriteLine($"Get Message Length: {this.messageDataLength}");
            this.decodeIndex += 4;
            length           -= 4;
            return(this.DecoderStep1GetMessageHeader(ref length, out need));
        }
Beispiel #5
0
        /// <summary>
        /// Decoder step 3: get _itemLength _lengthBits bytes, at most 3 byte
        /// </summary>
        /// <param name="length"></param>
        /// <param name="need"></param>
        /// <returns>The decoder step to execute next.</returns>
        private int DecoderStep3GetItemLength(ref int length, out int need)
        {
            if (!StreamDecoder.CheckAvailable(length, this.lengthBits, out need))
            {
                return(3);
            }

            Array.Copy(this.Buffer, this.decodeIndex, this.itemLengthBytes, 0, this.lengthBits);
            Array.Reverse(this.itemLengthBytes, 0, this.lengthBits);

            this.itemLength = BitConverter.ToInt32(this.itemLengthBytes, 0);
            Array.Clear(this.itemLengthBytes, 0, 4);
            Trace.WriteLineIf(this.format != SecsFormat.List, $"Get format: {this.format}, length: {this.itemLength}");

            this.decodeIndex       += this.lengthBits;
            this.messageDataLength -= this.lengthBits;
            length -= this.lengthBits;
            return(this.DecoderStep4GetItem(ref length, out need));
        }
Beispiel #6
0
        /// <summary>
        /// Decoder step 4: get item value
        /// </summary>
        /// <param name="length"></param>
        /// <param name="need"></param>
        /// <returns>The decoder step to execute next.</returns>
        private int DecoderStep4GetItem(ref int length, out int need)
        {
            need = 0;
            Item item;

            if (this.format == SecsFormat.List)
            {
                if (this.itemLength == 0)
                {
                    item = Item.L();
                }
                else
                {
                    this.stack.Push(new List <Item>(this.itemLength));
                    return(this.DecoderStep2GetItemHeader(ref length, out need));
                }
            }
            else
            {
                if (!StreamDecoder.CheckAvailable(length, this.itemLength, out need))
                {
                    return(4);
                }

                item = Item.BytesDecode(this.format, this.Buffer, this.decodeIndex, this.itemLength);
                Trace.WriteLine($"Complete Item: {this.format}");

                this.decodeIndex       += this.itemLength;
                this.messageDataLength -= (uint)this.itemLength;
                length -= this.itemLength;
            }

            if (this.stack.Count == 0)
            {
                Trace.WriteLine("Get Complete Data Message by stream decoded");
                this.dataMessageHandler(this.messageHeader, new SecsMessage(this.messageHeader.S, this.messageHeader.F, string.Empty, item, this.messageHeader.ReplyExpected));
                return(0);
            }

            var list = this.stack.Peek();

            list.Add(item);
            while (list.Count == list.Capacity)
            {
                item = Item.L(this.stack.Pop());
                Trace.WriteLine($"Complete List: {item.Count}");
                if (this.stack.Count > 0)
                {
                    list = this.stack.Peek();
                    list.Add(item);
                }
                else
                {
                    Trace.WriteLine("Get Complete Data Message by stream decoded");
                    this.dataMessageHandler(this.messageHeader, new SecsMessage(this.messageHeader.S, this.messageHeader.F, string.Empty, item, this.messageHeader.ReplyExpected));
                    return(0);
                }
            }

            return(this.DecoderStep2GetItemHeader(ref length, out need));
        }
Beispiel #7
0
        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="isActive">passive or active mode</param>
        /// <param name="ip">if active mode it should be remote device address, otherwise local listener address</param>
        /// <param name="port">if active mode it should be remote device listener's port</param>
        /// <param name="receiveBufferSize">Socket receive buffer size</param>
        public SecsGem(bool isActive, IPAddress ip, int port, int receiveBufferSize = 0x4000)
        {
            if (port <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(port), port, $"port number must greater than 0");
            }

            _taskFactory       = new TaskFactory(TaskScheduler.Default);
            _ip                = ip;
            _port              = port;
            _isActive          = isActive;
            _secsDecoder       = new StreamDecoder(receiveBufferSize, HandleControlMessage, HandleDataMessage);
            _decoderBufferSize = receiveBufferSize;
            #region Timer Action
            _timer7 = new Timer(delegate
            {
                _logger.Error($"T7 Timeout: {T7 / 1000} sec.");
                CommunicationStateChanging(ConnectionState.Retry);
            }, null, Timeout.Infinite, Timeout.Infinite);

            _timer8 = new Timer(delegate
            {
                _logger.Error($"T8 Timeout: {T8 / 1000} sec.");
                CommunicationStateChanging(ConnectionState.Retry);
            }, null, Timeout.Infinite, Timeout.Infinite);

            _timerLinkTest = new Timer(delegate
            {
                if (State == ConnectionState.Selected)
                {
                    SendControlMessage(MessageType.LinkTestRequest, NewSystemId);
                }
            }, null, Timeout.Infinite, Timeout.Infinite);
            #endregion
            var receiveCompleteEvent = new SocketAsyncEventArgs();
            receiveCompleteEvent.SetBuffer(_secsDecoder.Buffer, _secsDecoder.BufferOffset, _secsDecoder.BufferCount);
            receiveCompleteEvent.Completed += ReceiveEventCompleted;
            if (_isActive)
            {
                _startImpl = async() =>
                {
                    bool connected = false;
                    do
                    {
                        if (IsDisposed)
                        {
                            return;
                        }
                        CommunicationStateChanging(ConnectionState.Connecting);
                        try
                        {
                            if (IsDisposed)
                            {
                                return;
                            }
                            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                            await _socket.ConnectAsync(_ip, _port).ConfigureAwait(false);

                            connected = true;
                        }
                        catch (Exception ex)
                        {
                            if (IsDisposed)
                            {
                                return;
                            }
                            _logger.Error(ex.Message);
                            _logger.Info($"Start T5 Timer: {T5 / 1000} sec.");
                            await Task.Delay(T5);
                        }
                    } while (!connected);

                    CommunicationStateChanging(ConnectionState.Connected);

                    // hook receive event first, because no message will received before 'SelectRequest' send to device
                    if (!_socket.ReceiveAsync(receiveCompleteEvent))
                    {
                        ReceiveEventCompleted(_socket, receiveCompleteEvent);
                    }

                    SendControlMessage(MessageType.SelectRequest, NewSystemId);
                };

                //_stopImpl = delegate { };
            }
            else
            {
                var server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                server.Bind(new IPEndPoint(_ip, _port));
                server.Listen(0);

                _startImpl = async() =>
                {
                    bool connected = false;
                    do
                    {
                        if (IsDisposed)
                        {
                            return;
                        }
                        CommunicationStateChanging(ConnectionState.Connecting);
                        try
                        {
                            if (IsDisposed)
                            {
                                return;
                            }
                            _socket = await server.AcceptAsync().ConfigureAwait(false);

                            connected = true;
                        }
                        catch (Exception ex)
                        {
                            if (IsDisposed)
                            {
                                return;
                            }
                            _logger.Error(ex.Message);
                            await Task.Delay(2000);
                        }
                    } while (!connected);

                    CommunicationStateChanging(ConnectionState.Connected);
                    if (!_socket.ReceiveAsync(receiveCompleteEvent))
                    {
                        ReceiveEventCompleted(_socket, receiveCompleteEvent);
                    }
                };

                _stopImpl = delegate
                {
                    if (IsDisposed)
                    {
                        server.Dispose();
                    }
                };
            }

            _sendControlMessageCompleteHandler = SendControlMessageCompleteHandler;
            _sendDataMessageCompleteHandler    = SendDataMessageCompleteHandler;
        }
Beispiel #8
0
        /// <summary>
        /// <para xml:lang="en">Initializes a <see langword="new"/> instance of the <see cref="SecsGem"/> <see langword="class"/>.</para>
        /// </summary>
        /// <param name="isActive"><see langword="true"/> for active and <see langword="false"/> for passive mode.</param>
        /// <param name="ip">If active mode, it should be remote device address, otherwise local listener address.</param>
        /// <param name="port">If active mode, it should be remote device listener's port.</param>
        /// <param name="initialReceiveBufferSize">The initial socket receive buffer size.</param>
        public SecsGem(bool isActive, IPAddress ip, ushort port, int initialReceiveBufferSize = SecsGem.defaultInitalReceiveBufferSize)
        {
            if (initialReceiveBufferSize < 64)
            {
                throw new ArgumentOutOfRangeException(nameof(initialReceiveBufferSize), initialReceiveBufferSize, $"The buffet size is less than {64}. Recommended is the default value of {SecsGem.defaultInitalReceiveBufferSize}.");
            }

            this.secsDecoder = new StreamDecoder(initialReceiveBufferSize, this.HandleControlMessage, this.HandleDataMessage);

            this.IpAddress         = ip;
            this.Port              = port;
            this.IsActive          = isActive;
            this.DecoderBufferSize = initialReceiveBufferSize;

            #region Timer Action
            this.timer7 = new Timer(delegate
            {
                this.logger.Error($"T7 Timeout: {this.T7 / 1000} sec.");
                this.CommunicationStateChanging(ConnectionState.Retry);
            }, null, Timeout.Infinite, Timeout.Infinite);

            this.timer8 = new Timer(delegate
            {
                this.logger.Error($"T8 Timeout: {this.T8 / 1000} sec.");
                this.CommunicationStateChanging(ConnectionState.Retry);
            }, null, Timeout.Infinite, Timeout.Infinite);

            this.timerLinkTest = new Timer(delegate
            {
                if (this.State == ConnectionState.Selected)
                {
                    this.SendControlMessage(MessageType.LinkTestRequest, this.GetNewSystemId());
                }
            }, null, Timeout.Infinite, Timeout.Infinite);
            #endregion

            if (this.IsActive)
            {
                this.startImplementationFunction = async() =>
                {
                    var connected = false;
                    do
                    {
                        if (this.IsDisposed)
                        {
                            return;
                        }

                        this.CommunicationStateChanging(ConnectionState.Connecting);
                        try
                        {
                            if (this.IsDisposed)
                            {
                                return;
                            }

                            this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                            await this.socket.ConnectAsync(this.IpAddress, this.Port).ConfigureAwait(false);

                            connected = true;
                        }
                        catch (Exception ex)
                        {
                            if (this.IsDisposed)
                            {
                                return;
                            }

                            this.logger.Error(ex.Message, ex);
                            this.logger.Info($"Start T5 Timer: {this.T5 / 1000} sec.");
                            await Task.Delay(this.T5).ConfigureAwait(false);
                        }
                    } while (!connected);

                    // hook receive event first, because no message will received before 'SelectRequest' send to device
                    this.StartSocketReceive();
                    this.SendControlMessage(MessageType.SelectRequest, this.GetNewSystemId());
                };
            }
            else
            {
                this.serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                this.serverSocket.Bind(new IPEndPoint(this.IpAddress, this.Port));
                this.serverSocket.Listen(0);

                this.startImplementationFunction = async() =>
                {
                    var connected = false;
                    do
                    {
                        if (this.IsDisposed)
                        {
                            return;
                        }

                        this.CommunicationStateChanging(ConnectionState.Connecting);
                        try
                        {
                            if (this.IsDisposed)
                            {
                                return;
                            }

                            this.socket = await this.serverSocket.AcceptAsync().ConfigureAwait(false);

                            connected = true;
                        }
                        catch (Exception ex)
                        {
                            if (this.IsDisposed)
                            {
                                return;
                            }

                            this.logger.Error(ex.Message, ex);
                            await Task.Delay(2000).ConfigureAwait(false);
                        }
                    } while (!connected);

                    this.StartSocketReceive();
                };
            }
        }