mattercontrol/MatterControlLib/SetupWizard/SetupWizardTroubleshooting.cs

320 lines
8.9 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using MatterHackers.Agg;
using MatterHackers.Agg.Platform;
using MatterHackers.Agg.UI;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.ConfigurationPage.PrintLeveling;
using MatterHackers.MatterControl.DataStorage;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.PrinterCommunication;
using MatterHackers.SerialPortCommunication.FrostedSerial;
#if __ANDROID__
using Com.Hoho.Android.Usbserial.Driver;
using Android.Hardware.Usb;
using Android.Content;
#endif
namespace MatterHackers.MatterControl
{
public class SetupWizardTroubleshooting : DialogPage
{
private GuiWidget nextButton;
private CriteriaRow connectToPrinterRow;
// Used in Android
private System.Threading.Timer checkForPermissionTimer;
private PrinterConfig printer;
#if __ANDROID__
private static UsbManager usbManager
{
get { return (UsbManager) Android.App.Application.Context.ApplicationContext.GetSystemService(Context.UsbService); }
}
#endif
public SetupWizardTroubleshooting(PrinterConfig printer)
{
this.WindowTitle = "Troubleshooting".Localize();
this.printer = printer;
RefreshStatus();
nextButton = theme.CreateDialogButton("Continue".Localize());
nextButton.Click += (s, e) => UiThread.RunOnIdle(this.DialogWindow.Close);
nextButton.Visible = false;
this.AddPageAction(nextButton);
// Register listeners
printer.Connection.CommunicationStateChanged += Connection_CommunicationStateChanged;
}
public void Connection_CommunicationStateChanged(object test, EventArgs args)
{
if (printer.Connection.CommunicationState == CommunicationStates.Connected && connectToPrinterRow != null)
{
connectToPrinterRow.SetSuccessful();
nextButton.Visible = true;
}
}
protected override void OnCancel(out bool abortCancel)
{
abortCancel = true;
UiThread.RunOnIdle(() =>
{
this.DialogWindow.ChangeToPage(new AndroidConnectDevicePage(printer));
});
}
public override void OnClosed(EventArgs e)
{
// Unregister listeners
printer.Connection.CommunicationStateChanged -= Connection_CommunicationStateChanged;
if (checkForPermissionTimer != null)
{
checkForPermissionTimer.Dispose();
}
base.OnClosed(e);
}
private void RefreshStatus()
{
CriteriaRow.ResetAll();
// Clear the main container
contentRow.CloseAllChildren();
// Regen and refresh the troubleshooting criteria
var printerNameLabel = new TextWidget(string.Format("{0}:", "Connection Troubleshooting".Localize()), 0, 0, labelFontSize)
{
TextColor = theme.TextColor,
Margin = new BorderDouble(bottom: 10)
};
#if __ANDROID__
IUsbSerialPort serialPort = FrostedSerialPort.LoadSerialDriver(null);
#if ANDROID7
// Filter out the built-in 002 device and select the first item from the list
// On the T7 Android device, there is a non-printer device always registered at usb/002/002 that must be ignored
UsbDevice usbPrintDevice = usbManager.DeviceList.Values.Where(d => d.DeviceName != "/dev/bus/usb/002/002").FirstOrDefault();
#else
UsbDevice usbPrintDevice = usbManager.DeviceList.Values.FirstOrDefault();
#endif
UsbStatus usbStatus = new UsbStatus () {
IsDriverLoadable = (serialPort != null),
HasUsbDevice = true,
HasUsbPermission = false,
AnyUsbDeviceExists = usbPrintDevice != null
};
if (!usbStatus.IsDriverLoadable)
{
usbStatus.HasUsbDevice = usbPrintDevice != null;
if (usbStatus.HasUsbDevice) {
// TODO: Testing specifically for UsbClass.Comm seems fragile but no better alternative exists without more research
usbStatus.UsbDetails = new UsbDeviceDetails () {
ProductID = usbPrintDevice.ProductId,
VendorID = usbPrintDevice.VendorId,
DriverClass = usbManager.DeviceList.Values.First ().DeviceClass == Android.Hardware.Usb.UsbClass.Comm ? "cdcDriverType" : "ftdiDriverType"
};
usbStatus.Summary = string.Format ("No USB device definition found. Click the 'Fix' button to add an override for your device ", usbStatus.UsbDetails.VendorID, usbStatus.UsbDetails.ProductID);
}
}
usbStatus.HasUsbPermission = usbStatus.IsDriverLoadable && FrostedSerialPort.HasPermissionToDevice(serialPort);
contentRow.AddChild(printerNameLabel);
contentRow.AddChild(new CriteriaRow(
"USB Connection",
"Retry",
"No USB device found. Check and reseat cables and try again",
usbStatus.AnyUsbDeviceExists,
() => UiThread.RunOnIdle(RefreshStatus),
theme));
contentRow.AddChild(new CriteriaRow(
"USB Driver",
"Fix",
usbStatus.Summary,
usbStatus.IsDriverLoadable,
() =>
{
string overridePath = Path.Combine(ApplicationDataStorage.ApplicationUserDataPath, "data", "usboverride.local");
UsbDeviceDetails usbDetails = usbStatus.UsbDetails;
File.AppendAllText(overridePath, string.Format("{0},{1},{2}\r\n", usbDetails.VendorID, usbDetails.ProductID, usbDetails.DriverClass));
UiThread.RunOnIdle(() => RefreshStatus());
},
theme));
contentRow.AddChild(new CriteriaRow(
"USB Permission",
"Request Permission",
"Click the 'Request Permission' button to gain Android access rights",
usbStatus.HasUsbPermission,
() =>
{
if (checkForPermissionTimer == null)
{
checkForPermissionTimer = new System.Threading.Timer((state) =>
{
if (FrostedSerialPort.HasPermissionToDevice(serialPort))
{
UiThread.RunOnIdle(this.RefreshStatus);
checkForPermissionTimer.Dispose();
}
}, null, 200, 200);
}
FrostedSerialPort.RequestPermissionToDevice(serialPort);
},
theme));
#endif
connectToPrinterRow = new CriteriaRow(
"Connect to Printer".Localize(),
"Connect".Localize(),
"Click the 'Connect' button to retry the original connection attempt".Localize(),
false,
() => printer.Connection.Connect(),
theme);
contentRow.AddChild(connectToPrinterRow);
if (CriteriaRow.ActiveErrorItem != null) {
var errorText = new FlowLayoutWidget () {
Padding = new BorderDouble (0, 15)
};
errorText.AddChild(
new TextWidget(CriteriaRow.ActiveErrorItem.ErrorText)
{
TextColor = theme.PrimaryAccentColor
});
contentRow.AddChild(errorText);
}
}
private class CriteriaRow : FlowLayoutWidget
{
public static CriteriaRow ActiveErrorItem { get; private set; }
public string ErrorText { get; private set; }
private static bool stillSuccessful = true;
private static int criteriaCount = 0;
private static Color disabledTextColor = new Color(0.35, 0.35, 0.35);
private static Color disabledBackColor = new Color(0.22, 0.22, 0.22);
private static Color toggleColor = new Color(Color.Gray.red + 2, Color.Gray.green + 2, Color.Gray.blue + 2);
public CriteriaRow (string itemText, string fixitText, string errorText, bool succeeded, Action fixAction, ThemeConfig theme)
: base(FlowDirection.LeftToRight)
{
HAnchor = HAnchor.Stretch;
VAnchor = VAnchor.Absolute;
ErrorText = errorText;
base.Height = 40;
base.AddChild(new TextWidget (string.Format(" {0}. {1}", criteriaCount + 1, itemText)){
TextColor = stillSuccessful ? Color.White : disabledTextColor,
VAnchor = VAnchor.Center
});
if(stillSuccessful && !succeeded)
{
ActiveErrorItem = this;
}
base.AddChild(new HorizontalSpacer());
if(stillSuccessful) {
if(succeeded)
{
// Add checkmark image
AddSuccessIcon();
} else {
// Add Fix button
var button = theme.CreateDialogButton(fixitText);
button.VAnchor = VAnchor.Center;
button.Padding = new BorderDouble(3, 8);
button.Click += (s, e) => fixAction?.Invoke();
base.AddChild(button);
}
}
if(stillSuccessful)
{
this.BackgroundColor = (criteriaCount % 2 == 0) ? Color.Gray : toggleColor;
}
else
{
this.BackgroundColor = disabledBackColor;
}
stillSuccessful &= succeeded;
criteriaCount++;
}
public void SetSuccessful()
{
this.RemoveChild (this.Children.Last ());
ActiveErrorItem = null;
AddSuccessIcon();
}
public static void ResetAll()
{
criteriaCount = 0;
stillSuccessful = true;
ActiveErrorItem = null;
}
private void AddSuccessIcon()
{
base.AddChild (new ImageWidget (AggContext.StaticData.LoadImage (Path.Combine ("Icons", "426.png"))) {
VAnchor = VAnchor.Center
});
}
}
private class UsbStatus
{
public bool HasUsbDevice { get; set; }
public bool IsDriverLoadable { get; set; }
public string Summary { get; set; }
public bool HasUsbPermission { get; set; }
public bool AnyUsbDeviceExists { get ; set; }
public UsbDeviceDetails UsbDetails { get; set; }
}
private class UsbDeviceDetails
{
public int VendorID { get; set; }
public int ProductID { get; set; }
public string DriverClass { get; set; }
}
}
}