Last active
July 30, 2022 11:02
-
-
Save visuve/efbfa1eb8e2dc27bb66a1fbc8afd6c51 to your computer and use it in GitHub Desktop.
Deploy .uf2 files on a Pico and open a serial port for monitoring
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.IO.Ports; | |
| using System.Management; | |
| class PicoDeploy | |
| { | |
| private static void Main(string[] args) | |
| { | |
| if (args.Length == 0) | |
| { | |
| Console.WriteLine("Usage:"); | |
| Console.WriteLine("\t <serialport> e.g. COM5"); | |
| Console.WriteLine("\t <uf2filepath> [optional]"); | |
| return; | |
| } | |
| if (args.Length == 2) | |
| { | |
| Deploy(args[1]); | |
| } | |
| ReadSerial(args[0]); | |
| } | |
| private static void Deploy(string uf2file) | |
| { | |
| string extension = Path.GetExtension(uf2file); | |
| if (extension != ".uf2") | |
| { | |
| Console.WriteLine($"Expected .uf2 file extension, got \"{extension}\""); | |
| return; | |
| } | |
| try | |
| { | |
| DriveInfo[] drives = DriveInfo.GetDrives(); | |
| var picoDrive = drives.SingleOrDefault(drive => | |
| drive.DriveFormat == "FAT" && | |
| drive.DriveType == DriveType.Removable && | |
| drive.IsReady == true && | |
| drive.VolumeLabel == "RPI-RP2"); | |
| if (picoDrive == null) | |
| { | |
| Console.WriteLine("Failed to find a Pico drive for deployment!"); | |
| return; | |
| } | |
| string fileName = Path.GetFileName(uf2file); | |
| File.Copy(uf2file, Path.Combine(picoDrive.Name, fileName)); | |
| Console.WriteLine("Waiting 2s for the Pico to boot..."); | |
| Thread.Sleep(2000); | |
| } | |
| catch (Exception e) | |
| { | |
| Console.WriteLine("Failed to copy .uf2 file!"); | |
| Console.WriteLine(e.ToString()); | |
| return; | |
| } | |
| } | |
| private static void ReadSerial(string portName) | |
| { | |
| try | |
| { | |
| var serialPort = new SerialPort(portName); | |
| serialPort.BaudRate = 115200; | |
| serialPort.DataBits = 8; | |
| serialPort.StopBits = StopBits.One; | |
| serialPort.Parity = Parity.None; | |
| serialPort.Handshake = Handshake.XOnXOff; | |
| serialPort.DtrEnable = true; | |
| serialPort.DataReceived += (s, e) => | |
| { | |
| Console.Write(serialPort.ReadExisting()); | |
| }; | |
| serialPort.ErrorReceived += (s, e) => | |
| { | |
| Console.WriteLine("An error occurred while reading the serial port!"); | |
| Console.WriteLine(e.ToString()); | |
| Environment.Exit(0x0000001E); // ERROR_READ_FAULT, "The system cannot read from the specified device." | |
| }; | |
| // The SerialPort class does not fire any event when the whole device disappears | |
| var query = new WqlEventQuery() | |
| { | |
| EventClassName = "__InstanceOperationEvent", | |
| WithinInterval = new TimeSpan(0, 0, 5), | |
| Condition = "TargetInstance ISA 'WIN32_SerialPort'" | |
| }; | |
| var watcher = new ManagementEventWatcher(query); | |
| watcher.EventArrived += (s, e) => | |
| { | |
| if (e.NewEvent.ClassPath.ClassName != "__InstanceDeletionEvent") | |
| { | |
| return; | |
| } | |
| using var mbo = e.NewEvent.Properties["TargetInstance"].Value as ManagementBaseObject; | |
| string? deviceId = mbo?.Properties["DeviceID"]?.Value.ToString(); | |
| if (deviceId == portName) | |
| { | |
| Console.WriteLine($"{portName} disappeared! Closing..."); | |
| Environment.Exit(0x00000014); // ERROR_NOT_READY, "The device is not ready." | |
| } | |
| }; | |
| serialPort.Open(); | |
| Console.WriteLine($"{portName} opened!"); | |
| Console.WriteLine("Press any key to exit"); | |
| watcher.Start(); | |
| Console.ReadKey(); | |
| } | |
| catch (Exception e) | |
| { | |
| Console.WriteLine($"Failed to open/read {portName}!"); | |
| Console.WriteLine(e.ToString()); | |
| return; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment