mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	Merge branch 'master' of https://github.com/prusa3d/Slic3r into svg_icons
This commit is contained in:
		
						commit
						3c7ec5f7c6
					
				
					 50 changed files with 2399 additions and 15430 deletions
				
			
		|  | @ -1,5 +1,7 @@ | |||
| cmake_minimum_required(VERSION 3.0) | ||||
| 
 | ||||
| set(CMAKE_CXX_STANDARD 11) | ||||
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||||
| 
 | ||||
| add_definitions(-D_BSD_SOURCE -D_DEFAULT_SOURCE)   # To enable various useful macros and functions on Unices | ||||
| remove_definitions(-D_UNICODE -DUNICODE) | ||||
|  | @ -68,18 +70,31 @@ set(AVRDUDE_SOURCES | |||
| ) | ||||
| if (MSVC) | ||||
|     set(AVRDUDE_SOURCES ${AVRDUDE_SOURCES} | ||||
|         windows/utf8.c | ||||
|         windows/unistd.cpp | ||||
|         windows/getopt.c | ||||
|     ) | ||||
| endif() | ||||
| add_library(avrdude STATIC ${AVRDUDE_SOURCES}) | ||||
| 
 | ||||
| set(STANDALONE_SOURCES | ||||
|     main-standalone.c | ||||
| add_executable(avrdude-conf-gen conf-generate.cpp) | ||||
| 
 | ||||
| # Config file embedding | ||||
| add_custom_command( | ||||
|     DEPENDS avrdude-conf-gen ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf | ||||
|     OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf.h | ||||
|     COMMAND $<TARGET_FILE:avrdude-conf-gen> avrdude-slic3r.conf avrdude_slic3r_conf > avrdude-slic3r.conf.h | ||||
|     WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} | ||||
| ) | ||||
| add_executable(avrdude-slic3r ${STANDALONE_SOURCES}) | ||||
| 
 | ||||
| add_custom_target(gen_conf_h | ||||
|    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf.h | ||||
| ) | ||||
| 
 | ||||
| add_library(avrdude STATIC ${AVRDUDE_SOURCES}) | ||||
| add_dependencies(avrdude gen_conf_h) | ||||
| 
 | ||||
| add_executable(avrdude-slic3r main-standalone.cpp) | ||||
| target_link_libraries(avrdude-slic3r avrdude) | ||||
| set_target_properties(avrdude-slic3r PROPERTIES EXCLUDE_FROM_ALL TRUE) | ||||
| 
 | ||||
| if (WIN32) | ||||
|     target_compile_definitions(avrdude PRIVATE WIN32NATIVE=1) | ||||
|  |  | |||
|  | @ -158,8 +158,10 @@ static int arduino_open(PROGRAMMER * pgm, char * port) | |||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   if (stk500_getsync(pgm) < 0) | ||||
|   if (stk500_getsync(pgm) < 0) { | ||||
|     serial_close(&pgm->fd); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										424
									
								
								src/avrdude/avrdude-slic3r.conf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										424
									
								
								src/avrdude/avrdude-slic3r.conf
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,424 @@ | |||
| 
 | ||||
| # | ||||
| # This is a basic minimal config file embedded into the avrdude-slic3r binary | ||||
| # so that it can work in a standalone manner. | ||||
| # | ||||
| # Only the bits useful for Prusa3D devices were copied over from avrdude.conf | ||||
| # If needed, more configuration can still be loaded into avrdude-slic3r | ||||
| # via the -C command-line option. | ||||
| # | ||||
| 
 | ||||
| 
 | ||||
| programmer | ||||
|   id    = "wiring"; | ||||
|   desc  = "Wiring"; | ||||
|   type  = "wiring"; | ||||
|   connection_type = serial; | ||||
| ; | ||||
| 
 | ||||
| programmer | ||||
|   id    = "arduino"; | ||||
|   desc  = "Arduino"; | ||||
|   type  = "arduino"; | ||||
|   connection_type = serial; | ||||
| ; | ||||
| 
 | ||||
| programmer | ||||
|   id    = "avr109"; | ||||
|   desc  = "Atmel AppNote AVR109 Boot Loader"; | ||||
|   type  = "butterfly"; | ||||
|   connection_type = serial; | ||||
| ; | ||||
| 
 | ||||
| 
 | ||||
| #------------------------------------------------------------ | ||||
| # ATmega2560 | ||||
| #------------------------------------------------------------ | ||||
| 
 | ||||
| part | ||||
|     id               = "m2560"; | ||||
|     desc             = "ATmega2560"; | ||||
|     signature        = 0x1e 0x98 0x01; | ||||
|     has_jtag         = yes; | ||||
|     stk500_devcode   = 0xB2; | ||||
| #    avr910_devcode   = 0x43; | ||||
|     chip_erase_delay = 9000; | ||||
|     pagel            = 0xD7; | ||||
|     bs2              = 0xA0; | ||||
|     reset            = dedicated; | ||||
|     pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1", | ||||
|                        "x x x x  x x x x    x x x x  x x x x"; | ||||
| 
 | ||||
|     chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0", | ||||
|                        "x x x x  x x x x    x x x x  x x x x"; | ||||
| 
 | ||||
|     timeout   = 200; | ||||
|     stabdelay   = 100; | ||||
|     cmdexedelay   = 25; | ||||
|     synchloops    = 32; | ||||
|     bytedelay   = 0; | ||||
|     pollindex   = 3; | ||||
|     pollvalue   = 0x53; | ||||
|     predelay    = 1; | ||||
|     postdelay   = 1; | ||||
|     pollmethod    = 1; | ||||
| 
 | ||||
|     pp_controlstack     = | ||||
|         0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, | ||||
|         0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, | ||||
|         0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, | ||||
|         0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; | ||||
|     hventerstabdelay    = 100; | ||||
|     progmodedelay       = 0; | ||||
|     latchcycles         = 5; | ||||
|     togglevtg           = 1; | ||||
|     poweroffdelay       = 15; | ||||
|     resetdelayms        = 1; | ||||
|     resetdelayus        = 0; | ||||
|     hvleavestabdelay    = 15; | ||||
|     chiperasepulsewidth = 0; | ||||
|     chiperasepolltimeout = 10; | ||||
|     programfusepulsewidth = 0; | ||||
|     programfusepolltimeout = 5; | ||||
|     programlockpulsewidth = 0; | ||||
|     programlockpolltimeout = 5; | ||||
| 
 | ||||
|     idr                 = 0x31; | ||||
|     spmcr               = 0x57; | ||||
|     rampz               = 0x3b; | ||||
|     allowfullpagebitstream = no; | ||||
| 
 | ||||
|     ocdrev              = 4; | ||||
| 
 | ||||
|     memory "eeprom" | ||||
|         paged           = no; /* leave this "no" */ | ||||
|         page_size       = 8;  /* for parallel programming */ | ||||
|         size            = 4096; | ||||
|         min_write_delay = 9000; | ||||
|         max_write_delay = 9000; | ||||
|         readback_p1     = 0x00; | ||||
|         readback_p2     = 0x00; | ||||
|         read            = "  1   0   1   0      0   0   0   0", | ||||
|                           "  x   x   x   x    a11 a10  a9  a8", | ||||
|                           " a7  a6  a5  a4     a3  a2  a1  a0", | ||||
|                           "  o   o   o   o      o   o   o   o"; | ||||
| 
 | ||||
|         write           = "  1   1   0   0      0   0   0   0", | ||||
|                           "  x   x   x   x    a11 a10  a9  a8", | ||||
|                           " a7  a6  a5  a4     a3  a2  a1  a0",  | ||||
|                           "  i   i   i   i      i   i   i   i"; | ||||
| 
 | ||||
|   loadpage_lo = "  1   1   0   0      0   0   0   1", | ||||
|         "  0   0   0   0      0   0   0   0", | ||||
|         "  0   0   0   0      0  a2  a1  a0", | ||||
|         "  i   i   i   i      i   i   i   i"; | ||||
| 
 | ||||
|   writepage = "  1   1   0   0      0   0   1   0", | ||||
|         "  0   0   x   x    a11 a10  a9  a8", | ||||
|         " a7  a6  a5  a4     a3   0   0   0", | ||||
|         "  x   x   x   x      x   x   x   x"; | ||||
| 
 | ||||
|   mode    = 0x41; | ||||
|   delay   = 10; | ||||
|   blocksize = 8; | ||||
|   readsize  = 256; | ||||
|       ; | ||||
| 
 | ||||
|     memory "flash" | ||||
|         paged           = yes; | ||||
|         size            = 262144; | ||||
|         page_size       = 256; | ||||
|         num_pages       = 1024; | ||||
|         min_write_delay = 4500; | ||||
|         max_write_delay = 4500; | ||||
|         readback_p1     = 0x00; | ||||
|         readback_p2     = 0x00; | ||||
|         read_lo         = "  0   0   1   0      0   0   0   0", | ||||
|                           "a15 a14 a13 a12    a11 a10  a9  a8", | ||||
|                           " a7  a6  a5  a4     a3  a2  a1  a0", | ||||
|                           "  o   o   o   o      o   o   o   o"; | ||||
| 
 | ||||
|         read_hi         = "  0   0   1   0      1   0   0   0", | ||||
|                           "a15 a14 a13 a12    a11 a10  a9  a8", | ||||
|                           " a7  a6  a5  a4     a3  a2  a1  a0", | ||||
|                           "  o   o   o   o      o   o   o   o"; | ||||
| 
 | ||||
|         loadpage_lo     = "  0   1   0   0      0   0   0   0", | ||||
|                           "  x   x   x   x      x   x   x   x", | ||||
|                           "  x  a6  a5  a4     a3  a2  a1  a0", | ||||
|                           "  i   i   i   i      i   i   i   i"; | ||||
| 
 | ||||
|         loadpage_hi     = "  0   1   0   0      1   0   0   0", | ||||
|                           "  x   x   x   x      x   x   x   x", | ||||
|                           "  x  a6  a5  a4     a3  a2  a1  a0", | ||||
|                           "  i   i   i   i      i   i   i   i"; | ||||
| 
 | ||||
|         writepage       = "  0   1   0   0      1   1   0   0", | ||||
|                           "a15 a14 a13 a12    a11 a10  a9  a8", | ||||
|                           " a7   x   x   x      x   x   x   x", | ||||
|                           "  x   x   x   x      x   x   x   x"; | ||||
| 
 | ||||
|         load_ext_addr   = "  0   1   0   0      1   1   0   1", | ||||
|                           "  0   0   0   0      0   0   0   0", | ||||
|                           "  0   0   0   0      0   0   0 a16", | ||||
|                           "  0   0   0   0      0   0   0   0"; | ||||
| 
 | ||||
|   mode    = 0x41; | ||||
|   delay   = 10; | ||||
|   blocksize = 256; | ||||
|   readsize  = 256; | ||||
|       ; | ||||
| 
 | ||||
|     memory "lfuse" | ||||
|         size            = 1; | ||||
|         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0", | ||||
|                           "x x x x  x x x x  i i i i  i i i i"; | ||||
| 
 | ||||
|         read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0", | ||||
|                           "x x x x  x x x x  o o o o  o o o o"; | ||||
|         min_write_delay = 9000; | ||||
|         max_write_delay = 9000; | ||||
|       ; | ||||
| 
 | ||||
|     memory "hfuse" | ||||
|         size            = 1; | ||||
|         write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0", | ||||
|                           "x x x x  x x x x  i i i i  i i i i"; | ||||
| 
 | ||||
|         read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0", | ||||
|                           "x x x x  x x x x  o o o o  o o o o"; | ||||
|         min_write_delay = 9000; | ||||
|         max_write_delay = 9000; | ||||
|       ; | ||||
| 
 | ||||
|     memory "efuse" | ||||
|         size            = 1; | ||||
|         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0", | ||||
|                           "x x x x  x x x x  x x x x  x i i i"; | ||||
| 
 | ||||
|         read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0", | ||||
|                           "x x x x  x x x x  o o o o  o o o o"; | ||||
|         min_write_delay = 9000; | ||||
|         max_write_delay = 9000; | ||||
|       ; | ||||
| 
 | ||||
|     memory "lock" | ||||
|         size            = 1; | ||||
|         read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0", | ||||
|                           "x x x x  x x x x   x x o o  o o o o"; | ||||
| 
 | ||||
|         write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x", | ||||
|                           "x x x x  x x x x   1 1 i i  i i i i"; | ||||
|         min_write_delay = 9000; | ||||
|         max_write_delay = 9000; | ||||
|       ; | ||||
| 
 | ||||
|     memory "calibration" | ||||
|         size            = 1; | ||||
|         read            = "0 0 1 1  1 0 0 0    x x x x  x x x x", | ||||
|                           "0 0 0 0  0 0 0 0    o o o o  o o o o"; | ||||
|       ; | ||||
| 
 | ||||
|     memory "signature" | ||||
|         size            = 3; | ||||
|         read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x", | ||||
|                           "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o"; | ||||
|       ; | ||||
|   ; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #------------------------------------------------------------ | ||||
| # ATmega32u4 | ||||
| #------------------------------------------------------------ | ||||
| 
 | ||||
| part | ||||
|     id               = "m32u4"; | ||||
|     desc             = "ATmega32U4"; | ||||
|     signature        = 0x1e 0x95 0x87; | ||||
|     usbpid           = 0x2ff4; | ||||
|     has_jtag         = yes; | ||||
| #    stk500_devcode   = 0xB2; | ||||
| #    avr910_devcode   = 0x43; | ||||
|     chip_erase_delay = 9000; | ||||
|     pagel            = 0xD7; | ||||
|     bs2              = 0xA0; | ||||
|     reset            = dedicated; | ||||
|     pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1", | ||||
|                        "x x x x  x x x x    x x x x  x x x x"; | ||||
| 
 | ||||
|     chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0", | ||||
|                        "x x x x  x x x x    x x x x  x x x x"; | ||||
| 
 | ||||
|     timeout   = 200; | ||||
|     stabdelay   = 100; | ||||
|     cmdexedelay   = 25; | ||||
|     synchloops    = 32; | ||||
|     bytedelay   = 0; | ||||
|     pollindex   = 3; | ||||
|     pollvalue   = 0x53; | ||||
|     predelay    = 1; | ||||
|     postdelay   = 1; | ||||
|     pollmethod    = 1; | ||||
| 
 | ||||
|     pp_controlstack     = | ||||
|         0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, | ||||
|         0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, | ||||
|         0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, | ||||
|         0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; | ||||
|     hventerstabdelay    = 100; | ||||
|     progmodedelay       = 0; | ||||
|     latchcycles         = 5; | ||||
|     togglevtg           = 1; | ||||
|     poweroffdelay       = 15; | ||||
|     resetdelayms        = 1; | ||||
|     resetdelayus        = 0; | ||||
|     hvleavestabdelay    = 15; | ||||
|     chiperasepulsewidth = 0; | ||||
|     chiperasepolltimeout = 10; | ||||
|     programfusepulsewidth = 0; | ||||
|     programfusepolltimeout = 5; | ||||
|     programlockpulsewidth = 0; | ||||
|     programlockpolltimeout = 5; | ||||
| 
 | ||||
|     idr                 = 0x31; | ||||
|     spmcr               = 0x57; | ||||
|     rampz               = 0x3b; | ||||
|     allowfullpagebitstream = no; | ||||
| 
 | ||||
|     ocdrev              = 3; | ||||
| 
 | ||||
|     memory "eeprom" | ||||
|         paged           = no; /* leave this "no" */ | ||||
|         page_size       = 4;  /* for parallel programming */ | ||||
|         size            = 1024; | ||||
|         min_write_delay = 9000; | ||||
|         max_write_delay = 9000; | ||||
|         readback_p1     = 0x00; | ||||
|         readback_p2     = 0x00; | ||||
|         read            = "  1   0   1   0      0   0   0   0", | ||||
|                           "  x   x   x   x      x a10  a9  a8", | ||||
|                           " a7  a6  a5  a4     a3  a2  a1  a0", | ||||
|                           "  o   o   o   o      o   o   o   o"; | ||||
| 
 | ||||
|         write           = "  1   1   0   0      0   0   0   0", | ||||
|                           "  x   x   x   x      x a10  a9  a8", | ||||
|                           " a7  a6  a5  a4     a3  a2  a1  a0",  | ||||
|                           "  i   i   i   i      i   i   i   i"; | ||||
| 
 | ||||
|   loadpage_lo = "  1   1   0   0      0   0   0   1", | ||||
|         "  0   0   0   0      0   0   0   0", | ||||
|         "  0   0   0   0      0  a2  a1  a0", | ||||
|         "  i   i   i   i      i   i   i   i"; | ||||
| 
 | ||||
|   writepage = "  1   1   0   0      0   0   1   0", | ||||
|         "  0   0   x   x      x a10  a9  a8", | ||||
|         " a7  a6  a5  a4     a3   0   0   0", | ||||
|         "  x   x   x   x      x   x   x   x"; | ||||
| 
 | ||||
|   mode    = 0x41; | ||||
|   delay   = 20; | ||||
|   blocksize = 4; | ||||
|   readsize  = 256; | ||||
|       ; | ||||
| 
 | ||||
|     memory "flash" | ||||
|         paged           = yes; | ||||
|         size            = 32768; | ||||
|         page_size       = 128; | ||||
|         num_pages       = 256; | ||||
|         min_write_delay = 4500; | ||||
|         max_write_delay = 4500; | ||||
|         readback_p1     = 0x00; | ||||
|         readback_p2     = 0x00; | ||||
|         read_lo         = "  0   0   1   0      0   0   0   0", | ||||
|                           "  0 a14 a13 a12    a11 a10  a9  a8", | ||||
|                           " a7  a6  a5  a4     a3  a2  a1  a0", | ||||
|                           "  o   o   o   o      o   o   o   o"; | ||||
| 
 | ||||
|         read_hi         = "  0   0   1   0      1   0   0   0", | ||||
|                           "  0 a14 a13 a12    a11 a10  a9  a8", | ||||
|                           " a7  a6  a5  a4     a3  a2  a1  a0", | ||||
|                           "  o   o   o   o      o   o   o   o"; | ||||
| 
 | ||||
|         loadpage_lo     = "  0   1   0   0      0   0   0   0", | ||||
|                           "  x   x   x   x      x   x   x   x", | ||||
|                           "  x   x  a5  a4     a3  a2  a1  a0", | ||||
|                           "  i   i   i   i      i   i   i   i"; | ||||
| 
 | ||||
|         loadpage_hi     = "  0   1   0   0      1   0   0   0", | ||||
|                           "  x   x   x   x      x   x   x   x", | ||||
|                           "  x   x  a5  a4     a3  a2  a1  a0", | ||||
|                           "  i   i   i   i      i   i   i   i"; | ||||
| 
 | ||||
|         writepage       = "  0   1   0   0      1   1   0   0", | ||||
|                           " a15 a14 a13 a12    a11 a10  a9  a8", | ||||
|                           " a7  a6   x   x      x   x   x   x", | ||||
|                           "  x   x   x   x      x   x   x   x"; | ||||
| 
 | ||||
|   mode    = 0x41; | ||||
|   delay   = 6; | ||||
|   blocksize = 128; | ||||
|   readsize  = 256; | ||||
|       ; | ||||
| 
 | ||||
|     memory "lfuse" | ||||
|         size            = 1; | ||||
|         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0", | ||||
|                           "x x x x  x x x x  i i i i  i i i i"; | ||||
| 
 | ||||
|         read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0", | ||||
|                           "x x x x  x x x x  o o o o  o o o o"; | ||||
|         min_write_delay = 9000; | ||||
|         max_write_delay = 9000; | ||||
|       ; | ||||
| 
 | ||||
|     memory "hfuse" | ||||
|         size            = 1; | ||||
|         write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0", | ||||
|                           "x x x x  x x x x  i i i i  i i i i"; | ||||
| 
 | ||||
|         read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0", | ||||
|                           "x x x x  x x x x  o o o o  o o o o"; | ||||
|         min_write_delay = 9000; | ||||
|         max_write_delay = 9000; | ||||
|       ; | ||||
| 
 | ||||
|     memory "efuse" | ||||
|         size            = 1; | ||||
|         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0", | ||||
|                           "x x x x  x x x x  x x x x  i i i i"; | ||||
| 
 | ||||
|         read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0", | ||||
|                           "x x x x  x x x x  o o o o  o o o o"; | ||||
|         min_write_delay = 9000; | ||||
|         max_write_delay = 9000; | ||||
|       ; | ||||
| 
 | ||||
|     memory "lock" | ||||
|         size            = 1; | ||||
|         read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0", | ||||
|                           "x x x x  x x x x   x x o o  o o o o"; | ||||
| 
 | ||||
|         write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x", | ||||
|                           "x x x x  x x x x   1 1 i i  i i i i"; | ||||
|         min_write_delay = 9000; | ||||
|         max_write_delay = 9000; | ||||
|       ; | ||||
| 
 | ||||
|     memory "calibration" | ||||
|         size            = 1; | ||||
|         read            = "0 0 1 1  1 0 0 0    x x x x  x x x x", | ||||
|                           "0 0 0 0  0 0 0 0    o o o o  o o o o"; | ||||
|       ; | ||||
| 
 | ||||
|     memory "signature" | ||||
|         size            = 3; | ||||
|         read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x", | ||||
|                           "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o"; | ||||
|       ; | ||||
|   ; | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										1188
									
								
								src/avrdude/avrdude-slic3r.conf.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1188
									
								
								src/avrdude/avrdude-slic3r.conf.h
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -42,7 +42,6 @@ static void avrdude_oom_handler(const char *context, void *user_p) | |||
| 
 | ||||
| struct AvrDude::priv | ||||
| { | ||||
| 	std::string sys_config; | ||||
| 	std::deque<std::vector<std::string>> args; | ||||
| 	bool cancelled = false; | ||||
| 	int exit_code = 0; | ||||
|  | @ -54,8 +53,6 @@ struct AvrDude::priv | |||
| 
 | ||||
| 	std::thread avrdude_thread; | ||||
| 
 | ||||
| 	priv(std::string &&sys_config) : sys_config(sys_config) {} | ||||
| 
 | ||||
| 	void set_handlers(); | ||||
| 	void unset_handlers(); | ||||
| 	int run_one(const std::vector<std::string> &args); | ||||
|  | @ -110,7 +107,7 @@ int AvrDude::priv::run_one(const std::vector<std::string> &args) { | |||
| 
 | ||||
| 	message_fn(command_line.c_str(), command_line.size()); | ||||
| 
 | ||||
| 	const auto res = ::avrdude_main(static_cast<int>(c_args.size()), c_args.data(), sys_config.c_str()); | ||||
| 	const auto res = ::avrdude_main(static_cast<int>(c_args.size()), c_args.data()); | ||||
| 
 | ||||
| 	return res; | ||||
| } | ||||
|  | @ -130,7 +127,7 @@ int AvrDude::priv::run() { | |||
| 
 | ||||
| // Public
 | ||||
| 
 | ||||
| AvrDude::AvrDude(std::string sys_config) : p(new priv(std::move(sys_config))) {} | ||||
| AvrDude::AvrDude() : p(new priv()) {} | ||||
| 
 | ||||
| AvrDude::AvrDude(AvrDude &&other) : p(std::move(other.p)) {} | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,8 +22,7 @@ public: | |||
| 	typedef std::function<void(const char * /* task */, unsigned /* progress */)> ProgressFn; | ||||
| 	typedef std::function<void()> CompleteFn; | ||||
| 
 | ||||
| 	// Main c-tor, sys_config is the location of avrdude's main configuration file
 | ||||
| 	AvrDude(std::string sys_config); | ||||
| 	AvrDude(); | ||||
| 	AvrDude(AvrDude &&); | ||||
| 	AvrDude(const AvrDude &) = delete; | ||||
| 	AvrDude &operator=(AvrDude &&) = delete; | ||||
|  |  | |||
|  | @ -55,7 +55,7 @@ void avrdude_cancel(); | |||
| #define MSG_TRACE   (4) /* displayed with -vvvv, show trace commuication */ | ||||
| #define MSG_TRACE2  (5) /* displayed with -vvvvv */ | ||||
| 
 | ||||
| int avrdude_main(int argc, char * argv [], const char *sys_config); | ||||
| int avrdude_main(int argc, char * argv []); | ||||
| 
 | ||||
| #if defined(WIN32NATIVE) | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										41
									
								
								src/avrdude/conf-generate.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/avrdude/conf-generate.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| #include <iostream> | ||||
| #include <fstream> | ||||
| #include <ios> | ||||
| #include <iomanip> | ||||
| 
 | ||||
| 
 | ||||
| int main(int argc, char const *argv[]) | ||||
| { | ||||
|     if (argc != 3) { | ||||
|         std::cerr << "Usage: " << argv[0] << " <file> <symbol name>" << std::endl; | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     const char* filename = argv[1]; | ||||
|     const char* symbol = argv[2]; | ||||
| 
 | ||||
|     size_t size = 0; | ||||
|     std::fstream file(filename); | ||||
|     if (!file.good()) { | ||||
|         std::cerr << "Cannot read file: " << filename << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     std::cout << "/* WARN: This file is auto-generated from `" << filename << "` */" << std::endl; | ||||
|     std::cout << "unsigned char " << symbol << "[] = {"; | ||||
| 
 | ||||
|     char c; | ||||
|     std::cout << std::hex; | ||||
|     std::cout.fill('0'); | ||||
|     for (file.get(c); !file.eof(); size++, file.get(c)) { | ||||
|         if (size % 12 == 0) { std::cout << "\n    "; } | ||||
|         std::cout << "0x" << std::setw(2) << (unsigned)c << ", "; | ||||
|     } | ||||
| 
 | ||||
|     std::cout << "\n    0, 0\n};\n"; | ||||
| 
 | ||||
|     std::cout << std::dec; | ||||
|     std::cout << "size_t " << symbol << "_size = " << size << ";" << std::endl; | ||||
|     std::cout << "size_t " << symbol << "_size_yy = " << size + 2 << ";" << std::endl; | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
|  | @ -32,6 +32,8 @@ | |||
| 
 | ||||
| #include "config_gram.h" | ||||
| 
 | ||||
| #include "avrdude-slic3r.conf.h"    // Embedded config file | ||||
| 
 | ||||
| char default_programmer[MAX_STR_CONST]; | ||||
| char default_parallel[PATH_MAX]; | ||||
| char default_serial[PATH_MAX]; | ||||
|  | @ -325,7 +327,7 @@ int read_config(const char * file) | |||
|   FILE * f; | ||||
|   int r; | ||||
| 
 | ||||
|   f = fopen(file, "r"); | ||||
|   f = fopen_utf8(file, "r"); | ||||
|   if (f == NULL) { | ||||
|     avrdude_message(MSG_INFO, "%s: can't open config file \"%s\": %s\n", | ||||
|             progname, file, strerror(errno)); | ||||
|  | @ -347,3 +349,33 @@ int read_config(const char * file) | |||
| 
 | ||||
|   return r; | ||||
| } | ||||
| 
 | ||||
| typedef struct yy_buffer_state *YY_BUFFER_STATE; | ||||
| extern YY_BUFFER_STATE yy_scan_bytes(char *base, size_t size); | ||||
| extern void yy_delete_buffer(YY_BUFFER_STATE b); | ||||
| 
 | ||||
| int read_config_builtin() | ||||
| { | ||||
|   int r; | ||||
| 
 | ||||
|   lineno = 1; | ||||
|   infile = "(builtin)"; | ||||
| 
 | ||||
|   // Note: Can't use yy_scan_buffer, it's buggy (?), leads to fread from a null FILE*
 | ||||
|   // and so unfortunatelly we have to use the copying variant here
 | ||||
|   YY_BUFFER_STATE buffer = yy_scan_bytes(avrdude_slic3r_conf, avrdude_slic3r_conf_size); | ||||
|   if (buffer == NULL) { | ||||
|     avrdude_message(MSG_INFO, "%s: read_config_builtin: Failed to initialize parsing buffer\n", progname); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   r = yyparse(); | ||||
|   yy_delete_buffer(buffer); | ||||
| 
 | ||||
| #ifdef HAVE_YYLEX_DESTROY | ||||
|   /* reset lexer and free any allocated memory */ | ||||
|   yylex_destroy(); | ||||
| #endif | ||||
| 
 | ||||
|   return r; | ||||
| } | ||||
|  |  | |||
|  | @ -40,6 +40,9 @@ | |||
| #include "avrdude.h" | ||||
| #include "libavrdude.h" | ||||
| 
 | ||||
| #if defined(WIN32NATIVE) | ||||
| #include "windows/utf8.h" | ||||
| #endif | ||||
| 
 | ||||
| #define IHEX_MAXDATA 256 | ||||
| 
 | ||||
|  | @ -102,21 +105,25 @@ static int fmt_autodetect(char * fname, unsigned section); | |||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| static FILE *fopen_and_seek(const char *filename, const char *mode, unsigned section) | ||||
| FILE *fopen_utf8(const char *filename, const char *mode) | ||||
| { | ||||
|   FILE *file; | ||||
|   // On Windows we need to convert the filename to UTF-16
 | ||||
| #if defined(WIN32NATIVE) | ||||
|   static wchar_t fname_buffer[PATH_MAX]; | ||||
|   static wchar_t mode_buffer[MAX_MODE_LEN]; | ||||
| 
 | ||||
|   if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, fname_buffer, PATH_MAX) == 0) { return NULL; } | ||||
|   if (MultiByteToWideChar(CP_ACP, 0, mode, -1, mode_buffer, MAX_MODE_LEN) == 0) { return NULL; } | ||||
|   if (MultiByteToWideChar(CP_UTF8, 0, mode, -1, mode_buffer, MAX_MODE_LEN) == 0) { return NULL; } | ||||
| 
 | ||||
|   file = _wfopen(fname_buffer, mode_buffer); | ||||
|   return _wfopen(fname_buffer, mode_buffer); | ||||
| #else | ||||
|   file = fopen(filename, mode); | ||||
|   return fopen(filename, mode); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static FILE *fopen_and_seek(const char *filename, const char *mode, unsigned section) | ||||
| { | ||||
|   FILE *file = fopen_utf8(filename, mode); | ||||
| 
 | ||||
|   if (file == NULL) { | ||||
|     return NULL; | ||||
|  |  | |||
|  | @ -1527,8 +1527,10 @@ static int jtagmkII_open(PROGRAMMER * pgm, char * port) | |||
|    */ | ||||
|   jtagmkII_drain(pgm, 0); | ||||
| 
 | ||||
|   if (jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG) < 0) | ||||
|   if (jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG) < 0) { | ||||
|     serial_close(&pgm->fd); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1579,8 +1581,10 @@ static int jtagmkII_open_dw(PROGRAMMER * pgm, char * port) | |||
|    */ | ||||
|   jtagmkII_drain(pgm, 0); | ||||
| 
 | ||||
|   if (jtagmkII_getsync(pgm, EMULATOR_MODE_DEBUGWIRE) < 0) | ||||
|   if (jtagmkII_getsync(pgm, EMULATOR_MODE_DEBUGWIRE) < 0) { | ||||
|     serial_close(&pgm->fd); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1631,8 +1635,10 @@ static int jtagmkII_open_pdi(PROGRAMMER * pgm, char * port) | |||
|    */ | ||||
|   jtagmkII_drain(pgm, 0); | ||||
| 
 | ||||
|   if (jtagmkII_getsync(pgm, EMULATOR_MODE_PDI) < 0) | ||||
|   if (jtagmkII_getsync(pgm, EMULATOR_MODE_PDI) < 0) { | ||||
|     serial_close(&pgm->fd); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1684,8 +1690,10 @@ static int jtagmkII_dragon_open(PROGRAMMER * pgm, char * port) | |||
|    */ | ||||
|   jtagmkII_drain(pgm, 0); | ||||
| 
 | ||||
|   if (jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG) < 0) | ||||
|   if (jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG) < 0) { | ||||
|     serial_close(&pgm->fd); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1737,8 +1745,10 @@ static int jtagmkII_dragon_open_dw(PROGRAMMER * pgm, char * port) | |||
|    */ | ||||
|   jtagmkII_drain(pgm, 0); | ||||
| 
 | ||||
|   if (jtagmkII_getsync(pgm, EMULATOR_MODE_DEBUGWIRE) < 0) | ||||
|   if (jtagmkII_getsync(pgm, EMULATOR_MODE_DEBUGWIRE) < 0) { | ||||
|     serial_close(&pgm->fd); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1790,8 +1800,10 @@ static int jtagmkII_dragon_open_pdi(PROGRAMMER * pgm, char * port) | |||
|    */ | ||||
|   jtagmkII_drain(pgm, 0); | ||||
| 
 | ||||
|   if (jtagmkII_getsync(pgm, EMULATOR_MODE_PDI) < 0) | ||||
|   if (jtagmkII_getsync(pgm, EMULATOR_MODE_PDI) < 0) { | ||||
|     serial_close(&pgm->fd); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  | @ -3370,6 +3382,8 @@ static int jtagmkII_open32(PROGRAMMER * pgm, char * port) | |||
|   status = jtagmkII_getsync(pgm, -1); | ||||
|   if(status < 0) return -1; | ||||
| 
 | ||||
|   // FIXME: Error handling is bad here: memory leak in resp (?) and port not closed
 | ||||
| 
 | ||||
|   // AVR32 "special"
 | ||||
|   buf[0] = CMND_SET_PARAMETER; | ||||
|   buf[1] = 0x2D; | ||||
|  |  | |||
|  | @ -820,6 +820,8 @@ extern "C" { | |||
| 
 | ||||
| char * fmtstr(FILEFMT format); | ||||
| 
 | ||||
| FILE *fopen_utf8(const char *filename, const char *mode); | ||||
| 
 | ||||
| int fileio(int op, char * filename, FILEFMT format, | ||||
|            struct avrpart * p, char * memtype, int size, unsigned section); | ||||
| 
 | ||||
|  | @ -939,6 +941,7 @@ int init_config(void); | |||
| void cleanup_config(void); | ||||
| 
 | ||||
| int read_config(const char * file); | ||||
| int read_config_builtin(); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|  |  | |||
|  | @ -1,9 +0,0 @@ | |||
| #include "avrdude.h" | ||||
| 
 | ||||
| 
 | ||||
| static const char* SYS_CONFIG = "/etc/avrdude-slic3r.conf"; | ||||
| 
 | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
| 	return avrdude_main(argc, argv, SYS_CONFIG); | ||||
| } | ||||
							
								
								
									
										54
									
								
								src/avrdude/main-standalone.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/avrdude/main-standalone.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | |||
| extern "C" { | ||||
| #include "avrdude.h" | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| #include <stdlib.h> | ||||
| #include <vector> | ||||
| 
 | ||||
| extern "C" { | ||||
| #include "windows/utf8.h" | ||||
| } | ||||
| 
 | ||||
| struct ArgvUtf8 : std::vector<char*> | ||||
| { | ||||
| 	int argc; | ||||
| 
 | ||||
| 	ArgvUtf8(int argc_w, wchar_t *argv_w[]) : std::vector<char*>(argc_w + 1, nullptr), argc(0) | ||||
| 	{ | ||||
| 		for (int i = 0; i < argc_w; i++) { | ||||
| 			char *arg_utf8 = ::wstr_to_utf8(argv_w[i], -1); | ||||
| 			if (arg_utf8 != nullptr) { | ||||
| 				operator[](i) = arg_utf8; | ||||
| 				argc = i + 1; | ||||
| 			} else { | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	~ArgvUtf8() | ||||
| 	{ | ||||
| 		for (char *arg : *this) { | ||||
| 			if (arg != nullptr) { | ||||
| 				::free(arg); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| int wmain(int argc_w, wchar_t *argv_w[]) | ||||
| { | ||||
| 	ArgvUtf8 argv_utf8(argc_w, argv_w); | ||||
| 	return ::avrdude_main(argv_utf8.argc, &argv_utf8[0]); | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
| 	return ::avrdude_main(argc, argv); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -426,7 +426,7 @@ static int cleanup_main(int status) | |||
| /*
 | ||||
|  * main routine | ||||
|  */ | ||||
| int avrdude_main(int argc, char * argv [], const char *sys_config) | ||||
| int avrdude_main(int argc, char * argv []) | ||||
| { | ||||
|   int              rc;          /* general return code checking */ | ||||
|   int              exitrc;      /* exit code for main() */ | ||||
|  | @ -807,13 +807,15 @@ int avrdude_main(int argc, char * argv [], const char *sys_config) | |||
|                     "%sCopyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/\n" | ||||
|                     "%sCopyright (c) 2007-2014 Joerg Wunsch\n\n", | ||||
|                     progname, version, __DATE__, __TIME__, progbuf, progbuf); | ||||
|   avrdude_message(MSG_NOTICE, "%sSystem wide configuration file is \"%s\"\n", | ||||
|             progbuf, sys_config); | ||||
|   // avrdude_message(MSG_NOTICE, "%sSystem wide configuration file is \"%s\"\n",
 | ||||
|   //           progbuf, sys_config);
 | ||||
| 
 | ||||
|   rc = read_config(sys_config); | ||||
|   // rc = read_config(sys_config);
 | ||||
|   rc = read_config_builtin(); | ||||
|   if (rc) { | ||||
|     avrdude_message(MSG_INFO, "%s: error reading system wide configuration file \"%s\"\n", | ||||
|                     progname, sys_config); | ||||
|     // avrdude_message(MSG_INFO, "%s: error reading system wide configuration file \"%s\"\n",
 | ||||
|     //                 progname, sys_config);
 | ||||
|     avrdude_message(MSG_INFO, "%s: error reading built-in configuration file\n", progname); | ||||
|     return cleanup_main(1); | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -44,7 +44,7 @@ | |||
| #include "avrdude.h" | ||||
| #include "libavrdude.h" | ||||
| 
 | ||||
| long serial_recv_timeout = 5000; /* ms */ | ||||
| long serial_recv_timeout = 4000;  /* ms */ | ||||
| #define MAX_ZERO_READS 512 | ||||
| 
 | ||||
| struct baud_mapping { | ||||
|  | @ -150,6 +150,68 @@ static int ser_setspeed(union filedescriptor *fd, long baud) | |||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // Timeout read & write variants
 | ||||
| // Additionally to the regular -1 on I/O error, they return -2 on timeout
 | ||||
| ssize_t read_timeout(int fd, void *buf, size_t count, long timeout) | ||||
| { | ||||
|   struct timeval tm, tm2; | ||||
|   fd_set rfds; | ||||
|   int nfds; | ||||
| 
 | ||||
|   tm.tv_sec  = timeout / 1000L; | ||||
|   tm.tv_usec = (timeout % 1000L) * 1000; | ||||
| 
 | ||||
|   while (1) { | ||||
|     FD_ZERO(&rfds); | ||||
|     FD_SET(fd, &rfds); | ||||
|     tm2 = tm; | ||||
|     nfds = select(fd + 1, &rfds, NULL, NULL, &tm2); | ||||
| 
 | ||||
|     if (nfds == 0) { | ||||
|       return -2; | ||||
|     } else if (nfds == -1) { | ||||
|       if (errno == EINTR || errno == EAGAIN) { | ||||
|         continue; | ||||
|       } else { | ||||
|         return -1; | ||||
|       } | ||||
|     } else { | ||||
|       return read(fd, buf, count); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| ssize_t write_timeout(int fd, const void *buf, size_t count, long timeout) | ||||
| { | ||||
|   struct timeval tm, tm2; | ||||
|   fd_set wfds; | ||||
|   int nfds; | ||||
| 
 | ||||
|   tm.tv_sec  = timeout / 1000L; | ||||
|   tm.tv_usec = (timeout % 1000L) * 1000; | ||||
| 
 | ||||
|   while (1) { | ||||
|     FD_ZERO(&wfds); | ||||
|     FD_SET(fd, &wfds); | ||||
|     tm2 = tm; | ||||
|     nfds = select(fd + 1, NULL, &wfds, NULL, &tm2); | ||||
| 
 | ||||
|     if (nfds == 0) { | ||||
|       return -2; | ||||
|     } else if (nfds == -1) { | ||||
|       if (errno == EINTR || errno == EAGAIN) { | ||||
|         continue; | ||||
|       } else { | ||||
|         return -1; | ||||
|       } | ||||
|     } else { | ||||
|       return write(fd, buf, count); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * Given a port description of the form <host>:<port>, open a TCP | ||||
|  * connection to the specified destination, which is assumed to be a | ||||
|  | @ -314,6 +376,7 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t | |||
|   int rc; | ||||
|   const unsigned char * p = buf; | ||||
|   size_t len = buflen; | ||||
|   unsigned zero_writes = 0; | ||||
| 
 | ||||
|   if (!len) | ||||
|     return 0; | ||||
|  | @ -341,14 +404,25 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t | |||
| 
 | ||||
|   while (len) { | ||||
|     RETURN_IF_CANCEL(); | ||||
|     rc = write(fd->ifd, p, (len > 1024) ? 1024 : len); | ||||
|     if (rc < 0) { | ||||
|       avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", | ||||
|               progname, strerror(errno)); | ||||
|     rc = write_timeout(fd->ifd, p, (len > 1024) ? 1024 : len, serial_recv_timeout); | ||||
|     if (rc == -2) { | ||||
|       avrdude_message(MSG_NOTICE2, "%s: ser_send(): programmer is not responding\n", progname); | ||||
|       return -1; | ||||
|     } else if (rc == -1) { | ||||
|       avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", progname, strerror(errno)); | ||||
|       return -1; | ||||
|     } else if (rc == 0) { | ||||
|       zero_writes++; | ||||
|       if (zero_writes > MAX_ZERO_READS) { | ||||
|         avrdude_message(MSG_NOTICE2, "%s: ser_send(): programmer is not responding (too many zero writes)\n", | ||||
|                 progname); | ||||
|         return -1; | ||||
|       } | ||||
|     } else { | ||||
|       zero_writes = 0; | ||||
|       p += rc; | ||||
|       len -= rc; | ||||
|     } | ||||
|     p += rc; | ||||
|     len -= rc; | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
|  | @ -357,51 +431,21 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t | |||
| 
 | ||||
| static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen) | ||||
| { | ||||
|   struct timeval timeout, to2; | ||||
|   fd_set rfds; | ||||
|   int nfds; | ||||
|   int rc; | ||||
|   unsigned char * p = buf; | ||||
|   size_t len = 0; | ||||
|   unsigned zero_reads = 0; | ||||
| 
 | ||||
|   timeout.tv_sec  = serial_recv_timeout / 1000L; | ||||
|   timeout.tv_usec = (serial_recv_timeout % 1000L) * 1000; | ||||
|   to2 = timeout; | ||||
| 
 | ||||
|   while (len < buflen) { | ||||
|   reselect: | ||||
|     RETURN_IF_CANCEL(); | ||||
|     FD_ZERO(&rfds); | ||||
|     FD_SET(fd->ifd, &rfds); | ||||
| 
 | ||||
|     nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &to2); | ||||
|     // FIXME: The timeout has different behaviour on Linux vs other Unices
 | ||||
|     // On Linux, the timeout is modified by subtracting the time spent,
 | ||||
|     // on OS X (for example), it is not modified.
 | ||||
|     // POSIX recommends re-initializing it before selecting.
 | ||||
|     if (nfds == 0) { | ||||
|       avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n", | ||||
|                         progname); | ||||
|     rc = read_timeout(fd->ifd, p, (buflen - len > 1024) ? 1024 : buflen - len, serial_recv_timeout); | ||||
| 
 | ||||
|     if (rc == -2) { | ||||
|       avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n", progname); | ||||
|       return -1; | ||||
|     } | ||||
|     else if (nfds == -1) { | ||||
|       if (errno == EINTR || errno == EAGAIN) { | ||||
| 	avrdude_message(MSG_INFO, "%s: ser_recv(): programmer is not responding,reselecting\n", | ||||
|                         progname); | ||||
|         goto reselect; | ||||
|       } | ||||
|       else { | ||||
|         avrdude_message(MSG_INFO, "%s: ser_recv(): select(): %s\n", | ||||
|                 progname, strerror(errno)); | ||||
|         return -1; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     rc = read(fd->ifd, p, (buflen - len > 1024) ? 1024 : buflen - len); | ||||
|     if (rc < 0) { | ||||
|       avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", | ||||
|               progname, strerror(errno)); | ||||
|     } else if (rc == -1) { | ||||
|       avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, strerror(errno)); | ||||
|       return -1; | ||||
|     } else if (rc == 0) { | ||||
|       zero_reads++; | ||||
|  | @ -445,49 +489,26 @@ static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen | |||
| 
 | ||||
| static int ser_drain(union filedescriptor *fd, int display) | ||||
| { | ||||
|   struct timeval timeout; | ||||
|   fd_set rfds; | ||||
|   int nfds; | ||||
|   int rc; | ||||
|   unsigned char buf; | ||||
|   unsigned zero_reads = 0; | ||||
| 
 | ||||
|   timeout.tv_sec = 0; | ||||
|   timeout.tv_usec = 250000; | ||||
| 
 | ||||
|   if (display) { | ||||
|     avrdude_message(MSG_INFO, "drain>"); | ||||
|   } | ||||
| 
 | ||||
|   while (1) { | ||||
|     FD_ZERO(&rfds); | ||||
|     FD_SET(fd->ifd, &rfds); | ||||
| 
 | ||||
|   reselect: | ||||
|     RETURN_IF_CANCEL(); | ||||
|     nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &timeout); | ||||
|     if (nfds == 0) { | ||||
| 
 | ||||
|     rc = read_timeout(fd->ifd, &buf, 1, 250);   // Note: timeout needs to be kept low to not timeout in programmers
 | ||||
|     if (rc == -2) { | ||||
|       if (display) { | ||||
|         avrdude_message(MSG_INFO, "<drain\n"); | ||||
|       } | ||||
|        | ||||
|       break; | ||||
|     } | ||||
|     else if (nfds == -1) { | ||||
|       if (errno == EINTR) { | ||||
|         goto reselect; | ||||
|       } | ||||
|       else { | ||||
|         avrdude_message(MSG_INFO, "%s: ser_drain(): select(): %s\n", | ||||
|                 progname, strerror(errno)); | ||||
|         return -1; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     rc = read(fd->ifd, &buf, 1); | ||||
|     if (rc < 0) { | ||||
|       avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", | ||||
|               progname, strerror(errno)); | ||||
|       break; | ||||
|     } else if (rc == -1) { | ||||
|       avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", progname, strerror(errno)); | ||||
|       return -1; | ||||
|     } else if (rc == 0) { | ||||
|       zero_reads++; | ||||
|  |  | |||
|  | @ -34,16 +34,63 @@ | |||
| 
 | ||||
| #include <windows.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <ctype.h>   /* for isprint */ | ||||
| #include <errno.h>   /* ENOTTY */ | ||||
| 
 | ||||
| #include "avrdude.h" | ||||
| #include "libavrdude.h" | ||||
| #include "windows/utf8.h" | ||||
| 
 | ||||
| long serial_recv_timeout = 5000; /* ms */ | ||||
| 
 | ||||
| #define W32SERBUFSIZE 1024 | ||||
| 
 | ||||
| 
 | ||||
| // Get last error message string in UTF-8
 | ||||
| // Always return a valid null-terminated string
 | ||||
| // The returned string should be freed by the caller
 | ||||
| char* last_error_string(int wsa) | ||||
| { | ||||
| 	LPWSTR wbuffer = NULL; | ||||
| 
 | ||||
| 	(void)wsa; | ||||
| 
 | ||||
| 	DWORD wbuffer_len = FormatMessageW( | ||||
| 		FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||||
| 		FORMAT_MESSAGE_FROM_SYSTEM | | ||||
| 		FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
| 		NULL, | ||||
| #ifdef HAVE_LIBWS2_32 | ||||
| 		wsa ? WSAGetLastError() : GetLastError(), | ||||
| #else | ||||
| 		GetLastError(), | ||||
| #endif | ||||
| 		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||||
| 		(LPWSTR)&wbuffer, | ||||
| 		0, | ||||
| 		NULL); | ||||
| 
 | ||||
| 	if (wbuffer_len == 0) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	char *res = wstr_to_utf8(wbuffer, wbuffer_len); | ||||
| 
 | ||||
| 	LocalFree(wbuffer); | ||||
| 
 | ||||
| 	if (res == NULL) { | ||||
| 		// If we get here, conversion to UTF-8 failed
 | ||||
| 		res = strdup("(could not get error message)"); | ||||
| 		if (res == NULL) { | ||||
| 			avrdude_oom("last_error_string(): out of memory\n"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return res; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| struct baud_mapping { | ||||
|   long baud; | ||||
|   DWORD speed; | ||||
|  | @ -95,6 +142,7 @@ static BOOL serial_w32SetTimeOut(HANDLE hComPort, DWORD timeout) // in ms | |||
| 	// ctmo.ReadIntervalTimeout = timeout;
 | ||||
| 	// ctmo.ReadTotalTimeoutMultiplier = timeout;
 | ||||
| 	ctmo.ReadTotalTimeoutConstant = timeout; | ||||
| 	ctmo.WriteTotalTimeoutConstant = timeout; | ||||
| 
 | ||||
| 	return SetCommTimeouts(hComPort, &ctmo); | ||||
| } | ||||
|  | @ -129,7 +177,6 @@ static int | |||
| net_open(const char *port, union filedescriptor *fdp) | ||||
| { | ||||
| 	WSADATA wsaData; | ||||
| 	LPVOID lpMsgBuf; | ||||
| 
 | ||||
| 	char *hstr, *pstr, *end; | ||||
| 	unsigned int pnum; | ||||
|  | @ -175,18 +222,10 @@ net_open(const char *port, union filedescriptor *fdp) | |||
| 	free(hstr); | ||||
| 
 | ||||
| 	if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { | ||||
| 		FormatMessage( | ||||
| 			FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||||
| 			FORMAT_MESSAGE_FROM_SYSTEM | | ||||
| 			FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
| 			NULL, | ||||
| 			WSAGetLastError(), | ||||
| 			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||||
| 			(LPTSTR)&lpMsgBuf, | ||||
| 			0, | ||||
| 			NULL); | ||||
| 		avrdude_message(MSG_INFO, "%s: net_open(): Cannot open socket: %s\n", progname, (char *)lpMsgBuf); | ||||
| 		LocalFree(lpMsgBuf); | ||||
| 		const char *error = last_error_string(1); | ||||
| 		avrdude_message(MSG_INFO, "%s: net_open(): Cannot open socket: %s\n", progname, error); | ||||
| 		free(error); | ||||
| 
 | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -196,18 +235,9 @@ net_open(const char *port, union filedescriptor *fdp) | |||
| 	memcpy(&(sockaddr.sin_addr.s_addr), hp->h_addr, sizeof(struct in_addr)); | ||||
| 
 | ||||
| 	if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { | ||||
| 		FormatMessage( | ||||
| 			FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||||
| 			FORMAT_MESSAGE_FROM_SYSTEM | | ||||
| 			FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
| 			NULL, | ||||
| 			WSAGetLastError(), | ||||
| 			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||||
| 			(LPTSTR)&lpMsgBuf, | ||||
| 			0, | ||||
| 			NULL); | ||||
| 		avrdude_message(MSG_INFO, "%s: net_open(): Connect failed: %s\n", progname, (char *)lpMsgBuf); | ||||
| 		LocalFree(lpMsgBuf); | ||||
| 		const char *error = last_error_string(1); | ||||
| 		avrdude_message(MSG_INFO, "%s: net_open(): Connect failed: %s\n", progname); | ||||
| 		free(error); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -221,7 +251,6 @@ net_open(const char *port, union filedescriptor *fdp) | |||
| 
 | ||||
| static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp) | ||||
| { | ||||
| 	LPVOID lpMsgBuf; | ||||
| 	HANDLE hComPort=INVALID_HANDLE_VALUE; | ||||
| 	char *newname = 0; | ||||
| 
 | ||||
|  | @ -261,19 +290,9 @@ static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp) | |||
| 		OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | ||||
| 
 | ||||
| 	if (hComPort == INVALID_HANDLE_VALUE) { | ||||
| 		FormatMessage( | ||||
| 			FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||||
| 			FORMAT_MESSAGE_FROM_SYSTEM | | ||||
| 			FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
| 			NULL, | ||||
| 			GetLastError(), | ||||
| 			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
 | ||||
| 			(LPTSTR) &lpMsgBuf, | ||||
| 			0, | ||||
| 			NULL); | ||||
| 		avrdude_message(MSG_INFO, "%s: ser_open(): can't open device \"%s\": %s\n", | ||||
| 				progname, port, (char*)lpMsgBuf); | ||||
| 		LocalFree( lpMsgBuf ); | ||||
| 		const char *error = last_error_string(0); | ||||
| 		avrdude_message(MSG_INFO, "%s: ser_open(): can't open device \"%s\": %s\n", progname, port, error); | ||||
| 		free(error); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -346,14 +365,13 @@ static int ser_set_dtr_rts(union filedescriptor *fd, int is_on) | |||
| #ifdef HAVE_LIBWS2_32 | ||||
| static int net_send(union filedescriptor *fd, const unsigned char * buf, size_t buflen) | ||||
| { | ||||
| 	LPVOID lpMsgBuf; | ||||
| 	int rc; | ||||
| 	const unsigned char *p = buf; | ||||
| 	size_t len = buflen; | ||||
| 
 | ||||
| 	if (fd->ifd < 0) { | ||||
| 		avrdude_message(MSG_NOTICE, "%s: net_send(): connection not open\n", progname); | ||||
| 		exit(1); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!len) { | ||||
|  | @ -382,19 +400,10 @@ static int net_send(union filedescriptor *fd, const unsigned char * buf, size_t | |||
| 	while (len) { | ||||
| 		rc = send(fd->ifd, p, (len > 1024) ? 1024 : len, 0); | ||||
| 		if (rc < 0) { | ||||
| 			FormatMessage( | ||||
| 				FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||||
| 				FORMAT_MESSAGE_FROM_SYSTEM | | ||||
| 				FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
| 				NULL, | ||||
| 				WSAGetLastError(), | ||||
| 				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||||
| 				(LPTSTR)&lpMsgBuf, | ||||
| 				0, | ||||
| 				NULL); | ||||
| 			avrdude_message(MSG_INFO, "%s: net_send(): send error: %s\n", progname, (char *)lpMsgBuf); | ||||
| 			LocalFree(lpMsgBuf); | ||||
| 			exit(1); | ||||
| 			const char *error = last_error_string(1); | ||||
| 			avrdude_message(MSG_INFO, "%s: net_send(): send error: %s\n", progname, error); | ||||
| 			free(error); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		p += rc; | ||||
| 		len -= rc; | ||||
|  | @ -423,8 +432,7 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t | |||
| 	HANDLE hComPort=(HANDLE)fd->pfd; | ||||
| 
 | ||||
| 	if (hComPort == INVALID_HANDLE_VALUE) { | ||||
| 		avrdude_message(MSG_INFO, "%s: ser_send(): port not open\n", | ||||
|               progname);  | ||||
| 		avrdude_message(MSG_INFO, "%s: ser_send(): port not open\n", progname); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -449,18 +457,18 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t | |||
| 		} | ||||
|       avrdude_message(MSG_INFO, "\n"); | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| 	serial_w32SetTimeOut(hComPort,500); | ||||
| 
 | ||||
| 	if (!WriteFile (hComPort, buf, buflen, &written, NULL)) { | ||||
| 		avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", | ||||
|               progname, "sorry no info avail"); // TODO
 | ||||
| 	if (!WriteFile(hComPort, buf, buflen, &written, NULL)) { | ||||
| 		const char *error = last_error_string(0); | ||||
| 		avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", progname, error); | ||||
| 		free(error); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (written != buflen) { | ||||
| 		avrdude_message(MSG_INFO, "%s: ser_send(): size/send mismatch\n", | ||||
|               progname);  | ||||
| 		avrdude_message(MSG_INFO, "%s: ser_send(): size/send mismatch\n", progname); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -471,7 +479,6 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t | |||
| #ifdef HAVE_LIBWS2_32 | ||||
| static int net_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen) | ||||
| { | ||||
| 	LPVOID lpMsgBuf; | ||||
| 	struct timeval timeout, to2; | ||||
| 	fd_set rfds; | ||||
| 	int nfds; | ||||
|  | @ -481,7 +488,7 @@ static int net_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen | |||
| 
 | ||||
| 	if (fd->ifd < 0) { | ||||
| 		avrdude_message(MSG_INFO, "%s: net_recv(): connection not open\n", progname); | ||||
| 		exit(1); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	timeout.tv_sec  = serial_recv_timeout / 1000L; | ||||
|  | @ -504,37 +511,19 @@ reselect: | |||
| 				avrdude_message(MSG_NOTICE, "%s: ser_recv(): programmer is not responding, reselecting\n", progname); | ||||
| 				goto reselect; | ||||
| 			} else { | ||||
| 				FormatMessage( | ||||
| 					FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||||
| 					FORMAT_MESSAGE_FROM_SYSTEM | | ||||
| 					FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
| 					NULL, | ||||
| 					WSAGetLastError(), | ||||
| 					MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||||
| 					(LPTSTR)&lpMsgBuf, | ||||
| 					0, | ||||
| 					NULL); | ||||
| 				avrdude_message(MSG_INFO, "%s: ser_recv(): select(): %s\n", progname, (char *)lpMsgBuf); | ||||
| 				LocalFree(lpMsgBuf); | ||||
| 				exit(1); | ||||
| 				const char *error = last_error_string(1); | ||||
| 				avrdude_message(MSG_INFO, "%s: ser_recv(): select(): %s\n", progname, error); | ||||
| 				free(error); | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		rc = recv(fd->ifd, p, (buflen - len > 1024) ? 1024 : buflen - len, 0); | ||||
| 		if (rc < 0) { | ||||
| 			FormatMessage( | ||||
| 				FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||||
| 				FORMAT_MESSAGE_FROM_SYSTEM | | ||||
| 				FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
| 				NULL, | ||||
| 				WSAGetLastError(), | ||||
| 				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||||
| 				(LPTSTR)&lpMsgBuf, | ||||
| 				0, | ||||
| 				NULL); | ||||
| 			avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, (char *)lpMsgBuf); | ||||
| 			LocalFree(lpMsgBuf); | ||||
| 			exit(1); | ||||
| 			const char *error = last_error_string(1); | ||||
| 			avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, error); | ||||
| 			free(error); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		p += rc; | ||||
| 		len += rc; | ||||
|  | @ -579,37 +568,24 @@ static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen | |||
| 	RETURN_IF_CANCEL(); | ||||
| 
 | ||||
| 	HANDLE hComPort=(HANDLE)fd->pfd; | ||||
| 	 | ||||
| 
 | ||||
| 	if (hComPort == INVALID_HANDLE_VALUE) { | ||||
| 		avrdude_message(MSG_INFO, "%s: ser_read(): port not open\n", | ||||
|               progname);  | ||||
| 		avrdude_message(MSG_INFO, "%s: ser_read(): port not open\n", progname); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| 	serial_w32SetTimeOut(hComPort, serial_recv_timeout); | ||||
| 	 | ||||
| 
 | ||||
| 	if (!ReadFile(hComPort, buf, buflen, &read, NULL)) { | ||||
| 		LPVOID lpMsgBuf; | ||||
| 		FormatMessage(  | ||||
| 			FORMAT_MESSAGE_ALLOCATE_BUFFER |  | ||||
| 			FORMAT_MESSAGE_FROM_SYSTEM |  | ||||
| 			FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
| 			NULL, | ||||
| 			GetLastError(), | ||||
| 			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
 | ||||
| 			(LPTSTR) &lpMsgBuf, | ||||
| 			0, | ||||
| 			NULL 	); | ||||
| 		avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", | ||||
| 			      progname, (char*)lpMsgBuf); | ||||
| 		LocalFree( lpMsgBuf ); | ||||
| 		const char *error = last_error_string(0); | ||||
| 		avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, error); | ||||
| 		free(error); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	/* time out detected */ | ||||
| 	if (read == 0) { | ||||
| 		avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n", | ||||
|                                 progname); | ||||
| 		avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n", progname); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -664,20 +640,9 @@ static int ser_drain(union filedescriptor *fd, int display) | |||
| 
 | ||||
| 		readres=ReadFile(hComPort, buf, 1, &read, NULL); | ||||
| 		if (!readres) { | ||||
| 			LPVOID lpMsgBuf; | ||||
| 			FormatMessage(  | ||||
| 				FORMAT_MESSAGE_ALLOCATE_BUFFER |  | ||||
| 				FORMAT_MESSAGE_FROM_SYSTEM |  | ||||
| 				FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
| 				NULL, | ||||
| 				GetLastError(), | ||||
| 				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
 | ||||
| 				(LPTSTR) &lpMsgBuf, | ||||
| 				0, | ||||
| 				NULL 	); | ||||
| 			avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", | ||||
| 					  progname, (char*)lpMsgBuf); | ||||
| 			LocalFree( lpMsgBuf ); | ||||
| 			const char *error = last_error_string(0); | ||||
| 			avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", progname, error); | ||||
| 			free(error); | ||||
| 			return -1; | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -669,11 +669,15 @@ static int stk500_open(PROGRAMMER * pgm, char * port) | |||
| 
 | ||||
|   // MIB510 init
 | ||||
|   if (strcmp(ldata(lfirst(pgm->id)), "mib510") == 0 && | ||||
|       mib510_isp(pgm, 1) != 0) | ||||
|       mib510_isp(pgm, 1) != 0) { | ||||
|     serial_close(&pgm->fd); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   if (stk500_getsync(pgm) < 0) | ||||
|   if (stk500_getsync(pgm) < 0) { | ||||
|     serial_close(&pgm->fd); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  |  | |||
|  | @ -1695,8 +1695,10 @@ static int stk500v2_open(PROGRAMMER * pgm, char * port) | |||
|   stk500v2_drain(pgm, 0); | ||||
| 
 | ||||
|   if (pgm->bitclock != 0.0) { | ||||
|     if (pgm->set_sck_period(pgm, pgm->bitclock) != 0) | ||||
|     if (pgm->set_sck_period(pgm, pgm->bitclock) != 0) { | ||||
|       serial_close(&pgm->fd); | ||||
|       return -1; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
|  | @ -1753,8 +1755,10 @@ static int stk600_open(PROGRAMMER * pgm, char * port) | |||
|   stk500v2_drain(pgm, 0); | ||||
| 
 | ||||
|   if (pgm->bitclock != 0.0) { | ||||
|     if (pgm->set_sck_period(pgm, pgm->bitclock) != 0) | ||||
|     if (pgm->set_sck_period(pgm, pgm->bitclock) != 0) { | ||||
|       serial_close(&pgm->fd); | ||||
|       return -1; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
|  |  | |||
							
								
								
									
										45
									
								
								src/avrdude/windows/utf8.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/avrdude/windows/utf8.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | |||
| #include "utf8.h" | ||||
| 
 | ||||
| 
 | ||||
| char* wstr_to_utf8(LPWSTR wstr, int len) | ||||
| { | ||||
| 	char *res = NULL; | ||||
| 
 | ||||
| 	int res_size = WideCharToMultiByte(CP_UTF8, 0, wstr, len, NULL, 0, NULL, NULL); | ||||
| 	if (res_size > 0) { | ||||
| 		// Note: WideCharToMultiByte doesn't null-terminate if real (ie. > 0) buffer length is passed
 | ||||
| 		res = malloc(len != - 1 ? res_size + 1 : res_size); | ||||
| 		if (res == NULL) { return NULL; } | ||||
| 
 | ||||
| 		if (WideCharToMultiByte(CP_UTF8, 0, wstr, len, res, res_size, NULL, NULL) == res_size) { | ||||
| 			if (len != -1) { res[res_size] = '\0'; } | ||||
| 		} else { | ||||
| 			free(res); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return res; | ||||
| } | ||||
| 
 | ||||
| LPWSTR utf8_to_wstr(const char *str, int len) | ||||
| { | ||||
| 	LPWSTR res = NULL; | ||||
| 
 | ||||
| 	int res_size = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); | ||||
| 	if (res_size > 0) { | ||||
| 		// Note: MultiByteToWideChar doesn't null-terminate if real (ie. > 0) buffer length is passed
 | ||||
| 		res = malloc(len != - 1 ? res_size + 1 : res_size); | ||||
| 
 | ||||
| 		if (res == NULL) { return NULL; } | ||||
| 
 | ||||
| 		if (MultiByteToWideChar(CP_UTF8, 0, str, len, res, res_size) == res_size) { | ||||
| 			if (len != -1) { res[res_size] = L'\0'; } | ||||
| 		} else { | ||||
| 			free(res); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return res; | ||||
| } | ||||
							
								
								
									
										10
									
								
								src/avrdude/windows/utf8.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/avrdude/windows/utf8.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| #ifndef SLIC3R_AVRDUDE_UTF8_H | ||||
| #define SLIC3R_AVRDUDE_UTF8_H | ||||
| 
 | ||||
| #include <windows.h> | ||||
| 
 | ||||
| extern char* wstr_to_utf8(LPWSTR wstr, int len); | ||||
| extern LPWSTR utf8_to_wstr(const char *str, int len); | ||||
| 
 | ||||
| 
 | ||||
| #endif  // SLIC3R_AVRDUDE_UTF8_H
 | ||||
|  | @ -192,8 +192,10 @@ static int wiring_open(PROGRAMMER * pgm, char * port) | |||
|   /* drain any extraneous input */ | ||||
|   stk500v2_drain(pgm, 0); | ||||
| 
 | ||||
|   if (stk500v2_getsync(pgm) < 0) | ||||
|   if (stk500v2_getsync(pgm) < 0) { | ||||
|     serial_close(&pgm->fd); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  |  | |||
|  | @ -2488,6 +2488,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, | |||
|     // adds analyzer tags and updates analyzer's tracking data
 | ||||
|     if (m_enable_analyzer) | ||||
|     { | ||||
|         // PrusaMultiMaterial::Writer may generate GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines without updating m_last_height and m_last_width
 | ||||
|         // so, if the last role was erWipeTower we force export of GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines
 | ||||
|         bool last_was_wipe_tower = (m_last_analyzer_extrusion_role == erWipeTower); | ||||
| 
 | ||||
|         if (path.role() != m_last_analyzer_extrusion_role) | ||||
|         { | ||||
|             m_last_analyzer_extrusion_role = path.role(); | ||||
|  | @ -2505,7 +2509,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, | |||
|             gcode += buf; | ||||
|         } | ||||
| 
 | ||||
|         if (m_last_width != path.width) | ||||
|         if (last_was_wipe_tower || (m_last_width != path.width)) | ||||
|         { | ||||
|             m_last_width = path.width; | ||||
| 
 | ||||
|  | @ -2514,7 +2518,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, | |||
|             gcode += buf; | ||||
|         } | ||||
| 
 | ||||
|         if (m_last_height != path.height) | ||||
|         if (last_was_wipe_tower || (m_last_height != path.height)) | ||||
|         { | ||||
|             m_last_height = path.height; | ||||
| 
 | ||||
|  |  | |||
|  | @ -59,6 +59,17 @@ void PrintConfigDef::init_common_params() | |||
|     def->cli = "max-print-height=f"; | ||||
|     def->mode = comAdvanced; | ||||
|     def->default_value = new ConfigOptionFloat(200.0); | ||||
| 
 | ||||
|     def = this->add("slice_closing_radius", coFloat); | ||||
|     def->label = L("Slice gap closing radius"); | ||||
|     def->category = L("Advanced"); | ||||
|     def->tooltip = L("Cracks smaller than 2x gap closing radius are being filled during the triangle mesh slicing. " | ||||
|                      "The gap closing operation may reduce the final print resolution, therefore it is advisable to keep the value reasonably low."); | ||||
|     def->sidetext = L("mm"); | ||||
|     def->cli = "slice-closing-radius=f"; | ||||
|     def->min = 0; | ||||
| 	def->mode = comAdvanced; | ||||
| 	def->default_value = new ConfigOptionFloat(0.049); | ||||
| } | ||||
| 
 | ||||
| void PrintConfigDef::init_fff_params() | ||||
|  |  | |||
|  | @ -384,6 +384,7 @@ public: | |||
|     ConfigOptionEnum<SeamPosition>  seam_position; | ||||
| //    ConfigOptionFloat               seam_preferred_direction;
 | ||||
| //    ConfigOptionFloat               seam_preferred_direction_jitter;
 | ||||
|     ConfigOptionFloat               slice_closing_radius; | ||||
|     ConfigOptionBool                support_material; | ||||
|     // Automatic supports (generated based on support_material_threshold).
 | ||||
|     ConfigOptionBool                support_material_auto; | ||||
|  | @ -425,6 +426,7 @@ protected: | |||
|         OPT_PTR(layer_height); | ||||
|         OPT_PTR(raft_layers); | ||||
|         OPT_PTR(seam_position); | ||||
|         OPT_PTR(slice_closing_radius); | ||||
| //        OPT_PTR(seam_preferred_direction);
 | ||||
| //        OPT_PTR(seam_preferred_direction_jitter);
 | ||||
|         OPT_PTR(support_material); | ||||
|  | @ -963,6 +965,8 @@ public: | |||
|     //Number of the layers needed for the exposure time fade [3;20]
 | ||||
|     ConfigOptionInt  faded_layers /*= 10*/; | ||||
| 
 | ||||
|     ConfigOptionFloat slice_closing_radius; | ||||
| 
 | ||||
|     // Enabling or disabling support creation
 | ||||
|     ConfigOptionBool  supports_enable; | ||||
| 
 | ||||
|  | @ -1036,6 +1040,7 @@ protected: | |||
|     { | ||||
|         OPT_PTR(layer_height); | ||||
|         OPT_PTR(faded_layers); | ||||
|         OPT_PTR(slice_closing_radius); | ||||
|         OPT_PTR(supports_enable); | ||||
|         OPT_PTR(support_head_front_diameter); | ||||
|         OPT_PTR(support_head_penetration); | ||||
|  |  | |||
|  | @ -157,8 +157,6 @@ template<> class FilePrinter<FilePrinterFormat::SLA_PNGZIP> | |||
|         "expTimeFirst = " + expt_first_str + "\n" | ||||
|         "numFade = " + cnt_fade_layers + "\n" | ||||
|         "layerHeight = " + layerh_str + "\n" | ||||
|         "expTime = "+expt_str+" + resinType = generic+layerHeight = " | ||||
|                   +layerh_str+" + printer = DWARF3\n" | ||||
|         "usedMaterial = " + used_material + "\n" | ||||
|         "numSlow = " + cnt_slow_layers + "\n" | ||||
|         "numFast = " + cnt_fast_layers + "\n"; | ||||
|  |  | |||
|  | @ -453,7 +453,8 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_ | |||
|         } else if ( | ||||
|                opt_key == "layer_height" | ||||
|             || opt_key == "first_layer_height" | ||||
|             || opt_key == "raft_layers") { | ||||
|             || opt_key == "raft_layers" | ||||
|             || opt_key == "slice_closing_radius") { | ||||
|             steps.emplace_back(posSlice); | ||||
| 		} | ||||
| 		else if ( | ||||
|  | @ -1643,7 +1644,7 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z, | |||
|             const Print *print = this->print(); | ||||
|             auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();}); | ||||
|             mslicer.init(&mesh, callback); | ||||
|             mslicer.slice(z, &layers, callback); | ||||
| 			mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback); | ||||
|             m_print->throw_if_canceled(); | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -561,7 +561,7 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h, | |||
|         heights.emplace_back(hi); | ||||
| 
 | ||||
|     std::vector<ExPolygons> out; out.reserve(size_t(std::ceil(h/layerh))); | ||||
|     slicer.slice(heights, &out, thrfn); | ||||
|     slicer.slice(heights, 0.f, &out, thrfn); | ||||
| 
 | ||||
|     size_t count = 0; for(auto& o : out) count += o.size(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -2105,7 +2105,7 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const | |||
|     fullmesh.merge(get_pad()); | ||||
|     TriangleMeshSlicer slicer(&fullmesh); | ||||
|     SlicedSupports ret; | ||||
|     slicer.slice(heights, &ret, get().ctl().cancelfn); | ||||
|     slicer.slice(heights, 0.f, &ret, get().ctl().cancelfn); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
|  |  | |||
|  | @ -337,7 +337,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf | |||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             if (model_object.sla_support_points != model_object_new.sla_support_points) { | ||||
|             /*if (model_object.sla_support_points != model_object_new.sla_support_points) {
 | ||||
|                 model_object.sla_support_points = model_object_new.sla_support_points; | ||||
|                 if (it_print_object_status != print_object_status.end()) | ||||
|                     update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); | ||||
|  | @ -351,6 +351,18 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf | |||
|                     if (it_print_object_status != print_object_status.end()) | ||||
|                         update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); | ||||
|                 model_object.sla_points_status = model_object_new.sla_points_status; | ||||
|             }*/ | ||||
| 
 | ||||
|             bool old_user_modified = model_object.sla_points_status == sla::PointsStatus::UserModified; | ||||
|             bool new_user_modified = model_object_new.sla_points_status == sla::PointsStatus::UserModified; | ||||
|             if ((old_user_modified && ! new_user_modified) || // switching to automatic supports from manual supports
 | ||||
|                 (! old_user_modified && new_user_modified) || // switching to manual supports from automatic supports
 | ||||
|                 (new_user_modified && model_object.sla_support_points != model_object_new.sla_support_points)) { | ||||
|                 if (it_print_object_status != print_object_status.end()) | ||||
|                     update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); | ||||
| 
 | ||||
|                 model_object.sla_points_status = model_object_new.sla_points_status; | ||||
|                 model_object.sla_support_points = model_object_new.sla_support_points; | ||||
|             } | ||||
| 
 | ||||
|             // Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
 | ||||
|  | @ -625,7 +637,7 @@ void SLAPrint::process() | |||
|                                                        ilh, float(lh)); | ||||
| 
 | ||||
|         auto& layers = po.m_model_slices; layers.clear(); | ||||
|         slicer.slice(heights, &layers, [this](){ throw_if_canceled(); }); | ||||
| 		slicer.slice(heights, float(po.config().slice_closing_radius.value), &layers, [this](){ throw_if_canceled(); }); | ||||
|     }; | ||||
| 
 | ||||
|     // In this step we check the slices, identify island and cover them with
 | ||||
|  | @ -1358,7 +1370,8 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf | |||
|     bool invalidated = false; | ||||
|     for (const t_config_option_key &opt_key : opt_keys) { | ||||
| 		if (   opt_key == "layer_height" | ||||
|             || opt_key == "faded_layers") { | ||||
|             || opt_key == "faded_layers" | ||||
|             || opt_key == "slice_closing_radius") { | ||||
| 			steps.emplace_back(slaposObjectSlice); | ||||
|         } else if ( | ||||
|                opt_key == "supports_enable" | ||||
|  |  | |||
|  | @ -852,7 +852,7 @@ void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLin | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const | ||||
| void TriangleMeshSlicer::slice(const std::vector<float> &z, const float closing_radius, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const | ||||
| { | ||||
|     std::vector<Polygons> layers_p; | ||||
|     this->slice(z, &layers_p, throw_on_cancel); | ||||
|  | @ -861,13 +861,13 @@ void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<ExPolygo | |||
| 	layers->resize(z.size()); | ||||
| 	tbb::parallel_for( | ||||
| 		tbb::blocked_range<size_t>(0, z.size()), | ||||
| 		[&layers_p, layers, throw_on_cancel, this](const tbb::blocked_range<size_t>& range) { | ||||
| 		[&layers_p, closing_radius, layers, throw_on_cancel, this](const tbb::blocked_range<size_t>& range) { | ||||
|     		for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) { | ||||
| #ifdef SLIC3R_TRIANGLEMESH_DEBUG | ||||
|                 printf("Layer " PRINTF_ZU " (slice_z = %.2f):\n", layer_id, z[layer_id]); | ||||
| #endif | ||||
|                 throw_on_cancel(); | ||||
|     			this->make_expolygons(layers_p[layer_id], &(*layers)[layer_id]); | ||||
|     			this->make_expolygons(layers_p[layer_id], closing_radius, &(*layers)[layer_id]); | ||||
|     		} | ||||
|     	}); | ||||
| 	BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::make_expolygons in parallel - end"; | ||||
|  | @ -1600,7 +1600,7 @@ void TriangleMeshSlicer::make_expolygons_simple(std::vector<IntersectionLine> &l | |||
| #endif | ||||
| } | ||||
| 
 | ||||
| void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slices) const | ||||
| void TriangleMeshSlicer::make_expolygons(const Polygons &loops, const float closing_radius, ExPolygons* slices) const | ||||
| { | ||||
|     /*
 | ||||
|         Input loops are not suitable for evenodd nor nonzero fill types, as we might get | ||||
|  | @ -1655,7 +1655,7 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slic | |||
|     // 0.0499 comes from https://github.com/slic3r/Slic3r/issues/959
 | ||||
| //    double safety_offset = scale_(0.0499);
 | ||||
|     // 0.0001 is set to satisfy GH #520, #1029, #1364
 | ||||
|     double safety_offset = scale_(0.0001); | ||||
|     double safety_offset = scale_(closing_radius); | ||||
| 
 | ||||
|     /* The following line is commented out because it can generate wrong polygons,
 | ||||
|        see for example issue #661 */ | ||||
|  | @ -1670,17 +1670,17 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slic | |||
|     #endif | ||||
|      | ||||
|     // append to the supplied collection
 | ||||
|     /* Fix for issue #661 { */ | ||||
|     expolygons_append(*slices, offset2_ex(union_(loops, false), +safety_offset, -safety_offset)); | ||||
|     //expolygons_append(*slices, ex_slices);
 | ||||
|     /* } */ | ||||
|     if (safety_offset > 0) | ||||
|         expolygons_append(*slices, offset2_ex(union_(loops, false), +safety_offset, -safety_offset)); | ||||
|     else | ||||
|         expolygons_append(*slices, union_ex(loops, false)); | ||||
| } | ||||
| 
 | ||||
| void TriangleMeshSlicer::make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const | ||||
| void TriangleMeshSlicer::make_expolygons(std::vector<IntersectionLine> &lines, const float closing_radius, ExPolygons* slices) const | ||||
| { | ||||
|     Polygons pp; | ||||
|     this->make_loops(lines, &pp); | ||||
|     this->make_expolygons(pp, slices); | ||||
|     this->make_expolygons(pp, closing_radius, slices); | ||||
| } | ||||
| 
 | ||||
| void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const | ||||
|  |  | |||
|  | @ -165,7 +165,7 @@ public: | |||
| 	TriangleMeshSlicer(TriangleMesh* mesh) { this->init(mesh, [](){}); } | ||||
|     void init(TriangleMesh *mesh, throw_on_cancel_callback_type throw_on_cancel); | ||||
|     void slice(const std::vector<float> &z, std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const; | ||||
|     void slice(const std::vector<float> &z, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const; | ||||
|     void slice(const std::vector<float> &z, const float closing_radius, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const; | ||||
|     enum FacetSliceType { | ||||
|         NoSlice = 0, | ||||
|         Slicing = 1, | ||||
|  | @ -184,9 +184,9 @@ private: | |||
| 
 | ||||
|     void _slice_do(size_t facet_idx, std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex, const std::vector<float> &z) const; | ||||
|     void make_loops(std::vector<IntersectionLine> &lines, Polygons* loops) const; | ||||
|     void make_expolygons(const Polygons &loops, ExPolygons* slices) const; | ||||
|     void make_expolygons(const Polygons &loops, const float closing_radius, ExPolygons* slices) const; | ||||
|     void make_expolygons_simple(std::vector<IntersectionLine> &lines, ExPolygons* slices) const; | ||||
|     void make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const; | ||||
|     void make_expolygons(std::vector<IntersectionLine> &lines, const float closing_radius, ExPolygons* slices) const; | ||||
| }; | ||||
| 
 | ||||
| TriangleMesh make_cube(double x, double y, double z); | ||||
|  |  | |||
|  | @ -1004,7 +1004,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) | |||
|     p->btn_prev = new wxButton(this, wxID_ANY, _(L("< &Back"))); | ||||
|     p->btn_next = new wxButton(this, wxID_ANY, _(L("&Next >"))); | ||||
|     p->btn_finish = new wxButton(this, wxID_APPLY, _(L("&Finish"))); | ||||
|     p->btn_cancel = new wxButton(this, wxID_CANCEL); | ||||
|     p->btn_cancel = new wxButton(this, wxID_CANCEL, _(L("Cancel")));   // Note: The label needs to be present, otherwise we get accelerator bugs on Mac
 | ||||
|     p->btnsizer->AddStretchSpacer(); | ||||
|     p->btnsizer->Add(p->btn_prev, 0, wxLEFT, BTN_SPACING); | ||||
|     p->btnsizer->Add(p->btn_next, 0, wxLEFT, BTN_SPACING); | ||||
|  |  | |||
|  | @ -122,7 +122,6 @@ struct FirmwareDialog::priv | |||
| 	// This is a shared pointer holding the background AvrDude task
 | ||||
| 	// also serves as a status indication (it is set _iff_ the background task is running, otherwise it is reset).
 | ||||
| 	AvrDude::Ptr avrdude; | ||||
| 	std::string avrdude_config; | ||||
| 	unsigned progress_tasks_done; | ||||
| 	unsigned progress_tasks_bar; | ||||
| 	bool user_cancelled; | ||||
|  | @ -134,7 +133,6 @@ struct FirmwareDialog::priv | |||
| 		btn_flash_label_flashing(_(L("Cancel"))), | ||||
| 		label_status_flashing(_(L("Flashing in progress. Please do not disconnect the printer!"))), | ||||
| 		timer_pulse(q), | ||||
| 		avrdude_config((fs::path(::Slic3r::resources_dir()) / "avrdude" / "avrdude.conf").string()), | ||||
| 		progress_tasks_done(0), | ||||
| 		progress_tasks_bar(0), | ||||
| 		user_cancelled(false), | ||||
|  | @ -553,7 +551,7 @@ void FirmwareDialog::priv::perform_upload() | |||
| 	flashing_start(hex_file.device == HexFile::DEV_MK3 ? 2 : 1); | ||||
| 
 | ||||
| 	// Init the avrdude object
 | ||||
| 	AvrDude avrdude(avrdude_config); | ||||
| 	AvrDude avrdude; | ||||
| 
 | ||||
| 	// It is ok here to use the q-pointer to the FirmwareDialog
 | ||||
| 	// because the dialog ensures it doesn't exit before the background thread is done.
 | ||||
|  | @ -722,7 +720,7 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : | |||
| 	panel->SetSizer(vsizer); | ||||
| 
 | ||||
| 	auto *label_hex_picker = new wxStaticText(panel, wxID_ANY, _(L("Firmware image:"))); | ||||
| 	p->hex_picker = new wxFilePickerCtrl(panel, wxID_ANY, wxEmptyString, wxFileSelectorPromptStr,  | ||||
| 	p->hex_picker = new wxFilePickerCtrl(panel, wxID_ANY, wxEmptyString, wxFileSelectorPromptStr, | ||||
| 		"Hex files (*.hex)|*.hex|All files|*.*"); | ||||
| 
 | ||||
| 	auto *label_port_picker = new wxStaticText(panel, wxID_ANY, _(L("Serial port:"))); | ||||
|  | @ -770,7 +768,7 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : | |||
| 	// Experience says it needs to be 1, otherwise things won't get sized properly.
 | ||||
| 	vsizer->Add(p->spoiler, 1, wxEXPAND | wxBOTTOM, SPACING); | ||||
| 
 | ||||
| 	p->btn_close = new wxButton(panel, wxID_CLOSE); | ||||
| 	p->btn_close = new wxButton(panel, wxID_CLOSE, _(L("Close")));   // Note: The label needs to be present, otherwise we get accelerator bugs on Mac
 | ||||
| 	p->btn_flash = new wxButton(panel, wxID_ANY, p->btn_flash_label_ready); | ||||
| 	p->btn_flash->Disable(); | ||||
| 	auto *bsizer = new wxBoxSizer(wxHORIZONTAL); | ||||
|  |  | |||
|  | @ -896,8 +896,7 @@ void GLCanvas3D::Selection::add(unsigned int volume_idx, bool as_single_selectio | |||
|     if (needs_reset) | ||||
|         clear(); | ||||
| 
 | ||||
|     if (volume->is_modifier) | ||||
|         m_mode = Volume; | ||||
|     m_mode = volume->is_modifier ? Volume : Instance; | ||||
| 
 | ||||
|     switch (m_mode) | ||||
|     { | ||||
|  | @ -1261,17 +1260,22 @@ static double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to | |||
| 	return (axis.z() < 0) ? -angle : angle; | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) | ||||
| // Rotate an object around one of the axes. Only one rotation component is expected to be changing.
 | ||||
| void GLCanvas3D::Selection::rotate(const Vec3d& rotation, GLCanvas3D::TransformationType transformation_type) | ||||
| { | ||||
|     if (!m_valid) | ||||
|         return; | ||||
| 
 | ||||
|     // Only relative rotation values are allowed in the world coordinate system.
 | ||||
|     assert(! transformation_type.world() || transformation_type.relative()); | ||||
| 
 | ||||
|     int rot_axis_max; | ||||
|     //FIXME this does not work for absolute rotations (transformation_type.absolute() is true)
 | ||||
|     rotation.cwiseAbs().maxCoeff(&rot_axis_max); | ||||
| 
 | ||||
| 	// For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it.
 | ||||
| 	std::vector<int> object_instance_first(m_model->objects.size(), -1); | ||||
| 	auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, local](GLVolume &volume, int i) { | ||||
| 	auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, transformation_type](GLVolume &volume, int i) { | ||||
|         int first_volume_idx = object_instance_first[volume.object_idx()]; | ||||
|         if (rot_axis_max != 2 && first_volume_idx != -1) { | ||||
|             // Generic rotation, but no rotation around the Z axis.
 | ||||
|  | @ -1283,11 +1287,14 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) | |||
|             volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff)); | ||||
|         } else { | ||||
|             // extracts rotations from the composed transformation
 | ||||
|             Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); | ||||
|             Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix()); | ||||
|             if (rot_axis_max == 2 && !local) | ||||
| 			Vec3d new_rotation = transformation_type.world() ? | ||||
| 				Geometry::extract_euler_angles(Geometry::assemble_transform(Vec3d::Zero(), rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix()) : | ||||
| 				transformation_type.absolute() ? rotation : rotation + m_cache.volumes_data[i].get_instance_rotation(); | ||||
|             if (rot_axis_max == 2 && transformation_type.joint()) { | ||||
|                 // Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis.
 | ||||
|                 volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); | ||||
|                 double z_diff = rotation_diff_z(new_rotation, m_cache.volumes_data[i].get_instance_rotation()); | ||||
|                 volume.set_instance_offset(m_cache.dragging_center + Eigen::AngleAxisd(z_diff, Vec3d::UnitZ()) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); | ||||
|             } | ||||
|             volume.set_instance_rotation(new_rotation); | ||||
|             object_instance_first[volume.object_idx()] = i; | ||||
|         } | ||||
|  | @ -1300,7 +1307,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) | |||
|             rotate_instance(volume, i); | ||||
|         else if (is_single_volume() || is_single_modifier()) | ||||
|         { | ||||
|             if (local) | ||||
|             if (transformation_type.independent()) | ||||
|                 volume.set_volume_rotation(volume.get_volume_rotation() + rotation); | ||||
|             else | ||||
|             { | ||||
|  | @ -1318,7 +1325,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) | |||
|                 // extracts rotations from the composed transformation
 | ||||
|                 Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); | ||||
|                 Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); | ||||
|                 if (!local) | ||||
|                 if (transformation_type.joint()) | ||||
|                 { | ||||
|                     Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center); | ||||
|                     volume.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset); | ||||
|  | @ -5136,6 +5143,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|     { | ||||
|         // to remove hover on objects when the mouse goes out of this canvas
 | ||||
|         m_mouse.position = Vec2d(-1.0, -1.0); | ||||
|         // ensure m_mouse.left_down is reset (it may happen when switching canvas)
 | ||||
|         m_mouse.left_down = false; | ||||
|         m_dirty = true; | ||||
|     } | ||||
|     else if (evt.LeftDClick() && (toolbar_contains_mouse != -1)) | ||||
|  | @ -5203,12 +5212,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|         { | ||||
|             // event was taken care of by the SlaSupports gizmo
 | ||||
|         } | ||||
|         else if (view_toolbar_contains_mouse != -1) | ||||
|         else if (evt.LeftDown() && (view_toolbar_contains_mouse != -1)) | ||||
|         { | ||||
|             if (m_view_toolbar != nullptr) | ||||
|                 m_view_toolbar->do_action((unsigned int)view_toolbar_contains_mouse, *this); | ||||
|         } | ||||
|         else if (toolbar_contains_mouse != -1) | ||||
|         else if (evt.LeftDown() && (toolbar_contains_mouse != -1)) | ||||
|         { | ||||
|             m_toolbar_action_running = true; | ||||
|             m_mouse.set_start_position_3D_as_invalid(); | ||||
|  | @ -5388,7 +5397,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|         case Gizmos::Rotate: | ||||
|         { | ||||
|             // Apply new temporary rotations
 | ||||
|             m_selection.rotate(m_gizmos.get_rotation(), evt.AltDown()); | ||||
| 			TransformationType transformation_type(TransformationType::World_Relative_Joint); | ||||
| 			if (evt.AltDown()) | ||||
| 				transformation_type.set_independent(); | ||||
| 			m_selection.rotate(m_gizmos.get_rotation(), transformation_type); | ||||
|             wxGetApp().obj_manipul()->update_settings_value(m_selection); | ||||
|             break; | ||||
|         } | ||||
|  | @ -5403,7 +5415,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|         // the gizmo got the event and took some action, no need to do anything more here
 | ||||
|         m_dirty = true; | ||||
|     } | ||||
|     else if (evt.Dragging() && !gizmos_overlay_contains_mouse) | ||||
|     // do not process dragging if the mouse is into any of the HUD elements
 | ||||
|     else if (evt.Dragging() && !gizmos_overlay_contains_mouse && (toolbar_contains_mouse == -1) && (view_toolbar_contains_mouse == -1)) | ||||
|     { | ||||
|         m_mouse.dragging = true; | ||||
| 
 | ||||
|  | @ -5412,7 +5425,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|             if (m_layers_editing.state == LayersEditing::Editing) | ||||
|                 _perform_layer_editing_action(&evt); | ||||
|         } | ||||
|         else if (evt.LeftIsDown()) | ||||
|         // do not process the dragging if the left mouse was set down in another canvas
 | ||||
|         else if (m_mouse.left_down && evt.LeftIsDown()) | ||||
|         { | ||||
|             // if dragging over blank area with left button, rotate
 | ||||
| #if ENABLE_MOVE_MIN_THRESHOLD | ||||
|  |  | |||
|  | @ -375,6 +375,59 @@ class GLCanvas3D | |||
|     }; | ||||
| 
 | ||||
| public: | ||||
|     class TransformationType | ||||
|     { | ||||
| 	public: | ||||
| 		enum Enum { | ||||
| 			// Transforming in a world coordinate system
 | ||||
| 			World = 0, | ||||
| 			// Transforming in a local coordinate system
 | ||||
| 			Local = 1, | ||||
| 			// Absolute transformations, allowed in local coordinate system only.
 | ||||
| 			Absolute = 0, | ||||
| 			// Relative transformations, allowed in both local and world coordinate system.
 | ||||
| 			Relative = 2, | ||||
| 			// For group selection, the transformation is performed as if the group made a single solid body.
 | ||||
| 			Joint = 0, | ||||
| 			// For group selection, the transformation is performed on each object independently.
 | ||||
| 			Independent = 4, | ||||
| 
 | ||||
| 			World_Relative_Joint = World | Relative | Joint, | ||||
| 			World_Relative_Independent = World | Relative | Independent, | ||||
| 			Local_Absolute_Joint = Local | Absolute | Joint, | ||||
| 			Local_Absolute_Independent = Local | Absolute | Independent, | ||||
| 			Local_Relative_Joint = Local | Relative | Joint, | ||||
| 			Local_Relative_Independent = Local | Relative | Independent, | ||||
| 		}; | ||||
| 		 | ||||
| 		TransformationType() : m_value(World) {} | ||||
|         TransformationType(Enum value) : m_value(value) {} | ||||
|         TransformationType& operator=(Enum value) { m_value = value; return *this; } | ||||
| 
 | ||||
|         Enum operator()() const { return m_value; } | ||||
|         bool has(Enum v) const { return ((unsigned int)m_value & (unsigned int)v) != 0; } | ||||
| 
 | ||||
|         void set_world()        { this->remove(Local); } | ||||
|         void set_local()        { this->add(Local); } | ||||
|         void set_absolute()     { this->remove(Relative); } | ||||
|         void set_relative()     { this->add(Relative); } | ||||
|         void set_joint()        { this->remove(Independent); } | ||||
|         void set_independent()  { this->add(Independent); } | ||||
| 
 | ||||
|         bool world()        const { return ! this->has(Local); } | ||||
| 		bool local()        const { return this->has(Local); } | ||||
| 		bool absolute()     const { return ! this->has(Relative); } | ||||
| 		bool relative()     const { return this->has(Relative); } | ||||
| 		bool joint()        const { return ! this->has(Independent); } | ||||
| 		bool independent()  const { return this->has(Independent); } | ||||
| 
 | ||||
|     private: | ||||
|         void add(Enum v) { m_value = Enum((unsigned int)m_value | (unsigned int)v); } | ||||
|         void remove(Enum v) { m_value = Enum((unsigned int)m_value & (~(unsigned int)v)); } | ||||
| 
 | ||||
|         Enum    m_value; | ||||
|     }; | ||||
| 
 | ||||
|     class Selection | ||||
|     { | ||||
|     public: | ||||
|  | @ -553,7 +606,7 @@ public: | |||
|         void start_dragging(); | ||||
| 
 | ||||
|         void translate(const Vec3d& displacement, bool local = false); | ||||
|         void rotate(const Vec3d& rotation, bool local); | ||||
|         void rotate(const Vec3d& rotation, TransformationType transformation_type); | ||||
|         void flattening_rotate(const Vec3d& normal); | ||||
|         void scale(const Vec3d& scale, bool local); | ||||
|         void mirror(Axis axis); | ||||
|  |  | |||
|  | @ -25,6 +25,8 @@ | |||
| #include "GUI.hpp" | ||||
| #include "GUI_Utils.hpp" | ||||
| #include "GUI_App.hpp" | ||||
| #include "GUI_ObjectSettings.hpp" | ||||
| #include "GUI_ObjectList.hpp" | ||||
| #include "I18N.hpp" | ||||
| #include "PresetBundle.hpp" | ||||
| 
 | ||||
|  | @ -1922,7 +1924,7 @@ void GLGizmoSlaSupports::render_points(const GLCanvas3D::Selection& selection, b | |||
| 
 | ||||
| bool GLGizmoSlaSupports::is_mesh_update_necessary() const | ||||
| { | ||||
|     return (m_state == On) && (m_model_object != nullptr) && (m_model_object != m_old_model_object) && !m_model_object->instances.empty(); | ||||
|     return (m_state == On) && (m_model_object != m_old_model_object) && (m_model_object != nullptr) && !m_model_object->instances.empty(); | ||||
| 
 | ||||
|     //if (m_state != On || !m_model_object || m_model_object->instances.empty() || ! m_instance_matrix.isApprox(m_source_data.matrix))
 | ||||
|     //    return false;
 | ||||
|  | @ -2161,13 +2163,10 @@ bool GLGizmoSlaSupports::mouse_event(SLAGizmoEventType action, const Vec2d& mous | |||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void GLGizmoSlaSupports::delete_selected_points() | ||||
| void GLGizmoSlaSupports::delete_selected_points(bool force) | ||||
| { | ||||
|     if (!m_editing_mode) | ||||
|         return; | ||||
| 
 | ||||
|     for (unsigned int idx=0; idx<m_editing_mode_cache.size(); ++idx) { | ||||
|         if (m_editing_mode_cache[idx].second && (!m_editing_mode_cache[idx].first.is_new_island || !m_lock_unique_islands)) { | ||||
|         if (m_editing_mode_cache[idx].second && (!m_editing_mode_cache[idx].first.is_new_island || !m_lock_unique_islands || force)) { | ||||
|             m_editing_mode_cache.erase(m_editing_mode_cache.begin() + (idx--)); | ||||
|             m_unsaved_changes = true; | ||||
|         } | ||||
|  | @ -2228,9 +2227,41 @@ void GLGizmoSlaSupports::render_tooltip_texture() const { | |||
| #endif // not ENABLE_IMGUI
 | ||||
| 
 | ||||
| 
 | ||||
| std::vector<ConfigOption*> GLGizmoSlaSupports::get_config_options(const std::vector<std::string>& keys) const | ||||
| { | ||||
|     std::vector<ConfigOption*> out; | ||||
| 
 | ||||
|     if (!m_model_object) | ||||
|         return out; | ||||
| 
 | ||||
|     DynamicPrintConfig& object_cfg = m_model_object->config; | ||||
|     DynamicPrintConfig& print_cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; | ||||
|     std::unique_ptr<DynamicPrintConfig> default_cfg = nullptr; | ||||
| 
 | ||||
|     for (const std::string& key : keys) { | ||||
|         if (object_cfg.has(key)) | ||||
|             out.push_back(object_cfg.option(key)); | ||||
|         else | ||||
|             if (print_cfg.has(key)) | ||||
|                 out.push_back(print_cfg.option(key)); | ||||
|             else { // we must get it from defaults
 | ||||
|                 if (default_cfg == nullptr) | ||||
|                     default_cfg.reset(DynamicPrintConfig::new_from_defaults_keys(keys)); | ||||
|                 out.push_back(default_cfg->option(key)); | ||||
|             } | ||||
|     } | ||||
| 
 | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #if ENABLE_IMGUI | ||||
| void GLGizmoSlaSupports::on_render_input_window(float x, float y, const GLCanvas3D::Selection& selection) | ||||
| { | ||||
|     if (!m_model_object) | ||||
|         return; | ||||
| 
 | ||||
|     bool first_run = true; // This is a hack to redraw the button when all points are removed,
 | ||||
|                            // so it is not delayed until the background process finishes.
 | ||||
| RENDER_AGAIN: | ||||
|  | @ -2242,6 +2273,7 @@ RENDER_AGAIN: | |||
| 
 | ||||
|     bool force_refresh = false; | ||||
|     bool remove_selected = false; | ||||
|     bool remove_all = false; | ||||
| 
 | ||||
|     if (m_editing_mode) { | ||||
|         m_imgui->text(_(L("Left mouse click - add point"))); | ||||
|  | @ -2255,7 +2287,8 @@ RENDER_AGAIN: | |||
|         wxString str = ss.str(); | ||||
| 
 | ||||
|         bool old_combo_state = m_combo_box_open; | ||||
|         m_combo_box_open = m_imgui->combo(_(L("Head diameter")), options, str); | ||||
|         // The combo is commented out for now, until the feature is supported by backend.
 | ||||
|         // m_combo_box_open = m_imgui->combo(_(L("Head diameter")), options, str);
 | ||||
|         force_refresh |= (old_combo_state != m_combo_box_open); | ||||
| 
 | ||||
|         float current_number = atof(str); | ||||
|  | @ -2279,6 +2312,10 @@ RENDER_AGAIN: | |||
|         remove_selected = m_imgui->button(_(L("Remove selected points"))); | ||||
|         m_imgui->disabled_end(); | ||||
| 
 | ||||
|         m_imgui->disabled_begin(m_editing_mode_cache.empty()); | ||||
|         remove_all = m_imgui->button(_(L("Remove all points"))); | ||||
|         m_imgui->disabled_end(); | ||||
| 
 | ||||
|         m_imgui->text(" "); // vertical gap
 | ||||
| 
 | ||||
|         if (m_imgui->button(_(L("Apply changes")))) { | ||||
|  | @ -2293,13 +2330,29 @@ RENDER_AGAIN: | |||
|         } | ||||
|     } | ||||
|     else { // not in editing mode:
 | ||||
|         /*ImGui::PushItemWidth(100.0f);
 | ||||
|         ImGui::PushItemWidth(100.0f); | ||||
|         m_imgui->text(_(L("Minimal points distance: "))); | ||||
|         ImGui::SameLine(); | ||||
|         bool value_changed = ImGui::SliderFloat("", &m_minimal_point_distance, 0.f, 20.f, "%.f mm"); | ||||
| 
 | ||||
|         std::vector<ConfigOption*> opts = get_config_options({"support_points_density_relative", "support_points_minimal_distance"}); | ||||
|         float density = static_cast<ConfigOptionInt*>(opts[0])->value; | ||||
|         float minimal_point_distance = static_cast<ConfigOptionFloat*>(opts[1])->value; | ||||
| 
 | ||||
|         bool value_changed = ImGui::SliderFloat("", &minimal_point_distance, 0.f, 20.f, "%.f mm"); | ||||
|         if (value_changed) | ||||
|             m_model_object->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = minimal_point_distance; | ||||
| 
 | ||||
|         m_imgui->text(_(L("Support points density: "))); | ||||
|         ImGui::SameLine(); | ||||
|         value_changed |= ImGui::SliderFloat(" ", &m_density, 0.f, 200.f, "%.f %%");*/ | ||||
|         if (ImGui::SliderFloat(" ", &density, 0.f, 200.f, "%.f %%")) { | ||||
|             value_changed = true; | ||||
|             m_model_object->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)density; | ||||
|         } | ||||
| 
 | ||||
|         if (value_changed) { // Update side panel
 | ||||
|             wxGetApp().obj_settings()->UpdateAndShow(true); | ||||
|             wxGetApp().obj_list()->update_settings_items(); | ||||
|         } | ||||
| 
 | ||||
|         bool generate = m_imgui->button(_(L("Auto-generate points [A]"))); | ||||
| 
 | ||||
|  | @ -2310,6 +2363,12 @@ RENDER_AGAIN: | |||
|         if (m_imgui->button(_(L("Manual editing [M]")))) | ||||
|             switch_to_editing_mode(); | ||||
| 
 | ||||
|         m_imgui->disabled_begin(m_editing_mode_cache.empty()); | ||||
|         remove_all = m_imgui->button(_(L("Remove all points"))); | ||||
|         m_imgui->disabled_end(); | ||||
| 
 | ||||
|         m_imgui->text(""); | ||||
| 
 | ||||
|         m_imgui->text(m_model_object->sla_points_status == sla::PointsStatus::None ? "No points  (will be autogenerated)" : | ||||
|                      (m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated ? "Autogenerated points (no modifications)" : | ||||
|                      (m_model_object->sla_points_status == sla::PointsStatus::UserModified ? "User-modified points" : | ||||
|  | @ -2324,10 +2383,14 @@ RENDER_AGAIN: | |||
|     } | ||||
|     m_old_editing_state = m_editing_mode; | ||||
| 
 | ||||
|     if (remove_selected) { | ||||
|     if (remove_selected || remove_all) { | ||||
|         force_refresh = false; | ||||
|         m_parent.reload_scene(true); | ||||
|         delete_selected_points(); | ||||
|         if (remove_all) | ||||
|             select_point(AllPoints); | ||||
|         delete_selected_points(remove_all); | ||||
|         if (remove_all && !m_editing_mode) | ||||
|             editing_mode_apply_changes(); | ||||
|         if (first_run) { | ||||
|             first_run = false; | ||||
|             goto RENDER_AGAIN; | ||||
|  | @ -2375,19 +2438,22 @@ void GLGizmoSlaSupports::on_set_state() | |||
|             m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance); | ||||
|     } | ||||
|     if (m_state == Off) { | ||||
|         if (m_old_state != Off && m_model_object) { // the gizmo was just turned Off
 | ||||
|         if (m_old_state != Off) { // the gizmo was just turned Off
 | ||||
| 
 | ||||
|             if (m_unsaved_changes) { | ||||
|                 wxMessageDialog dlg(GUI::wxGetApp().plater(), _(L("Do you want to save your manually edited support points ?\n")), | ||||
|                                     _(L("Save changes?")), wxICON_QUESTION | wxYES | wxNO); | ||||
|                 if (dlg.ShowModal() == wxID_YES) | ||||
|                     editing_mode_apply_changes(); | ||||
|                 else | ||||
|                     editing_mode_discard_changes(); | ||||
|             if (m_model_object) { | ||||
|                 if (m_unsaved_changes) { | ||||
|                     wxMessageDialog dlg(GUI::wxGetApp().plater(), _(L("Do you want to save your manually edited support points ?\n")), | ||||
|                                         _(L("Save changes?")), wxICON_QUESTION | wxYES | wxNO); | ||||
|                     if (dlg.ShowModal() == wxID_YES) | ||||
|                         editing_mode_apply_changes(); | ||||
|                     else | ||||
|                         editing_mode_discard_changes(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             m_parent.toggle_model_objects_visibility(true); | ||||
|             m_editing_mode = false; // so it is not active next time the gizmo opens
 | ||||
|             m_editing_mode_cache.clear(); | ||||
|         } | ||||
|     } | ||||
|     m_old_state = m_state; | ||||
|  | @ -2492,7 +2558,7 @@ void GLGizmoSlaSupports::auto_generate() | |||
|                 "Are you sure you want to do it?\n" | ||||
|                 )), _(L("Warning")), wxICON_WARNING | wxYES | wxNO); | ||||
| 
 | ||||
|     if (m_model_object->sla_points_status != sla::PointsStatus::UserModified || dlg.ShowModal() == wxID_YES) { | ||||
|     if (m_model_object->sla_points_status != sla::PointsStatus::UserModified || m_editing_mode_cache.empty() || dlg.ShowModal() == wxID_YES) { | ||||
|         m_model_object->sla_support_points.clear(); | ||||
|         m_model_object->sla_points_status = sla::PointsStatus::Generating; | ||||
|         m_editing_mode_cache.clear(); | ||||
|  |  | |||
|  | @ -498,7 +498,7 @@ public: | |||
|     virtual ~GLGizmoSlaSupports(); | ||||
|     void set_sla_support_data(ModelObject* model_object, const GLCanvas3D::Selection& selection); | ||||
|     bool mouse_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down); | ||||
|     void delete_selected_points(); | ||||
|     void delete_selected_points(bool force = false); | ||||
| 
 | ||||
| private: | ||||
|     bool on_init(); | ||||
|  | @ -536,6 +536,8 @@ private: | |||
|     int m_canvas_width; | ||||
|     int m_canvas_height; | ||||
| 
 | ||||
|     std::vector<ConfigOption*> get_config_options(const std::vector<std::string>& keys) const; | ||||
| 
 | ||||
|     // Methods that do the model_object and editing cache synchronization,
 | ||||
|     // editing mode selection, etc:
 | ||||
|     enum { | ||||
|  |  | |||
|  | @ -177,33 +177,40 @@ bool GUI_App::OnInit() | |||
| 
 | ||||
|         if (this->plater() != nullptr) | ||||
|             this->obj_manipul()->update_if_dirty(); | ||||
|     }); | ||||
| 
 | ||||
|     // On OS X the UI tends to freeze in weird ways if modal dialogs(config wizard, update notifications, ...)
 | ||||
|     // are shown before or in the same event callback with the main frame creation.
 | ||||
|     // Therefore we schedule them for later using CallAfter.
 | ||||
|     CallAfter([this]() { | ||||
|         try { | ||||
|             if (!preset_updater->config_update()) | ||||
|                 mainframe->Close(); | ||||
|         } catch (const std::exception &ex) { | ||||
|             show_error(nullptr, ex.what()); | ||||
|         // Preset updating & Configwizard are done after the above initializations,
 | ||||
|         // and after MainFrame is created & shown.
 | ||||
|         // The extra CallAfter() is needed because of Mac, where this is the only way
 | ||||
|         // to popup a modal dialog on start without screwing combo boxes.
 | ||||
|         // This is ugly but I honestly found not better way to do it.
 | ||||
|         // Neither wxShowEvent nor wxWindowCreateEvent work reliably.
 | ||||
|         static bool once = true; | ||||
|         if (once) { | ||||
|             once = false; | ||||
| 
 | ||||
|             try { | ||||
|                 if (!preset_updater->config_update()) { | ||||
|                     mainframe->Close(); | ||||
|                 } | ||||
|             } catch (const std::exception &ex) { | ||||
|                 show_error(nullptr, ex.what()); | ||||
|             } | ||||
| 
 | ||||
|             CallAfter([this] { | ||||
|                 if (!config_wizard_startup(app_conf_exists)) { | ||||
|                     // Only notify if there was not wizard so as not to bother too much ...
 | ||||
|                     preset_updater->slic3r_update_notify(); | ||||
|                 } | ||||
|                 preset_updater->sync(preset_bundle); | ||||
|             }); | ||||
| 
 | ||||
|             load_current_presets(); | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
|     CallAfter([this]() { | ||||
|         if (!config_wizard_startup(app_conf_exists)) { | ||||
|             // Only notify if there was not wizard so as not to bother too much ...
 | ||||
|             preset_updater->slic3r_update_notify(); | ||||
|         } | ||||
|         preset_updater->sync(preset_bundle); | ||||
| 
 | ||||
|         load_current_presets(); | ||||
|     }); | ||||
| 
 | ||||
| 
 | ||||
|     mainframe->Show(true); | ||||
|     return m_initialized = true; | ||||
|     m_initialized = true; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| unsigned GUI_App::get_colour_approx_luma(const wxColour &colour) | ||||
|  |  | |||
|  | @ -1180,25 +1180,29 @@ Geometry::Transformation volume_to_bed_transformation(const Geometry::Transforma | |||
| { | ||||
|     Geometry::Transformation out; | ||||
| 
 | ||||
| 	// Is the angle close to a multiple of 90 degrees?
 | ||||
| 	auto ninety_degrees = [](double a) {  | ||||
| 		a = fmod(std::abs(a), 0.5 * PI); | ||||
| 		if (a > 0.25 * PI) | ||||
| 			a = 0.5 * PI - a; | ||||
| 		return a < 0.001; | ||||
| 	}; | ||||
|     if (instance_transformation.is_scaling_uniform()) { | ||||
|         // No need to run the non-linear least squares fitting for uniform scaling.
 | ||||
|         // Just set the inverse.
 | ||||
| 		out.set_from_transform(instance_transformation.get_matrix(true).inverse()); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	else if (ninety_degrees(instance_transformation.get_rotation().x()) && ninety_degrees(instance_transformation.get_rotation().y()) && ninety_degrees(instance_transformation.get_rotation().z())) | ||||
| 	{ | ||||
| 		// Anisotropic scaling, rotation by multiples of ninety degrees.
 | ||||
| 		Eigen::Matrix3d instance_rotation_trafo = | ||||
| 			(Eigen::AngleAxisd(instance_transformation.get_rotation().z(), Vec3d::UnitZ()) * | ||||
| 			 Eigen::AngleAxisd(instance_transformation.get_rotation().y(), Vec3d::UnitY()) * | ||||
| 			 Eigen::AngleAxisd(instance_transformation.get_rotation().x(), Vec3d::UnitX())).toRotationMatrix(); | ||||
| 		Eigen::Matrix3d instance_rotation_trafo_inv = | ||||
| 			(Eigen::AngleAxisd(- instance_transformation.get_rotation().x(), Vec3d::UnitX()) * | ||||
| 			 Eigen::AngleAxisd(- instance_transformation.get_rotation().y(), Vec3d::UnitY()) * | ||||
| 			 Eigen::AngleAxisd(- instance_transformation.get_rotation().z(), Vec3d::UnitZ())).toRotationMatrix(); | ||||
| 		Vec3d euler_angles_inv = Geometry::extract_euler_angles(instance_rotation_trafo_inv); | ||||
| 
 | ||||
| 		Eigen::Matrix3d instance_trafo = instance_rotation_trafo * | ||||
| 			Eigen::Scaling(instance_transformation.get_scaling_factor().cwiseProduct(instance_transformation.get_mirror())); | ||||
| 		Eigen::Matrix3d volume_rotation_trafo = | ||||
| 			(Eigen::AngleAxisd(-instance_transformation.get_rotation().x(), Vec3d::UnitX()) * | ||||
| 			 Eigen::AngleAxisd(-instance_transformation.get_rotation().y(), Vec3d::UnitY()) * | ||||
| 			 Eigen::AngleAxisd(-instance_transformation.get_rotation().z(), Vec3d::UnitZ())).toRotationMatrix(); | ||||
| 
 | ||||
| 		// 8 corners of the bounding box.
 | ||||
| 		auto pts = Eigen::MatrixXd(8, 3); | ||||
|  | @ -1211,101 +1215,27 @@ Geometry::Transformation volume_to_bed_transformation(const Geometry::Transforma | |||
| 		pts(6, 0) = bbox.max.x(); pts(6, 1) = bbox.max.y(); pts(6, 2) = bbox.min.z(); | ||||
| 		pts(7, 0) = bbox.max.x(); pts(7, 1) = bbox.max.y(); pts(7, 2) = bbox.max.z(); | ||||
| 
 | ||||
| 		// Current parameters: 3x scale, 3x rotation
 | ||||
| 		auto beta = Eigen::MatrixXd(3 + 3, 1); | ||||
| 		beta << 1., 1., 1., euler_angles_inv(0), euler_angles_inv(1), euler_angles_inv(2); | ||||
| 		// Corners of the bounding box transformed into the modifier mesh coordinate space, with inverse rotation applied to the modifier.
 | ||||
| 		auto qs = pts *  | ||||
| 			(instance_rotation_trafo * | ||||
| 			 Eigen::Scaling(instance_transformation.get_scaling_factor().cwiseProduct(instance_transformation.get_mirror())) *  | ||||
| 			 volume_rotation_trafo).inverse().transpose(); | ||||
| 		// Fill in scaling based on least squares fitting of the bounding box corners.
 | ||||
| 		Vec3d scale; | ||||
| 		for (int i = 0; i < 3; ++ i) | ||||
| 			scale(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i)); | ||||
| 
 | ||||
| 		{ | ||||
| 			// Trafo from world to the coordinate system of the modifier mesh, with the inverse rotation applied to the modifier.
 | ||||
| 			Eigen::Matrix3d A_scaling = instance_trafo * instance_rotation_trafo_inv; | ||||
| 			// Corners of the bounding box transformed into the modifier mesh coordinate space, with inverse rotation applied to the modifier.
 | ||||
| 			auto qs = pts * A_scaling.inverse().transpose(); | ||||
| 			// Fill in scaling based on least squares fitting of the bounding box corners.
 | ||||
| 			for (int i = 0; i < 3; ++i) | ||||
| 				beta(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i)); | ||||
| 		} | ||||
| 
 | ||||
|         // Jacobian
 | ||||
|         // rows: 8 corners of a cube times 3 dimensions,
 | ||||
|         // cols: 3x scale, 3x rotation
 | ||||
|         auto J = Eigen::MatrixXd(8 * 3, 3 + 3); | ||||
| 
 | ||||
|         // Until convergence:
 | ||||
|         Eigen::Matrix3d s, dsx, dsy, dsz; | ||||
|     	Eigen::Matrix3d rx, drx, ry, dry, rz, drz; | ||||
|         s.setIdentity(); | ||||
|         rx.setIdentity(); ry.setIdentity(); rz.setIdentity(); | ||||
|         dsx.setZero(); dsy.setZero(); dsz.setZero(); | ||||
|         drx.setZero(); dry.setZero(); drz.setZero(); | ||||
|         dsx(0, 0) = 1.; dsy(1, 1) = 1.; dsz(2, 2) = 1.; | ||||
| 
 | ||||
|         // Solve the non-linear Least Squares problem by Levenberg–Marquardt algorithm (modified Gauss–Newton iteration)
 | ||||
|     	const double eps = 1.e-7; | ||||
| 		auto   beta_best = beta; | ||||
| 		double beta_best_error = 1e10; | ||||
|         for (size_t iter = 0; iter < 200; ++ iter) { | ||||
|             // Current rotation & scaling transformation.
 | ||||
|             auto trafo = instance_trafo * | ||||
|                          Eigen::AngleAxisd(beta(5), Vec3d::UnitZ()) * | ||||
|                          Eigen::AngleAxisd(beta(4), Vec3d::UnitY()) * | ||||
|                          Eigen::AngleAxisd(beta(3), Vec3d::UnitX()) * | ||||
|                          Eigen::Scaling(Vec3d(beta(0), beta(1), beta(2))); | ||||
|             // Current error after rotation & scaling.
 | ||||
| 			auto dy = (pts - pts * trafo.transpose()).eval(); | ||||
| 			double err = 0; | ||||
| 			for (int i = 0; i < 8; ++i) | ||||
| 				err += dy.row(i).norm(); | ||||
| 			if (err < beta_best_error) { | ||||
| 				beta_best = beta; | ||||
| 				beta_best_error = err; | ||||
| 			} | ||||
|             // Fill in the Jacobian at current beta.
 | ||||
|             double cos_rx = cos(beta(3)); | ||||
|             double sin_rx = sin(beta(3)); | ||||
|             double cos_ry = cos(beta(4)); | ||||
|             double sin_ry = sin(beta(4)); | ||||
|             double cos_rz = cos(beta(5)); | ||||
|             double sin_rz = sin(beta(5)); | ||||
|             rx  <<  1.,          0.,     0.,     0.,  cos_rx, -sin_rx,      0., sin_rx,  cos_rx; | ||||
|             drx <<  0.,          0.,     0.,     0., -sin_rx, -cos_rx,      0., cos_rx, -sin_rx; | ||||
|             ry  <<  cos_ry,      0., sin_ry,     0.,      1.,      0., -sin_ry,     0.,  cos_ry; | ||||
|             dry << -sin_ry,      0., cos_ry,     0.,      0.,      0., -cos_ry,     0., -sin_ry; | ||||
|             rz  <<  cos_rz, -sin_rz,     0., sin_rz,  cos_rz,      0.,      0.,     0.,      1.; | ||||
|             drz << -sin_rz, -cos_rz,     0., cos_rz, -sin_rz,      0.,      0.,     0.,      0.; | ||||
|             s(0, 0) = beta(0); | ||||
|             s(1, 1) = beta(1); | ||||
|             s(2, 2) = beta(2); | ||||
|             auto rot = (instance_trafo * rz * ry * rx).eval(); | ||||
|     		auto jrx = pts * (instance_trafo * rz * ry * drx * s).transpose(); | ||||
|     		auto jry = pts * (instance_trafo * rz * dry * rx * s).transpose(); | ||||
|     		auto jrz = pts * (instance_trafo * drz * ry * rx * s).transpose(); | ||||
|             for (int r = 0; r < 8; ++ r) { | ||||
|                 for (int i = 0; i < 3; ++ i) { | ||||
| 					J(r * 3 + i, 0) = rot(i, 0) * pts(r, 0); | ||||
| 					J(r * 3 + i, 1) = rot(i, 1) * pts(r, 1); | ||||
| 					J(r * 3 + i, 2) = rot(i, 2) * pts(r, 2); | ||||
|                     J(r * 3 + i, 3) = jrx(r, i); | ||||
|                     J(r * 3 + i, 4) = jry(r, i); | ||||
|                     J(r * 3 + i, 5) = jrz(r, i); | ||||
|                 } | ||||
|             } | ||||
|             // Solving the normal equations for delta beta.
 | ||||
| 			auto rhs = (J.transpose() * Eigen::Map<Eigen::VectorXd>(dy.data(), dy.size())).eval(); | ||||
| 			double lambda = 1.; //  0.01;
 | ||||
| 			auto A   = (J.transpose() * J + Eigen::Matrix<double, 6, 6>::Identity() * lambda).eval(); | ||||
| 			auto L   = A.ldlt(); | ||||
| 			auto delta_beta = L.solve(rhs).eval(); | ||||
|             // Check for convergence.
 | ||||
|             auto delta_beta_max = delta_beta.cwiseAbs().maxCoeff(); | ||||
| 			if (delta_beta_max < eps) | ||||
|                 break; | ||||
|             beta = beta + delta_beta; | ||||
|         } | ||||
| 
 | ||||
| 		out.set_rotation(Vec3d(beta_best(3), beta_best(4), beta_best(5))); | ||||
| 		out.set_scaling_factor(Vec3d(std::abs(beta_best(0)), std::abs(beta_best(1)), std::abs(beta_best(2)))); | ||||
| 		out.set_mirror(Vec3d(beta_best(0) > 0 ? 1. : -1, beta_best(1) > 0 ? 1. : -1, beta_best(2) > 0 ? 1. : -1)); | ||||
| 		out.set_rotation(Geometry::extract_euler_angles(volume_rotation_trafo)); | ||||
| 		out.set_scaling_factor(Vec3d(std::abs(scale(0)), std::abs(scale(1)), std::abs(scale(2)))); | ||||
| 		out.set_mirror(Vec3d(scale(0) > 0 ? 1. : -1, scale(1) > 0 ? 1. : -1, scale(2) > 0 ? 1. : -1)); | ||||
|     } | ||||
| 	else | ||||
| 	{ | ||||
| 		// General anisotropic scaling, general rotation.
 | ||||
| 		// Keep the modifier mesh in the instance coordinate system, so the modifier mesh will not be aligned with the world.
 | ||||
| 		// Scale it to get the required size.
 | ||||
| 		out.set_scaling_factor(instance_transformation.get_scaling_factor().cwiseInverse()); | ||||
| 	} | ||||
| 
 | ||||
|     return out; | ||||
| } | ||||
|  |  | |||
|  | @ -361,16 +361,21 @@ void ObjectManipulation::change_rotation_value(const Vec3d& rotation) | |||
|     GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); | ||||
|     const GLCanvas3D::Selection& selection = canvas->get_selection(); | ||||
| 
 | ||||
|     Vec3d delta_rotation = rotation - m_cache.rotation; | ||||
| 	GLCanvas3D::TransformationType transformation_type(GLCanvas3D::TransformationType::World_Relative_Joint); | ||||
| 	if (selection.is_single_full_instance() || selection.requires_local_axes()) | ||||
| 		transformation_type.set_independent(); | ||||
| 	if (selection.is_single_full_instance()) { | ||||
|         //FIXME GLCanvas3D::Selection::rotate() does not process absoulte rotations correctly: It does not recognize the axis index, which was changed.
 | ||||
| 		// transformation_type.set_absolute();
 | ||||
| 		transformation_type.set_local(); | ||||
| 	} | ||||
| 
 | ||||
|     Vec3d rad_rotation; | ||||
|     for (size_t i = 0; i < 3; ++i) | ||||
|     { | ||||
|         rad_rotation(i) = Geometry::deg2rad(delta_rotation(i)); | ||||
|     } | ||||
| 		rad_rotation(i) = Geometry::deg2rad((transformation_type.absolute()) ? rotation(i) : rotation(i) - m_cache.rotation(i)); | ||||
| 
 | ||||
|     canvas->get_selection().start_dragging(); | ||||
|     canvas->get_selection().rotate(rad_rotation, selection.is_single_full_instance() || selection.requires_local_axes()); | ||||
| 	canvas->get_selection().rotate(rad_rotation, transformation_type); | ||||
|     canvas->do_rotate(); | ||||
| 
 | ||||
|     m_cache.rotation = rotation; | ||||
|  |  | |||
|  | @ -416,11 +416,14 @@ void Preview::load_print() | |||
|         load_print_as_sla(); | ||||
| } | ||||
| 
 | ||||
| void Preview::reload_print(bool force) | ||||
| void Preview::reload_print(bool force, bool keep_volumes) | ||||
| { | ||||
|     m_canvas->reset_volumes(); | ||||
|     m_canvas->reset_legend_texture(); | ||||
|     m_loaded = false; | ||||
|     if (!keep_volumes) | ||||
|     { | ||||
|         m_canvas->reset_volumes(); | ||||
|         m_canvas->reset_legend_texture(); | ||||
|         m_loaded = false; | ||||
|     } | ||||
| 
 | ||||
|     if (!IsShown() && !force) | ||||
|         return; | ||||
|  | @ -644,7 +647,7 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool for | |||
| 
 | ||||
|     bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF); | ||||
|     if (color_print_enable) { | ||||
|         const auto& cfg = wxGetApp().preset_bundle->full_config(); | ||||
|         const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->printers.get_edited_preset().config; | ||||
|         if (cfg.opt<ConfigOptionFloats>("nozzle_diameter")->values.size() > 1)  | ||||
|             color_print_enable = false; | ||||
|     } | ||||
|  |  | |||
|  | @ -127,7 +127,7 @@ public: | |||
|     void set_drop_target(wxDropTarget* target); | ||||
| 
 | ||||
|     void load_print(); | ||||
|     void reload_print(bool force = false); | ||||
|     void reload_print(bool force = false, bool keep_volumes = false); | ||||
|     void refresh_print(); | ||||
| 
 | ||||
| private: | ||||
|  |  | |||
|  | @ -2001,6 +2001,9 @@ void Plater::priv::schedule_background_process() | |||
|     this->background_process_timer.Start(500, wxTIMER_ONE_SHOT); | ||||
|     // Notify the Canvas3D that something has changed, so it may invalidate some of the layer editing stuff.
 | ||||
|     this->view3D->get_canvas3d()->set_config(this->config); | ||||
|     // Reset gcode preview
 | ||||
|     this->preview->get_canvas3d()->reset_volumes(); | ||||
|     this->preview->get_canvas3d()->reset_legend_texture(); | ||||
| } | ||||
| 
 | ||||
| void Plater::priv::update_print_volume_state() | ||||
|  | @ -2265,7 +2268,8 @@ void Plater::priv::set_current_panel(wxPanel* panel) | |||
|     else if (current_panel == preview) | ||||
|     { | ||||
|         this->q->reslice();         | ||||
|         preview->reload_print(); | ||||
|         // keeps current gcode preview, if any
 | ||||
|         preview->reload_print(false, true); | ||||
|         preview->set_canvas_as_dirty(); | ||||
|         view_toolbar.select_item("Preview"); | ||||
|     } | ||||
|  | @ -2984,7 +2988,7 @@ void Plater::export_gcode() | |||
|     default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); | ||||
|     auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string()); | ||||
| 
 | ||||
|     wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save Zip file as:")), | ||||
|     wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")), | ||||
|         start_dir, | ||||
|         from_path(default_output_file.filename()), | ||||
|         GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_PNGZIP, default_output_file.extension().string()), | ||||
|  |  | |||
|  | @ -354,7 +354,7 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config) | |||
| const std::vector<std::string>& Preset::print_options() | ||||
| {     | ||||
|     static std::vector<std::string> s_opts { | ||||
|         "layer_height", "first_layer_height", "perimeters", "spiral_vase", "top_solid_layers", "bottom_solid_layers",  | ||||
|         "layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius", "top_solid_layers", "bottom_solid_layers",  | ||||
|         "extra_perimeters", "ensure_vertical_shell_thickness", "avoid_crossing_perimeters", "thin_walls", "overhangs",  | ||||
|         "seam_position", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern", | ||||
|         "infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "fill_angle", "bridge_angle",  | ||||
|  | @ -460,6 +460,7 @@ const std::vector<std::string>& Preset::sla_print_options() | |||
|             "support_object_elevation", | ||||
|             "support_points_density_relative", | ||||
|             "support_points_minimal_distance", | ||||
|             "slice_closing_radius", | ||||
|             "pad_enable", | ||||
|             "pad_wall_thickness", | ||||
|             "pad_wall_height", | ||||
|  |  | |||
|  | @ -157,7 +157,7 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent) | |||
|     btn_cancel->Disable(); | ||||
|     btn_error = new wxButton(this, wxID_ANY, _(L("Show error message"))); | ||||
|     btn_error->Disable(); | ||||
|     auto *btn_close = new wxButton(this, wxID_CANCEL, _(L("Close"))); | ||||
|     auto *btn_close = new wxButton(this, wxID_CANCEL, _(L("Close")));  // Note: The label needs to be present, otherwise we get accelerator bugs on Mac
 | ||||
|     btnsizer->Add(btn_cancel, 0, wxRIGHT, SPACING); | ||||
|     btnsizer->Add(btn_error, 0); | ||||
|     btnsizer->AddStretchSpacer(); | ||||
|  |  | |||
|  | @ -1108,12 +1108,14 @@ void TabPrint::build() | |||
| 		optgroup = page->new_optgroup(_(L("Flow"))); | ||||
| 		optgroup->append_single_option_line("bridge_flow_ratio"); | ||||
| 
 | ||||
| 		optgroup = page->new_optgroup(_(L("Slicing"))); | ||||
| 		optgroup->append_single_option_line("slice_closing_radius"); | ||||
| 		optgroup->append_single_option_line("resolution"); | ||||
| 		optgroup->append_single_option_line("xy_size_compensation"); | ||||
| 		optgroup->append_single_option_line("elefant_foot_compensation"); | ||||
| 
 | ||||
| 		optgroup = page->new_optgroup(_(L("Other"))); | ||||
| 		optgroup->append_single_option_line("clip_multipart_objects"); | ||||
| 		optgroup->append_single_option_line("elefant_foot_compensation"); | ||||
| 		optgroup->append_single_option_line("xy_size_compensation"); | ||||
| //		#            optgroup->append_single_option_line("threads");
 | ||||
| 		optgroup->append_single_option_line("resolution"); | ||||
| 
 | ||||
| 	page = add_options_page(_(L("Output options")), "page_white_go.png"); | ||||
| 		optgroup = page->new_optgroup(_(L("Sequential printing"))); | ||||
|  | @ -3292,6 +3294,10 @@ void TabSLAPrint::build() | |||
| //    optgroup->append_single_option_line("pad_edge_radius");
 | ||||
|     optgroup->append_single_option_line("pad_wall_slope"); | ||||
| 
 | ||||
| 	page = add_options_page(_(L("Advanced")), "wrench.png"); | ||||
| 	optgroup = page->new_optgroup(_(L("Slicing"))); | ||||
| 	optgroup->append_single_option_line("slice_closing_radius"); | ||||
| 
 | ||||
| 	page = add_options_page(_(L("Output options")), "page_white_go.png"); | ||||
| 	optgroup = page->new_optgroup(_(L("Output file"))); | ||||
| 	Option option = optgroup->get_option("output_filename_format"); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Enrico Turri
						Enrico Turri