/// <summary>
            /// Parses data read from the SD in STANDBY mode and inserts it into the queue
            /// of responses.
            /// </summary>
            /// <remarks>
            /// This function takes advantage of the fact that a result response
            /// from the SD for an AT command has a unique exact length among all other
            /// possible AT command responses.
            /// </remarks>
            private void Parse()
            {
                byte[] delim = (byte[])s_Cmds[c_ATR_DELIMETER];

                // Extract responses and put them in the response queue
                bool foundResponse = false;
                int startIndex = 0;
                int closeIndex = 0;

                while (0 <= (startIndex = BytesIndexOf(m_readBuffer, startIndex, m_bytesInRead, delim)))
                {
                    // Find closing delimeter
                    closeIndex = BytesIndexOf(m_readBuffer, startIndex + 1, m_bytesInRead, delim);

                    if (-1 == closeIndex) break;

                    foundResponse = true;
                    SDResponse response = new SDResponse();

                    // Check for result response
                    int len = closeIndex + delim.Length - startIndex;
                    response.Data = null;

                    if (((byte[])s_Cmds[c_ATR_OK]).Length == len)
                    {
                        response.Type = c_ATR_OK;
                    }
                    else if (((byte[])s_Cmds[c_ATR_ERROR]).Length == len)
                    {
                        response.Type = c_ATR_ERROR;
                    }
                    else if (((byte[])s_Cmds[c_ATR_DISCONNECT]).Length == len)
                    {
                        response.Type = c_ATR_DISCONNECT;
                    }
                    else if (BytesEqual(m_readBuffer, startIndex, (byte[])s_Cmds[c_ATR_CONNECT], 0, ((byte[])s_Cmds[c_ATR_CONNECT]).Length))
                    {
                        response.Type = c_ATR_CONNECT;

                        SDResponse addrResponse = new SDResponse();

                        addrResponse.Type = -1;
                        addrResponse.Data = new byte[len - ((byte[])s_Cmds[c_ATR_CONNECT]).Length];

                        Array.Copy(m_readBuffer, ((byte[])s_Cmds[c_ATR_CONNECT]).Length, addrResponse.Data, 0, addrResponse.Data.Length);

                        m_responseQueue.Add(addrResponse);
                    }
                    else
                    {
                        response.Type = -1;
                        response.Data = new byte[len];

                        Array.Copy(m_readBuffer, startIndex, response.Data, 0, len);
                    }

                    m_responseQueue.Add(response);

                    startIndex = closeIndex + 1;
                }

                if (foundResponse)
                {   // Move all remaining bytes to the front of the read buffer
                    int lastIndex = (0 > startIndex) ? closeIndex + delim.Length : startIndex;

                    m_bytesInRead = m_bytesInRead - lastIndex;

                    if (0 < m_bytesInRead)
                    {
                        Array.Copy(m_readBuffer, lastIndex, m_readBuffer, 0, m_bytesInRead);
                    }
                }
            }
            /// <summary>
            /// An online read; reads up to len bytes from the SD into the given buffer
            /// and stops if the given timeout expires.  In the case of a disconnect,
            /// reads up to len chars and returns them, if that's not possible then
            /// returns up to the "\r\nDISCONNECT\r\n" message and indicates disconnect
            /// by returning -1.  Sets buffer to empty if no data could be read.
            /// </summary>
            /// <param name="buf">
            /// The buffer to read into
            /// </param>
            /// <param name="to">
            /// The max amount of time to read
            /// </param>
            /// <returns>
            /// The number of bytes read, or -1 on disconnect
            /// </returns>
            internal int Read(ref byte[] buf, int to)
            {
                // Check for a disconnect
                if (0 < m_responseQueue.Count) return -1;

                // Take bytes from the read buffer if there are any
                int bytesRead = 0;
                int bytesToRead = buf.Length;

                if (0 < m_bytesInRead)
                {
                    bytesRead = (m_bytesInRead >= bytesToRead) ? bytesToRead : m_bytesInRead;

                    Array.Copy(m_readBuffer, buf, bytesRead);

                    m_bytesInRead -= bytesRead;
                    bytesToRead -= bytesRead;

                    if (0 < m_bytesInRead) Array.Copy(m_readBuffer, bytesRead, m_readBuffer, 0, m_bytesInRead);
                }

                // Read from SerialStream if there is more to read
                if (0 < bytesToRead) bytesRead += m_stream.Read(buf, bytesRead, bytesToRead, to);

                // Check for "\r\nDISCONNECT\r\n" in newly read bytes
                byte[] bytes_CR = new byte[] { c_CR };
                byte[] disconnect = ((byte[])s_Cmds[c_ATR_DISCONNECT]);

                if (disconnect.Length > m_bytesInRead)
                {
                    // Search for the beginning of "\r\nDISCONNECT\r\n" in buf
                    int prefixIndex = (0 < bytesRead - disconnect.Length) ? bytesRead - disconnect.Length : 0;
                    prefixIndex = BytesIndexOf(buf, prefixIndex, bytesRead, bytes_CR);

                    if (0 <= prefixIndex)
                    {
                        // Read more if not enough bytes to check for "\r\nDISCONNECT\r\n"
                        int endLen = bytesRead - prefixIndex + m_bytesInRead;

                        if (endLen < disconnect.Length)
                        {
                            int num = m_stream.Read(m_readBuffer, m_bytesInRead, disconnect.Length - endLen, c_DefaultReadTimeout);

                            m_bytesInRead += num;

                            if (disconnect.Length - endLen != num) return bytesRead;
                        }

                        // Check if last read bytes are equal to "\r\nDISCONNECT\r\n"
                        if (BytesEqual(buf, prefixIndex, disconnect, 0, bytesRead - prefixIndex)
                            && BytesEqual(m_readBuffer, 0, disconnect, bytesRead - prefixIndex, disconnect.Length - (bytesRead - prefixIndex))
                           )
                        {
                            // Then remove the "\r\nDISCONNECT\r\n" prefix from buf
                            bytesRead -= bytesRead - prefixIndex;
                            bytesRead = (bytesRead == 0) ? -1 : bytesRead;

                            SDResponse dResponse = new SDResponse();
                            dResponse.Type = c_ATR_DISCONNECT;
                            dResponse.Data = null;

                            m_responseQueue.Add(dResponse);
                        }
                    }
                }

                return bytesRead;
            }