/// <summary>
        /// Sends the given telegram.
        /// If necessary additional information like a checksum can be inserted here.
        /// </summary>
        /// <param name="buffer">Buffer containing the data.</param>
        /// <param name="telegramLength">Length of the telegram in bytes.</param>
        public void SendTelegram(byte[] buffer, short telegramLength)
        {
            var crc = ModbusUtils.CalcCrc(buffer, telegramLength - 2);

            buffer[telegramLength - 2] = (byte)(crc & 0x00ff);
            buffer[telegramLength - 1] = (byte)((crc & 0xff00) >> 8);

            // ticks and _NextSend are multiples of 100 ns
            var dt = _nextSend - DateTime.Now.Ticks;

            if (dt > 0)
            {
                Thread.Sleep(Math.Max(1, (int)dt / 10000));
            }

            // clear buffers
            _serial.DiscardInBuffer();
            _serial.DiscardOutBuffer();

            // next send is 3.5 chars after the end of this telegram
            _nextSend = DateTime.Now.Ticks + (telegramLength * 2 + 7) * _halfCharLength;
#if NETMF
            try
            {
                _serial.Write(buffer, 0, telegramLength);
                // make sure all bytes are sent out
                _serial.Flush();
            }
            catch (ArgumentException)
            {
                // happens some times -> Close -> Open -> try again
                try
                {
                    _serial.Close();
                }
                catch
                {
                    // ignored
                }
                _serial.Open();
                _serial.Write(buffer, 0, telegramLength);
                _serial.Flush();
            }
#else
            _serial.Write(buffer, 0, telegramLength);
#endif
        }
        /// <summary>
        /// Parses a telegram received by ReceiveTelegram.
        /// </summary>
        /// <param name="buffer">Buffer containing the data.</param>
        /// <param name="telegramLength">Total length of the telegram in bytes.</param>
        /// <param name="isResponse">true if the telegram is a response telegram; false if the telegram is a request telegram.</param>
        /// <param name="telegramContext">
        /// If isResponse == true: pass the telegramContext returned by CreateTelegram from the request.
        /// If isResponse == false: returns the telegramContext from the received request. It must pe passed to the CreateTelegram method for the response.
        /// </param>
        /// <param name="address">Returns the device address.</param>
        /// <param name="fkt">Returns the function code.</param>
        /// <param name="dataPos">Returns the offset in buffer of the function code specific data.</param>
        /// <param name="dataLength">Returns the length of the function code specific data.</param>
        /// <returns>Returns true if this is the matching response according to the telegramContext; else false. If isResponse == false this method should return always true.</returns>
        public bool ParseTelegram(byte[] buffer, short telegramLength, bool isResponse, ref object telegramContext, out byte address, out byte fkt,
                                  out short dataPos, out short dataLength)
        {
            if (telegramLength < 4)
            {
                throw new ModbusException(ModbusErrorCode.ResponseTooShort);
            }
            var crc = ModbusUtils.CalcCrc(buffer, telegramLength - 2);

            if (buffer[telegramLength - 2] != (byte)(crc & 0x00ff) ||
                buffer[telegramLength - 1] != (byte)((crc & 0xff00) >> 8))
            {
                throw new ModbusException(ModbusErrorCode.CrcError);
            }
            address    = buffer[0];
            fkt        = buffer[1];
            dataPos    = 2;
            dataLength = (short)(telegramLength - 4);
            return(true);
        }
        /// <summary>
        /// Sends the given telegram.
        /// If necessary additional information like a checksum can be inserted here.
        /// </summary>
        /// <param name="buffer">Buffer containing the data.</param>
        /// <param name="telegramLength">Length of the telegram in bytes.</param>
        public void SendTelegram(byte[] buffer, short telegramLength)
        {
            var crc = ModbusUtils.CalcCrc(buffer, telegramLength - 2);

            buffer[telegramLength - 2] = (byte)(crc & 0x00ff);
            buffer[telegramLength - 1] = (byte)((crc & 0xff00) >> 8);

            // ticks and _NextSend are multiples of 100 ns
            var dt = this.nextSend - DateTime.Now.Ticks;

            if (dt > 0)
            {
                Thread.Sleep(Math.Max(1, (int)dt / 10000));
            }

            // clear buffers
            this.serial.ClearReadBuffer();
            this.serial.ClearWriteBuffer();

            // next send is 3.5 chars after the end of this telegram
            this.nextSend = DateTime.Now.Ticks + (telegramLength * 2 + 7) * this.halfCharLength;

            this.serial.Write(buffer, 0, telegramLength);
        }
        /// <summary>
        /// Waits and receives a telegram.
        /// </summary>
        /// <param name="buffer">Buffer to write data into.</param>
        /// <param name="desiredDataLength">Desired length of the function code specific data in bytes. -1 if length is unknown.</param>
        /// <param name="timeout">Timeout in milliseconds to wait for the telegram.</param>
        /// <param name="telegramLength">Returns the total length of the telegram in bytes.</param>
        /// <returns>Returns true if the telegram was received successfully; false on timeout.</returns>
        public bool ReceiveTelegram(byte[] buffer, short desiredDataLength, int timeout, out short telegramLength)
        {
            short desiredLength;

            if (desiredDataLength >= 0)
            {
                desiredLength = (short)(desiredDataLength + 4);
                if (desiredLength > buffer.Length)
                {
                    throw new ArgumentException(string.Concat("buffer size (", buffer.Length, ") must be at least 4 byte larger than desiredDataLength (", desiredDataLength, ")"));
                }
            }
            else
            {
                desiredLength = -1;
            }

            var  n            = 0;
            var  tOut         = DateTime.Now.AddMilliseconds(timeout);
            long nextRead     = 0;
            var  errorChecked = false;

            while (true)
            {
                //if ((desiredLength > 0 || n == 0) && DateTime.Now > tOut)
                if (DateTime.Now > tOut)
                {
                    break;
                }
                if (this.serial.BytesToRead > 0)
                {
                    if (desiredLength > 0)
                    {
                        n += this.serial.Read(buffer, n, desiredLength - n);
                    }
                    else
                    {
                        n += this.serial.Read(buffer, n, buffer.Length - n);
                    }
                    // a delay of more than 1.5 chars means end of telegram /////, but since this is a extreme short time, we extend it by factor 2
                    nextRead = DateTime.Now.Ticks + 6 * this.halfCharLength;
                }
                if (!errorChecked && n >= 2)
                {
                    errorChecked = true;
                    if ((buffer[1] & 0x80) != 0)
                    {
                        // modbus error, so desired length is 5
                        desiredLength = 5;
                    }
                }
                if (desiredLength > 0 && n == desiredLength)
                {
                    telegramLength = (short)n;
                    return(true);
                }
                if (desiredLength <= 0 && n >= 2 && DateTime.Now.Ticks > nextRead && this.serial.BytesToRead == 0)
                {
                    var crc = ModbusUtils.CalcCrc(buffer, n - 2);
                    if (buffer[n - 2] != (byte)(crc & 0x00ff) ||
                        buffer[n - 1] != (byte)((crc & 0xff00) >> 8))
                    {
                        // read a little bit longer
                        Thread.Sleep(1);
                        nextRead = DateTime.Now.Ticks + 6 * this.halfCharLength;
                    }
                    else
                    {
                        telegramLength = (short)n;
                        return(true);
                    }
                }
            }
            telegramLength = 0;
            return(false);
        }