using CLCapture; using CommandLine; using SharedDriver; using System.IO.Ports; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Text.RegularExpressions; Regex regAddressPort = new Regex("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\:[0-9]+"); Regex regAddress = new Regex("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+"); LogicAnalyzerDriver? driver = null; TaskCompletionSource captureCompletedTask; Console.CancelKeyPress += Console_CancelKeyPress; return await Parser.Default.ParseArguments(args) .MapResult( async (CLCaptureOptions opts) => await Capture(opts), async (CLNetworkOptions opts) => Configure(opts), errs => Task.FromResult(-1) ); async Task Capture(CLCaptureOptions opts) { bool isNetworkAddress = regAddressPort.IsMatch(opts.AddressPort); var ports = SerialPort.GetPortNames(); if (!isNetworkAddress && !ports.Any(p => p.ToLower() == opts.AddressPort.ToLower())) { Console.WriteLine("Cannot find specified serial port or address has an incorrect format."); return -1; } if (opts.SamplingFrequency > 100000000 || opts.SamplingFrequency < 3100) { Console.WriteLine("Requested sampling frequency out of range (3100-100000000)."); return -1; } int[]? channels = opts.Channels?.Split(",", StringSplitOptions.RemoveEmptyEntries).Select(c => int.Parse(c)).ToArray(); if (channels == null || channels.Any(c => c < 1 || c > 24)) { Console.WriteLine("Specified capture channels out of range."); return -1; } int maxChannel = channels.Max(); int channelMode = maxChannel <= 8 ? 0 : (maxChannel <= 16 ? 1 : 2); int channelCount = maxChannel <= 8 ? 8 : (maxChannel <= 16 ? 16 : 24); int minPreSamples = 2; int maxPreSamples = channelMode == 0 ? 98303 : (channelMode == 1 ? 49151 : 24576); int minPostSamples = 512; int maxPostSamples = channelMode == 0 ? 131069 : (channelMode == 1 ? 65533 : 32765); int maxTotalSamples = channelMode == 0 ? 131071 : (channelMode == 1 ? 65535 : 32767); if (opts.PreSamples + opts.PostSamples > maxTotalSamples) { Console.WriteLine($"Total samples exceed the supported maximum ({maxTotalSamples} for the {channelCount} channel mode)."); return -1; } if (opts.PreSamples < minPreSamples) { Console.WriteLine($"Pre-samples cannot be less than {minPreSamples}."); return -1; } if (opts.PreSamples > maxPreSamples) { Console.WriteLine($"Pre-samples cannot be more than {maxPreSamples} for the {channelCount} channel mode."); return -1; } if (opts.PostSamples < minPostSamples) { Console.WriteLine($"Post-samples cannot be less than {minPostSamples}."); return -1; } if (opts.PostSamples > maxPostSamples) { Console.WriteLine($"Post-samples cannot be more than {maxPostSamples} for the {channelCount} channel mode."); return -1; } if (opts.Trigger == null) { Console.WriteLine("Invalid trigger definition."); return -1; } if (opts.Trigger.Value == null) { Console.WriteLine("Invalid trigger value."); return -1; } switch (opts.Trigger.TriggerType) { case CLTriggerType.Edge: if (opts.Trigger.Channel < 1 || opts.Trigger.Channel > 24) { Console.WriteLine("Trigger channel out of range."); return -1; } break; case CLTriggerType.Fast: if (opts.Trigger.Value.Length > 5) { Console.WriteLine("Fast trigger only supports up to 5 channels."); return -1; } if (opts.Trigger.Value.Length + opts.Trigger.Channel > 17) { Console.WriteLine("Fast trigger can only be used with the first 16 channels."); return -1; } break; case CLTriggerType.Complex: if (opts.Trigger.Value.Length > 16) { Console.WriteLine("Complex trigger only supports up to 16 channels."); return -1; } if (opts.Trigger.Value.Length + opts.Trigger.Channel > 17) { Console.WriteLine("Complex trigger can only be used with the first 16 channels."); return -1; } break; } Console.WriteLine($"Opening logic analyzer in {opts.AddressPort}..."); try { driver = new LogicAnalyzerDriver(opts.AddressPort); } catch { Console.WriteLine($"Error detecting Logic Analyzer in port/address {opts.AddressPort}"); return -1; } Console.WriteLine($"Conneced to device {driver.DeviceVersion} in port/address {opts.AddressPort}"); captureCompletedTask = new TaskCompletionSource(); channels = opts.Channels.Split(",", StringSplitOptions.RemoveEmptyEntries).Select(c => int.Parse(c) - 1).ToArray(); if (opts.Trigger.TriggerType == CLTriggerType.Edge) { Console.WriteLine("Starting edge triggered capture..."); var resStart = driver.StartCapture(opts.SamplingFrequency, opts.PreSamples, opts.PostSamples, channels, opts.Trigger.Channel - 1, opts.Trigger.Value == "0", CaptureFinished); if (resStart != CaptureError.None) { switch (resStart) { case CaptureError.Busy: Console.WriteLine("Device is busy, stop the capture before starting a new one."); return -1; case CaptureError.BadParams: Console.WriteLine("Specified parameters are incorrect.\r\n\r\n -Frequency must be between 3.1Khz and 100Mhz\r\n -PreSamples must be between 2 and 31743\r\n -PostSamples must be between 512 and 32767\r\n -Total samples cannot exceed 32767"); return -1; case CaptureError.HardwareError: Console.WriteLine("Device reported error starting capture. Restart the device and try again."); return -1; case CaptureError.UnexpectedError: Console.WriteLine("Unexpected error. Restart the device and try again."); return -1; } } Console.WriteLine("Capture running..."); } else { if (opts.Trigger.TriggerType == CLTriggerType.Fast) Console.WriteLine("Starting fast pattern triggered capture"); else Console.WriteLine("Starting complex pattern triggered capture"); int bitCount = opts.Trigger.Value.Length; ushort triggerPattern = 0; for (int buc = 0; buc < opts.Trigger.Value.Length; buc++) { if (opts.Trigger.Value[buc] == '1') triggerPattern |= (UInt16)(1 << buc); } var resStart = driver.StartPatternCapture(opts.SamplingFrequency, opts.PreSamples, opts.PostSamples, channels, opts.Trigger.Channel - 1, bitCount, triggerPattern, opts.Trigger.TriggerType == CLTriggerType.Fast, CaptureFinished); if (resStart != CaptureError.None) { switch (resStart) { case CaptureError.Busy: Console.WriteLine("Device is busy, stop the capture before starting a new one."); return -1; case CaptureError.BadParams: Console.WriteLine("Specified parameters are incorrect. Check the documentation in the repository to validate them."); return -1; case CaptureError.HardwareError: Console.WriteLine("Device reported error starting capture. Restart the device and try again."); return -1; case CaptureError.UnexpectedError: Console.WriteLine("Unexpected error. Restart the device and try again."); return -1; } } Console.WriteLine("Capture running..."); } var result = await captureCompletedTask.Task; if (result.Samples == null) { Console.WriteLine("Capture aborted."); return -1; } Console.WriteLine("Capture complete, writting output file..."); var file = File.Create(opts.OutputFile); StreamWriter sw = new StreamWriter(file); sw.WriteLine(String.Join(',', channels.Select(c => $"Channel {c + 1}").ToArray())); StringBuilder sb = new StringBuilder(); for (int sample = 0; sample < result.Samples.Length; sample++) { sb.Clear(); for (int buc = 0; buc < opts.Channels.Length; buc++) { if ((result.Samples[sample] & ((UInt128)1 << buc)) == 0) sb.Append("0,"); else sb.Append("1,"); } sw.WriteLine(sb.ToString()); } sw.Close(); sw.Dispose(); file.Close(); file.Dispose(); Console.WriteLine("Done."); return 1; } int Configure(CLNetworkOptions opts) { var ports = SerialPort.GetPortNames(); if (!ports.Any(p => p.ToLower() == opts.SerialPort)) { Console.WriteLine("Cannot find specified serial port."); return -1; } if (opts.AccessPoint.Length > 32) { Console.WriteLine("Invalid access point name."); return -1; } if (opts.Password.Length > 63) { Console.WriteLine("Invalid password."); return -1; } if (!regAddress.IsMatch(opts.Address)) { Console.WriteLine("Invalid IP address."); return -1; } if (opts.Port < 1) { Console.WriteLine("Invalid TCP port."); return -1; } Console.WriteLine($"Opening logic analyzer in port {opts.SerialPort}..."); try { driver = new LogicAnalyzerDriver(opts.SerialPort); } catch { Console.WriteLine($"Error detecting Logic Analyzer in port {opts.SerialPort}"); return -1; } Console.WriteLine($"Conneced to device {driver.DeviceVersion} in port {opts.SerialPort}"); if (driver.DeviceVersion == null || !driver.DeviceVersion.Contains("WIFI")) { Console.WriteLine($"Device does not support WiFi. Aborting operation."); driver.Dispose(); return -1; } bool result = driver.SendNetworkConfig(opts.AccessPoint, opts.Password, opts.Address, opts.Port); if (!result) { Console.WriteLine("Error updating the network settings, restart the device and try again."); driver.Dispose(); return -1; } driver.Dispose(); Console.WriteLine("Done."); return 1; } void CaptureFinished(CaptureEventArgs e) { captureCompletedTask.SetResult(e); } void Console_CancelKeyPress(object? sender, ConsoleCancelEventArgs e) { if (driver != null) { try { driver.StopCapture(); driver.Dispose(); } catch { } driver = null; } }