static private bool SendBulkData(byte[] Data) { /* From MPPICKIT3: * * This class allows the user to send/receive any amount of data as a series of * HID reports. It isolates the user from knowing how to hook to MPLABComm * and from knowing how data is turned into reports. You basically, open, * read, write and close. It extends HID which is the class that actually * knows how to send/receive reports. * * Protocol notes: HID wants to send information in reports. We chose a report size of 64 bytes. * The Real ICE/ICD3/PK3, do not have a symetric protocol implementation with respect to the PC. * In other words, the requirements for the USB driver implementation in the embedded side of * these tools are not the same as the requirements of the USB driver in the PC side. * If you look at the PK3 FW driver you will see it does not look like the GetData/SendData defined * here. However, both the transmission and reception use the same protocol format. * In the PC side, GetData gets called and we can safely assume that GetData will not * need to read from the middle of a message. GetData is called to get a message. This message * might have the excepted len (passed as a parameter) or any other len. As long as a message * is received, GetData must return indicating how much data it got. * Of course, that means that when calling GetData, you'd better pass a buffer big enough * to handle the largest possible response (which might not be the one you were expecting) * the PK3 can send. * This allows the following situation to occur: * PC -> Send command * PK3 -> Send response * Or * PC -> Send command * PK3 -> Send working indication * PK3 -> Send response * * Note: the following examples show how data is packetized into reports. The * examples are the same regardless of who is sending our who is receiving * (PC or PK3 FW).* * An example of 32 (0x20) bytes of data being sent in s single report * * +----------+ * | data1 | byte 0 <-- beginnig of report 1 * | data2 | byte 6 * : : * | 0x20 | byte 60 <- length of data in this message (little endian) * | 0x00 | byte 61 In this case the length is 0x20 or 32 bytes * | 0x00 | byte 62 * | 0x00 | byte 63 <-- end of report 1. End of transmission * +----------+ * * * An example of 67 bytes (0x43 in hex) being sent. It * requires sending 2 reports with 60 bytes in the first one (64 bytes of * report size - 4 bytes for the length) and 7 in the * * +----------+ * | data1 | byte 0 <-- beginnig of report 1 * | data2 | byte 6 * : : * | 0x43 | byte 60 <- length of data in this message (little endian) * | 0x00 | byte 61 In this case the length is 0x43 or 67 bytes * | 0x00 | byte 62 * | 0x00 | byte 63 <-- end of report 1 * +----------+ * +----------+ * | data61 | byte 0 <-- beginning of report 2 * | data62 | * | data63 | * | data64 | * | data65 | * | data66 | * : : * : : * | padding | byte 60 <--- note NO length included here. Only in the * | padding | byte 61 very first report * | padding | byte 62 * | padding | byte 63 <-- end of report 2 * +----------+ * * @author jose */ // Add the total message length at the end of the first USB report int size = Data.Length + 2 + 4; // Round the packet size up to the nearest USB report size if (size % 64 != 0) { size = size + (64 - size % 64); } byte[] TotalData = new byte[size]; // Fill the buffer with our pad value. Useful data will overwrite as necessary. for (int i = 0; i < TotalData.Length; i++) { TotalData[i] = 0x5B; } if (Data.Length <= 60) { // Only one report needed Array.Copy(Data, 0, TotalData, 0, Data.Length); } else { // Muliple reports needed Array.Copy(Data, 0, TotalData, 0, 60); Array.Copy(Data, 60, TotalData, 64, Data.Length - 60); } TotalData[60] = Convert.ToByte((Data.Length + 2) & 0xFF); TotalData[61] = Convert.ToByte(((Data.Length + 2) >> 8) & 0xFF); TotalData[62] = Convert.ToByte(((Data.Length + 2) >> 16) & 0xFF); TotalData[63] = Convert.ToByte(((Data.Length + 2) >> 24) & 0xFF); uint Checksum = GetTwosCompWordChecksum(Data); // If the data packet is more than one report big, add 4 to the index to skip // over the Bulk Transfer Checksum if (TotalData.Length > 0x40) { TotalData[Data.Length + 4 + 0] = Convert.ToByte(Checksum & 0xFF); TotalData[Data.Length + 4 + 1] = Convert.ToByte((Checksum >> 8) & 0xFF); } else { // The packet is only 1 report, so we don't need to adjust for the DWORD Length TotalData[Data.Length + 0] = Convert.ToByte(Checksum & 0xFF); TotalData[Data.Length + 1] = Convert.ToByte((Checksum >> 8) & 0xFF); } byte[] outgoingData = new byte[64]; ResetStatusBar((int)(TotalData.Length / 64)); for (int reportCount = 0; reportCount * 64 < TotalData.Length; reportCount++) { Array.Copy(TotalData, reportCount * 64, outgoingData, 0, 64); Pk3.writeUSB(outgoingData); StepStatusBar(); } if (Pk3.readUSB()) { // Evaluate response to determine success or failure if ((Pk3.Usb_read_array[1] == 0x00) && (Pk3.Usb_read_array[2] == 0x00)) { // we got a "success" indicator return(true); } else { // we got something crazy return(false); } } else { return(false); } }
static private void SendCommandWithDataNoResponse(uint Command, byte[] Data) { /* HID report payloads are 64 bytes. The PICkit3 message structure requires the first * report have the 2-byte command and 4-byte message size. The rest of that report can * be payload for the command. Subsequent reports in the same message do not require * the command or the size. Message size is Data Bytes + Command Bytes. */ byte[] usbCommand = new byte[] { (byte)(((ushort)Command) & 0xFF), (byte)(((ushort)Command >> 8) & 0xFF) }; //byte[] usbWriteBuffer = new byte[64]; int DataLength = 0; if (Data == null) { DataLength = 0; } else { DataLength = Data.Length; } //// WARNING: This assumes ONLY ONE report is needed (So don't do memory transfers yet!). //if ((Data != null) && (Data.Length > 58)) // 64 - 4 (length) - 2 (command) // throw new ArgumentException("Data transfer must require only one USB transaction.", "Data"); // Add the total message length at the end of the first USB report int size = DataLength + 2 + 4; // Round the packet size up to the nearest USB report size if (size % 64 != 0) { size = size + (64 - size % 64); } byte[] usbWriteBuffer = new byte[size]; // Fill the buffer with our pad value. Useful data will overwrite as necessary. for (int i = 0; i < usbWriteBuffer.Length; i++) { usbWriteBuffer[i] = 0x5B; } // Copy the command into the buffer. usbWriteBuffer[0] = (byte)(((ushort)Command) & 0xFF); usbWriteBuffer[1] = (byte)(((ushort)Command >> 8) & 0xFF); // Copy the data into the buffer. if (Data == null) { // No data to send. Only one report needed. } else if (Data.Length <= 58) // 64 - 4 (length) - 2 (command) { // Only one report needed Array.Copy(Data, 0, usbWriteBuffer, 2, Data.Length); } else { // Muliple reports needed Array.Copy(Data, 0, usbWriteBuffer, 2, 60); Array.Copy(Data, 58, usbWriteBuffer, 64, Data.Length - 58); } // Fill in the length of the message usbWriteBuffer[60] = Convert.ToByte(DataLength + usbCommand.Length & 0xFF); usbWriteBuffer[61] = Convert.ToByte(DataLength + usbCommand.Length >> 8 & 0xFF); usbWriteBuffer[62] = Convert.ToByte(DataLength + usbCommand.Length >> 16 & 0xFF); usbWriteBuffer[63] = Convert.ToByte(DataLength + usbCommand.Length >> 24 & 0xFF); // Note that a checksum is not sent in this type of transaction. byte[] outgoingData = new byte[64]; for (int reportCount = 0; reportCount * 64 < usbWriteBuffer.Length; reportCount++) { Array.Copy(usbWriteBuffer, reportCount * 64, outgoingData, 0, 64); Pk3.writeUSB(outgoingData); } }