protected static ESPPacket makeFromBufferSPP(List <Byte> buffer, Devices lastV1Type)
        {
            int startIdx = -1;
            int endIdx   = -1;

            // Make a copy of the buffer as it was at the beginning of the method call
            List <Byte> curStartBuffer = new List <Byte>();

            mCopyBuffer(buffer, curStartBuffer);

            for (int index = 0; index < buffer.Count; index++)
            {
                byte test = buffer[index];                //.ByteValue();
                if (test == frameDelimitedConstant)
                {
                    if (startIdx == -1)
                    {
                        // We are looking for the start index
                        startIdx = index;
                    }
                    else
                    {
                        // We are looking for the end index
                        if (index == startIdx + 1)
                        {
                            // There are two delimiters together. This is expected to happen during startup when we can
                            // receive the end of one packet followed by a valid packet. In this instance, we want to
                            // move the start index to the beginning of the new packet
                            startIdx = index;
                        }
                        else
                        {
                            // This should be the end of the packet so save the index and stop searching
                            endIdx = index;
                            break;
                        }
                    }
                }
            }

            if (startIdx == -1 || endIdx == -1)
            {
                // Copy start and end buffer in case the next call fails
                mCopyBuffer(curStartBuffer, mLastStartBuffer);
                mCopyBuffer(buffer, mLastEndBuffer);
                // We did not receive a full packet
                return(null);
            }

            if (startIdx != 0 && ESPLibraryLogController.LOG_WRITE_ERROR)
            {
                //Log.e(LOG_TAG, "Skipping " + startIdx + " bytes because there was no delimiter at index 0");
                //Log.e(LOG_TAG, "  Current buffer: " + getBufferLogString(buffer));
                //Log.e(LOG_TAG, "  Last Start buffer: " + getBufferLogString(mLastStartBuffer));
                //Log.e(LOG_TAG, "  Last End buffer: " + getBufferLogString(mLastEndBuffer));
            }

            // Process the buffer
            int          i            = startIdx;
            int          payloadIdx   = 0;
            ESPPacket    retPacket    = null;
            ProcessState processState = ProcessState.START_PACK_BYTE;
            bool         dataError    = false;

            // Store these values until we have a packet to put them into
            byte tempLength     = 0;
            byte tempDest       = 0;
            byte tempOrigin     = 0;
            byte packetChecksum = 0;
            byte espChecksum    = 0;

            while (i <= endIdx)
            {
                // Read the next byte from the buffer
                byte curByte = buffer[i];                //.get(i).byteValue();

                if (curByte == frameDataEscapeConstant)
                {
                    // Check the next byte to see if it should be turned into an 0x7F or 0x7D
                    i++;
                    curByte = buffer[i];                    //.get(i).byteValue();
                    // Skip the next byte after the delimiter
                    if (curByte == (byte)0x5D)
                    {
                        // If we find 0x5D after the delimiter, turn it into an 0x7D
                        curByte = (byte)0x7D;
                    }
                    else if (curByte == (byte)0x5F)
                    {
                        // If we find 0x5F after the delimiter, turn it into an 0x7F
                        curByte = (byte)0x7F;
                    }
                }

                switch (processState)
                {
                default:
                case ProcessState.START_PACK_BYTE:
                    if (curByte != frameDelimitedConstant)
                    {
                        // How did THIS happen?!?
                        dataError = true;
                        if (ESPLibraryLogController.LOG_WRITE_ERROR)
                        {
                            //Log.e(LOG_TAG, "Missing 0x7F at startIdx: " + startIdx);
                        }
                    }

                    // Move to the next state. If there is a data error, the next state will never be used so
                    // we don't need to check for that.
                    processState = ProcessState.PACKET_LENGTH;
                    break;

                case ProcessState.PACKET_LENGTH:
                    tempLength = curByte;

                    // Update the checksum
                    packetChecksum += curByte;

                    // Move to the next state. If there is a data error, the next state will never be used so
                    // we don't need to check for that.
                    processState = ProcessState.SOF;
                    break;

                case ProcessState.SOF:
                    if (curByte != startOfFrameConstant)
                    {
                        // Bad data so let's bail
                        dataError = true;
                        if (ESPLibraryLogController.LOG_WRITE_ERROR)
                        {
                            //Log.e(LOG_TAG, "Missing SOF at the expected index: " + i);
                        }
                    }

                    // Update the checksum
                    packetChecksum += curByte;
                    espChecksum    += curByte;

                    // Move to the next state. If there is a data error, the next state will never be used so
                    // we don't need to check for that.
                    processState = ProcessState.DESTINATION;
                    break;

                case ProcessState.DESTINATION:
                    if ((curByte & destinationIdentifierBaseConstant) != destinationIdentifierBaseConstant)
                    {
                        // This is not a valid destination
                        dataError = true;
                        if (ESPLibraryLogController.LOG_WRITE_ERROR)
                        {
                            //Log.e(LOG_TAG, "Invalid destination ID (" + String.format("%02X ", curByte) + ") at the expected index: " + i);
                        }
                    }

                    tempDest = curByte;

                    // Update the checksum
                    packetChecksum += curByte;
                    espChecksum    += curByte;

                    // Move to the next state. If there is a data error, the next state will never be used so
                    // we don't need to check for that.
                    processState = ProcessState.ORIGINATOR;
                    break;

                case ProcessState.ORIGINATOR:
                    if ((curByte & originationIdentifierBaseConstant) != originationIdentifierBaseConstant)
                    {
                        // This is not a valid originator
                        dataError = true;
                        if (ESPLibraryLogController.LOG_WRITE_ERROR)
                        {
                            //Log.e(LOG_TAG, "Invalid originator ID (" + String.format("%02X ", curByte) + ") at the expected index: " + i);
                        }
                    }

                    tempOrigin = curByte;

                    // Update the checksum
                    packetChecksum += curByte;
                    espChecksum    += curByte;

                    // Move to the next state. If there is a data error, the next state will never be used so
                    // we don't need to check for that.
                    processState = ProcessState.PACKET_ID;
                    break;

                case ProcessState.PACKET_ID:
                    // Make the packet
                    retPacket = PacketFactory.getPacket(PacketIdLookup.getConstant(curByte));
                    if (retPacket == null)
                    {
                        // We couldn't build the packet so stop trying
                        dataError = true;
                        if (ESPLibraryLogController.LOG_WRITE_ERROR)
                        {
                            //Log.e(LOG_TAG, "Unable to generate packet for packet id (" + String.format("%02X ", curByte) + ")");
                        }
                    }
                    else
                    {
                        // We have a good packet so fill it up
                        retPacket.headerDelimter = frameDelimitedConstant;                                  //<- We can't get here if this wasn't true
                        retPacket.packetLength   = tempLength;

                        retPacket.startOfFrame          = startOfFrameConstant;                          //<- We can't get here if this wasn't true
                        retPacket.destinationIdentifier = tempDest;
                        // Don't store the upper nibble of the destinations
                        retPacket.m_destination = (byte)(tempDest - destinationIdentifierBaseConstant);
                        // Don't store the upper nibble of the origin
                        retPacket.originatorIdentifier = (byte)(tempOrigin - originationIdentifierBaseConstant);
                        retPacket.packetIdentifier     = curByte;

                        // If the packet is from a V1 set the ESPPacket V1 type to the appropriate Device type.
                        if (IsPacketFromV1(retPacket.originatorIdentifier))
                        {
                            retPacket.m_valentineType = DevicesUtils.DevicesFromByteValue(retPacket.originatorIdentifier);
                        }
                        else
                        {
                            retPacket.m_valentineType = lastV1Type;
                        }
                        // If the last known V1 type is unknown check to see if the ESPPacket is V1connection version response.
                        if (retPacket.m_valentineType == Devices.UNKNOWN)
                        {
                            if (retPacket.packetIdentifier != PacketId.respVersion.ToByteValue() || retPacket.originatorIdentifier != Devices.V1CONNECT.ToByteValue())
                            {
                                // Always allow the V1connection version responses to pass through
                                // Don't process any other data until we know what type of V1 we are working with
                                dataError = true;
                                if (ESPLibraryLogController.LOG_WRITE_ERROR)
                                {
                                    //Log.e(LOG_TAG, "Ignore packet id 0x" + String.Format("%02X ", curByte) + " because the V1 type is unknown");
                                }
                            }
                        }
                    }

                    // Update the checksum
                    packetChecksum += curByte;
                    espChecksum    += curByte;

                    // Move to the next state. If there is a data error, the next state will never be used so
                    // we don't need to check for that.
                    processState = ProcessState.PAYLOAD_LENGTH;
                    break;

                case ProcessState.PAYLOAD_LENGTH:
                    if (curByte != 0)
                    {
                        byte tmp;
                        if ((retPacket.m_valentineType == Devices.VALENTINE1_LEGACY) || (retPacket.m_valentineType == Devices.VALENTINE1_WITHOUT_CHECKSUM))
                        {
                            tmp = curByte;
                        }
                        else
                        {
                            // If this packet is from a V1 that supports checksum, we want to decrement the payload length by 1
                            // to make packet match packets from Legacy and non-checksum V1's
                            tmp = (byte)(curByte - 1);
                        }
                        retPacket.payloadLength = tmp;
                        // If payloadLength is zero, then the next byte in the buffer will be the packet checksum. For non-checksum V1 devices
                        // the payloadLength is greater than zero so the next byte will be payload data.
                        if (retPacket.payloadLength == 0)
                        {
                            processState = ProcessState.PACKET_CHEKSUM;
                        }
                        else
                        {
                            retPacket.payloadData = new byte[retPacket.payloadLength];
                            processState          = ProcessState.PAYLOAD;
                        }
                        // Always include the payload length in the packet data.
                        espChecksum    += curByte;                             // Update the PACKET checksum
                        packetChecksum += curByte;
                    }
                    else
                    {
                        // There is no payload data so go to the end of frame.
                        processState = ProcessState.EOF;
                    }
                    break;

                case ProcessState.PAYLOAD:
                    retPacket.payloadData[payloadIdx] = curByte;
                    payloadIdx++;
                    // Update the ESP checksum.
                    espChecksum += curByte;
                    // Update the PACKET checksum
                    packetChecksum += curByte;
                    // If we have reached the end of the payload data, handle checking the checksum.
                    if (payloadIdx == retPacket.payloadLength)
                    {
                        if ((retPacket.m_valentineType == Devices.VALENTINE1_LEGACY) || (retPacket.m_valentineType == Devices.VALENTINE1_WITHOUT_CHECKSUM))
                        {
                            // Get the EOF byte next
                            processState = ProcessState.EOF;
                        }
                        else
                        {
                            processState = ProcessState.PACKET_CHEKSUM;
                        }
                    }
                    break;

                case ProcessState.PACKET_CHEKSUM:
                    // If the calculated checksum does not equal the checksum byte, an error has occurred.
                    if (espChecksum != curByte)
                    {
                        // The checksum does not match
                        dataError = true;
                        if (ESPLibraryLogController.LOG_WRITE_ERROR)
                        {
                            //Log.e(LOG_TAG, "Bad ESP checksum. Expected 0x" + String.format("%02X ", espChecksum) + " but found 0x" + String.format("%02X ", curByte));
                        }
                    }
                    // Store the checksum
                    packetChecksum    += curByte;
                    retPacket.checkSum = curByte;
                    // Get the EOF byte next
                    processState = ProcessState.EOF;
                    break;

                case ProcessState.EOF:
                    if (curByte != endOfFrameConstant)
                    {
                        // Bad data so let's bail
                        dataError = true;
                        if (ESPLibraryLogController.LOG_WRITE_ERROR)
                        {
                            //Log.e(LOG_TAG, "Unable to find EOF at the expected index: " + i);
                        }
                    }
                    retPacket.endOfFrame = curByte;
                    // Update the packet checksum
                    packetChecksum += curByte;
                    // Move to the next state. If there is a data error, the next state will never be used so
                    // we don't need to check for that.
                    processState = ProcessState.BT_CHECKSUM;
                    break;

                case ProcessState.BT_CHECKSUM:
                    // Update the packet checksum
                    if (packetChecksum != curByte)
                    {
                        // We are missing something
                        dataError = true;
                        if (ESPLibraryLogController.LOG_WRITE_ERROR)
                        {
                            //Log.e(LOG_TAG, "Bad packet checksum. Expected 0x" + String.format("%02X ", packetChecksum) + " but found 0x" + String.format("%02X ", curByte));
                        }
                    }
                    retPacket.packetChecksum = curByte;

                    // Move to the next state. If there is a data error, the next state will never be used so
                    // we don't need to check for that.
                    processState = ProcessState.END_PACK_BYTE;
                    break;

                case ProcessState.END_PACK_BYTE:
                    if (i != endIdx)
                    {
                        // We should be at the end of the data by now
                        dataError = true;
                        if (ESPLibraryLogController.LOG_WRITE_ERROR)
                        {
                            //Log.e(LOG_TAG, "Excpected to be at index " + endIdx + " but we are at index " + i);
                        }
                    }
                    else if (curByte != frameDelimitedConstant)
                    {
                        // How did THIS happen?!?
                        dataError = true;
                        if (ESPLibraryLogController.LOG_WRITE_ERROR)
                        {
                            //Log.e(LOG_TAG, "Missing 0x7F at endIdx: " + endIdx);
                        }
                    }

                    retPacket.endDelimter = curByte;

                    // Move to the next state. If there is a data error, the next state will never be used so
                    // we don't need to check for that.
                    processState = ProcessState.START_PACK_BYTE;
                    break;
                }

                if (dataError)
                {
                    // Stop processing the data
                    break;
                }

                // Increment the index to the next byte
                i++;
            }

            // Remove all bytes up to and including the end index
            TrimBuffer(buffer, endIdx);

            // Copy start and end buffer in case the next call fails
            mCopyBuffer(curStartBuffer, mLastStartBuffer);
            mCopyBuffer(buffer, mLastEndBuffer);

            if (dataError)
            {
                return(null);
            }

            // Force the ESPPacket checksum to zero if the V1 does not support checksums before returning the packet.
            if ((retPacket.V1Type == Devices.VALENTINE1_LEGACY) || (retPacket.V1Type == Devices.VALENTINE1_WITHOUT_CHECKSUM))
            {
                retPacket.checkSum = 0;
            }
            return(retPacket);
        }
        protected static ESPPacket makeFromBufferLE(List <Byte> buffer, Devices lastV1Type)
        {
            if (buffer.Count == 0)
            {
                return(null);
            }
            int bufferSize = buffer.Count;

            if (buffer[0] != startOfFrameConstant || buffer[bufferSize - 1] != endOfFrameConstant)
            {
                return(null);
            }

            bool         dataError    = false;
            ProcessState processState = ProcessState.SOF;
            ESPPacket    retPacket    = null;
            byte         espChecksum  = 0;
            byte         tempDest     = 0;
            byte         tempOrigin   = 0;
            int          payloadIdx   = 0;

            for (int i = 0; i < bufferSize; i++)
            {
                byte curByte = buffer[i];
                switch (processState)
                {
                case ProcessState.SOF:
                    if (curByte != startOfFrameConstant)
                    {
                        dataError = true;
                    }
                    espChecksum += curByte;
                    processState = ProcessState.DESTINATION;
                    break;

                case ProcessState.DESTINATION:
                    if ((curByte & destinationIdentifierBaseConstant) != destinationIdentifierBaseConstant)
                    {
                        dataError = true;
                    }

                    tempDest     = curByte;
                    espChecksum += curByte;
                    processState = ProcessState.ORIGINATOR;
                    break;

                case ProcessState.ORIGINATOR:
                    if ((curByte & originationIdentifierBaseConstant) != originationIdentifierBaseConstant)
                    {
                        // This is not a valid originator
                        dataError = true;
                    }
                    tempOrigin   = curByte;
                    espChecksum += curByte;
                    processState = ProcessState.PACKET_ID;
                    break;

                case ProcessState.PACKET_ID:
                    // Make the packet
                    retPacket = PacketFactory.getPacket(PacketIdLookup.getConstant(curByte));
                    if (retPacket == null)
                    {
                        // We couldn't build the packet so stop trying
                        dataError = true;
                    }
                    else
                    {
                        // We have a good packet so fill it up
                        retPacket.headerDelimter = frameDelimitedConstant;                                  //<- We can't get here if this wasn't true
                        // The packet length for LE is equal to the size of the buffer..
                        retPacket.packetLength = (byte)bufferSize;

                        retPacket.startOfFrame          = startOfFrameConstant;                          //<- We can't get here if this wasn't true
                        retPacket.destinationIdentifier = tempDest;
                        // Don't store the upper nibble of the destinations
                        retPacket.m_destination = (byte)(tempDest - destinationIdentifierBaseConstant);
                        // Don't store the upper nibble of the origin
                        retPacket.originatorIdentifier = (byte)(tempOrigin - originationIdentifierBaseConstant);
                        retPacket.packetIdentifier     = curByte;

                        // If the packet is from a V1 set the ESPPacket V1 type to the appropriate Device type.
                        if (IsPacketFromV1(retPacket.originatorIdentifier))
                        {
                            retPacket.m_valentineType = DevicesUtils.DevicesFromByteValue(retPacket.originatorIdentifier);
                        }
                        else
                        {
                            retPacket.m_valentineType = lastV1Type;
                        }
                        // If the last known V1 type is unknown check to see if the ESPPacket is V1connection version response.
                        if (retPacket.m_valentineType == Devices.UNKNOWN)
                        {
                            if (retPacket.packetIdentifier != PacketId.respVersion.ToByteValue() || retPacket.originatorIdentifier != Devices.V1CONNECT.ToByteValue())
                            {
                                // Always allow the V1connection version responses to pass through
                                // Don't process any other data until we know what type of V1 we are working with
                                dataError = true;
                                if (ESPLibraryLogController.LOG_WRITE_ERROR)
                                {
                                    //Log.e(LOG_TAG, "Ignore packet id 0x" + String.Format("%02X ", curByte) + " because the V1 type is unknown");
                                }
                            }
                        }
                    }
                    espChecksum += curByte;
                    processState = ProcessState.PAYLOAD_LENGTH;
                    break;

                case ProcessState.PAYLOAD_LENGTH:
                    if (curByte != 0)
                    {
                        byte tmp;
                        // If this packet is from a V1 that supports checksum, we want to decrement the payload length by 1, to make packet match packets from
                        // Legacy and non-checksum V1's
                        if ((retPacket.m_valentineType == Devices.VALENTINE1_LEGACY) || (retPacket.m_valentineType == Devices.VALENTINE1_WITHOUT_CHECKSUM))
                        {
                            tmp = curByte;
                        }
                        else
                        {
                            // If this packet is from a V1 that supports checksum, we want to decrement the packet length by 1
                            // to make packet match packets from Legacy and non-checksum V1's
                            tmp = (byte)(curByte - 1);
                        }

                        retPacket.payloadLength = tmp;
                        // If payloadLength is zero, then the next byte in the buffer will be the packet checksum. For non-checksum V1 devices
                        // the payloadLength is greater than zero so the next byte will be payload data.
                        if (retPacket.payloadLength == 0)
                        {
                            processState = ProcessState.PACKET_CHEKSUM;
                        }
                        else
                        {
                            retPacket.payloadData = new byte[retPacket.payloadLength];
                            processState          = ProcessState.PAYLOAD;
                        }
                        // Always include the payload length in the packet data.
                        espChecksum += curByte;
                    }
                    else
                    {
                        // There is no payload data so go to the end of frame.
                        processState = ProcessState.EOF;
                    }
                    break;

                case ProcessState.PAYLOAD:
                    retPacket.payloadData[payloadIdx] = curByte;
                    payloadIdx++;
                    // Update the ESP checksum.
                    espChecksum += curByte;
                    // If we have reached the end of the payload data, move on to the next byte in the buffer.
                    if (payloadIdx == retPacket.payloadLength)
                    {
                        if ((retPacket.m_valentineType == Devices.VALENTINE1_LEGACY) || (retPacket.m_valentineType == Devices.VALENTINE1_WITHOUT_CHECKSUM))
                        {
                            // Get the EOF byte next
                            processState = ProcessState.EOF;
                        }
                        else
                        {
                            processState = ProcessState.PACKET_CHEKSUM;
                        }
                    }
                    break;

                case ProcessState.PACKET_CHEKSUM:
                    if (espChecksum != curByte)
                    {
                        // The checksum does not match
                        dataError = true;
                        if (ESPLibraryLogController.LOG_WRITE_ERROR)
                        {
                            //Log.e(LOG_TAG, "Bad ESP checksum. Expected 0x" + String.Format("%02X ", espChecksum) + " but found 0x" + String.Format("%02X ", curByte));
                        }
                    }
                    else
                    {
                        // Store the checksum
                        retPacket.checkSum = curByte;
                    }

                    // Get the EOF byte next
                    processState = ProcessState.EOF;
                    break;

                case ProcessState.EOF:
                    if (curByte != endOfFrameConstant)
                    {
                        // Bad data so let's bail
                        dataError = true;
                        if (ESPLibraryLogController.LOG_WRITE_ERROR)
                        {
                            //Log.e(LOG_TAG, "Unable to find EOF at the expected index: " + i);
                        }
                    }

                    retPacket.endOfFrame = curByte;
                    break;

                case ProcessState.BT_CHECKSUM:
                case ProcessState.END_PACK_BYTE:
                case ProcessState.PACKET_LENGTH:
                case ProcessState.START_PACK_BYTE:
                default:
                    // We should never get here, so something went wrong
                    dataError = true;
                    break;
                }
                if (dataError)
                {
                    break;
                }
            }

            buffer.Clear();
            if (dataError)
            {
                return(null);
            }
            // Force the ESPPacket checksum to zero if the V1 does not support checksums before returning the packet.
            if ((retPacket.m_valentineType == Devices.VALENTINE1_LEGACY) || (retPacket.m_valentineType == Devices.VALENTINE1_WITHOUT_CHECKSUM))
            {
                retPacket.checkSum = 0;
            }

            retPacket.packetChecksum = retPacket.makePacketChecksum();
            return(retPacket);
        }