public const int RESPONSE_CRC      = -0x0002; // UInt16BE

        // returns the dycrypted response payload only
        protected byte[] Decode(MedtronicCnlSession pumpSession, byte[] payload)
        {
            if (payload.Length < MM_PAYLOAD + NGP_PAYLOAD + NGP55_PAYLOAD + RESPONSE_PAYLOAD ||
                payload[MM_COMMAND] == (byte)CommandType.READ_INFO ||
                payload[MM_COMMAND] == (byte)CommandType.REQUEST_LINK_KEY_RESPONSE)
            {
                throw new EncryptionException("Message received for decryption wrong type/size");
            }

            byte encryptedPayloadSize = payload[MM_PAYLOAD + NGP_PAYLOAD + NGP55_ENCRYPTED_SIZE];

            if (encryptedPayloadSize == 0)
            {
                throw new EncryptionException("Could not decrypt Medtronic Message (encryptedPayloadSize == 0)");
            }

            var encryptedPayload = new MedtronicMessageBuffer(encryptedPayloadSize);

            encryptedPayload.Put(payload, MM_PAYLOAD + NGP_PAYLOAD + NGP55_PAYLOAD, encryptedPayloadSize);
            var decryptedPayload = Decrypt(pumpSession.getKey(), pumpSession.getIV(), encryptedPayload);

            if (decryptedPayload == null)
            {
                throw new EncryptionException("Could not decrypt Medtronic Message (decryptedPayload == null)");
            }

#if DEBUG
            string outputstring = HexDump.DumpHexstring(decryptedPayload);
            Log.d(TAG, "DECRYPTED: " + outputstring);
#endif

            return(decryptedPayload);
        }
        protected async Task <byte[]> ReadMessage(UsbHidDriver mDevice, int timeout = READ_TIMEOUT_MS)
        {
            ByteArrayOutputStream responseMessage = new ByteArrayOutputStream();

            int messageSize = 0;
            int bytesRead;

            do
            {
                var rawBytes = await mDevice.Read(timeout);

                bytesRead = rawBytes?.Length ?? -1;

                if (bytesRead == -1)
                {
                    throw new TimeoutException("Timeout waiting for response from pump");
                }
                else if (bytesRead > 0)
                {
                    // Validate the header
                    var responseBuffer = new MedtronicMessageBuffer(bytesRead);
                    ValidateHeader(responseBuffer);
                    messageSize = responseBuffer.MessageLength;
                    responseMessage.write(responseBuffer, 4, messageSize);
                }
                else
                {
                    Log.w(TAG, "readMessage: got a zero-sized response.");
                }
            } while (bytesRead > 0 && messageSize == USB_MAX_MESSAGE_SIZE);

            string responsestring = HexDump.DumpHexstring(responseMessage.toByteArray());

            Log.d(TAG, "READ: " + responsestring);

            return(responseMessage.toByteArray());
        }
        protected void SendMessage(UsbHidDriver mDevice)
        {
            int pos     = 0;
            var message = Encode();

            // chop into pieces and send each individual piece
            while (message.Length > pos)
            {
                var outputBuffer = new MedtronicMessageBuffer(USB_BLOCKSIZE);
                int sendLength   = (pos + USB_MAX_MESSAGE_SIZE > message.Length)
                    ? message.Length - pos
                    : USB_MAX_MESSAGE_SIZE;
                outputBuffer.Put(HeaderBytes);
                outputBuffer.Put((byte)sendLength);
                outputBuffer.Put(message, pos, sendLength);

                // separate the send concern
                mDevice.Write(outputBuffer, WRITE_TIMEOUT_MS);
                pos += sendLength;

                string outputstring = HexDump.DumpHexstring(outputBuffer);
                Log.d(TAG, "WRITE: " + outputstring);
            }
        }