/// <summary> /// Constructor must be initialized with the HidDevice, the Teensy this /// report is for and the HexImage object to upload. /// </summary> public HidUploadReport(HidDevice device, Teensy teensy, HexImage image) : base(device) { Teensy = teensy; Image = image; // The block size must be less than the HID report length. if (teensy.DataBlockSize > device.ReportLength - 1) { throw new TeensyException( $"The data block size of a {Constants.TeensyWord} must be smaller than the HID report size, including the first byte, which is the report ID."); } }
/// <summary> /// Find a Teensy with the specified serial number. Returns null if not /// found. If desired, the result can also be filtered by UsbType. If /// serialNumber is 0, this will return the first Teensy found. type, if /// present, will still be used to filter results. /// </summary> public Teensy Find(uint serialNumber = 0, UsbTypes?type = null) { Teensy result = null; EnumTeensies(teensy => { if (serialNumber == 0 || teensy.SerialNumber == serialNumber) { if (!type.HasValue || type.Value == teensy.UsbType) { result = teensy; } } return(result == null); }); return(result); }
/// <summary> /// Upload an image to the Teensy. /// </summary> public void Upload() { #if DEBUG // ReSharper disable HeuristicUnreachableCode #pragma warning disable 162 const string filePath = null; //const string filePath = "T:\\Source\\Teensy.Net\\TestFiles\\blinkLC.hex.TeensyNetOutput"; //const string filePath = "T:\\Source\\Teensy.Net\\TestFiles\\blink32.hex.TeensyNetOutput"; // ReSharper disable once ConditionIsAlwaysTrueOrFalse if (filePath != null) { TestOutputStream = File.Open(filePath, FileMode.Create, FileAccess.Write, FileShare.None); } #pragma warning restore 162 // ReSharper restore HeuristicUnreachableCode #endif Image.Chunk((bytes, imageOffset) => { // The data offset is how much free space to leave in the HID // report data before writing of actual image data. The address // is always first, but writing image data should occur at this // offset. var dataOffset = 2u; // Add address (image offset). if (Teensy.DataBlockSize <= 256 && Teensy.FlashSize < 0x10000) { AddData((byte)(imageOffset & 0xFF)); AddData((byte)((imageOffset >> 8) & 0xFF)); } else if (Teensy.DataBlockSize == 256) { AddData((byte)((imageOffset >> 8) & 0xFF)); AddData((byte)((imageOffset >> 16) & 0xFF)); } else { AddData((byte)(imageOffset & 0xFF)); AddData((byte)((imageOffset >> 8) & 0xFF)); AddData((byte)((imageOffset >> 16) & 0xFF)); dataOffset = 64; } // Copy data to report, starting at data offset. SetDataStart(dataOffset); Fill(bytes); if (imageOffset == 0) { Teensy.ProvideFeedback( $"Erasing {Constants.TeensyWord} Flash Memory"); } Write(); // The first write erases the chip and needs a little // longer to complete. Thread.Sleep(imageOffset == 0 ? 3000 : 500); Teensy.ProvideFeedback(imageOffset + Teensy.DataBlockSize, Image.Size); }); #if DEBUG if (TestOutputStream != null) { TestOutputStream.Close(); TestOutputStream.Dispose(); TestOutputStream = null; } #endif }
/// <summary> /// Create a Teensy from management object, if the management object /// specifies Teensy information. /// </summary> private Teensy CreateTeensy(ManagementBaseObject o) { Teensy result = null; var teensyType = TeensyTypes.Unknown; string portName = null; var serialNumber = (uint)0; var usbType = UsbTypes.Disconnected; // Safely get a field value from management object. T GetFieldValue <T>(string fieldName) { var value = default(T); Utility.Try(() => { var obj = o[fieldName]; if (obj is T test) { value = test; } }); return(value); } // Given a field that is a string array, return the index value or // null. string GetFieldPart(string fieldName, int index) { string value = null; var stringParts = GetFieldValue <string[]>(fieldName); if (stringParts != null && index < stringParts.Length) { value = stringParts[index]; } return(value); } // Given a field that is a string to be split, return the index value // or null. string GetSplitField(string fieldName, char[] splitOn, int index) { string value = null; var stringParts = GetFieldValue <string>(fieldName)?.Split(splitOn); if (stringParts != null && index < stringParts.Length) { value = stringParts[index]; } return(value); } var parts = GetFieldValue <string>("PNPDeviceID")?.Split('\\'); if (parts?.Length > 2 && parts[0] == "USB") { var id = Convert.ToUInt32(parts[1].Substring( parts[1].IndexOf("PID_", StringComparison.Ordinal) + 4, 4), 16); if (id == SerialNumberId) { var hwId = GetFieldPart("HardwareID", 0); if (hwId != null) { portName = GetSplitField("Caption", new[] { '(', ')' }, 1); if (portName != null) { serialNumber = Convert.ToUInt32(parts[2]); usbType = UsbTypes.Serial; switch (hwId.Substring(hwId.IndexOf( "REV_", StringComparison.Ordinal) + 4, 4)) { case "0273": { teensyType = TeensyTypes.TeensyLc; break; } case "0274": { teensyType = TeensyTypes.Teensy30; break; } case "0275": { // There is not a unique value for Teensy 3.1 // so we assume 3.2. teensyType = TeensyTypes.Teensy32; break; } case "0276": { teensyType = TeensyTypes.Teensy35; break; } case "0277": { teensyType = TeensyTypes.Teensy36; break; } case "0279": { teensyType = TeensyTypes.Teensy40; break; } } } } } // Device is running bootloader? Have to use HID. else if (id == Constants.BootloaderId) { serialNumber = Utility.FixSerialNumber( Convert.ToUInt32(parts[2], 16)); // Find Teensy running bootloader. using (var teensy = HidDevice.FindDevice(serialNumber)) { if (teensy != null) { teensyType = teensy.TeensyType; usbType = UsbTypes.Bootloader; } } } // We must know these things! if (teensyType != TeensyTypes.Unknown && usbType != UsbTypes.Disconnected && serialNumber != 0) { result = new Teensy(this, teensyType, portName, serialNumber, usbType); } } return(result); }
/// <summary> /// Constructor must be initialized with the Teensy type and the reader to /// read image data from. /// </summary> public HexImage(TeensyTypes type, TextReader reader, bool disposeStream = false) { if (reader == null) { throw new TeensyException( "The HEX stream to read must be specified."); } TeensyType = Teensy.CheckType(type); switch (TeensyType) { case TeensyTypes.Teensy2: { DataBlockSize = 128; break; } case TeensyTypes.Teensy2PlusPlus: { DataBlockSize = 256; break; } case TeensyTypes.TeensyLc: { DataBlockSize = 512; break; } default: { DataBlockSize = 1024; break; } } // Initialize image. var valid = false; var size = Teensy.GetFlashSize(TeensyType); _data = new byte[size]; for (var i = 0; i < size; i++) { _data[i] = 0xFF; } var lineNumber = (uint)1; // Upper Linear Base Address. var ulba = (uint)0; // Segment Base Address. var segba = (uint)0; // Do not allow parsing to throw exception. We may need to dispose of // the stream after. var exception = Utility.Try(() => { var tempData = new byte[0]; while (ParseLine(reader.ReadLine(), ref ulba, ref segba, ref tempData, ref valid)) { ++lineNumber; } }); if (disposeStream) { Utility.Try(reader.Dispose); } if (exception != null) { Utility.Throw( exception, $"Invalid HEX file image data was found on or near line {lineNumber}."); } // Determine the total length of data that will be written. var totalLength = 0u; Chunk((bytes, imageOffset) => { totalLength = imageOffset + DataBlockSize; }); // Reset Data to match actual size. Array.Resize(ref _data, (int)totalLength); }