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); } }
protected async Task <byte[]> ReadFromPump(UsbHidDriver mDevice, MedtronicCnlSession pumpSession, string tag) { tag = " (" + tag + ")"; MultipacketSession multipacketSession = null; byte[] tupple; byte[] payload = null; byte[] decrypted = null; bool fetchMoreData = true; int retry = 0; int expectedSegments = 0; int cmd; while (fetchMoreData) { if (multipacketSession != null) { do { if (expectedSegments < 1) { tupple = multipacketSession.MissingSegments(); new MultipacketResendPacketsMessage(pumpSession, tupple).send(mDevice); expectedSegments = read16BEtoUInt(tupple, 0x02); } try { payload = await ReadMessage(mDevice, MULTIPACKET_TIMEOUT_MS); break; } catch (TimeoutException e) { if (++retry >= SEGMENT_RETRY) { throw new TimeoutException("Timeout waiting for response from pump (multipacket)" + tag); } Log.d(TAG, "*** Multisession timeout, expecting:" + expectedSegments + " retry: " + retry); expectedSegments = 0; } } while (retry > 0); } else { try { payload = await ReadMessage(mDevice, READ_TIMEOUT_MS); } catch (TimeoutException e) { throw new TimeoutException("Timeout waiting for response from pump" + tag); } } if (payload.Length < 0x0039) { Log.d(TAG, "*** bad response" + HexDump.DumpHexstring(payload, 0x12, payload.Length - 0x14)); fetchMoreData = true; } else { decrypted = Decode(pumpSession, payload); cmd = read16BEtoUInt(decrypted, RESPONSE_COMMAND); Log.d(TAG, "CMD: " + HexDump.ToHexstring(cmd)); if (MedtronicSendMessageRequestMessage.MessageType.EHSM_SESSION.response(cmd)) { // EHSM_SESSION(0) Log.d(TAG, "*** EHSM response" + HexDump.DumpHexstring(decrypted)); fetchMoreData = true; } else if (MedtronicSendMessageRequestMessage.MessageType.NAK_COMMAND.response(cmd)) { Log.d(TAG, "*** NAK response" + HexDump.DumpHexstring(decrypted)); ClearMessage(mDevice, ERROR_CLEAR_TIMEOUT_MS); // if multipacket was in progress we may need to clear 2 EHSM_SESSION(1) messages from pump short nakcmd = read16BEtoShort(decrypted, 3); byte nakcode = decrypted[5]; throw new UnexpectedMessageException("Pump sent a NAK(" + string.Format("%02X", nakcmd) + ":" + string.Format("%02X", nakcode) + ") response" + tag); } else if (MedtronicSendMessageRequestMessage.MessageType.INITIATE_MULTIPACKET_TRANSFER.response(cmd)) { multipacketSession = new MultipacketSession(decrypted); new AckMessage(pumpSession, MedtronicSendMessageRequestMessage.MessageType.INITIATE_MULTIPACKET_TRANSFER.response()).send(mDevice); expectedSegments = multipacketSession.PacketsToFetch; fetchMoreData = true; } else if (MedtronicSendMessageRequestMessage.MessageType.MULTIPACKET_SEGMENT_TRANSMISSION.response(cmd)) { if (multipacketSession == null) { throw new UnexpectedMessageException("multipacketSession not initiated before segment received" + tag); } multipacketSession.AddSegment(decrypted); expectedSegments--; if (multipacketSession.PayloadComplete) { Log.d(TAG, "*** Multisession Complete"); new AckMessage(pumpSession, MedtronicSendMessageRequestMessage.MessageType.MULTIPACKET_SEGMENT_TRANSMISSION.response()).send(mDevice); // read 0412 = EHSM_SESSION(1) payload = await ReadMessage(mDevice, READ_TIMEOUT_MS); decrypted = Decode(pumpSession, payload); Log.d(TAG, "*** response" + HexDump.DumpHexstring(decrypted)); return(multipacketSession.Response); } else { fetchMoreData = true; } } else if (MedtronicSendMessageRequestMessage.MessageType.END_HISTORY_TRANSMISSION.response(cmd)) { Log.d(TAG, "*** END_HISTORY_TRANSMISSION response" + HexDump.DumpHexstring(decrypted)); fetchMoreData = false; } else if (MedtronicSendMessageRequestMessage.MessageType.READ_PUMP_TIME.response(cmd)) { Log.d(TAG, "*** READ_PUMP_TIME response" + HexDump.DumpHexstring(decrypted)); fetchMoreData = false; } else if (MedtronicSendMessageRequestMessage.MessageType.READ_PUMP_STATUS.response(cmd)) { Log.d(TAG, "*** READ_PUMP_STATUS response" + HexDump.DumpHexstring(decrypted)); fetchMoreData = false; } else if (MedtronicSendMessageRequestMessage.MessageType.READ_HISTORY_INFO.response(cmd)) { Log.d(TAG, "*** READ_HISTORY_INFO response" + HexDump.DumpHexstring(decrypted)); fetchMoreData = false; } else if (MedtronicSendMessageRequestMessage.MessageType.READ_BASAL_PATTERN.response(cmd)) { Log.d(TAG, "*** READ_BASAL_PATTERN response" + HexDump.DumpHexstring(decrypted)); fetchMoreData = false; } else if (MedtronicSendMessageRequestMessage.MessageType.READ_BOLUS_WIZARD_CARB_RATIOS.response(cmd)) { Log.d(TAG, "*** READ_BOLUS_WIZARD_CARB_RATIOS response" + HexDump.DumpHexstring(decrypted)); fetchMoreData = false; } else if (MedtronicSendMessageRequestMessage.MessageType.READ_BOLUS_WIZARD_SENSITIVITY_FACTORS.response(cmd)) { Log.d(TAG, "*** READ_BOLUS_WIZARD_SENSITIVITY_FACTORS response" + HexDump.DumpHexstring(decrypted)); fetchMoreData = false; } else if (MedtronicSendMessageRequestMessage.MessageType.READ_BOLUS_WIZARD_BG_TARGETS.response(cmd)) { Log.d(TAG, "*** READ_BOLUS_WIZARD_BG_TARGETS response" + HexDump.DumpHexstring(decrypted)); fetchMoreData = false; } else { Log.d(TAG, "*** ??? response" + HexDump.DumpHexstring(decrypted)); fetchMoreData = true; } } } // when returning non-multipacket decrypted data, we need to trim the 2 byte checksum if (decrypted == null) { return(payload); } return(decrypted.Partial(0, decrypted.Length - 2)); }