2022-09-20 18:01:15 -07:00
/ *
Copyright ( c ) 2022 , Lars Brubaker
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 ;
2016-05-19 17:55:46 -07:00
using System.Collections.Generic ;
2016-09-20 09:39:57 -07:00
using System.IO ;
2016-05-19 17:55:46 -07:00
using System.Linq ;
2017-08-20 02:34:39 -07:00
using MatterHackers.Agg.Platform ;
2016-09-20 09:39:57 -07:00
using MatterHackers.MatterControl.SlicerConfiguration ;
2016-07-20 20:05:56 -07:00
using MatterHackers.MatterControl.Tests.Automation ;
2016-09-20 09:39:57 -07:00
using NUnit.Framework ;
2022-07-15 17:28:39 -07:00
using TestInvoker ;
2016-05-19 17:55:46 -07:00
namespace MatterControl.Tests.MatterControl
{
2016-07-26 15:34:52 -07:00
[TestFixture, Category("OemProfiles")]
public class OemProfileTests
2016-05-19 17:55:46 -07:00
{
2017-09-22 10:31:05 -07:00
private static List < PrinterTestDetails > allPrinters ;
2022-07-15 17:28:39 -07:00
private static string printerSettingsDirectory = Path . Combine ( MatterControlUtilities . StaticDataPath , "Profiles" ) ;
2016-05-19 17:55:46 -07:00
2022-01-24 11:12:46 -08:00
private string pauseGCode = @ "M76 ; pause print timer
G91
G1 Z10 E - 5.0 F1800
G90
2022-01-25 16:27:22 -08:00
G1 X5 F [ travel_speed ]
2022-01-24 11:12:46 -08:00
M300 S3000 P30 ; Pause Tone
M300 S1500 P30 ; Pause Tone
M300 S3000 P30 ; Pause Tone
M300 S1500 P30 ; Pause Tone
M300 S3000 P30 ; Pause Tone
M300 S1500 P30 ; Pause Tone
M300 S3000 P30 ; Pause Tone
M300 S1500 P30 ; Pause Tone
M300 S750 P30 ; Pause Tone
M300 S1500 P30 ; Pause Tone
M300 S750 P30 ; Pause Tone
M300 S1500 P30 ; Pause Tone
M300 S750 P30 ; Pause Tone
M300 S1500 P30 ; Pause Tone
M300 S750 P30 ; Pause Tone ";
2022-01-25 16:27:22 -08:00
private string resumeGCode = @ "M75 ; Start the print job timer
G91
G1 Z - 10 F1800
G90
M300 S750 P30 ; Resume Tone
M300 S1500 P30 ; Resume Tone
M300 S750 P30 ; Resume Tone
M300 S1500 P30 ; Resume Tone
M300 S750 P30 ; Resume Tone
M300 S1500 P30 ; Resume Tone
M300 S750 P30 ; Resume Tone
M300 S1500 P30 ; Resume Tone
M300 S3000 P30 ; Resume Tone
M300 S1500 P30 ; Resume Tone
M300 S3000 P30 ; Resume Tone
M300 S1500 P30 ; Resume Tone
M300 S3000 P30 ; Resume Tone
M300 S1500 P30 ; Resume Tone
M300 S3000 P30 ; Resume Tone ";
2016-07-26 15:34:52 -07:00
static OemProfileTests ( )
2016-05-19 17:55:46 -07:00
{
2022-07-15 17:28:39 -07:00
StaticData . RootPath = MatterControlUtilities . StaticDataPath ;
MatterControlUtilities . OverrideAppDataLocation ( MatterControlUtilities . RootPath ) ;
2016-07-20 15:23:26 -07:00
allPrinters = ( from printerFile in new DirectoryInfo ( printerSettingsDirectory ) . GetFiles ( "*.printer" , SearchOption . AllDirectories )
2017-09-22 10:31:05 -07:00
select new PrinterTestDetails
2016-05-19 17:55:46 -07:00
{
2016-07-19 17:28:06 -07:00
PrinterName = printerFile . Name ,
2016-08-08 15:58:55 -07:00
Oem = printerFile . Directory . Name ,
2016-07-19 17:28:06 -07:00
ConfigPath = printerFile . FullName ,
2016-07-20 15:23:26 -07:00
RelativeFilePath = printerFile . FullName . Substring ( printerSettingsDirectory . Length + 1 ) ,
PrinterSettings = PrinterSettings . LoadFile ( printerFile . FullName )
2016-05-19 17:55:46 -07:00
} ) . ToList ( ) ;
2016-06-07 09:41:12 -07:00
}
2022-07-15 17:28:39 -07:00
[Test, ChildProcessTest]
2022-03-31 17:40:54 -07:00
public void ModifyPulsePrinterProfilesSettings ( )
2021-12-09 10:54:35 -08:00
{
2022-01-24 11:14:33 -08:00
// This is not really a test. It updaets our profiles with new settings.
2022-03-13 11:12:01 -07:00
return ;
2021-12-09 10:54:35 -08:00
2022-07-15 17:28:39 -07:00
StaticData . RootPath = MatterControlUtilities . StaticDataPath ;
MatterControlUtilities . OverrideAppDataLocation ( MatterControlUtilities . RootPath ) ;
2021-12-09 10:54:35 -08:00
string profilePath = @"C:\\Users\\LarsBrubaker\\Downloads\\Pulse E Profiles" ;
allPrinters = ( from printerFile in new DirectoryInfo ( profilePath ) . GetFiles ( "*.printer" , SearchOption . TopDirectoryOnly )
select new PrinterTestDetails
{
PrinterName = printerFile . Name ,
Oem = printerFile . Directory . Name ,
ConfigPath = printerFile . FullName ,
RelativeFilePath = printerFile . FullName . Substring ( printerSettingsDirectory . Length + 1 ) ,
PrinterSettings = PrinterSettings . LoadFile ( printerFile . FullName )
} ) . ToList ( ) ;
2022-01-24 11:12:46 -08:00
string ConvertString ( string input )
{
return input . Replace ( "\n" , "\\n" ) . Replace ( "\r" , "" ) ;
}
2021-12-09 10:54:35 -08:00
void ChangeSettings ( PrinterSettings printerSettings )
{
2022-01-20 14:52:03 -08:00
var printerModel = printerSettings . GetValue ( SettingsKey . model ) ;
2021-12-09 10:54:35 -08:00
// general
printerSettings . SetValue ( SettingsKey . fill_density , "30%" ) ;
printerSettings . SetValue ( SettingsKey . avoid_crossing_perimeters , "1" ) ;
printerSettings . SetValue ( SettingsKey . merge_overlapping_lines , "1" ) ;
printerSettings . SetValue ( SettingsKey . seam_placement , "Centered In Back" ) ;
printerSettings . SetValue ( SettingsKey . expand_thin_walls , "1" ) ;
printerSettings . SetValue ( SettingsKey . coast_at_end_distance , "0" ) ;
printerSettings . SetValue ( SettingsKey . monotonic_solid_infill , "1" ) ;
printerSettings . SetValue ( SettingsKey . infill_overlap_perimeter , "20%" ) ;
printerSettings . SetValue ( SettingsKey . avoid_crossing_max_ratio , "3" ) ;
printerSettings . SetValue ( SettingsKey . perimeter_start_end_overlap , "35" ) ;
// speed
printerSettings . SetValue ( SettingsKey . external_perimeter_speed , "25" ) ;
printerSettings . SetValue ( SettingsKey . perimeter_acceleration , "800" ) ;
printerSettings . SetValue ( SettingsKey . default_acceleration , "1300" ) ;
printerSettings . SetValue ( SettingsKey . bridge_over_infill , "1" ) ;
// adheasion
printerSettings . SetValue ( SettingsKey . create_skirt , "1" ) ;
// support
2022-01-25 16:27:22 -08:00
printerSettings . SetValue ( SettingsKey . retract_lift , ".6" ) ;
2021-12-09 10:54:35 -08:00
printerSettings . SetValue ( SettingsKey . min_extrusion_before_retract , "0" ) ;
printerSettings . SetValue ( SettingsKey . retract_before_travel_avoid , "20" ) ;
2022-01-25 16:27:22 -08:00
// printer gcode settings
printerSettings . SetValue ( SettingsKey . pause_gcode , ConvertString ( pauseGCode ) ) ;
printerSettings . SetValue ( SettingsKey . resume_gcode , ConvertString ( resumeGCode ) ) ;
2022-01-20 14:52:03 -08:00
2022-03-31 17:40:54 -07:00
printerSettings . SetValue ( SettingsKey . support_material_create_perimeter , "1" ) ;
2022-01-25 16:27:22 -08:00
// e series settings
2022-01-24 11:12:46 -08:00
if ( printerModel . Contains ( 'E' ) )
2022-01-20 14:52:03 -08:00
{
2022-03-31 17:40:54 -07:00
// clear all material settings
printerSettings . MaterialLayers = new List < PrinterSettingsLayer > ( ) ;
2022-03-08 17:37:42 -08:00
printerSettings . ActiveMaterialKey = "" ;
printerSettings . SetValue ( SettingsKey . has_swappable_bed , "1" ) ;
printerSettings . SetValue ( SettingsKey . bed_temperature_buildtak , "55" ) ;
printerSettings . SetValue ( SettingsKey . bed_temperature_garolite , "75" ) ;
printerSettings . SetValue ( SettingsKey . bed_temperature_glass , "75" ) ;
printerSettings . SetValue ( SettingsKey . bed_temperature_kapton , "55" ) ;
printerSettings . SetValue ( SettingsKey . bed_temperature_pei , "75" ) ;
printerSettings . SetValue ( SettingsKey . bed_temperature_pp , "55" ) ;
2022-03-11 18:04:32 -08:00
var zHeight = 215 ;
// check the build height based on the extruder type
switch ( printerModel [ 3 ] )
{
case '3' : // Volcano
case '6' : // LGX E3Dv6
zHeight = 205 ;
break ;
}
printerSettings . SetValue ( SettingsKey . build_height , zHeight . ToString ( ) ) ;
2022-03-31 17:40:54 -07:00
// make sure the start gcode travels fast to priming line
var startGCode = printerSettings . GetValue ( SettingsKey . start_gcode ) ;
startGCode = startGCode . Replace ( "G1 Y5 X5 Z0.8 F1800 ; Purge line" , "G1 Y5 X5 [travel_speed] ; Purge line\\nG1 Z0.8 F1800" ) ;
printerSettings . SetValue ( SettingsKey . start_gcode , startGCode ) ;
2022-01-20 14:52:03 -08:00
}
2022-01-25 16:27:22 -08:00
// 32 bit settings
2022-01-20 14:52:03 -08:00
if ( printerModel . Contains ( 'M' ) | | printerModel . Contains ( 'S' ) )
{
2022-01-25 16:27:22 -08:00
// If the board is 32 bit we cannot update the firmware.
2022-01-20 14:52:03 -08:00
// make sure it does not show a firmware updater
printerSettings . SetValue ( SettingsKey . include_firmware_updater , "None" ) ;
}
2021-12-09 10:54:35 -08:00
}
foreach ( var printer in allPrinters )
{
ChangeSettings ( printer . PrinterSettings ) ;
printer . PrinterSettings . Save ( Path . Combine ( Path . GetDirectoryName ( printer . ConfigPath ) , "output" , printer . PrinterName ) , true ) ;
}
int a = 0 ;
}
2022-07-15 17:28:39 -07:00
[Test, ChildProcessTest]
2022-03-23 18:06:35 -07:00
public void AllMaterialsLibraryHasGoodProfiles ( )
2022-03-11 18:04:32 -08:00
{
2022-07-15 17:28:39 -07:00
var materialSettingsDirectory = Path . Combine ( MatterControlUtilities . StaticDataPath , "Materials" ) ;
2022-03-11 18:04:32 -08:00
var directoryInfo = new DirectoryInfo ( materialSettingsDirectory ) ;
var files = directoryInfo . GetFiles ( "*.material" , SearchOption . AllDirectories ) ;
var profiles = files . Select ( f = > PrinterSettings . LoadFile ( f . FullName ) ) . ToList ( ) ;
2022-03-18 15:58:13 -07:00
var allMaterialIds = new HashSet < string > ( ) ;
2022-03-23 18:06:35 -07:00
var notPresentKeys = new string [ ]
{
"brims" ,
"brims_layers" ,
"coast_at_end_distance" ,
"create_brim" ,
"create_skirt" ,
"expand_thin_walls" ,
"extruder_count" ,
"extrusion_multiplier" ,
"extrusion_ratio" ,
"filament_diameter" ,
"fill_angle" ,
// "fill_density", // BASF uses this
"fill_pattern" ,
"fill_thin_gaps" ,
"first_layer_extrusion_width" ,
"first_layer_height" ,
"layer_height" ,
"monotonic_solid_infill"
} ;
var isPresentKeys = new string [ ]
{
2022-03-25 09:53:43 -07:00
"bed_temperature_blue_tape" ,
2022-03-23 18:06:35 -07:00
"bed_temperature_buildtak" ,
"bed_temperature_garolite" ,
"bed_temperature_glass" ,
"bed_temperature_kapton" ,
"bed_temperature_pei" ,
2022-03-29 15:50:08 -07:00
"bed_temperature_pp" ,
2022-03-23 18:06:35 -07:00
"filament_density" ,
"layer_id" ,
"layer_name" ,
"material_sku" ,
"temperature" ,
} ;
2022-03-21 17:59:29 -07:00
for ( var i = 0 ; i < profiles . Count ; i + + )
2022-03-11 18:04:32 -08:00
{
2022-03-21 17:59:29 -07:00
var profile = profiles [ i ] ;
2022-03-11 18:04:32 -08:00
Assert . AreEqual ( 1 , profile . MaterialLayers . Count , "Each material profile should have 1 material in it" ) ;
var material = profile . MaterialLayers [ 0 ] ;
profile . ActiveMaterialKey = material . LayerID ;
2022-03-21 17:59:29 -07:00
Assert . IsTrue ( ! string . IsNullOrEmpty ( profile . GetValue ( SettingsKey . material_sku ) ) , $"All profiles should have a material_sku set {files[i].FullName}" ) ;
Assert . IsTrue ( ! allMaterialIds . Contains ( material . LayerID ) , $"Every material needs a unique Id {files[i].FullName}" ) ;
2022-03-23 18:06:35 -07:00
foreach ( var key in isPresentKeys )
{
Assert . IsTrue ( material . ContainsKey ( key ) , $"Material {files[i].FullName} should include {key} setting" ) ;
}
2022-04-08 14:16:06 -07:00
if ( profile . GetValue ( SettingsKey . layer_name ) . ToLower ( ) . Contains ( "nylon" ) )
{
// make sure the setting for garolite is greater than 0 and not NC
double . TryParse ( profile . GetValue ( SettingsKey . bed_temperature_garolite ) , out double temp ) ;
Assert . Greater ( temp , 0 ) ;
}
2022-03-23 18:06:35 -07:00
foreach ( var key in notPresentKeys )
{
Assert . IsTrue ( ! material . ContainsKey ( key ) , $"Material {files[i].FullName} should not include {key} setting" ) ;
}
2022-03-18 15:58:13 -07:00
allMaterialIds . Add ( material . LayerID ) ;
}
2022-03-11 18:04:32 -08:00
}
2022-09-20 18:01:15 -07:00
[Test]
2016-12-20 10:43:39 -08:00
public void LayerGCodeHasExpectedValue ( )
{
// Verifies "layer_gcode" is expected value: "; LAYER:[layer_num]"
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-12-20 10:43:39 -08:00
{
if ( settings . GetValue ( SettingsKey . layer_gcode ) ! = "; LAYER:[layer_num]" )
{
printer . RuleViolated = true ;
2020-08-13 17:29:01 -07:00
// SetSettingInOem(printer, settings, SettingsKey.layer_gcode, "; LAYER:[layer_num]");
}
} ) ;
}
2016-12-20 10:43:39 -08:00
2020-08-13 17:29:01 -07:00
private static void SetSettingInOem ( PrinterTestDetails printer , PrinterSettings settings , string key , string value )
{
// Fix existing invalid items...
string layerValue ;
if ( settings . OemLayer . TryGetValue ( key , out layerValue ) & & layerValue = = "" )
{
settings . OemLayer . Remove ( key ) ;
}
2016-12-20 10:43:39 -08:00
2020-08-13 17:29:01 -07:00
if ( settings . QualityLayer ? . TryGetValue ( key , out layerValue ) = = true & & layerValue = = "" )
{
settings . QualityLayer . Remove ( key ) ;
}
2016-12-20 10:43:39 -08:00
2020-08-13 17:29:01 -07:00
if ( settings . MaterialLayer ? . TryGetValue ( key , out layerValue ) = = true & & layerValue = = "" )
{
settings . MaterialLayer . Remove ( key ) ;
}
2016-12-20 10:43:39 -08:00
2020-08-13 17:29:01 -07:00
settings . OemLayer [ key ] = value ;
// Reset to default values
settings . UserLayer . Remove ( SettingsKey . active_quality_key ) ;
settings . UserLayer . Remove ( SettingsKey . active_material_key ) ;
settings . StagedUserSettings = new PrinterSettingsLayer ( ) ;
settings . Save ( printer . ConfigPath ) ;
2016-12-20 10:43:39 -08:00
}
2016-07-25 16:13:20 -07:00
[Test]
2016-07-26 15:32:36 -07:00
public void StartGCodeWithExtrudesMustFollowM109Heatup ( )
2016-07-25 16:13:20 -07:00
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-07-25 16:13:20 -07:00
{
2016-07-26 15:32:36 -07:00
// Get the start_gcode string
string startGcode = settings . OemLayer . ValueOrDefault ( SettingsKey . start_gcode ) ? ? string . Empty ;
2016-07-25 16:13:20 -07:00
2016-07-26 15:32:36 -07:00
// Only validate start_gcode configs that have M109 and extrude statements
if ( startGcode . Contains ( "M109" ) & & startGcode . Contains ( "G1 E" ) )
2016-07-25 16:13:20 -07:00
{
2018-11-25 07:39:09 -08:00
// Split start_gcode on newlines
2016-07-25 16:13:20 -07:00
var lines = startGcode . Split ( new string [ ] { "\\n" } , StringSplitOptions . RemoveEmptyEntries ) . Select ( l = > l . ToUpper ( ) . Trim ( ) ) . ToList ( ) ;
2016-07-26 15:32:36 -07:00
// Find first instance of M109 or 'G1 E' extrude
2016-07-25 16:13:20 -07:00
string m109Line = lines . Where ( l = > l . StartsWith ( "M109 " ) ) . FirstOrDefault ( ) ;
2016-07-26 15:32:36 -07:00
string extrudeLine = lines . Where ( l = > l . StartsWith ( "G1 E" ) ) . FirstOrDefault ( ) ;
2016-07-25 16:13:20 -07:00
2020-08-12 07:55:10 -07:00
if ( m109Line = = null )
2016-07-25 16:13:20 -07:00
{
printer . RuleViolated = true ;
return ;
}
int m109Pos = lines . IndexOf ( m109Line ) ;
2016-07-26 15:32:36 -07:00
int extrudePos = lines . IndexOf ( extrudeLine ) ;
2016-07-25 16:13:20 -07:00
Assert . IsNotNull ( m109Line ) ;
2020-08-12 07:55:10 -07:00
// Assert.IsNotNull(emptyExtrudeLine);
// Assert.Greater(emptyExtrudePos, m109Pos);
2016-07-25 16:13:20 -07:00
2016-07-26 15:32:36 -07:00
if ( extrudePos < m109Pos )
2016-07-25 16:13:20 -07:00
{
printer . RuleViolated = true ;
}
}
} ) ;
}
2016-05-19 17:55:46 -07:00
[Test]
public void CsvBedSizeExistsAndHasTwoValues ( )
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-05-19 17:55:46 -07:00
{
2016-06-07 09:49:48 -07:00
// Bed size is not required in slice files
2016-07-20 15:23:26 -07:00
if ( printer . RelativeFilePath . IndexOf ( ".slice" , StringComparison . OrdinalIgnoreCase ) ! = - 1 )
2016-06-07 09:49:48 -07:00
{
return ;
}
2016-06-07 09:41:12 -07:00
2016-07-20 15:23:26 -07:00
string bedSize = settings . GetValue ( SettingsKey . bed_size ) ;
2016-05-19 17:55:46 -07:00
// Must exist in all configs
2016-09-20 09:39:57 -07:00
Assert . IsTrue ( ! string . IsNullOrEmpty ( bedSize ) , "[bed_size] must exist: " + printer . RelativeFilePath ) ;
2016-05-19 17:55:46 -07:00
string [ ] segments = bedSize . Trim ( ) . Split ( ',' ) ;
// Must be a CSV and have two values
2016-07-20 15:23:26 -07:00
Assert . AreEqual ( 2 , segments . Length , "[bed_size] should have two values separated by a comma: " + printer . RelativeFilePath ) ;
2016-05-19 17:55:46 -07:00
} ) ;
}
[Test]
public void CsvPrintCenterExistsAndHasTwoValues ( )
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-05-19 17:55:46 -07:00
{
2016-06-07 09:49:48 -07:00
// Printer center is not required in slice files
2016-07-20 15:23:26 -07:00
if ( printer . RelativeFilePath . IndexOf ( ".slice" , StringComparison . OrdinalIgnoreCase ) ! = - 1 )
2016-06-07 09:49:48 -07:00
{
return ;
}
2016-07-20 15:23:26 -07:00
string printCenter = settings . GetValue ( SettingsKey . print_center ) ;
2016-05-19 17:55:46 -07:00
// Must exist in all configs
2016-09-20 09:39:57 -07:00
Assert . IsTrue ( ! string . IsNullOrEmpty ( printCenter ) , "[print_center] must exist: " + printer . RelativeFilePath ) ;
2016-05-19 17:55:46 -07:00
string [ ] segments = printCenter . Trim ( ) . Split ( ',' ) ;
// Must be a CSV and have only two values
2016-07-20 15:23:26 -07:00
Assert . AreEqual ( 2 , segments . Length , "[print_center] should have two values separated by a comma: " + printer . RelativeFilePath ) ;
2022-03-21 13:55:53 -07:00
#if false
// save out the material settings
foreach ( var materialLayer in settings . MaterialLayers )
{
// create an empyt profile
var materialSettings = new PrinterSettings ( ) ;
// copy just this material setting to it
materialSettings . MaterialLayers . Add ( materialLayer . Clone ( ) ) ;
// save it
var fileName = ApplicationController . Instance . SanitizeFileName ( materialLayer . Name ) ;
if ( ! string . IsNullOrEmpty ( fileName ) )
{
fileName = Path . Combine ( @"C:\temp" , "materials" , fileName ) + ".material" ;
File . WriteAllText ( fileName , JsonConvert . SerializeObject ( materialSettings , Formatting . Indented ) ) ;
}
}
#endif
2016-05-19 17:55:46 -07:00
} ) ;
}
[Test]
public void RetractLengthIsLessThanTwenty ( )
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-05-19 17:55:46 -07:00
{
2019-01-07 09:18:51 -08:00
string retractLengthString = settings . GetValue ( SettingsKey . retract_length ) ;
2016-05-19 17:55:46 -07:00
if ( ! string . IsNullOrEmpty ( retractLengthString ) )
{
float retractLength ;
if ( ! float . TryParse ( retractLengthString , out retractLength ) )
{
2016-07-20 15:23:26 -07:00
Assert . Fail ( "Invalid [retract_length] value (float parse failed): " + printer . RelativeFilePath ) ;
2016-05-19 17:55:46 -07:00
}
2016-07-20 15:23:26 -07:00
Assert . Less ( retractLength , 20 , "[retract_length]: " + printer . RelativeFilePath ) ;
2016-05-19 17:55:46 -07:00
}
} ) ;
}
[Test]
public void ExtruderCountIsGreaterThanZero ( )
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-05-19 17:55:46 -07:00
{
2016-07-20 15:23:26 -07:00
string extruderCountString = settings . GetValue ( "extruder_count" ) ;
2016-05-25 11:04:51 -07:00
if ( ! string . IsNullOrEmpty ( extruderCountString ) )
2016-05-19 17:55:46 -07:00
{
2016-05-25 11:04:51 -07:00
int extruderCount ;
if ( ! int . TryParse ( extruderCountString , out extruderCount ) )
{
2016-07-20 15:23:26 -07:00
Assert . Fail ( "Invalid [extruder_count] value (int parse failed): " + printer . RelativeFilePath ) ;
2016-05-25 11:04:51 -07:00
}
2016-05-19 17:55:46 -07:00
2016-05-25 11:04:51 -07:00
// Must be greater than zero
2016-07-20 15:23:26 -07:00
Assert . Greater ( extruderCount , 0 , "[extruder_count]: " + printer . RelativeFilePath ) ;
2016-05-19 17:55:46 -07:00
}
} ) ;
}
[Test]
public void MinFanSpeedOneHundredOrLess ( )
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-05-19 17:55:46 -07:00
{
2018-10-26 14:51:04 -07:00
string fanSpeedString = settings . GetValue ( SettingsKey . min_fan_speed ) ;
2016-05-19 17:55:46 -07:00
if ( ! string . IsNullOrEmpty ( fanSpeedString ) )
{
// Must be valid int data
int minFanSpeed ;
if ( ! int . TryParse ( fanSpeedString , out minFanSpeed ) )
{
2016-07-20 15:23:26 -07:00
Assert . Fail ( "Invalid [min_fan_speed] value (int parse failed): " + printer . RelativeFilePath ) ;
2016-05-19 17:55:46 -07:00
}
// Must be less than or equal to 100
2016-07-20 15:23:26 -07:00
Assert . LessOrEqual ( minFanSpeed , 100 , "[min_fan_speed]: " + printer . RelativeFilePath ) ;
2016-05-19 17:55:46 -07:00
}
} ) ;
}
2016-07-25 14:18:56 -07:00
[Test]
public void PlaAndAbsDensitySetCorrectly ( )
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-07-25 14:18:56 -07:00
{
2016-08-10 14:04:33 -07:00
if ( settings . OemLayer . ContainsKey ( SettingsKey . layer_name ) )
2016-07-25 14:18:56 -07:00
{
2016-08-10 14:04:33 -07:00
if ( settings . OemLayer [ SettingsKey . layer_name ] . ToUpper ( ) = = "ABS" )
2016-07-25 14:18:56 -07:00
{
double absDensity = settings . GetValue < double > ( SettingsKey . filament_density ) ;
if ( absDensity ! = 1.04 )
{
Assert . Fail ( "[filament_density] value should be set to ABS 1.04: " + printer . RelativeFilePath ) ;
}
}
2016-08-10 14:04:33 -07:00
else if ( settings . OemLayer [ SettingsKey . layer_name ] . ToUpper ( ) = = "PLA" )
2016-07-25 14:18:56 -07:00
{
double absDensity = settings . GetValue < double > ( SettingsKey . filament_density ) ;
if ( absDensity ! = 1.24 )
{
Assert . Fail ( "[filament_density] value should be set to PLA 1.24: " + printer . RelativeFilePath ) ;
}
}
}
} ) ;
}
2016-05-19 17:55:46 -07:00
[Test]
public void MaxFanSpeedOneHundredOrLess ( )
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-05-19 17:55:46 -07:00
{
2018-10-26 14:51:04 -07:00
string fanSpeedString = settings . GetValue ( SettingsKey . max_fan_speed ) ;
2016-05-19 17:55:46 -07:00
if ( ! string . IsNullOrEmpty ( fanSpeedString ) )
{
// Must be valid int data
int maxFanSpeed ;
if ( ! int . TryParse ( fanSpeedString , out maxFanSpeed ) )
{
2016-07-20 15:23:26 -07:00
Assert . Fail ( "Invalid [max_fan_speed] value (int parse failed): " + printer . RelativeFilePath ) ;
2016-05-19 17:55:46 -07:00
}
// Must be less than or equal to 100
2016-07-20 15:23:26 -07:00
Assert . LessOrEqual ( maxFanSpeed , 100 , "[max_fan_speed]: " + printer . RelativeFilePath ) ;
2016-05-19 17:55:46 -07:00
}
} ) ;
}
[Test]
public void NoCurlyBracketsInGcode ( )
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-05-19 17:55:46 -07:00
{
// TODO: Why aren't we testing all gcode sections?
2017-06-29 09:47:34 -07:00
string [ ] keysToTest = { SettingsKey . start_gcode , SettingsKey . end_gcode } ;
2016-05-19 17:55:46 -07:00
foreach ( string gcodeKey in keysToTest )
{
2016-07-20 15:23:26 -07:00
string gcode = settings . GetValue ( gcodeKey ) ;
2020-08-12 07:55:10 -07:00
if ( gcode . Contains ( "{" ) | | gcode . Contains ( "}" ) )
2016-05-19 17:55:46 -07:00
{
2016-07-20 15:23:26 -07:00
Assert . Fail ( string . Format ( "[{0}] Curly brackets not allowed: {1}" , gcodeKey , printer . RelativeFilePath ) ) ;
2016-05-19 17:55:46 -07:00
}
}
} ) ;
}
2016-07-20 15:38:38 -07:00
[Test]
2016-12-19 17:20:57 -08:00
public void BottomSolidLayersNotZero ( )
2016-05-19 17:55:46 -07:00
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-05-19 17:55:46 -07:00
{
2019-01-07 09:18:51 -08:00
string bottomSolidLayers = settings . GetValue ( SettingsKey . bottom_solid_layers ) ;
2016-05-23 15:28:46 -07:00
if ( ! string . IsNullOrEmpty ( bottomSolidLayers ) )
2016-05-19 17:55:46 -07:00
{
2016-12-19 17:20:57 -08:00
if ( bottomSolidLayers = = "0" )
2016-05-23 15:28:46 -07:00
{
printer . RuleViolated = true ;
return ;
}
2016-05-19 17:55:46 -07:00
2020-08-12 07:55:10 -07:00
// Assert.AreEqual("1mm", bottomSolidLayers, "[bottom_solid_layers] must be 1mm: " + printer.RelativeFilePath);
2016-05-23 15:28:46 -07:00
}
2016-05-19 17:55:46 -07:00
} ) ;
}
[Test]
public void NoFirstLayerBedTempInStartGcode ( )
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-05-19 17:55:46 -07:00
{
2017-06-29 09:47:34 -07:00
string startGcode = settings . GetValue ( SettingsKey . start_gcode ) ;
2019-01-11 14:39:40 -08:00
Assert . False ( startGcode . Contains ( SettingsKey . first_layer_bed_temperature ) , "[start_gcode] should not contain [first_layer_bed_temperature]" + printer . RelativeFilePath ) ;
2016-05-19 17:55:46 -07:00
} ) ;
}
2016-08-08 15:58:55 -07:00
[Test]
2016-05-25 11:04:51 -07:00
public void FirstLayerHeightLessThanNozzleDiameterXExtrusionMultiplier ( )
2016-05-19 17:55:46 -07:00
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-05-19 17:55:46 -07:00
{
2019-01-11 14:39:40 -08:00
if ( settings . GetValue ( SettingsKey . output_only_first_layer ) = = "1" )
2016-05-31 15:11:29 -07:00
{
return ;
}
2016-07-20 15:23:26 -07:00
float nozzleDiameter = float . Parse ( settings . GetValue ( SettingsKey . nozzle_diameter ) ) ;
float layerHeight = float . Parse ( settings . GetValue ( SettingsKey . layer_height ) ) ;
2016-05-19 17:55:46 -07:00
2016-05-25 11:04:51 -07:00
float firstLayerExtrusionWidth ;
2016-07-20 15:23:26 -07:00
string firstLayerExtrusionWidthString = settings . GetValue ( SettingsKey . first_layer_extrusion_width ) ;
2016-05-25 11:04:51 -07:00
if ( ! string . IsNullOrEmpty ( firstLayerExtrusionWidthString ) & & firstLayerExtrusionWidthString . Trim ( ) ! = "0" )
{
firstLayerExtrusionWidth = ValueOrPercentageOf ( firstLayerExtrusionWidthString , nozzleDiameter ) ;
}
else
{
firstLayerExtrusionWidth = nozzleDiameter ;
}
2016-07-20 15:23:26 -07:00
string firstLayerHeightString = settings . GetValue ( SettingsKey . first_layer_height ) ;
2016-05-19 17:55:46 -07:00
if ( ! string . IsNullOrEmpty ( firstLayerHeightString ) )
{
float firstLayerHeight = ValueOrPercentageOf ( firstLayerHeightString , layerHeight ) ;
2020-08-13 07:18:52 -07:00
if ( firstLayerHeight > firstLayerExtrusionWidth )
2016-05-19 17:55:46 -07:00
{
printer . RuleViolated = true ;
return ;
}
}
} ) ;
}
2016-08-08 15:58:55 -07:00
[Test]
2016-05-23 14:30:27 -07:00
public void LayerHeightLessThanNozzleDiameter ( )
2016-05-19 17:55:46 -07:00
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-05-19 17:55:46 -07:00
{
2019-01-11 14:39:40 -08:00
if ( settings . GetValue ( SettingsKey . output_only_first_layer ) = = "1" )
2016-05-31 15:18:16 -07:00
{
return ;
}
2016-07-20 15:23:26 -07:00
float nozzleDiameter = float . Parse ( settings . GetValue ( SettingsKey . nozzle_diameter ) ) ;
float layerHeight = float . Parse ( settings . GetValue ( SettingsKey . layer_height ) ) ;
2016-05-19 17:55:46 -07:00
2016-08-08 15:58:55 -07:00
double maximumLayerHeight = nozzleDiameter * 85 ;
2016-05-25 11:04:51 -07:00
2016-05-19 17:55:46 -07:00
// TODO: Remove once validated and resolved
2016-08-08 15:58:55 -07:00
if ( layerHeight > = maximumLayerHeight )
2016-05-19 17:55:46 -07:00
{
printer . RuleViolated = true ;
return ;
}
2016-08-08 15:58:55 -07:00
Assert . Less ( layerHeight , maximumLayerHeight , "[layer_height] must be less than [minimumLayerHeight]: " + printer . RelativeFilePath ) ;
2016-05-19 17:55:46 -07:00
} ) ;
}
[Test]
2016-05-25 11:04:51 -07:00
public void FirstLayerExtrusionWidthGreaterThanNozzleDiameterIfSet ( )
2016-05-19 17:55:46 -07:00
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-05-19 17:55:46 -07:00
{
2016-07-20 15:23:26 -07:00
float nozzleDiameter = float . Parse ( settings . GetValue ( SettingsKey . nozzle_diameter ) ) ;
2016-05-19 17:55:46 -07:00
2016-07-20 15:23:26 -07:00
string firstLayerExtrusionWidthString = settings . GetValue ( SettingsKey . first_layer_extrusion_width ) ;
2016-05-19 17:55:46 -07:00
if ( ! string . IsNullOrEmpty ( firstLayerExtrusionWidthString ) )
{
float firstLayerExtrusionWidth = ValueOrPercentageOf ( firstLayerExtrusionWidthString , nozzleDiameter ) ;
2016-05-25 11:04:51 -07:00
if ( firstLayerExtrusionWidth = = 0 )
2016-05-19 17:55:46 -07:00
{
2016-05-25 11:04:51 -07:00
// Ignore zeros
2016-05-19 17:55:46 -07:00
return ;
}
2016-07-20 15:23:26 -07:00
Assert . GreaterOrEqual ( firstLayerExtrusionWidth , nozzleDiameter , "[first_layer_extrusion_width] must be nozzle diameter or greater: " + printer . RelativeFilePath ) ;
2016-05-19 17:55:46 -07:00
}
} ) ;
}
[Test]
public void SupportMaterialAssignedToExtruderOne ( )
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-05-19 17:55:46 -07:00
{
2020-08-12 07:55:10 -07:00
var supportMaterialExtruder = settings . GetValue < int > ( SettingsKey . support_material_extruder ) ;
var extruderCount = settings . GetValue < int > ( SettingsKey . extruder_count ) ;
// the support extruder should be 0 unless you are on a material setting
2020-08-13 17:51:51 -07:00
if ( supportMaterialExtruder < = 0
| | ( settingsType = = SettingsType . Material & & extruderCount > 1 )
| | ( settingsType = = SettingsType . Quality & & extruderCount > 1 ) )
2016-05-19 17:55:46 -07:00
{
2020-08-12 07:55:10 -07:00
// this is a valid printer profile
}
else
{
// this needs to be fixed
printer . RuleViolated = true ;
2016-05-19 17:55:46 -07:00
}
} ) ;
}
2016-08-08 15:58:55 -07:00
[Test]
2016-05-19 17:55:46 -07:00
public void SupportInterfaceMaterialAssignedToExtruderOne ( )
{
2020-08-12 07:55:10 -07:00
ValidateOnAllPrinters ( ( printer , settings , settingsType ) = >
2016-05-19 17:55:46 -07:00
{
2020-08-13 07:18:52 -07:00
var supportMaterialInterfaceExtruder = settings . GetValue < int > ( SettingsKey . support_material_interface_extruder ) ;
var extruderCount = settings . GetValue < int > ( SettingsKey . extruder_count ) ;
// the support extruder should be 0 unless you are on a material setting
2020-08-13 17:44:02 -07:00
if ( supportMaterialInterfaceExtruder < = 0
| | ( settingsType = = SettingsType . Material & & extruderCount > 1 )
| | ( settingsType = = SettingsType . Quality & & extruderCount > 1 ) )
2016-06-09 16:02:54 -07:00
{
2020-08-13 07:18:52 -07:00
// this is a valid printer profile
}
else
{
// this needs to be fixed
printer . RuleViolated = true ;
2016-06-09 16:02:54 -07:00
}
2016-05-19 17:55:46 -07:00
} ) ;
}
private static float ValueOrPercentageOf ( string valueOrPercent , float baseValue )
{
if ( valueOrPercent . Contains ( "%" ) )
{
float percentage = float . Parse ( valueOrPercent . Replace ( "%" , "" ) ) / 100 ;
return baseValue * percentage ;
}
else
{
return float . Parse ( valueOrPercent ) ;
}
}
2020-08-12 07:55:10 -07:00
public enum SettingsType
{
All ,
Material ,
Quality
}
2016-05-19 17:55:46 -07:00
/// <summary>
2018-11-25 07:39:09 -08:00
/// Calls the given delegate for each printer as well as each quality/material layer, passing in a PrinterConfig object that has
2016-07-20 15:23:26 -07:00
/// printer settings loaded into a SettingsLayer as well as state about the printer
2016-05-19 17:55:46 -07:00
/// </summary>
/// <param name="action">The action to invoke for each printer</param>
2020-08-12 07:55:10 -07:00
private void ValidateOnAllPrinters ( Action < PrinterTestDetails , PrinterSettings , SettingsType > action )
2016-05-19 17:55:46 -07:00
{
var ruleViolations = new List < string > ( ) ;
foreach ( var printer in allPrinters )
{
printer . RuleViolated = false ;
2016-06-07 09:41:12 -07:00
2016-12-20 10:43:39 -08:00
var printerSettings = printer . PrinterSettings ;
printerSettings . AutoSave = false ;
// Disable active material/quality overrides
2018-01-10 12:55:41 -08:00
printerSettings . ActiveMaterialKey = "" ;
2016-12-20 10:43:39 -08:00
printerSettings . ActiveQualityKey = "" ;
2016-07-20 15:23:26 -07:00
2016-12-20 10:43:39 -08:00
// Validate just the OemLayer
2020-08-12 07:55:10 -07:00
action ( printer , printerSettings , SettingsType . All ) ;
2016-05-19 17:55:46 -07:00
if ( printer . RuleViolated )
{
2016-07-20 15:23:26 -07:00
ruleViolations . Add ( printer . RelativeFilePath ) ;
2016-06-07 09:41:12 -07:00
}
2016-12-20 10:43:39 -08:00
// Validate material layers
2016-07-20 15:23:26 -07:00
foreach ( var layer in printer . PrinterSettings . MaterialLayers )
2016-06-07 09:41:12 -07:00
{
printer . RuleViolated = false ;
2018-01-10 12:55:41 -08:00
printerSettings . ActiveMaterialKey = layer . LayerID ;
2016-12-20 10:43:39 -08:00
// Validate the settings with this material layer active
2020-08-12 07:55:10 -07:00
action ( printer , printerSettings , SettingsType . Material ) ;
2016-06-07 09:41:12 -07:00
if ( printer . RuleViolated )
{
2016-07-20 15:23:26 -07:00
ruleViolations . Add ( printer . RelativeFilePath + " -> " + layer . Name ) ;
2016-06-07 09:41:12 -07:00
}
}
2018-01-10 12:55:41 -08:00
printerSettings . ActiveMaterialKey = "" ;
2016-12-20 10:43:39 -08:00
// Validate quality layers
2016-07-20 15:23:26 -07:00
foreach ( var layer in printer . PrinterSettings . QualityLayers )
2016-06-07 09:41:12 -07:00
{
printer . RuleViolated = false ;
2016-12-20 10:43:39 -08:00
printerSettings . ActiveQualityKey = layer . LayerID ;
// Validate the settings with this quality layer active
2020-08-12 07:55:10 -07:00
action ( printer , printerSettings , SettingsType . Quality ) ;
2016-06-07 09:41:12 -07:00
if ( printer . RuleViolated )
{
2016-07-20 15:23:26 -07:00
ruleViolations . Add ( printer . RelativeFilePath + " -> " + layer . Name ) ;
2016-06-07 09:41:12 -07:00
}
2016-05-19 17:55:46 -07:00
}
}
2016-05-23 14:30:27 -07:00
Assert . IsTrue (
ruleViolations . Count = = 0 , /* Use == instead of Assert.AreEqual to better convey failure details */
string . Format ( "One or more printers violate this rule: \r\n\r\n{0}\r\n" , string . Join ( "\r\n" , ruleViolations . ToArray ( ) ) ) ) ;
2016-05-19 17:55:46 -07:00
}
2017-09-22 10:31:05 -07:00
private class PrinterTestDetails
2016-05-19 17:55:46 -07:00
{
public string PrinterName { get ; set ; }
2020-08-12 07:55:10 -07:00
2016-05-19 17:55:46 -07:00
public string Oem { get ; set ; }
2020-08-12 07:55:10 -07:00
2016-05-19 17:55:46 -07:00
public string ConfigPath { get ; set ; }
2020-08-12 07:55:10 -07:00
2016-07-20 15:23:26 -07:00
public string RelativeFilePath { get ; set ; }
2020-08-12 07:55:10 -07:00
2016-07-20 15:23:26 -07:00
public PrinterSettings PrinterSettings { get ; set ; }
2016-05-19 17:55:46 -07:00
2018-11-25 07:39:09 -08:00
// HACK: short term hack to support a general purpose test rollup function for cases where multiple config files
// violate a rule and in the short term we want to report and resolve the issues in batch rather than having a
2016-05-19 17:55:46 -07:00
// single test failure. Long term the single test failure better communicates the issue and assist with troubleshooting
// by using .AreEqual .LessOrEqual, etc. to communicate intent
public bool RuleViolated { get ; set ; } = false ;
}
}
}