/// <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)); }
private void parseMessage(byte[] bytes, int length, bool isMessageComplelte = false) { if (isMessageComplelte == true) { } else { if (length == 14 && isHeader == true) { //it is a header isHeader = false; Array.Copy(bytes, messageBytes, length); byte[] messageLengths = new byte[4]; Array.Copy(bytes, 0, messageLengths, 0, 4); Array.Reverse(messageLengths, 0, 4); _messageDataLength = (int)BitConverter.ToUInt32(messageLengths, 0); MsgHeader = MessageHeader.Decode(bytes, 4); } else { isHeader = true; if (_messageDataLength - 10 == length) { //it is the message int index = 0; Item item = decoder.BufferedDecodeItem(bytes, ref index); Msg = new SecsMessage(MsgHeader.S, MsgHeader.F, MsgHeader.ReplyExpected, "", item); SecsDataReceivedEventArgs arg = new SecsDataReceivedEventArgs(Msg, SCESEquipment); DataReceived(SocketClient, arg); } } } }
public StreamDecoder(int streamBufferSize, Action <MessageHeader> controlMsgHandler, Action <MessageHeader, SecsMessage> dataMsgHandler) { _buffer = new byte[streamBufferSize]; _bufferOffset = 0; _decodeIndex = 0; _dataMsgHandler = dataMsgHandler; _controlMsgHandler = controlMsgHandler; _decoders = new Decoder[] { GetTotalMessageLength, GetMessageHeader, GetItemHeader, GetItemLength, GetItem, }; // 0: get total message length 4 bytes int GetTotalMessageLength(ref int length, out int need) { if (!CheckAvailable(ref length, 4, out need)) { return(0); } Array.Reverse(_buffer, _decodeIndex, 4); _messageDataLength = BitConverter.ToUInt32(_buffer, _decodeIndex); Trace.WriteLine($"Get Message Length: {_messageDataLength}"); _decodeIndex += 4; length -= 4; return(GetMessageHeader(ref length, out need)); } // 1: get message header 10 bytes int GetMessageHeader(ref int length, out int need) { if (!CheckAvailable(ref length, 10, out need)) { return(1); } _msgHeader = MessageHeader.Decode(_buffer, _decodeIndex); _decodeIndex += 10; _messageDataLength -= 10; length -= 10; if (_messageDataLength == 0) { if (_msgHeader.MessageType == MessageType.DataMessage) { _dataMsgHandler(_msgHeader, new SecsMessage(_msgHeader.S, _msgHeader.F, _msgHeader.ReplyExpected, string.Empty)); } else { _controlMsgHandler(_msgHeader); } return(0); } if (length >= _messageDataLength) { Trace.WriteLine("Get Complete Data Message with total data"); _dataMsgHandler(_msgHeader, new SecsMessage(_msgHeader.S, _msgHeader.F, _msgHeader.ReplyExpected, string.Empty, BufferedDecodeItem(_buffer, ref _decodeIndex))); length -= (int)_messageDataLength; _messageDataLength = 0; return(0); //completeWith message received } return(GetItemHeader(ref length, out need)); } // 2: get _format + lengthBits(2bit) 1 byte int GetItemHeader(ref int length, out int need) { if (!CheckAvailable(ref length, 1, out need)) { return(2); } _format = (SecsFormat)(_buffer[_decodeIndex] & 0xFC); _lengthBits = (byte)(_buffer[_decodeIndex] & 3); _decodeIndex++; _messageDataLength--; length--; return(GetItemLength(ref length, out need)); } // 3: get _itemLength _lengthBits bytes, at most 3 byte int GetItemLength(ref int length, out int need) { if (!CheckAvailable(ref length, _lengthBits, out need)) { return(3); } Array.Copy(_buffer, _decodeIndex, _itemLengthBytes, 0, _lengthBits); Array.Reverse(_itemLengthBytes, 0, _lengthBits); _itemLength = BitConverter.ToInt32(_itemLengthBytes, 0); Array.Clear(_itemLengthBytes, 0, 4); Trace.WriteLineIf(_format != SecsFormat.List, $"Get format: {_format}, length: {_itemLength}"); _decodeIndex += _lengthBits; _messageDataLength -= _lengthBits; length -= _lengthBits; return(GetItem(ref length, out need)); } // 4: get item value int GetItem(ref int length, out int need) { need = 0; Item item; if (_format == SecsFormat.List) { if (_itemLength == 0) { item = Item.L(); } else { _stack.Push(new List <Item>(_itemLength)); return(GetItemHeader(ref length, out need)); } } else { if (!CheckAvailable(ref length, _itemLength, out need)) { return(4); } item = Item.BytesDecode(ref _format, _buffer, ref _decodeIndex, ref _itemLength); Trace.WriteLine($"Complete Item: {_format}"); _decodeIndex += _itemLength; _messageDataLength -= (uint)_itemLength; length -= _itemLength; } if (_stack.Count == 0) { Trace.WriteLine("Get Complete Data Message by stream decoded"); _dataMsgHandler(_msgHeader, new SecsMessage(_msgHeader.S, _msgHeader.F, _msgHeader.ReplyExpected, string.Empty, item)); return(0); } var list = _stack.Peek(); list.Add(item); while (list.Count == list.Capacity) { item = Item.L(_stack.Pop()); Trace.WriteLine($"Complete List: {item.Count}"); if (_stack.Count > 0) { list = _stack.Peek(); list.Add(item); } else { Trace.WriteLine("Get Complete Data Message by stream decoded"); _dataMsgHandler(_msgHeader, new SecsMessage(_msgHeader.S, _msgHeader.F, _msgHeader.ReplyExpected, string.Empty, item)); return(0); } } return(GetItemHeader(ref length, out need)); } bool CheckAvailable(ref int length, int required, out int need) { need = required - length; if (need > 0) { return(false); } need = 0; return(true); } }