2018-11-24 07:52:33 -08:00
/ *
2019-01-04 18:25:33 -08:00
Copyright ( c ) 2019 , Lars Brubaker , John Lewin
2018-11-24 07:52:33 -08:00
All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are met :
1. Redistributions of source code must retain the above copyright notice , this
list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright notice ,
this list of conditions and the following disclaimer in the documentation
and / or other materials provided with the distribution .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies ,
either expressed or implied , of the FreeBSD Project .
* /
using System ;
2019-01-03 16:58:05 -08:00
using System.Collections.Generic ;
2019-01-22 17:01:28 -08:00
using System.Linq ;
2018-11-24 07:52:33 -08:00
using MatterHackers.Agg ;
2019-01-18 18:16:21 -08:00
using MatterHackers.Agg.UI ;
2018-11-24 07:52:33 -08:00
using MatterHackers.Localizations ;
2019-03-08 16:59:04 -08:00
using MatterHackers.MatterControl.ConfigurationPage.PrintLeveling ;
2019-01-22 13:38:56 -08:00
using MatterHackers.MatterControl.DesignTools ;
2021-03-05 15:07:50 -08:00
using MatterHackers.MatterControl.PrinterControls.PrinterConnections ;
2018-11-24 07:52:33 -08:00
using MatterHackers.MatterControl.SlicerConfiguration ;
2021-02-09 16:54:31 -08:00
using MatterHackers.VectorMath ;
2018-11-24 07:52:33 -08:00
namespace MatterHackers.MatterControl
{
public static class SettingsValidation
{
2019-01-24 08:24:18 -08:00
/// <summary>
2019-05-11 12:08:03 -07:00
/// Validates the printer settings satisfy all requirements.
2019-01-24 08:24:18 -08:00
/// </summary>
2019-05-11 12:08:03 -07:00
/// <param name="printer">The printer to validate.</param>
/// <returns>A list of all warnings and errors.</returns>
2019-04-30 08:19:29 -07:00
public static List < ValidationError > ValidateSettings ( this PrinterConfig printer , SettingsContext settings = null , bool validatePrintBed = true )
2018-11-24 07:52:33 -08:00
{
2021-02-12 10:06:11 -08:00
var fffPrinter = printer . Settings . Slicer . PrinterType = = PrinterType . FFF ;
2019-01-28 17:10:12 -08:00
if ( settings = = null )
{
settings = new SettingsContext ( printer , null , NamedSettingsLayers . All ) ;
}
2018-11-24 15:27:18 -08:00
2019-01-04 17:09:42 -08:00
var errors = new List < ValidationError > ( ) ;
2019-01-03 16:58:05 -08:00
2019-02-11 13:57:00 -08:00
var extruderCount = settings . GetValue < int > ( SettingsKey . extruder_count ) ;
2019-04-05 10:54:49 -07:00
// Check to see if supports are required
2020-03-30 12:00:30 -07:00
if ( ! settings . GetValue < bool > ( SettingsKey . create_per_layer_support ) )
2019-01-17 16:30:44 -08:00
{
2020-03-30 12:00:30 -07:00
var supportGenerator = new SupportGenerator ( printer . Bed . Scene , . 05 ) ;
if ( supportGenerator . RequiresSupport ( ) )
2019-01-17 16:30:44 -08:00
{
2020-08-28 06:57:45 -07:00
errors . Add ( new ValidationError ( ValidationErrors . UnsupportedParts )
2019-01-18 18:16:21 -08:00
{
2020-03-30 12:00:30 -07:00
Error = "Possible Unsupported Parts Detected" . Localize ( ) ,
Details = "Some parts may require support structures to print correctly" . Localize ( ) ,
ErrorLevel = ValidationErrorLevel . Warning ,
FixAction = new NamedAction ( )
{
Title = "Generate Supports" . Localize ( ) ,
Action = ( ) = >
{
2020-08-27 07:47:37 -07:00
// Find and InvokeClick on the Generate Supports toolbar button
var sharedParent = ApplicationController . Instance . DragDropData . View3DWidget . Parents < GuiWidget > ( ) . FirstOrDefault ( w = > w . Name = = "View3DContainerParent" ) ;
2020-03-30 12:00:30 -07:00
if ( sharedParent ! = null )
{
var supportsPopup = sharedParent . FindDescendant ( "Support SplitButton" ) ;
supportsPopup . InvokeClick ( ) ;
}
}
}
} ) ;
}
2019-01-17 16:30:44 -08:00
}
2021-02-09 16:54:31 -08:00
if ( ! settings . GetValue < bool > ( SettingsKey . extruder_offset ) )
{
var t0Offset = printer . Settings . Helpers . ExtruderOffset ( 0 ) ;
if ( t0Offset ! = Vector3 . Zero )
{
errors . Add (
new SettingsValidationError ( SettingsKey . extruder_offset )
{
Error = "Nozzle 1 should have offsets set to 0." . Localize ( ) ,
ValueDetails = "{0} = {1}\n{2} = {3}" . FormatWith (
GetSettingsName ( SettingsKey . extruder_offset ) ,
settings . GetValue < double > ( SettingsKey . extruder_offset ) ,
GetSettingsName ( SettingsKey . extruder_offset ) ,
settings . GetValue < double > ( SettingsKey . extruder_offset ) ) ,
2021-02-19 17:40:24 -08:00
ErrorLevel = ValidationErrorLevel . Warning ,
2021-02-09 16:54:31 -08:00
} ) ;
}
}
2020-08-27 07:47:37 -07:00
// Check to see if current OEM layer matches downloaded OEM layer
{
2020-10-30 18:03:37 -07:00
if ( printer . Settings . GetValue ( SettingsKey . make ) ! = "Other"
& & ProfileManager . GetOemSettingsNeedingUpdate ( printer ) . Any ( ) )
2020-08-27 07:47:37 -07:00
{
2020-08-28 13:51:20 -07:00
errors . Add ( new ValidationError ( ValidationErrors . SettingsUpdateAvailable )
2020-08-27 07:47:37 -07:00
{
2020-08-28 13:51:20 -07:00
Error = "Settings Update Available" . Localize ( ) ,
Details = "The default settings for this printer have changed and can be updated" . Localize ( ) ,
ErrorLevel = ValidationErrorLevel . Warning ,
FixAction = new NamedAction ( )
2020-08-27 07:47:37 -07:00
{
2020-08-28 13:51:20 -07:00
Title = "Update Settings..." . Localize ( ) ,
Action = ( ) = >
2020-08-27 07:47:37 -07:00
{
2020-08-28 13:51:20 -07:00
DialogWindow . Show ( new UpdateSettingsPage ( printer ) ) ;
2020-08-27 07:47:37 -07:00
}
2020-08-28 13:51:20 -07:00
}
} ) ;
2020-08-27 07:47:37 -07:00
}
}
2019-05-16 15:56:43 -07:00
if ( printer . Connection . IsConnected
& & ! PrinterSetupRequired ( printer )
& & validatePrintBed
& & errors . Count ( e = > e . ErrorLevel = = ValidationErrorLevel . Error ) = = 0
2019-04-30 08:19:29 -07:00
& & ! printer . PrintableItems ( printer . Bed . Scene ) . Any ( ) )
2019-04-24 21:06:10 -07:00
{
2020-08-28 06:57:45 -07:00
errors . Add ( new ValidationError ( ValidationErrors . NoPrintableParts )
2019-04-24 21:06:10 -07:00
{
Error = "Empty Bed" . Localize ( ) ,
Details = "No printable parts exists within the bounds of the printer bed. Add content to continue" . Localize ( ) ,
ErrorLevel = ValidationErrorLevel . Error ,
} ) ;
}
2018-11-24 07:52:33 -08:00
try
{
if ( settings . GetValue < bool > ( SettingsKey . validate_layer_height ) )
{
if ( settings . GetValue < double > ( SettingsKey . layer_height ) > settings . GetValue < double > ( SettingsKey . nozzle_diameter ) )
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( SettingsKey . layer_height )
2019-01-04 17:09:42 -08:00
{
Error = "{0} must be less than or equal to the {1}." . Localize ( ) . FormatWith (
2019-01-05 12:04:49 -08:00
GetSettingsName ( SettingsKey . layer_height ) ,
GetSettingsName ( SettingsKey . nozzle_diameter ) ) ,
2019-01-05 12:25:08 -08:00
ValueDetails = "{0} = {1}\n{2} = {3}" . FormatWith (
2019-01-05 12:04:49 -08:00
GetSettingsName ( SettingsKey . layer_height ) ,
settings . GetValue < double > ( SettingsKey . layer_height ) ,
GetSettingsName ( SettingsKey . nozzle_diameter ) ,
settings . GetValue < double > ( SettingsKey . nozzle_diameter ) ) ,
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
else if ( settings . GetValue < double > ( SettingsKey . layer_height ) < = 0 )
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( SettingsKey . layer_height )
2019-01-04 17:09:42 -08:00
{
Error = "{0} must be greater than 0." . Localize ( ) . FormatWith ( GetSettingsName ( SettingsKey . layer_height ) ) ,
} ) ;
2018-11-24 07:52:33 -08:00
}
2019-01-04 22:21:34 -08:00
if ( settings . GetValue < double > ( SettingsKey . first_layer_height ) > settings . GetValue < double > ( SettingsKey . nozzle_diameter ) )
2018-11-24 07:52:33 -08:00
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( SettingsKey . first_layer_height )
2019-01-04 17:09:42 -08:00
{
Error = "{0} must be less than or equal to the {1}." . Localize ( ) . FormatWith (
2019-01-05 12:26:48 -08:00
GetSettingsName ( SettingsKey . first_layer_height ) ,
2019-01-04 17:09:42 -08:00
GetSettingsName ( SettingsKey . nozzle_diameter ) ) ,
2019-01-05 12:25:08 -08:00
ValueDetails = "{0} = {1}\n{2} = {3}" . FormatWith (
2019-01-05 12:04:49 -08:00
GetSettingsName ( SettingsKey . first_layer_height ) ,
settings . GetValue < double > ( SettingsKey . first_layer_height ) ,
GetSettingsName ( SettingsKey . nozzle_diameter ) ,
settings . GetValue < double > ( SettingsKey . nozzle_diameter ) ) ,
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
}
2018-11-29 13:13:18 -08:00
string [ ] startGCode = settings . GetValue ( SettingsKey . start_gcode ) . Replace ( "\\n" , "\n" ) . Split ( '\n' ) ;
2019-03-08 08:07:12 -08:00
// Print recovery is incompatible with firmware leveling - ensure not enabled in startGCode
2020-09-30 18:38:34 -07:00
if ( settings . GetValue < bool > ( SettingsKey . recover_is_enabled )
& & ! settings . GetValue < bool > ( SettingsKey . has_hardware_leveling ) )
2018-11-24 07:52:33 -08:00
{
2019-03-08 08:07:12 -08:00
// Ensure we don't have hardware leveling commands in the start gcode.
2018-11-24 07:52:33 -08:00
foreach ( string startGCodeLine in startGCode )
{
if ( startGCodeLine . StartsWith ( "G29" ) )
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( SettingsKey . start_gcode )
2019-01-04 17:09:42 -08:00
{
Error = "Start G-Code cannot contain G29 if Print Recovery is enabled." . Localize ( ) ,
2019-01-04 17:49:58 -08:00
Details = "Your Start G-Code should not contain a G29 if you are planning on using Print Recovery. Change your start G-Code or turn off Print Recovery." . Localize ( ) ,
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
if ( startGCodeLine . StartsWith ( "G30" ) )
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( SettingsKey . start_gcode )
2019-01-04 17:09:42 -08:00
{
Error = "Start G-Code cannot contain G30 if Print Leveling is enabled." . Localize ( ) ,
2019-01-04 17:49:58 -08:00
Details = "Your Start G-Code should not contain a G30 if you are planning on using Print Recovery. Change your start G-Code or turn off Print Recovery." . Localize ( ) ,
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
}
}
2020-09-30 18:38:34 -07:00
var levelingEnabled = printer . Settings . GetValue < bool > ( SettingsKey . print_leveling_enabled ) & ! settings . GetValue < bool > ( SettingsKey . has_hardware_leveling ) ;
2019-03-08 08:03:12 -08:00
var levelingRequired = printer . Settings . GetValue < bool > ( SettingsKey . print_leveling_required_to_print ) ;
if ( levelingEnabled | | levelingRequired )
2018-11-24 07:52:33 -08:00
{
2019-03-08 08:07:12 -08:00
// Ensure we don't have hardware leveling commands in the start gcode.
2018-11-24 07:52:33 -08:00
foreach ( string startGCodeLine in startGCode )
{
if ( startGCodeLine . StartsWith ( "G29" ) )
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( SettingsKey . start_gcode )
2019-01-04 17:09:42 -08:00
{
Error = "Start G-Code cannot contain G29 if Print Leveling is enabled." . Localize ( ) ,
2019-01-04 17:49:58 -08:00
Details = "Your Start G-Code should not contain a G29 if you are planning on using print leveling. Change your start G-Code or turn off print leveling." . Localize ( ) ,
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
if ( startGCodeLine . StartsWith ( "G30" ) )
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( SettingsKey . start_gcode )
2019-01-04 17:09:42 -08:00
{
Error = "Start G-Code cannot contain G30 if Print Leveling is enabled." . Localize ( ) ,
2019-01-04 17:49:58 -08:00
Details = "Your Start G-Code should not contain a G30 if you are planning on using print leveling. Change your start G-Code or turn off print leveling." . Localize ( ) ,
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
}
2019-03-08 08:52:17 -08:00
bool heatedBed = printer . Settings . GetValue < bool > ( SettingsKey . has_heated_bed ) ;
double bedTemperature = printer . Settings . GetValue < double > ( SettingsKey . bed_temperature ) ;
if ( heatedBed
2019-05-16 15:56:43 -07:00
& & printer . Connection . IsConnected
& & ! PrinterSetupRequired ( printer )
& & printer . Settings . Helpers . PrintLevelingData is PrintLevelingData levelingData
2019-03-08 08:52:17 -08:00
& & ! levelingData . IssuedLevelingTempWarning
2020-11-13 16:36:03 -08:00
& & Math . Abs ( bedTemperature - levelingData . BedTemperature ) > 10
2020-12-05 07:32:10 -08:00
& & ! printer . Settings . Helpers . ValidateLevelingWithProbe )
2019-03-08 08:52:17 -08:00
{
errors . Add (
2020-08-28 06:57:45 -07:00
new ValidationError ( ValidationErrors . BedLevelingTemperature )
2019-03-08 08:52:17 -08:00
{
Error = "Bed Leveling Temperature" . Localize ( ) ,
Details = string . Format (
"Bed Leveling data created at {0}°C versus current {1}°C" . Localize ( ) ,
levelingData . BedTemperature ,
bedTemperature ) ,
ErrorLevel = ValidationErrorLevel . Warning ,
FixAction = new NamedAction ( )
{
2019-03-08 16:59:04 -08:00
Title = "Recalibrate" ,
2019-03-08 08:52:17 -08:00
Action = ( ) = >
{
2019-03-08 16:59:04 -08:00
UiThread . RunOnIdle ( ( ) = >
{
DialogWindow . Show ( new PrintLevelingWizard ( printer ) ) ;
} ) ;
} ,
2019-05-11 12:08:03 -07:00
IsEnabled = ( ) = > printer . Connection . IsConnected
2019-03-08 08:52:17 -08:00
}
} ) ;
}
2020-09-30 14:35:26 -07:00
2020-11-04 16:53:30 -08:00
if ( levelingEnabled
& & ! settings . GetValue < bool > ( SettingsKey . has_hardware_leveling )
& & settings . GetValue < bool > ( SettingsKey . has_z_probe )
& & settings . GetValue < bool > ( SettingsKey . use_z_probe )
& & settings . GetValue < bool > ( SettingsKey . validate_leveling )
& & ( settings . GetValue < double > ( SettingsKey . validation_threshold ) < . 001
| | settings . GetValue < double > ( SettingsKey . validation_threshold ) > . 5 ) )
{
var threshold = settings . GetValue < double > ( SettingsKey . validation_threshold ) ;
errors . Add (
new SettingsValidationError ( SettingsKey . validation_threshold )
{
Error = "The Validation Threshold mush be greater than 0 and less than .5mm. It is currently {0}." . Localize ( ) . FormatWith ( threshold ) ,
ValueDetails = "{0} = {1}" . FormatWith ( GetSettingsName ( SettingsKey . validation_threshold ) , threshold ) ,
} ) ;
}
2020-09-30 14:35:26 -07:00
// check if the leveling data has too large a range
if ( printer . Settings . Helpers . PrintLevelingData . SampledPositions . Count > 3 )
{
var minLevelZ = double . MaxValue ;
var maxLevelZ = double . MinValue ;
foreach ( var levelPosition in printer . Settings . Helpers . PrintLevelingData . SampledPositions )
{
minLevelZ = Math . Min ( minLevelZ , levelPosition . Z ) ;
2020-09-30 18:31:47 -07:00
maxLevelZ = Math . Max ( maxLevelZ , levelPosition . Z ) ;
2020-09-30 14:35:26 -07:00
}
var delta = maxLevelZ - minLevelZ ;
var maxDelta = printer . Settings . GetValue < double > ( SettingsKey . nozzle_diameter ) * 10 ;
if ( delta > maxDelta )
{
errors . Add (
new ValidationError ( ValidationErrors . BedLevelingMesh )
{
2020-09-30 18:31:47 -07:00
Error = "Leveling Data Warning" . Localize ( ) ,
Details = "The leveling data might be invalid. It changes by as much as {0:0.##}mm. Leveling calibration should be re-run" . Localize ( ) . FormatWith ( delta ) ,
2020-09-30 14:35:26 -07:00
ErrorLevel = ValidationErrorLevel . Warning ,
FixAction = new NamedAction ( )
{
Title = "Recalibrate" ,
Action = ( ) = >
{
UiThread . RunOnIdle ( ( ) = >
{
DialogWindow . Show ( new PrintLevelingWizard ( printer ) ) ;
} ) ;
} ,
IsEnabled = ( ) = > printer . Connection . IsConnected
}
} ) ;
}
}
2018-11-24 07:52:33 -08:00
}
2020-08-11 11:06:56 -07:00
printer . Settings . ForTools < double > ( SettingsKey . baby_step_z_offset , ( key , value , i ) = >
2018-11-24 07:52:33 -08:00
{
2020-08-11 11:06:56 -07:00
// Make sure the z offsets are not too big
if ( Math . Abs ( value ) > 2 )
{
// Static path generation for non-SliceSettings value
var location = "Location" . Localize ( ) + ":"
+ "\n" + "Controls" . Localize ( )
+ "\n • " + "Movement" . Localize ( )
+ "\n • " + "Z Offset" . Localize ( ) ;
2020-08-09 12:37:37 -07:00
2020-08-11 11:06:56 -07:00
errors . Add (
2020-08-28 06:57:45 -07:00
new ValidationError ( ValidationErrors . ZOffset )
2020-08-11 11:06:56 -07:00
{
Error = "Z Offset is too large." . Localize ( ) ,
Details = string . Format (
"{0}\n\n{1}" ,
"The Z Offset for your printer, sometimes called Baby Stepping, is greater than 2mm and invalid. Clear the value and re-level the bed." . Localize ( ) ,
location )
} ) ;
}
} ) ;
2018-11-24 07:52:33 -08:00
if ( settings . GetValue < double > ( SettingsKey . first_layer_extrusion_width ) > settings . GetValue < double > ( SettingsKey . nozzle_diameter ) * 4 )
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( SettingsKey . first_layer_extrusion_width )
2019-01-04 17:09:42 -08:00
{
Error = "{0} must be less than or equal to the {1} * 4." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . first_layer_extrusion_width ) ,
GetSettingsName ( SettingsKey . nozzle_diameter ) ) ,
2019-01-05 12:25:08 -08:00
ValueDetails = "{0} = {1}\n{2} = {3}" . FormatWith (
2019-01-05 12:04:49 -08:00
GetSettingsName ( SettingsKey . first_layer_extrusion_width ) ,
settings . GetValue < double > ( SettingsKey . first_layer_extrusion_width ) ,
GetSettingsName ( SettingsKey . nozzle_diameter ) ,
settings . GetValue < double > ( SettingsKey . nozzle_diameter ) )
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
if ( settings . GetValue < double > ( SettingsKey . first_layer_extrusion_width ) < = 0 )
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( SettingsKey . first_layer_extrusion_width )
2019-01-04 17:09:42 -08:00
{
Error = "{0} must be greater than 0." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . first_layer_extrusion_width ) ) ,
2019-01-05 12:25:08 -08:00
ValueDetails = "{0} = {1}" . FormatWith (
2019-01-04 17:49:58 -08:00
GetSettingsName ( SettingsKey . first_layer_extrusion_width ) ,
settings . GetValue < double > ( SettingsKey . first_layer_extrusion_width ) ) ,
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
2021-01-26 17:26:10 -08:00
if ( settings . GetValue < double > ( SettingsKey . fill_density ) < = 0 )
{
errors . Add (
new SettingsValidationError ( SettingsKey . fill_density )
{
Error = "{0} should be greater than 0." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . fill_density ) ) ,
ErrorLevel = ValidationErrorLevel . Warning ,
ValueDetails = "{0} = {1}" . FormatWith (
GetSettingsName ( SettingsKey . fill_density ) ,
settings . GetValue < double > ( SettingsKey . fill_density ) ) ,
} ) ;
}
if ( settings . GetValue < double > ( SettingsKey . perimeters ) < = 0 )
{
errors . Add (
new SettingsValidationError ( SettingsKey . perimeters )
{
Error = "{0} should be greater than 0." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . perimeters ) ) ,
ErrorLevel = ValidationErrorLevel . Warning ,
ValueDetails = "{0} = {1}" . FormatWith (
GetSettingsName ( SettingsKey . perimeters ) ,
settings . GetValue < double > ( SettingsKey . perimeters ) ) ,
} ) ;
}
2020-09-20 07:59:48 -07:00
if ( settings . GetValue < double > ( SettingsKey . infill_overlap_perimeter ) < - settings . GetValue < double > ( SettingsKey . nozzle_diameter )
2020-09-20 08:30:15 -07:00
| | settings . GetValue < double > ( SettingsKey . infill_overlap_perimeter ) > settings . GetValue < double > ( SettingsKey . nozzle_diameter ) )
2020-09-20 07:59:48 -07:00
{
errors . Add (
new SettingsValidationError ( SettingsKey . infill_overlap_perimeter )
{
Error = "{0} must be greater than 0 and less than your nozzle diameter. You may be missing a '%'." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . infill_overlap_perimeter ) ) ,
ValueDetails = "{0} = {1}, {2} = {3}" . FormatWith (
GetSettingsName ( SettingsKey . infill_overlap_perimeter ) ,
settings . GetValue < double > ( SettingsKey . infill_overlap_perimeter ) ,
GetSettingsName ( SettingsKey . nozzle_diameter ) ,
settings . GetValue < double > ( SettingsKey . nozzle_diameter ) ) ,
} ) ;
}
2021-02-12 10:06:11 -08:00
if ( printer . Connection . IsConnected
& & printer . Settings ? . Helpers . ComPort ( ) = = "Emulator"
& & fffPrinter )
2018-11-24 07:52:33 -08:00
{
2019-01-04 17:09:42 -08:00
errors . Add (
2020-11-13 16:36:03 -08:00
new SettingsValidationError ( SettingsKey . com_port , "Connected to Emulator" . Localize ( ) )
2019-01-04 17:09:42 -08:00
{
2020-09-20 08:30:15 -07:00
Error = "You are connected to the Emulator not an actual printer." . Localize ( ) ,
ErrorLevel = ValidationErrorLevel . Warning ,
2021-03-05 15:07:50 -08:00
FixAction = new NamedAction ( )
{
Title = "Switch" . Localize ( ) ,
IsEnabled = ( ) = > ! printer . Connection . Printing & & ! printer . Connection . Paused ,
Action = ( ) = > UiThread . RunOnIdle ( ( ) = >
{
// make sure we are not connected or we can't change the port
printer . Connection . Disable ( ) ;
// User initiated connect attempt failed, show port selection dialog
DialogWindow . Show ( new SetupStepComPortOne ( printer ) ) ;
} )
}
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
if ( settings . GetValue < double > ( SettingsKey . external_perimeter_extrusion_width ) < = 0 )
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( SettingsKey . external_perimeter_extrusion_width )
2019-01-04 17:09:42 -08:00
{
Error = "{0} must be greater than 0." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . external_perimeter_extrusion_width ) ) ,
2019-01-05 12:25:08 -08:00
ValueDetails = "{0} = {1}" . FormatWith (
2019-01-04 17:49:58 -08:00
GetSettingsName ( SettingsKey . external_perimeter_extrusion_width ) ,
settings . GetValue < double > ( SettingsKey . external_perimeter_extrusion_width ) ) ,
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
if ( settings . GetValue < double > ( SettingsKey . min_fan_speed ) > 100 )
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( SettingsKey . min_fan_speed )
2019-01-04 17:09:42 -08:00
{
Error = "The {0} can only go as high as 100%." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . min_fan_speed ) ) ,
2019-01-05 12:25:08 -08:00
ValueDetails = "It is currently set to {0}." . Localize ( ) . FormatWith (
2019-01-04 17:49:58 -08:00
settings . GetValue < double > ( SettingsKey . min_fan_speed ) ) ,
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
if ( settings . GetValue < double > ( SettingsKey . max_fan_speed ) > 100 )
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( SettingsKey . max_fan_speed )
2019-01-04 17:09:42 -08:00
{
Error = "The {0} can only go as high as 100%." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . max_fan_speed ) ) ,
2019-01-05 12:25:08 -08:00
ValueDetails = "It is currently set to {0}." . Localize ( ) . FormatWith (
2019-01-04 17:49:58 -08:00
settings . GetValue < double > ( SettingsKey . max_fan_speed ) ) ,
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
2019-02-11 13:57:00 -08:00
if ( extruderCount < 1 )
2018-11-24 07:52:33 -08:00
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( SettingsKey . extruder_count )
2019-01-04 17:09:42 -08:00
{
Error = "The {0} must be at least 1." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . extruder_count ) ) ,
2019-02-11 13:57:00 -08:00
ValueDetails = "It is currently set to {0}." . Localize ( ) . FormatWith ( extruderCount ) ,
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
if ( settings . GetValue < double > ( SettingsKey . fill_density ) < 0 | | settings . GetValue < double > ( SettingsKey . fill_density ) > 1 )
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( SettingsKey . fill_density )
2019-01-04 17:09:42 -08:00
{
2019-01-04 17:49:58 -08:00
Error = "The {0} must be between 0 and 1." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . fill_density ) ) ,
2019-01-05 12:25:08 -08:00
ValueDetails = "It is currently set to {0}." . Localize ( ) . FormatWith (
2019-01-04 17:49:58 -08:00
settings . GetValue < double > ( SettingsKey . fill_density ) ) ,
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
2019-01-04 18:25:33 -08:00
// marlin firmware can only take a max of 128 bytes in a single instruction, make sure no lines are longer than that
2019-01-03 16:58:05 -08:00
ValidateGCodeLinesShortEnough ( SettingsKey . cancel_gcode , printer , errors ) ;
ValidateGCodeLinesShortEnough ( SettingsKey . connect_gcode , printer , errors ) ;
ValidateGCodeLinesShortEnough ( SettingsKey . end_gcode , printer , errors ) ;
ValidateGCodeLinesShortEnough ( SettingsKey . layer_gcode , printer , errors ) ;
ValidateGCodeLinesShortEnough ( SettingsKey . pause_gcode , printer , errors ) ;
ValidateGCodeLinesShortEnough ( SettingsKey . resume_gcode , printer , errors ) ;
ValidateGCodeLinesShortEnough ( SettingsKey . start_gcode , printer , errors ) ;
2018-11-29 13:13:18 -08:00
2018-11-24 07:52:33 -08:00
// If the given speed is part of the current slice engine then check that it is greater than 0.
2019-01-04 21:46:22 -08:00
ValidateGoodSpeedSettingGreaterThan0 ( SettingsKey . bridge_speed , printer , errors ) ;
ValidateGoodSpeedSettingGreaterThan0 ( SettingsKey . air_gap_speed , printer , errors ) ;
ValidateGoodSpeedSettingGreaterThan0 ( SettingsKey . external_perimeter_speed , printer , errors ) ;
2019-01-03 16:58:05 -08:00
ValidateGoodSpeedSettingGreaterThan0 ( SettingsKey . first_layer_speed , printer , errors ) ;
2019-01-04 21:46:22 -08:00
ValidateGoodSpeedSettingGreaterThan0 ( SettingsKey . infill_speed , printer , errors ) ;
ValidateGoodSpeedSettingGreaterThan0 ( SettingsKey . perimeter_speed , printer , errors ) ;
ValidateGoodSpeedSettingGreaterThan0 ( SettingsKey . small_perimeter_speed , printer , errors ) ;
ValidateGoodSpeedSettingGreaterThan0 ( SettingsKey . solid_infill_speed , printer , errors ) ;
ValidateGoodSpeedSettingGreaterThan0 ( SettingsKey . support_material_speed , printer , errors ) ;
2019-01-03 16:58:05 -08:00
ValidateGoodSpeedSettingGreaterThan0 ( SettingsKey . top_solid_infill_speed , printer , errors ) ;
2019-01-04 21:46:22 -08:00
ValidateGoodSpeedSettingGreaterThan0 ( SettingsKey . travel_speed , printer , errors ) ;
ValidateGoodSpeedSettingGreaterThan0 ( SettingsKey . retract_speed , printer , errors ) ;
2018-11-24 07:52:33 -08:00
}
catch ( Exception e )
{
2019-01-04 17:09:42 -08:00
errors . Add (
2020-08-28 06:57:45 -07:00
new ValidationError ( ValidationErrors . ExceptionDuringSliceSettingsValidation )
2019-01-04 17:09:42 -08:00
{
Error = "Unexpected error validating settings" . Localize ( ) ,
Details = e . Message
} ) ;
2018-11-24 07:52:33 -08:00
}
2019-01-03 16:58:05 -08:00
return errors ;
2018-11-24 07:52:33 -08:00
}
2019-01-24 08:24:18 -08:00
/// <summary>
2019-05-11 12:08:03 -07:00
/// Validates printer satisfies all requirements.
2019-01-24 08:24:18 -08:00
/// </summary>
2019-05-11 12:08:03 -07:00
/// <param name="printer">The printer to validate.</param>
/// <returns>A list of all warnings and errors.</returns>
2019-05-16 15:31:19 -07:00
public static List < ValidationError > Validate ( this PrinterConfig printer )
2019-01-24 08:24:18 -08:00
{
var errors = new List < ValidationError > ( ) ;
2021-02-12 10:06:11 -08:00
var fffPrinter = printer . Settings . Slicer . PrinterType = = PrinterType . FFF ;
if ( ! printer . Connection . IsConnected
& & fffPrinter )
2019-01-24 08:24:18 -08:00
{
2020-08-28 06:57:45 -07:00
errors . Add ( new ValidationError ( ValidationErrors . PrinterDisconnected )
2019-01-24 08:24:18 -08:00
{
Error = "Printer Disconnected" . Localize ( ) ,
2019-03-08 17:17:04 -08:00
Details = "Connect to your printer to continue" . Localize ( ) ,
FixAction = new NamedAction ( )
{
Title = "Connect" . Localize ( ) ,
2019-04-05 12:06:22 -07:00
Action = ( ) = > ApplicationController . Instance . ConnectToPrinter ( printer )
2019-03-08 17:17:04 -08:00
}
2019-01-24 08:24:18 -08:00
} ) ;
}
2019-05-16 15:56:43 -07:00
if ( PrinterSetupRequired ( printer ) )
2019-01-24 08:24:18 -08:00
{
2020-08-28 06:57:45 -07:00
errors . Add ( new ValidationError ( ValidationErrors . PrinterSetupRequired )
2019-01-24 08:24:18 -08:00
{
Error = "Printer Setup Required" . Localize ( ) ,
Details = "Printer Setup must be run before printing" . Localize ( ) ,
FixAction = new NamedAction ( )
{
ID = "SetupPrinter" ,
Title = "Setup" . Localize ( ) + "..." ,
Action = ( ) = >
{
2019-05-01 13:28:32 -07:00
UiThread . RunOnIdle ( ( ) = >
2019-01-24 08:24:18 -08:00
{
2019-05-01 13:28:32 -07:00
DialogWindow . Show (
new PrinterCalibrationWizard ( printer , AppContext . Theme ) ,
advanceToIncompleteStage : true ) ;
2019-01-24 08:24:18 -08:00
} ) ;
}
}
} ) ;
}
2019-03-29 13:58:39 -07:00
// Concatenate printer and settings errors
2019-06-14 14:13:23 -07:00
errors . AddRange ( printer . ValidateSettings ( validatePrintBed : ! printer . Bed . EditContext . IsGGCodeSource ) ) ;
2019-01-24 08:24:18 -08:00
return errors ;
}
2019-05-16 15:56:43 -07:00
private static bool PrinterSetupRequired ( PrinterConfig printer )
{
return printer . Connection . IsConnected
& & PrinterCalibrationWizard . SetupRequired ( printer , requiresLoadedFilament : true ) ;
}
2018-11-24 07:52:33 -08:00
private static string GetSettingsName ( string settingsKey )
{
2019-01-06 13:19:01 -08:00
var settingData = PrinterSettings . SettingsData [ settingsKey ] ;
2018-11-24 07:52:33 -08:00
return settingData . PresentationName . Localize ( ) ;
}
2019-01-04 21:24:21 -08:00
private static bool ValidateGCodeLinesShortEnough ( string settingsKey , PrinterConfig printer , List < ValidationError > errors )
2018-11-29 13:13:18 -08:00
{
// make sure the custom gcode does not have lines too long to print
2019-01-04 21:25:04 -08:00
foreach ( string line in printer . Settings . GetValue ( settingsKey ) . Replace ( "\\n" , "\n" ) . Split ( '\n' ) )
2018-11-29 13:13:18 -08:00
{
var trimedLine = line . Split ( ';' ) [ 0 ] . Trim ( ) ;
var length = trimedLine . Length ;
if ( length > 100 )
{
2019-01-06 11:38:12 -08:00
var details = "Found a line that is {0} characters long.\n{1}..." . Localize ( ) . FormatWith ( length , trimedLine . Substring ( 0 , 20 ) ) ;
errors . Add (
new SettingsValidationError ( settingsKey )
{
Error = "All G-Code lines mush be shorter than 100 characters (excluding comments)." . Localize ( ) . FormatWith (
GetSettingsName ( settingsKey ) ) ,
Details = details ,
} ) ;
2019-01-04 17:09:42 -08:00
2018-11-29 13:13:18 -08:00
return false ;
}
}
return true ;
}
2019-01-04 21:58:16 -08:00
private static void ValidateGoodSpeedSettingGreaterThan0 ( string settingsKey , PrinterConfig printer , List < ValidationError > errors )
2018-11-24 07:52:33 -08:00
{
2019-01-04 21:58:16 -08:00
var actualSpeedValueString = printer . Settings . GetValue ( settingsKey ) ;
2018-11-24 07:52:33 -08:00
var speedValueString = actualSpeedValueString ;
if ( speedValueString . EndsWith ( "%" ) )
{
speedValueString = speedValueString . Substring ( 0 , speedValueString . Length - 1 ) ;
}
2019-01-04 17:09:42 -08:00
2018-11-24 07:52:33 -08:00
bool valueWasNumber = true ;
2019-01-04 17:09:42 -08:00
if ( ! double . TryParse ( speedValueString , out double speedToCheck ) )
2018-11-24 07:52:33 -08:00
{
valueWasNumber = false ;
}
if ( ! valueWasNumber
2019-06-26 18:27:23 -07:00
| | ( printer . Settings . IsActive ( settingsKey )
2018-11-24 07:52:33 -08:00
& & speedToCheck < = 0 ) )
{
2019-01-04 17:09:42 -08:00
errors . Add (
2019-01-04 21:58:16 -08:00
new SettingsValidationError ( settingsKey )
2019-01-04 17:09:42 -08:00
{
2019-01-06 11:38:12 -08:00
Error = "The {0} must be greater than 0." . Localize ( ) . FormatWith ( GetSettingsName ( settingsKey ) ) ,
2019-01-04 17:49:58 -08:00
Details = "It is currently set to {0}." . Localize ( ) . FormatWith ( actualSpeedValueString ) ,
2019-01-04 17:09:42 -08:00
} ) ;
2018-11-24 07:52:33 -08:00
}
}
}
}