Configtool: major restructuring.
We distinguish between printers and boards now. Most of the code was split into one file per tab/window and moved into configtool/.
This commit is contained in:
parent
943a8326a9
commit
d7789ee217
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,219 @@
|
||||||
|
|
||||||
|
/***************************************************************************\
|
||||||
|
* *
|
||||||
|
* 1. CPU *
|
||||||
|
* *
|
||||||
|
\***************************************************************************/
|
||||||
|
|
||||||
|
//PROCESSORS_START
|
||||||
|
#ifndef __AVR_ATmega644__
|
||||||
|
#ifndef __AVR_ATmega644P__
|
||||||
|
#ifndef __AVR_ATmega1284__
|
||||||
|
#ifndef __AVR_ATmega1284P__
|
||||||
|
#error Wrong CPU type.
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
//PROCESSORS_END
|
||||||
|
|
||||||
|
/** \def F_CPU
|
||||||
|
CPU clock rate. #ifndef required for Arduino compatibility.
|
||||||
|
*/
|
||||||
|
#ifndef F_CPU
|
||||||
|
#define F_CPU 20000000UL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** \def MOTHERBOARD
|
||||||
|
This is the motherboard, as opposed to the extruder. See extruder/ directory
|
||||||
|
for GEN3 extruder firmware.
|
||||||
|
*/
|
||||||
|
#define MOTHERBOARD
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************\
|
||||||
|
* *
|
||||||
|
* 2. PINOUTS *
|
||||||
|
* *
|
||||||
|
\***************************************************************************/
|
||||||
|
|
||||||
|
#include "../arduino.h"
|
||||||
|
|
||||||
|
#define X_STEP_PIN DIO29
|
||||||
|
#define X_DIR_PIN DIO28
|
||||||
|
#define X_MIN_PIN DIO0
|
||||||
|
//#define X_MAX_PIN xxxx
|
||||||
|
//#define X_ENABLE_PIN xxxx
|
||||||
|
//#define X_INVERT_DIR
|
||||||
|
//#define X_INVERT_MIN
|
||||||
|
//#define X_INVERT_MAX
|
||||||
|
//#define X_INVERT_ENABLE
|
||||||
|
|
||||||
|
#define Y_STEP_PIN DIO27
|
||||||
|
#define Y_DIR_PIN DIO26
|
||||||
|
#define Y_MIN_PIN DIO1
|
||||||
|
//#define Y_MAX_PIN xxxx
|
||||||
|
//#define Y_ENABLE_PIN xxxx
|
||||||
|
//#define Y_INVERT_DIR
|
||||||
|
//#define Y_INVERT_MIN
|
||||||
|
//#define Y_INVERT_MAX
|
||||||
|
//#define Y_INVERT_ENABLE
|
||||||
|
|
||||||
|
#define Z_STEP_PIN DIO23
|
||||||
|
#define Z_DIR_PIN DIO22
|
||||||
|
#define Z_MIN_PIN DIO2
|
||||||
|
//#define Z_MAX_PIN xxxx
|
||||||
|
//#define Z_ENABLE_PIN xxxx
|
||||||
|
//#define Z_INVERT_DIR
|
||||||
|
//#define Z_INVERT_MIN
|
||||||
|
//#define Z_INVERT_MAX
|
||||||
|
//#define Z_INVERT_ENABLE
|
||||||
|
|
||||||
|
#define E_STEP_PIN DIO19
|
||||||
|
#define E_DIR_PIN DIO18
|
||||||
|
//#define E_ENABLE_PIN xxxx
|
||||||
|
//#define E_INVERT_DIR
|
||||||
|
//#define E_INVERT_ENABLE
|
||||||
|
|
||||||
|
#define PS_ON_PIN DIO15
|
||||||
|
//#define PS_MOSFET_PIN xxxx
|
||||||
|
#define STEPPER_ENABLE_PIN DIO25
|
||||||
|
#define STEPPER_INVERT_ENABLE
|
||||||
|
|
||||||
|
/** \def DEBUG_LED_PIN
|
||||||
|
|
||||||
|
Enable flashing of a LED during motor stepping.
|
||||||
|
|
||||||
|
Disabled by default. Uncommenting this makes the binary a few bytes larger
|
||||||
|
and adds a few cycles to the step timing interrrupt in timer.c. Also used
|
||||||
|
for precision profiling (profiling works even without actually having such
|
||||||
|
a LED in hardware), see
|
||||||
|
http://reprap.org/wiki/Teacup_Firmware#Doing_precision_profiling
|
||||||
|
*/
|
||||||
|
//#define DEBUG_LED_PIN DIO21
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************\
|
||||||
|
* *
|
||||||
|
* 3. TEMPERATURE SENSORS *
|
||||||
|
* *
|
||||||
|
\***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef DEFINE_TEMP_SENSOR
|
||||||
|
#define DEFINE_TEMP_SENSOR(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** \def TEMP_MAX6675 TEMP_THERMISTOR TEMP_AD595 TEMP_PT100 TEMP_INTERCOM
|
||||||
|
Which temperature sensor types are you using? Leave all used ones
|
||||||
|
uncommented, comment out all others to save binary size and enhance
|
||||||
|
performance.
|
||||||
|
*/
|
||||||
|
//#define TEMP_MAX6675
|
||||||
|
#define TEMP_THERMISTOR
|
||||||
|
//#define TEMP_AD595
|
||||||
|
//#define TEMP_PT100
|
||||||
|
//#define TEMP_INTERCOM
|
||||||
|
|
||||||
|
/** \def TEMP_SENSOR_PIN
|
||||||
|
Temperature sensor pins a user should be able to choose from in configtool.
|
||||||
|
All commented out.
|
||||||
|
*/
|
||||||
|
//#define TEMP_SENSOR_PIN AIO0
|
||||||
|
//#define TEMP_SENSOR_PIN AIO1
|
||||||
|
//#define TEMP_SENSOR_PIN AIO7
|
||||||
|
|
||||||
|
/** \def DEFINE_TEMP_SENSOR
|
||||||
|
Define your temperature sensors here. One line for each sensor, only
|
||||||
|
limited by the number of available ATmega pins.
|
||||||
|
|
||||||
|
Types are same as TEMP_ list above - TT_MAX6675, TT_THERMISTOR, TT_AD595,
|
||||||
|
TT_PT100, TT_INTERCOM. See list in temp.c.
|
||||||
|
|
||||||
|
The "additional" field is used for TT_THERMISTOR only. It defines the
|
||||||
|
name of the table(s) in ThermistorTable.h to use. Typically, this is
|
||||||
|
THERMISTOR_EXTRUDER for the first or only table, or THERMISTOR_BED for
|
||||||
|
the second table. See also early in ThermistorTable.{single|double}.h.
|
||||||
|
|
||||||
|
For a GEN3 set temp_type to TT_INTERCOM and temp_pin to AIO0. The pin
|
||||||
|
won't be used in this case.
|
||||||
|
*/
|
||||||
|
// name type pin additional
|
||||||
|
//DEFINE_TEMP_SENSORS_START
|
||||||
|
DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, AIO1, THERMISTOR_EXTRUDER)
|
||||||
|
DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO0, THERMISTOR_BED)
|
||||||
|
//DEFINE_TEMP_SENSORS_END
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************\
|
||||||
|
* *
|
||||||
|
* 4. HEATERS *
|
||||||
|
* *
|
||||||
|
\***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef DEFINE_HEATER
|
||||||
|
#define DEFINE_HEATER(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** \def HEATER_PIN
|
||||||
|
Heater pins a user should be able to choose from in configtool. All
|
||||||
|
commented out.
|
||||||
|
*/
|
||||||
|
//#define HEATER_PIN DIO3
|
||||||
|
//#define HEATER_PIN DIO4
|
||||||
|
//#define HEATER_PIN DIO5
|
||||||
|
|
||||||
|
/** \def DEFINE_HEATER
|
||||||
|
Define your heaters and devices here.
|
||||||
|
|
||||||
|
To attach a heater to a temp sensor above, simply use exactly the same
|
||||||
|
name - copy+paste is your friend. Some common names are 'extruder',
|
||||||
|
'bed', 'fan', 'motor', ... names with special meaning can be found
|
||||||
|
in gcode_process.c. Currently, these are:
|
||||||
|
HEATER_extruder (M104)
|
||||||
|
HEATER_bed (M140)
|
||||||
|
HEATER_fan (M106)
|
||||||
|
|
||||||
|
Devices don't neccessarily have a temperature sensor, e.g. fans or
|
||||||
|
milling spindles. Operate such devices by setting their power (M106),
|
||||||
|
instead of setting their temperature (M104).
|
||||||
|
|
||||||
|
Also note, the index of a heater (M106 P#) can differ from the index of
|
||||||
|
its attached temperature sensor (M104 P#) in case sensor-less devices
|
||||||
|
are defined or the order of the definitions differs. The first defined
|
||||||
|
device has the index 0 (zero).
|
||||||
|
|
||||||
|
Set 'pwm' to ...
|
||||||
|
1 for using PWM on a PWM-able pin and on/off on other pins.
|
||||||
|
0 for using on/off on a PWM-able pin, too.
|
||||||
|
Using PWM usually gives smoother temperature control but can conflict
|
||||||
|
with slow switches, like solid state relays. PWM frequency can be
|
||||||
|
influenced globally with FAST_PWM, see below.
|
||||||
|
*/
|
||||||
|
// name port pwm
|
||||||
|
//DEFINE_HEATERS_START
|
||||||
|
DEFINE_HEATER(extruder, DIO4, 1)
|
||||||
|
DEFINE_HEATER(bed, DIO3, 1)
|
||||||
|
|
||||||
|
#define HEATER_EXTRUDER HEATER_extruder
|
||||||
|
#define HEATER_BED HEATER_bed
|
||||||
|
//DEFINE_HEATERS_END
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************\
|
||||||
|
* *
|
||||||
|
* 5. COMMUNICATION OPTIONS *
|
||||||
|
* *
|
||||||
|
\***************************************************************************/
|
||||||
|
|
||||||
|
/** \def BAUD
|
||||||
|
Baud rate for the serial RS232 protocol connection to the host. Usually
|
||||||
|
115200, other common values are 19200, 38400 or 57600. Ignored when USB_SERIAL
|
||||||
|
is defined.
|
||||||
|
*/
|
||||||
|
#define BAUD 115200
|
||||||
|
|
||||||
|
/** \def USB_SERIAL
|
||||||
|
Define this for using USB instead of the serial RS232 protocol. Works on
|
||||||
|
USB-equipped ATmegas, like the ATmega32U4, only.
|
||||||
|
*/
|
||||||
|
//#define USB_SERIAL
|
||||||
|
|
@ -0,0 +1,215 @@
|
||||||
|
|
||||||
|
/***************************************************************************\
|
||||||
|
* *
|
||||||
|
* 1. CPU *
|
||||||
|
* *
|
||||||
|
\***************************************************************************/
|
||||||
|
|
||||||
|
//PROCESSORS_START
|
||||||
|
#ifndef __AVR_ATmega1280__
|
||||||
|
#ifndef __AVR_ATmega2560__
|
||||||
|
#error Wrong CPU type.
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
//PROCESSORS_END
|
||||||
|
|
||||||
|
/** \def F_CPU
|
||||||
|
CPU clock rate. #ifndef required for Arduino compatibility.
|
||||||
|
*/
|
||||||
|
#ifndef F_CPU
|
||||||
|
#define F_CPU 16000000UL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** \def MOTHERBOARD
|
||||||
|
This is the motherboard, as opposed to the extruder. See extruder/ directory
|
||||||
|
for GEN3 extruder firmware.
|
||||||
|
*/
|
||||||
|
#define MOTHERBOARD
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************\
|
||||||
|
* *
|
||||||
|
* 2. PINOUTS *
|
||||||
|
* *
|
||||||
|
\***************************************************************************/
|
||||||
|
|
||||||
|
#include "../arduino.h"
|
||||||
|
|
||||||
|
#define X_STEP_PIN DIO54
|
||||||
|
#define X_DIR_PIN DIO55
|
||||||
|
#define X_MIN_PIN DIO3
|
||||||
|
//#define X_MAX_PIN DIO2
|
||||||
|
#define X_ENABLE_PIN DIO38
|
||||||
|
//#define X_INVERT_DIR
|
||||||
|
//#define X_INVERT_MIN
|
||||||
|
//#define X_INVERT_MAX
|
||||||
|
#define X_INVERT_ENABLE
|
||||||
|
|
||||||
|
#define Y_STEP_PIN DIO60
|
||||||
|
#define Y_DIR_PIN DIO61
|
||||||
|
#define Y_MIN_PIN DIO14
|
||||||
|
//#define Y_MAX_PIN DIO15
|
||||||
|
#define Y_ENABLE_PIN DIO56
|
||||||
|
//#define Y_INVERT_DIR
|
||||||
|
//#define Y_INVERT_MIN
|
||||||
|
//#define Y_INVERT_MAX
|
||||||
|
#define Y_INVERT_ENABLE
|
||||||
|
|
||||||
|
#define Z_STEP_PIN DIO46
|
||||||
|
#define Z_DIR_PIN DIO48
|
||||||
|
#define Z_MIN_PIN DIO18
|
||||||
|
//#define Z_MAX_PIN DIO19
|
||||||
|
#define Z_ENABLE_PIN DIO62
|
||||||
|
//#define Z_INVERT_DIR
|
||||||
|
//#define Z_INVERT_MIN
|
||||||
|
//#define Z_INVERT_MAX
|
||||||
|
#define Z_INVERT_ENABLE
|
||||||
|
|
||||||
|
#define E_STEP_PIN DIO26
|
||||||
|
#define E_DIR_PIN DIO28
|
||||||
|
#define E_ENABLE_PIN DIO24
|
||||||
|
//#define E_INVERT_DIR
|
||||||
|
#define E_INVERT_ENABLE
|
||||||
|
|
||||||
|
//#define PS_ON_PIN xxxx
|
||||||
|
//#define PS_MOSFET_PIN xxxx
|
||||||
|
//#define STEPPER_ENABLE_PIN xxxx
|
||||||
|
//#define STEPPER_INVERT_ENABLE
|
||||||
|
|
||||||
|
/** \def DEBUG_LED_PIN
|
||||||
|
|
||||||
|
Enable flashing of a LED during motor stepping.
|
||||||
|
|
||||||
|
Disabled by default. Uncommenting this makes the binary a few bytes larger
|
||||||
|
and adds a few cycles to the step timing interrrupt in timer.c. Also used
|
||||||
|
for precision profiling (profiling works even without actually having such
|
||||||
|
a LED in hardware), see
|
||||||
|
http://reprap.org/wiki/Teacup_Firmware#Doing_precision_profiling
|
||||||
|
*/
|
||||||
|
//#define DEBUG_LED_PIN DIO13
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************\
|
||||||
|
* *
|
||||||
|
* 3. TEMPERATURE SENSORS *
|
||||||
|
* *
|
||||||
|
\***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef DEFINE_TEMP_SENSOR
|
||||||
|
#define DEFINE_TEMP_SENSOR(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** \def TEMP_MAX6675 TEMP_THERMISTOR TEMP_AD595 TEMP_PT100 TEMP_INTERCOM
|
||||||
|
Which temperature sensor types are you using? Leave all used ones
|
||||||
|
uncommented, comment out all others to save binary size and enhance
|
||||||
|
performance.
|
||||||
|
*/
|
||||||
|
//#define TEMP_MAX6675
|
||||||
|
#define TEMP_THERMISTOR
|
||||||
|
//#define TEMP_AD595
|
||||||
|
//#define TEMP_PT100
|
||||||
|
//#define TEMP_INTERCOM
|
||||||
|
|
||||||
|
/** \def TEMP_SENSOR_PIN
|
||||||
|
Temperature sensor pins a user should be able to choose from in configtool.
|
||||||
|
All commented out.
|
||||||
|
*/
|
||||||
|
//#define TEMP_SENSOR_PIN AIO13
|
||||||
|
//#define TEMP_SENSOR_PIN AIO14
|
||||||
|
//#define TEMP_SENSOR_PIN AIO15
|
||||||
|
|
||||||
|
/** \def DEFINE_TEMP_SENSOR
|
||||||
|
Define your temperature sensors here. One line for each sensor, only
|
||||||
|
limited by the number of available ATmega pins.
|
||||||
|
|
||||||
|
Types are same as TEMP_ list above - TT_MAX6675, TT_THERMISTOR, TT_AD595,
|
||||||
|
TT_PT100, TT_INTERCOM. See list in temp.c.
|
||||||
|
|
||||||
|
The "additional" field is used for TT_THERMISTOR only. It defines the
|
||||||
|
name of the table(s) in ThermistorTable.h to use. Typically, this is
|
||||||
|
THERMISTOR_EXTRUDER for the first or only table, or THERMISTOR_BED for
|
||||||
|
the second table. See also early in ThermistorTable.{single|double}.h.
|
||||||
|
|
||||||
|
For a GEN3 set temp_type to TT_INTERCOM and temp_pin to AIO0. The pin
|
||||||
|
won't be used in this case.
|
||||||
|
*/
|
||||||
|
// name type pin additional
|
||||||
|
//DEFINE_TEMP_SENSORS_START
|
||||||
|
DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, AIO13, THERMISTOR_EXTRUDER)
|
||||||
|
DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO14, THERMISTOR_BED)
|
||||||
|
//DEFINE_TEMP_SENSORS_END
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************\
|
||||||
|
* *
|
||||||
|
* 4. HEATERS *
|
||||||
|
* *
|
||||||
|
\***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef DEFINE_HEATER
|
||||||
|
#define DEFINE_HEATER(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** \def HEATER_PIN
|
||||||
|
Heater pins a user should be able to choose from in configtool. All
|
||||||
|
commented out.
|
||||||
|
*/
|
||||||
|
//#define HEATER_PIN DIO5
|
||||||
|
//#define HEATER_PIN DIO8
|
||||||
|
//#define HEATER_PIN DIO10
|
||||||
|
|
||||||
|
/** \def DEFINE_HEATER
|
||||||
|
Define your heaters and devices here.
|
||||||
|
|
||||||
|
To attach a heater to a temp sensor above, simply use exactly the same
|
||||||
|
name - copy+paste is your friend. Some common names are 'extruder',
|
||||||
|
'bed', 'fan', 'motor', ... names with special meaning can be found
|
||||||
|
in gcode_process.c. Currently, these are:
|
||||||
|
HEATER_extruder (M104)
|
||||||
|
HEATER_bed (M140)
|
||||||
|
HEATER_fan (M106)
|
||||||
|
|
||||||
|
Devices don't neccessarily have a temperature sensor, e.g. fans or
|
||||||
|
milling spindles. Operate such devices by setting their power (M106),
|
||||||
|
instead of setting their temperature (M104).
|
||||||
|
|
||||||
|
Also note, the index of a heater (M106 P#) can differ from the index of
|
||||||
|
its attached temperature sensor (M104 P#) in case sensor-less devices
|
||||||
|
are defined or the order of the definitions differs. The first defined
|
||||||
|
device has the index 0 (zero).
|
||||||
|
|
||||||
|
Set 'pwm' to ...
|
||||||
|
1 for using PWM on a PWM-able pin and on/off on other pins.
|
||||||
|
0 for using on/off on a PWM-able pin, too.
|
||||||
|
Using PWM usually gives smoother temperature control but can conflict
|
||||||
|
with slow switches, like solid state relays. PWM frequency can be
|
||||||
|
influenced globally with FAST_PWM, see below.
|
||||||
|
*/
|
||||||
|
// name port pwm
|
||||||
|
//DEFINE_HEATERS_START
|
||||||
|
DEFINE_HEATER(extruder, DIO10, 1)
|
||||||
|
DEFINE_HEATER(bed, DIO8, 1)
|
||||||
|
|
||||||
|
#define HEATER_EXTRUDER HEATER_extruder
|
||||||
|
#define HEATER_BED HEATER_bed
|
||||||
|
//DEFINE_HEATERS_END
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************\
|
||||||
|
* *
|
||||||
|
* 5. COMMUNICATION OPTIONS *
|
||||||
|
* *
|
||||||
|
\***************************************************************************/
|
||||||
|
|
||||||
|
/** \def BAUD
|
||||||
|
Baud rate for the serial RS232 protocol connection to the host. Usually
|
||||||
|
115200, other common values are 19200, 38400 or 57600. Ignored when USB_SERIAL
|
||||||
|
is defined.
|
||||||
|
*/
|
||||||
|
#define BAUD 115200
|
||||||
|
|
||||||
|
/** \def USB_SERIAL
|
||||||
|
Define this for using USB instead of the serial RS232 protocol. Works on
|
||||||
|
USB-equipped ATmegas, like the ATmega32U4, only.
|
||||||
|
*/
|
||||||
|
//#define USB_SERIAL
|
||||||
|
|
@ -0,0 +1,160 @@
|
||||||
|
|
||||||
|
Syntax rules for configuration files in order to be used with the graphical
|
||||||
|
configuration utility.
|
||||||
|
|
||||||
|
|
||||||
|
Variable Names - both board and printer files
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
Every #define variable used in the configuration must appear in the file.
|
||||||
|
If the variable is being given a value, it must appear normally i.e.
|
||||||
|
|
||||||
|
#define NAME value
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
#define NAME
|
||||||
|
|
||||||
|
If a variable is NOT to be defined, then it must be included in a single line
|
||||||
|
comment:
|
||||||
|
|
||||||
|
//#define NAME
|
||||||
|
|
||||||
|
It is immaterial if the name as a comment has a value. This line just marks
|
||||||
|
place where the variable will be inserted if it is defined. Although there
|
||||||
|
may be arbitrary spaces before and after the "//", no other intervening
|
||||||
|
characters may be placed on this line.
|
||||||
|
|
||||||
|
The above is based on the variable NAME, not on value. For example, for
|
||||||
|
acceleration there are three different and mutually exclusive variable names:
|
||||||
|
|
||||||
|
//#define ACCELERATION_REPRAP
|
||||||
|
#define ACCELERATION_RAMPING
|
||||||
|
//#define ACCELERATION_TEMPORAL
|
||||||
|
|
||||||
|
All of these names MUST appear in the header file (with at most one of them
|
||||||
|
un-commented out).
|
||||||
|
|
||||||
|
However, the variable KINEMATICS only has a finite set of values and would
|
||||||
|
seem to be a similar field, but there is only one variable name: KINEMATICS
|
||||||
|
- so it should only appear once.
|
||||||
|
|
||||||
|
This is ok:
|
||||||
|
|
||||||
|
//#define KINEMATICS KINEMATICS_STRAIGHT
|
||||||
|
|
||||||
|
as is this:
|
||||||
|
|
||||||
|
#define KINEMATICS KINEMATICS_STRAIGHT
|
||||||
|
|
||||||
|
but this is not:
|
||||||
|
|
||||||
|
#define KINEMATICS KINEMATICS_STRAIGHT
|
||||||
|
//#define KINEMATICS KINEMATICS_COREXY
|
||||||
|
|
||||||
|
|
||||||
|
Help Text - both board and printer files
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
The help text that is displayed on the GUI comes directly from the
|
||||||
|
configuration file itself. In order to be parsed correctly, help text must
|
||||||
|
be formatted as follows:
|
||||||
|
|
||||||
|
The start of a help text block is as follows:
|
||||||
|
|
||||||
|
/** \def NAME1 NAME2 NAME2 NAME4 ...
|
||||||
|
|
||||||
|
All subsequent lines are copied exactly as entered into the help text until
|
||||||
|
the end delimiter is reached. The end delimiter is a line that starts with '*/'.
|
||||||
|
|
||||||
|
Note that it is possible to specify multiple names on the start line. This
|
||||||
|
allows identical help text for similar or related fields.
|
||||||
|
|
||||||
|
|
||||||
|
Processor Preamble - Board file
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
The utility parses out the processor types from the config file when it loads
|
||||||
|
it, and it provides an interface where processors may be added or removed.
|
||||||
|
When a file is saved, the utility needs to know 1) where to insert the new
|
||||||
|
processor preamble, and 2) what to remove from the old file. To achieve this,
|
||||||
|
there is a sequence that identifies the start of the processor preamble, and
|
||||||
|
a sequence that indicates the end. As follows:
|
||||||
|
|
||||||
|
//PROCESSORS_START
|
||||||
|
#ifndef __AVR_ATmega1280__
|
||||||
|
#ifndef __AVR_ATmega2560__
|
||||||
|
#error Wrong CPU type.
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
//PROCESSORS_END
|
||||||
|
|
||||||
|
when a file is saved, all of the lines between these two delimiters are removed
|
||||||
|
and a new preamble is generated based on the values from the screen. The
|
||||||
|
supported processor types are defined in a python list in the data.py file. As
|
||||||
|
additional processors are supported, then can be added to this list.
|
||||||
|
|
||||||
|
If the START/END delimiters are not present, then the processor preamble will
|
||||||
|
not be generated and the content from the original file will be retained.
|
||||||
|
|
||||||
|
|
||||||
|
Temperature Sensor Considerations - Board file
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
The board configuration file has a section that includes the definition of
|
||||||
|
temperature sensors. Because the number of temperature sensors may grow or
|
||||||
|
shrink, or might even be 0, the utility needs to know where to place these
|
||||||
|
definitions. For this reason, delimiters are used to mark the beginning
|
||||||
|
and end of this section:
|
||||||
|
|
||||||
|
//DEFINE_TEMP_SENSORS_START
|
||||||
|
DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, AIO13, THERMISTOR_EXTRUDER)
|
||||||
|
DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO14, THERMISTOR_BED)
|
||||||
|
//DEFINE_TEMP_SENSORS_END
|
||||||
|
|
||||||
|
If the START/END delimiters are not found in the file, then the temperature
|
||||||
|
sensor definitions will not be generated and the original contents of the
|
||||||
|
file will be retained.
|
||||||
|
|
||||||
|
In addition to this, it is possible to limit the number of pins that are
|
||||||
|
available to the user to use for thermistors. To do this, enter as many
|
||||||
|
lines of the following form as are needed. Note that these lines are
|
||||||
|
commented out. If no such lines are defined, then ALL pin names will be
|
||||||
|
allowed.
|
||||||
|
|
||||||
|
//#define THERMISTOR_PIN AIO13
|
||||||
|
//#define THERMISTOR_PIN AIO14
|
||||||
|
//#define THERMISTOR_PIN AIO15
|
||||||
|
|
||||||
|
|
||||||
|
Heater Considerations - Board file
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
The board configuration file has a section that includes the definition of
|
||||||
|
heaters. Because the number of heaters may grow or shrink, or might even be 0,
|
||||||
|
the utility needs to know where to place these definitions. For this reason,
|
||||||
|
delimiters are used to mark the beginning and end of this section:
|
||||||
|
|
||||||
|
//DEFINE_HEATERS_START
|
||||||
|
DEFINE_HEATER(extruder, DIO10, 1)
|
||||||
|
DEFINE_HEATER(bed, DIO8, 1)
|
||||||
|
|
||||||
|
#define HEATER_EXTRUDER HEATER_extruder
|
||||||
|
#define HEATER_BED HEATER_bed
|
||||||
|
//DEFINE_HEATERS_END
|
||||||
|
|
||||||
|
Note that these delimiters also enclose the defines for the heater names. This
|
||||||
|
is different than in the sensor case where these definitions are not necessary.
|
||||||
|
|
||||||
|
If the START/END delimiters are not found in the file, then the temperature
|
||||||
|
sensor definitions will not be generated and the original contents of the
|
||||||
|
file will be retained.
|
||||||
|
|
||||||
|
In addition to this, it is possible to limit the number of pins that are
|
||||||
|
available to the user to use for heaters. To do this, enter as many lines of
|
||||||
|
the following form as are needed. Note that these lines are commented out.
|
||||||
|
If no such lines are defined, then ALL pin names will be allowed.
|
||||||
|
|
||||||
|
//#define HEATER_PIN DIO10
|
||||||
|
//#define HEATER_PIN DIO8
|
||||||
|
//#define HEATER_PIN DIO5
|
||||||
|
|
@ -0,0 +1,339 @@
|
||||||
|
|
||||||
|
/***************************************************************************\
|
||||||
|
* *
|
||||||
|
* 6. MECHANICAL/HARDWARE *
|
||||||
|
* *
|
||||||
|
\***************************************************************************/
|
||||||
|
|
||||||
|
/** \def KINEMATICS
|
||||||
|
This defines the type of kinematics your printer uses. That's essential!
|
||||||
|
|
||||||
|
Valid values (see dda_kinematics.h):
|
||||||
|
|
||||||
|
KINEMATICS_STRAIGHT Motors move axis directions directly. This is the
|
||||||
|
traditional type, found in many printers, including
|
||||||
|
Mendel, Prusa i3, Mendel90, Ormerod, Mantis.
|
||||||
|
|
||||||
|
KINEMATICS_COREXY A bot using CoreXY kinematics. Typical for CoreXY are
|
||||||
|
long and crossing toothed belts and a print head moving
|
||||||
|
on the X-Y-plane.
|
||||||
|
*/
|
||||||
|
#define KINEMATICS KINEMATICS_STRAIGHT
|
||||||
|
|
||||||
|
/** \def STEPS_PER_M_X STEPS_PER_M_Y STEPS_PER_M_Z STEPS_PER_M_E
|
||||||
|
Steps per meter ( = steps per mm * 1000 ), calculate these values
|
||||||
|
appropriate for your machine.
|
||||||
|
|
||||||
|
All numbers are integers, so no decimal point, please :-)
|
||||||
|
|
||||||
|
Valid range: 20 to 4'0960'000 (0.02 to 40960 steps/mm)
|
||||||
|
*/
|
||||||
|
#define STEPS_PER_M_X 40000
|
||||||
|
#define STEPS_PER_M_Y 40000
|
||||||
|
#define STEPS_PER_M_Z 320000
|
||||||
|
#define STEPS_PER_M_E 96271
|
||||||
|
|
||||||
|
/** \def MAXIMUM_FEEDRATE_X MAXIMUM_FEEDRATE_Y MAXIMUM_FEEDRATE_Z MAXIMUM_FEEDRATE_E
|
||||||
|
Used for G0 rapid moves and as a cap for all other feedrates.
|
||||||
|
*/
|
||||||
|
#define MAXIMUM_FEEDRATE_X 6000
|
||||||
|
#define MAXIMUM_FEEDRATE_Y 6000
|
||||||
|
#define MAXIMUM_FEEDRATE_Z 200
|
||||||
|
#define MAXIMUM_FEEDRATE_E 6000
|
||||||
|
|
||||||
|
/** \def SEARCH_FEEDRATE_X SEARCH_FEEDRATE_Y SEARCH_FEEDRATE_Z
|
||||||
|
Used when doing precision endstop search and as default feedrate. No
|
||||||
|
SEARCH_FEEDRATE_E, as E can't be searched.
|
||||||
|
*/
|
||||||
|
#define SEARCH_FEEDRATE_X 200
|
||||||
|
#define SEARCH_FEEDRATE_Y 200
|
||||||
|
#define SEARCH_FEEDRATE_Z 50
|
||||||
|
|
||||||
|
/** \def ENDSTOP_CLEARANCE_X ENDSTOP_CLEARANCE_Y ENDSTOP_CLEARANCE_Z
|
||||||
|
|
||||||
|
When hitting an endstop, Teacup properly decelerates instead of doing an
|
||||||
|
aprupt stop to save your mechanics. Ineviteably, this means it overshoots
|
||||||
|
the endstop trigger point by some distance.
|
||||||
|
|
||||||
|
To deal with this, Teacup adapts homing movement speeds to what your
|
||||||
|
endstops can deal with. The higher the allowed acceleration ( = deceleration,
|
||||||
|
see #define ACCELERATION) and the more clearance the endstop comes with,
|
||||||
|
the faster Teacup will do homing movements.
|
||||||
|
|
||||||
|
Set here how many micrometers (mm * 1000) your endstop allows the carriage
|
||||||
|
to overshoot the trigger point. Typically 1000 or 2000 for mechanical
|
||||||
|
endstops, more for optical ones. You can set it to zero, in which case
|
||||||
|
SEARCH_FEEDRATE_{XYZ} is used, but expect very slow homing movements.
|
||||||
|
|
||||||
|
Units: micrometers
|
||||||
|
Sane values: 0 to 20000 (0 to 20 mm)
|
||||||
|
Valid range: 0 to 1000000
|
||||||
|
*/
|
||||||
|
#define ENDSTOP_CLEARANCE_X 1000
|
||||||
|
#define ENDSTOP_CLEARANCE_Y 1000
|
||||||
|
#define ENDSTOP_CLEARANCE_Z 100
|
||||||
|
|
||||||
|
/** \def X_MIN X_MAX Y_MIN Y_MAX Z_MIN Z_MAX
|
||||||
|
Soft axis limits, in mm. Define them to your machine's size relative to what
|
||||||
|
your host considers to be the origin.
|
||||||
|
*/
|
||||||
|
//#define X_MIN 0.0
|
||||||
|
//#define X_MAX 200.0
|
||||||
|
|
||||||
|
//#define Y_MIN 0.0
|
||||||
|
//#define Y_MAX 200.0
|
||||||
|
|
||||||
|
//#define Z_MIN 0.0
|
||||||
|
//#define Z_MAX 140.0
|
||||||
|
|
||||||
|
/** \def E_ABSOLUTE
|
||||||
|
Some G-code creators produce relative length commands for the extruder,
|
||||||
|
others absolute ones. G-code using absolute lengths can be recognized when
|
||||||
|
there are G92 E0 commands from time to time. If you have G92 E0 in your
|
||||||
|
G-code, define this flag.
|
||||||
|
|
||||||
|
This is the startup default and can be changed with M82/M83 while running.
|
||||||
|
*/
|
||||||
|
#define E_ABSOLUTE
|
||||||
|
|
||||||
|
/** \def ACCELERATION_REPRAP ACCELERATION_RAMPING ACCELERATION_TEMPORAL
|
||||||
|
Choose optionally one of ACCELERATION_REPRAP, ACCELERATION_RAMPING or
|
||||||
|
ACCELERATION_TEMPORAL. With none of them defined, movements are done
|
||||||
|
without acceleration. Recommended is ACCELERATION_RAMPING.
|
||||||
|
*/
|
||||||
|
//#define ACCELERATION_REPRAP
|
||||||
|
#define ACCELERATION_RAMPING
|
||||||
|
//#define ACCELERATION_TEMPORAL
|
||||||
|
|
||||||
|
/** \def ACCELERATION
|
||||||
|
How fast to accelerate when using ACCELERATION_RAMPING. Start with 10 for
|
||||||
|
milling (high precision) or 1000 for printing.
|
||||||
|
|
||||||
|
Units: mm/s^2
|
||||||
|
Useful range: 1 to 10'000
|
||||||
|
*/
|
||||||
|
#define ACCELERATION 1000 /* float */
|
||||||
|
|
||||||
|
/** \def LOOKAHEAD
|
||||||
|
Define this to enable look-ahead during *ramping* acceleration to smoothly
|
||||||
|
transition between moves instead of performing a dead stop every move.
|
||||||
|
Enabling look-ahead requires about 3600 bytes of flash memory.
|
||||||
|
*/
|
||||||
|
#define LOOKAHEAD
|
||||||
|
|
||||||
|
/** \def MAX_JERK_X MAX_JERK_Y MAX_JERK_Z MAX_JERK_E
|
||||||
|
When performing look-ahead, we need to decide what an acceptable jerk to the
|
||||||
|
mechanics is. Look-ahead attempts to instantly change direction at movement
|
||||||
|
crossings, which means instant changes in the speed of the axes participating
|
||||||
|
in the movement. Define here how big the speed bumps on each of the axes is
|
||||||
|
allowed to be.
|
||||||
|
|
||||||
|
If you want a full stop before and after moving a specific axis, define
|
||||||
|
MAX_JERK of this axis to 0. This is often wanted for the Z axis. If you want
|
||||||
|
to ignore jerk on an axis, define it to twice the maximum feedrate of this
|
||||||
|
axis.
|
||||||
|
|
||||||
|
Having these values too low results in more than neccessary slowdown at
|
||||||
|
movement crossings, but is otherwise harmless. Too high values can result
|
||||||
|
in stepper motors suddenly stalling. If angles between movements in your
|
||||||
|
G-code are small and your printer runs through entire curves full speed,
|
||||||
|
there's no point in raising the values.
|
||||||
|
|
||||||
|
Units: mm/min
|
||||||
|
Sane values: 0 to 400
|
||||||
|
Valid range: 0 to 65535
|
||||||
|
*/
|
||||||
|
#define MAX_JERK_X 200
|
||||||
|
#define MAX_JERK_Y 200
|
||||||
|
#define MAX_JERK_Z 0
|
||||||
|
#define MAX_JERK_E 200
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************\
|
||||||
|
* *
|
||||||
|
* 7. MISCELLANEOUS OPTIONS *
|
||||||
|
* *
|
||||||
|
\***************************************************************************/
|
||||||
|
|
||||||
|
/** \def USE_INTERNAL_PULLUPS
|
||||||
|
The ATmega has internal pullup resistors on it's input pins which are
|
||||||
|
counterproductive with the commonly used eletronic endstops, so they should
|
||||||
|
be switched off. For other endstops, like mechanical ones, you may want to
|
||||||
|
uncomment this.
|
||||||
|
*/
|
||||||
|
//#define USE_INTERNAL_PULLUPS
|
||||||
|
|
||||||
|
/** \def TEMP_HYSTERESIS
|
||||||
|
Actual temperature must be target +/- this hysteresis before target
|
||||||
|
temperature is considered to be achieved. Also, BANG_BANG tries to stay
|
||||||
|
within half of this hysteresis.
|
||||||
|
|
||||||
|
Unit: degree Celsius
|
||||||
|
*/
|
||||||
|
#define TEMP_HYSTERESIS 10
|
||||||
|
|
||||||
|
/** \def TEMP_RESIDENCY_TIME
|
||||||
|
Actual temperature must be close to target (within set temperature
|
||||||
|
+- TEMP_HYSTERESIS) for this long before target is achieved (and a M116
|
||||||
|
succeeds).
|
||||||
|
|
||||||
|
Unit: seconds
|
||||||
|
*/
|
||||||
|
#define TEMP_RESIDENCY_TIME 60
|
||||||
|
|
||||||
|
/** \def TEMP_EWMA
|
||||||
|
Smooth noisy temperature sensors. Good hardware shouldn't be noisy. Set to
|
||||||
|
1.0 for unfiltered data (and a 140 bytes smaller binary).
|
||||||
|
|
||||||
|
Instrument Engineer's Handbook, 4th ed, Vol 2 p126 says values of
|
||||||
|
0.05 to 0.1 are typical. Smaller is smoother but slower adjusting, larger is
|
||||||
|
quicker but rougher. If you need to use this, set the PID parameter to zero
|
||||||
|
(M132 S0) to make the PID loop insensitive to noise.
|
||||||
|
|
||||||
|
Valid range: 0.001 to 1.0
|
||||||
|
*/
|
||||||
|
#define TEMP_EWMA 1.0 /* float */
|
||||||
|
|
||||||
|
/** \def HEATER_SANITY_CHECK
|
||||||
|
Check if heater responds to changes in target temperature, disable and spit
|
||||||
|
errors if not largely untested, please comment in forum if this works, or
|
||||||
|
doesn't work for you!
|
||||||
|
*/
|
||||||
|
//#define HEATER_SANITY_CHECK
|
||||||
|
|
||||||
|
/** \def XONXOFF
|
||||||
|
Xon/Xoff flow control.
|
||||||
|
|
||||||
|
Redundant when using RepRap Host for sending G-code, but mandatory when
|
||||||
|
sending G-code files with a plain terminal emulator, like GtkTerm (Linux),
|
||||||
|
CoolTerm (Mac) or HyperTerminal (Windows).
|
||||||
|
*/
|
||||||
|
//#define XONXOFF
|
||||||
|
|
||||||
|
/** \def EECONFIG
|
||||||
|
Enable EEPROM configuration storage.
|
||||||
|
|
||||||
|
Enabled by default. Commenting this out makes the binary several hundred
|
||||||
|
bytes smaller, so you might want to disable EEPROM storage on small MCUs,
|
||||||
|
like the ATmega168.
|
||||||
|
*/
|
||||||
|
#define EECONFIG
|
||||||
|
|
||||||
|
/** \def DEBUG
|
||||||
|
Enables /heaps/ of extra output, and some extra M-codes.
|
||||||
|
|
||||||
|
WARNING: this WILL break most host-side talkers that expect particular
|
||||||
|
responses from firmware such as reprap host and replicatorG use with serial
|
||||||
|
terminal or other suitable talker only.
|
||||||
|
*/
|
||||||
|
//#define DEBUG
|
||||||
|
|
||||||
|
/** \def BANG_BANG
|
||||||
|
Drops PID loop from heater control, reduces code size significantly
|
||||||
|
(1300 bytes!).
|
||||||
|
*/
|
||||||
|
//#define BANG_BANG
|
||||||
|
|
||||||
|
/** \def BANG_BANG_ON
|
||||||
|
PWM value for Bang Bang 'on'.
|
||||||
|
*/
|
||||||
|
//#define BANG_BANG_ON 200
|
||||||
|
|
||||||
|
/** \def BANG_BANG_OFF
|
||||||
|
PWM value for Bang Bang 'off'.
|
||||||
|
*/
|
||||||
|
//#define BANG_BANG_OFF 45
|
||||||
|
|
||||||
|
/** \def MOVEBUFFER_SIZE
|
||||||
|
Move buffer size, in number of moves.
|
||||||
|
|
||||||
|
Note that each move takes a fair chunk of ram (107 bytes as of this writing),
|
||||||
|
so don't make the buffer too big. However, a larger movebuffer will probably
|
||||||
|
help with lots of short consecutive moves, as each move takes a bunch of
|
||||||
|
math (hence time) to set up so a longer buffer allows more of the math to
|
||||||
|
be done during preceding longer moves.
|
||||||
|
*/
|
||||||
|
#define MOVEBUFFER_SIZE 8
|
||||||
|
|
||||||
|
/** \def DC_EXTRUDER DC_EXTRUDER_PWM
|
||||||
|
If you have a DC motor extruder, configure it as a "heater" above and define
|
||||||
|
this value as the index or name. You probably also want to comment out
|
||||||
|
E_STEP_PIN and E_DIR_PIN in the Pinouts section above.
|
||||||
|
*/
|
||||||
|
//#define DC_EXTRUDER HEATER_motor
|
||||||
|
//#define DC_EXTRUDER_PWM 180
|
||||||
|
|
||||||
|
/** \def USE_WATCHDOG
|
||||||
|
Teacup implements a watchdog, which has to be reset every 250ms or it will
|
||||||
|
reboot the controller. As rebooting (and letting the GCode sending
|
||||||
|
application trying to continue the build with a then different Home point)
|
||||||
|
is probably even worse than just hanging, and there is no better restore
|
||||||
|
code in place, this is disabled for now.
|
||||||
|
*/
|
||||||
|
//#define USE_WATCHDOG
|
||||||
|
|
||||||
|
/** \def REFERENCE
|
||||||
|
Which analog reference to use. See analog.h for choices.
|
||||||
|
*/
|
||||||
|
#define REFERENCE REFERENCE_AVCC
|
||||||
|
|
||||||
|
/** \def STEP_INTERRUPT_INTERRUPTIBLE
|
||||||
|
This option makes the step interrupt interruptible (nested). This should
|
||||||
|
help immensely with dropped serial characters, but may also make debugging
|
||||||
|
infuriating due to the complexities arising from nested interrupts.
|
||||||
|
|
||||||
|
Note: disable this option if you're using a '168 or for some reason your
|
||||||
|
ram usage is above 90%. This option hugely increases likelihood of stack
|
||||||
|
smashing.
|
||||||
|
*/
|
||||||
|
#define STEP_INTERRUPT_INTERRUPTIBLE 1
|
||||||
|
|
||||||
|
/** \def TH_COUNT
|
||||||
|
Temperature history count. This is how many temperature readings to keep in
|
||||||
|
order to calculate derivative in PID loop higher values make PID derivative
|
||||||
|
term more stable at the expense of reaction time.
|
||||||
|
*/
|
||||||
|
#define TH_COUNT 8
|
||||||
|
|
||||||
|
/** \def FAST_PWM
|
||||||
|
Teacup offers two PWM frequencies, 76(61) Hz and 78000(62500) Hz on a
|
||||||
|
20(16) MHz electronics. The slower one is the default, as it's the safer
|
||||||
|
choice and reduces MOSFET heating. Drawback is, in a quiet environment you
|
||||||
|
might notice the heaters and your power supply humming.
|
||||||
|
|
||||||
|
Uncomment this option if you want to get rid of this humming and can afford
|
||||||
|
a hotter MOSFET or want faster PWM for other reasons.
|
||||||
|
|
||||||
|
See also: http://reprap.org/wiki/Gen7_Research#MOSFET_heat_and_PWM
|
||||||
|
*/
|
||||||
|
//#define FAST_PWM
|
||||||
|
|
||||||
|
/** \def PID_SCALE
|
||||||
|
This is the scaling of internally stored PID values. 1024L is a good value.
|
||||||
|
*/
|
||||||
|
#define PID_SCALE 1024L
|
||||||
|
|
||||||
|
/** \def ENDSTOP_STEPS
|
||||||
|
Number of steps to run into the endstops intentionally. As endstops trigger
|
||||||
|
false alarm sometimes, Teacup debounces them by counting a number of
|
||||||
|
consecutive positives.
|
||||||
|
|
||||||
|
Valid range: 1...255. Use 4 or less for reliable endstops, 8 or even more
|
||||||
|
for flaky ones.
|
||||||
|
*/
|
||||||
|
#define ENDSTOP_STEPS 4
|
||||||
|
|
||||||
|
/** \def CANNED_CYCLE
|
||||||
|
G-code commands in this string will be executed over and over again, without
|
||||||
|
user interaction or even a serial connection. It's purpose is e.g. for
|
||||||
|
exhibitions or when using Teacup for other purposes than printing. You can
|
||||||
|
add any G-code supported by Teacup.
|
||||||
|
|
||||||
|
Note: don't miss these newlines (\n) and backslashes (\).
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
#define CANNED_CYCLE "G1 X100 F3000\n" \
|
||||||
|
"G4 P500\n" \
|
||||||
|
"G1 X0\n" \
|
||||||
|
"G4 P500\n"
|
||||||
|
*/
|
||||||
|
|
@ -0,0 +1,339 @@
|
||||||
|
|
||||||
|
/***************************************************************************\
|
||||||
|
* *
|
||||||
|
* 6. MECHANICAL/HARDWARE *
|
||||||
|
* *
|
||||||
|
\***************************************************************************/
|
||||||
|
|
||||||
|
/** \def KINEMATICS
|
||||||
|
This defines the type of kinematics your printer uses. That's essential!
|
||||||
|
|
||||||
|
Valid values (see dda_kinematics.h):
|
||||||
|
|
||||||
|
KINEMATICS_STRAIGHT Motors move axis directions directly. This is the
|
||||||
|
traditional type, found in many printers, including
|
||||||
|
Mendel, Prusa i3, Mendel90, Ormerod, Mantis.
|
||||||
|
|
||||||
|
KINEMATICS_COREXY A bot using CoreXY kinematics. Typical for CoreXY are
|
||||||
|
long and crossing toothed belts and a print head moving
|
||||||
|
on the X-Y-plane.
|
||||||
|
*/
|
||||||
|
#define KINEMATICS KINEMATICS_STRAIGHT
|
||||||
|
|
||||||
|
/** \def STEPS_PER_M_X STEPS_PER_M_Y STEPS_PER_M_Z STEPS_PER_M_E
|
||||||
|
Steps per meter ( = steps per mm * 1000 ), calculate these values
|
||||||
|
appropriate for your machine.
|
||||||
|
|
||||||
|
All numbers are integers, so no decimal point, please :-)
|
||||||
|
|
||||||
|
Valid range: 20 to 4'0960'000 (0.02 to 40960 steps/mm)
|
||||||
|
*/
|
||||||
|
#define STEPS_PER_M_X 1280000
|
||||||
|
#define STEPS_PER_M_Y 1280000
|
||||||
|
#define STEPS_PER_M_Z 1280000
|
||||||
|
#define STEPS_PER_M_E 96271
|
||||||
|
|
||||||
|
/** \def MAXIMUM_FEEDRATE_X MAXIMUM_FEEDRATE_Y MAXIMUM_FEEDRATE_Z MAXIMUM_FEEDRATE_E
|
||||||
|
Used for G0 rapid moves and as a cap for all other feedrates.
|
||||||
|
*/
|
||||||
|
#define MAXIMUM_FEEDRATE_X 600
|
||||||
|
#define MAXIMUM_FEEDRATE_Y 600
|
||||||
|
#define MAXIMUM_FEEDRATE_Z 600
|
||||||
|
#define MAXIMUM_FEEDRATE_E 2000
|
||||||
|
|
||||||
|
/** \def SEARCH_FEEDRATE_X SEARCH_FEEDRATE_Y SEARCH_FEEDRATE_Z
|
||||||
|
Used when doing precision endstop search and as default feedrate. No
|
||||||
|
SEARCH_FEEDRATE_E, as E can't be searched.
|
||||||
|
*/
|
||||||
|
#define SEARCH_FEEDRATE_X 50
|
||||||
|
#define SEARCH_FEEDRATE_Y 50
|
||||||
|
#define SEARCH_FEEDRATE_Z 50
|
||||||
|
|
||||||
|
/** \def ENDSTOP_CLEARANCE_X ENDSTOP_CLEARANCE_Y ENDSTOP_CLEARANCE_Z
|
||||||
|
|
||||||
|
When hitting an endstop, Teacup properly decelerates instead of doing an
|
||||||
|
aprupt stop to save your mechanics. Ineviteably, this means it overshoots
|
||||||
|
the endstop trigger point by some distance.
|
||||||
|
|
||||||
|
To deal with this, Teacup adapts homing movement speeds to what your
|
||||||
|
endstops can deal with. The higher the allowed acceleration ( = deceleration,
|
||||||
|
see #define ACCELERATION) and the more clearance the endstop comes with,
|
||||||
|
the faster Teacup will do homing movements.
|
||||||
|
|
||||||
|
Set here how many micrometers (mm * 1000) your endstop allows the carriage
|
||||||
|
to overshoot the trigger point. Typically 1000 or 2000 for mechanical
|
||||||
|
endstops, more for optical ones. You can set it to zero, in which case
|
||||||
|
SEARCH_FEEDRATE_{XYZ} is used, but expect very slow homing movements.
|
||||||
|
|
||||||
|
Units: micrometers
|
||||||
|
Sane values: 0 to 20000 (0 to 20 mm)
|
||||||
|
Valid range: 0 to 1000000
|
||||||
|
*/
|
||||||
|
#define ENDSTOP_CLEARANCE_X 1000
|
||||||
|
#define ENDSTOP_CLEARANCE_Y 1000
|
||||||
|
#define ENDSTOP_CLEARANCE_Z 100
|
||||||
|
|
||||||
|
/** \def X_MIN X_MAX Y_MIN Y_MAX Z_MIN Z_MAX
|
||||||
|
Soft axis limits, in mm. Define them to your machine's size relative to what
|
||||||
|
your host considers to be the origin.
|
||||||
|
*/
|
||||||
|
//#define X_MIN 0.0
|
||||||
|
//#define X_MAX 200.0
|
||||||
|
|
||||||
|
//#define Y_MIN 0.0
|
||||||
|
//#define Y_MAX 200.0
|
||||||
|
|
||||||
|
//#define Z_MIN 0.0
|
||||||
|
//#define Z_MAX 140.0
|
||||||
|
|
||||||
|
/** \def E_ABSOLUTE
|
||||||
|
Some G-code creators produce relative length commands for the extruder,
|
||||||
|
others absolute ones. G-code using absolute lengths can be recognized when
|
||||||
|
there are G92 E0 commands from time to time. If you have G92 E0 in your
|
||||||
|
G-code, define this flag.
|
||||||
|
|
||||||
|
This is the startup default and can be changed with M82/M83 while running.
|
||||||
|
*/
|
||||||
|
#define E_ABSOLUTE
|
||||||
|
|
||||||
|
/** \def ACCELERATION_REPRAP ACCELERATION_RAMPING ACCELERATION_TEMPORAL
|
||||||
|
Choose optionally one of ACCELERATION_REPRAP, ACCELERATION_RAMPING or
|
||||||
|
ACCELERATION_TEMPORAL. With none of them defined, movements are done
|
||||||
|
without acceleration. Recommended is ACCELERATION_RAMPING.
|
||||||
|
*/
|
||||||
|
//#define ACCELERATION_REPRAP
|
||||||
|
#define ACCELERATION_RAMPING
|
||||||
|
//#define ACCELERATION_TEMPORAL
|
||||||
|
|
||||||
|
/** \def ACCELERATION
|
||||||
|
How fast to accelerate when using ACCELERATION_RAMPING. Start with 10 for
|
||||||
|
milling (high precision) or 1000 for printing.
|
||||||
|
|
||||||
|
Units: mm/s^2
|
||||||
|
Useful range: 1 to 10'000
|
||||||
|
*/
|
||||||
|
#define ACCELERATION 100 /* float */
|
||||||
|
|
||||||
|
/** \def LOOKAHEAD
|
||||||
|
Define this to enable look-ahead during *ramping* acceleration to smoothly
|
||||||
|
transition between moves instead of performing a dead stop every move.
|
||||||
|
Enabling look-ahead requires about 3600 bytes of flash memory.
|
||||||
|
*/
|
||||||
|
#define LOOKAHEAD
|
||||||
|
|
||||||
|
/** \def MAX_JERK_X MAX_JERK_Y MAX_JERK_Z MAX_JERK_E
|
||||||
|
When performing look-ahead, we need to decide what an acceptable jerk to the
|
||||||
|
mechanics is. Look-ahead attempts to instantly change direction at movement
|
||||||
|
crossings, which means instant changes in the speed of the axes participating
|
||||||
|
in the movement. Define here how big the speed bumps on each of the axes is
|
||||||
|
allowed to be.
|
||||||
|
|
||||||
|
If you want a full stop before and after moving a specific axis, define
|
||||||
|
MAX_JERK of this axis to 0. This is often wanted for the Z axis. If you want
|
||||||
|
to ignore jerk on an axis, define it to twice the maximum feedrate of this
|
||||||
|
axis.
|
||||||
|
|
||||||
|
Having these values too low results in more than neccessary slowdown at
|
||||||
|
movement crossings, but is otherwise harmless. Too high values can result
|
||||||
|
in stepper motors suddenly stalling. If angles between movements in your
|
||||||
|
G-code are small and your printer runs through entire curves full speed,
|
||||||
|
there's no point in raising the values.
|
||||||
|
|
||||||
|
Units: mm/min
|
||||||
|
Sane values: 0 to 400
|
||||||
|
Valid range: 0 to 65535
|
||||||
|
*/
|
||||||
|
#define MAX_JERK_X 20
|
||||||
|
#define MAX_JERK_Y 20
|
||||||
|
#define MAX_JERK_Z 0
|
||||||
|
#define MAX_JERK_E 200
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************\
|
||||||
|
* *
|
||||||
|
* 7. MISCELLANEOUS OPTIONS *
|
||||||
|
* *
|
||||||
|
\***************************************************************************/
|
||||||
|
|
||||||
|
/** \def USE_INTERNAL_PULLUPS
|
||||||
|
The ATmega has internal pullup resistors on it's input pins which are
|
||||||
|
counterproductive with the commonly used eletronic endstops, so they should
|
||||||
|
be switched off. For other endstops, like mechanical ones, you may want to
|
||||||
|
uncomment this.
|
||||||
|
*/
|
||||||
|
//#define USE_INTERNAL_PULLUPS
|
||||||
|
|
||||||
|
/** \def TEMP_HYSTERESIS
|
||||||
|
Actual temperature must be target +/- this hysteresis before target
|
||||||
|
temperature is considered to be achieved. Also, BANG_BANG tries to stay
|
||||||
|
within half of this hysteresis.
|
||||||
|
|
||||||
|
Unit: degree Celsius
|
||||||
|
*/
|
||||||
|
#define TEMP_HYSTERESIS 10
|
||||||
|
|
||||||
|
/** \def TEMP_RESIDENCY_TIME
|
||||||
|
Actual temperature must be close to target (within set temperature
|
||||||
|
+- TEMP_HYSTERESIS) for this long before target is achieved (and a M116
|
||||||
|
succeeds).
|
||||||
|
|
||||||
|
Unit: seconds
|
||||||
|
*/
|
||||||
|
#define TEMP_RESIDENCY_TIME 60
|
||||||
|
|
||||||
|
/** \def TEMP_EWMA
|
||||||
|
Smooth noisy temperature sensors. Good hardware shouldn't be noisy. Set to
|
||||||
|
1.0 for unfiltered data (and a 140 bytes smaller binary).
|
||||||
|
|
||||||
|
Instrument Engineer's Handbook, 4th ed, Vol 2 p126 says values of
|
||||||
|
0.05 to 0.1 are typical. Smaller is smoother but slower adjusting, larger is
|
||||||
|
quicker but rougher. If you need to use this, set the PID parameter to zero
|
||||||
|
(M132 S0) to make the PID loop insensitive to noise.
|
||||||
|
|
||||||
|
Valid range: 0.001 to 1.0
|
||||||
|
*/
|
||||||
|
#define TEMP_EWMA 1.0 /* float */
|
||||||
|
|
||||||
|
/** \def HEATER_SANITY_CHECK
|
||||||
|
Check if heater responds to changes in target temperature, disable and spit
|
||||||
|
errors if not largely untested, please comment in forum if this works, or
|
||||||
|
doesn't work for you!
|
||||||
|
*/
|
||||||
|
//#define HEATER_SANITY_CHECK
|
||||||
|
|
||||||
|
/** \def XONXOFF
|
||||||
|
Xon/Xoff flow control.
|
||||||
|
|
||||||
|
Redundant when using RepRap Host for sending G-code, but mandatory when
|
||||||
|
sending G-code files with a plain terminal emulator, like GtkTerm (Linux),
|
||||||
|
CoolTerm (Mac) or HyperTerminal (Windows).
|
||||||
|
*/
|
||||||
|
//#define XONXOFF
|
||||||
|
|
||||||
|
/** \def EECONFIG
|
||||||
|
Enable EEPROM configuration storage.
|
||||||
|
|
||||||
|
Enabled by default. Commenting this out makes the binary several hundred
|
||||||
|
bytes smaller, so you might want to disable EEPROM storage on small MCUs,
|
||||||
|
like the ATmega168.
|
||||||
|
*/
|
||||||
|
#define EECONFIG
|
||||||
|
|
||||||
|
/** \def DEBUG
|
||||||
|
Enables /heaps/ of extra output, and some extra M-codes.
|
||||||
|
|
||||||
|
WARNING: this WILL break most host-side talkers that expect particular
|
||||||
|
responses from firmware such as reprap host and replicatorG use with serial
|
||||||
|
terminal or other suitable talker only.
|
||||||
|
*/
|
||||||
|
//#define DEBUG
|
||||||
|
|
||||||
|
/** \def BANG_BANG
|
||||||
|
Drops PID loop from heater control, reduces code size significantly
|
||||||
|
(1300 bytes!).
|
||||||
|
*/
|
||||||
|
//#define BANG_BANG
|
||||||
|
|
||||||
|
/** \def BANG_BANG_ON
|
||||||
|
PWM value for Bang Bang 'on'.
|
||||||
|
*/
|
||||||
|
//#define BANG_BANG_ON 200
|
||||||
|
|
||||||
|
/** \def BANG_BANG_OFF
|
||||||
|
PWM value for Bang Bang 'off'.
|
||||||
|
*/
|
||||||
|
//#define BANG_BANG_OFF 45
|
||||||
|
|
||||||
|
/** \def MOVEBUFFER_SIZE
|
||||||
|
Move buffer size, in number of moves.
|
||||||
|
|
||||||
|
Note that each move takes a fair chunk of ram (107 bytes as of this writing),
|
||||||
|
so don't make the buffer too big. However, a larger movebuffer will probably
|
||||||
|
help with lots of short consecutive moves, as each move takes a bunch of
|
||||||
|
math (hence time) to set up so a longer buffer allows more of the math to
|
||||||
|
be done during preceding longer moves.
|
||||||
|
*/
|
||||||
|
#define MOVEBUFFER_SIZE 8
|
||||||
|
|
||||||
|
/** \def DC_EXTRUDER DC_EXTRUDER_PWM
|
||||||
|
If you have a DC motor extruder, configure it as a "heater" above and define
|
||||||
|
this value as the index or name. You probably also want to comment out
|
||||||
|
E_STEP_PIN and E_DIR_PIN in the Pinouts section above.
|
||||||
|
*/
|
||||||
|
//#define DC_EXTRUDER HEATER_motor
|
||||||
|
//#define DC_EXTRUDER_PWM 180
|
||||||
|
|
||||||
|
/** \def USE_WATCHDOG
|
||||||
|
Teacup implements a watchdog, which has to be reset every 250ms or it will
|
||||||
|
reboot the controller. As rebooting (and letting the GCode sending
|
||||||
|
application trying to continue the build with a then different Home point)
|
||||||
|
is probably even worse than just hanging, and there is no better restore
|
||||||
|
code in place, this is disabled for now.
|
||||||
|
*/
|
||||||
|
//#define USE_WATCHDOG
|
||||||
|
|
||||||
|
/** \def REFERENCE
|
||||||
|
Which analog reference to use. See analog.h for choices.
|
||||||
|
*/
|
||||||
|
#define REFERENCE REFERENCE_AVCC
|
||||||
|
|
||||||
|
/** \def STEP_INTERRUPT_INTERRUPTIBLE
|
||||||
|
This option makes the step interrupt interruptible (nested). This should
|
||||||
|
help immensely with dropped serial characters, but may also make debugging
|
||||||
|
infuriating due to the complexities arising from nested interrupts.
|
||||||
|
|
||||||
|
Note: disable this option if you're using a '168 or for some reason your
|
||||||
|
ram usage is above 90%. This option hugely increases likelihood of stack
|
||||||
|
smashing.
|
||||||
|
*/
|
||||||
|
#define STEP_INTERRUPT_INTERRUPTIBLE 1
|
||||||
|
|
||||||
|
/** \def TH_COUNT
|
||||||
|
Temperature history count. This is how many temperature readings to keep in
|
||||||
|
order to calculate derivative in PID loop higher values make PID derivative
|
||||||
|
term more stable at the expense of reaction time.
|
||||||
|
*/
|
||||||
|
#define TH_COUNT 8
|
||||||
|
|
||||||
|
/** \def FAST_PWM
|
||||||
|
Teacup offers two PWM frequencies, 76(61) Hz and 78000(62500) Hz on a
|
||||||
|
20(16) MHz electronics. The slower one is the default, as it's the safer
|
||||||
|
choice and reduces MOSFET heating. Drawback is, in a quiet environment you
|
||||||
|
might notice the heaters and your power supply humming.
|
||||||
|
|
||||||
|
Uncomment this option if you want to get rid of this humming and can afford
|
||||||
|
a hotter MOSFET or want faster PWM for other reasons.
|
||||||
|
|
||||||
|
See also: http://reprap.org/wiki/Gen7_Research#MOSFET_heat_and_PWM
|
||||||
|
*/
|
||||||
|
//#define FAST_PWM
|
||||||
|
|
||||||
|
/** \def PID_SCALE
|
||||||
|
This is the scaling of internally stored PID values. 1024L is a good value.
|
||||||
|
*/
|
||||||
|
#define PID_SCALE 1024L
|
||||||
|
|
||||||
|
/** \def ENDSTOP_STEPS
|
||||||
|
Number of steps to run into the endstops intentionally. As endstops trigger
|
||||||
|
false alarm sometimes, Teacup debounces them by counting a number of
|
||||||
|
consecutive positives.
|
||||||
|
|
||||||
|
Valid range: 1...255. Use 4 or less for reliable endstops, 8 or even more
|
||||||
|
for flaky ones.
|
||||||
|
*/
|
||||||
|
#define ENDSTOP_STEPS 4
|
||||||
|
|
||||||
|
/** \def CANNED_CYCLE
|
||||||
|
G-code commands in this string will be executed over and over again, without
|
||||||
|
user interaction or even a serial connection. It's purpose is e.g. for
|
||||||
|
exhibitions or when using Teacup for other purposes than printing. You can
|
||||||
|
add any G-code supported by Teacup.
|
||||||
|
|
||||||
|
Note: don't miss these newlines (\n) and backslashes (\).
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
#define CANNED_CYCLE "G1 X100 F3000\n" \
|
||||||
|
"G4 P500\n" \
|
||||||
|
"G1 X0\n" \
|
||||||
|
"G4 P500\n"
|
||||||
|
*/
|
||||||
|
|
@ -1,229 +0,0 @@
|
||||||
helpText = {
|
|
||||||
'STEPS_PER_M': "steps per meter ( = steps per mm * 1000 ) \
|
|
||||||
calculate these values appropriate for your machine.\n\
|
|
||||||
for threaded rods, this is:\n\n\
|
|
||||||
\t(steps motor per turn) / (pitch of the thread) * 1000\n\n\
|
|
||||||
for belts, this is\n\n\
|
|
||||||
\t(steps per motor turn) / (number of gear teeth) / (belt module) * 1000\n\n\
|
|
||||||
half-stepping doubles the number, quarter stepping requires * 4, etc.\n\
|
|
||||||
valid range = 20 to 4,0960,000 (0.02 to 40960 steps/mm). \
|
|
||||||
all numbers are integers, so no decimal point",
|
|
||||||
|
|
||||||
'MAXIMUM_FEEDRATE': "maximum feed rate - in mm/min - for G0 rapid moves and \
|
|
||||||
as a cap for all other feedrates",
|
|
||||||
|
|
||||||
'SEARCH_FEEDRATE': "search feed rate - in mm/min - used when doing precision \
|
|
||||||
endstop search and as a default feed rate",
|
|
||||||
|
|
||||||
'ENDSTOP_CLEARANCE': "When hitting an endstop, Teacup properly decelerates \
|
|
||||||
instead of doing an abrupt stop\nto save your mechanics. Inevitably, this \
|
|
||||||
means it overshoots the endstop trigger point by some distance.\n\n\
|
|
||||||
To deal with this, Teacup adapts homing movement speeds to what your endstops \
|
|
||||||
can deal with.\nThe higher the allowed acceleration and the more clearance \
|
|
||||||
the endstop comes with, the faster Teacup\nwill do homing movements.\n\n\
|
|
||||||
Set here how many micrometers (mm * 1000) your endstop allows the carriage to \
|
|
||||||
overshoot the\ntrigger point. Typically 1000 or 2000 for mechanical endstops, \
|
|
||||||
more for optical ones.\nYou can set it to zero, in which case \
|
|
||||||
SEARCH_FEEDRATE_{XYZ} is used, but expect very slow\nhoming movements.\n\n\
|
|
||||||
Units: micrometers\n\
|
|
||||||
Sane values: 0 to 20000 (0 to 20 mm)\n\
|
|
||||||
Valid range: 0 to 1000000",
|
|
||||||
|
|
||||||
'MINMAX': "soft axis limits, in mm.\n\ndefine them to your machine's size \
|
|
||||||
relative to what your host considers to be the origin.",
|
|
||||||
|
|
||||||
'E_ABSOLUTE': "some G-Code creators produce relative length commands for the \
|
|
||||||
extruder,\nothers absolute ones. G-Code using absolute lengths can be \
|
|
||||||
recognized when there\nare G92 E0 commands from time to time. if you have \
|
|
||||||
G92 E0 in your G-code, check this box.",
|
|
||||||
|
|
||||||
'ACCELERATION_REPRAP': "acceleration, reprap style.\n\n\
|
|
||||||
Each movement starts at the speed of the previous command and accelerates or \
|
|
||||||
decelerates\nlinearly to reach target speed at the end of the movement.",
|
|
||||||
'ACCELERATION_RAMPING': "acceleration and deceleration ramping.\n\n\
|
|
||||||
Each movement starts at (almost) no speed, linearly accelerates to target \
|
|
||||||
speed and decelerates\njust in time to smoothly stop at the target.",
|
|
||||||
'ACCELERATION_TEMPORAL': "This algorithm causes the timer to fire when any \
|
|
||||||
axis needs to step, instead of\n\synchronising to the axis with the most \
|
|
||||||
steps ala bresenham",
|
|
||||||
'ACCELERATION' : "how fast to accelerate when using acceleration ramping.\n\n\
|
|
||||||
given in mm/s^2, decimal allowed, useful range 1. to 10,000.\n\
|
|
||||||
Start with 10. for milling (high precision) or 1000. for printing",
|
|
||||||
'LOOKAHEAD': "Define this to enable look-ahead during *ramping* acceleration to \
|
|
||||||
smoothly transition\nbetween moves instead of performing a dead stop every \
|
|
||||||
move. Enabling look-ahead requires about\n3600 bytes of flash memory.",
|
|
||||||
'MAX_JERK': "When performing look-ahead, we need to decide what an acceptable \
|
|
||||||
jerk to the\nmechanics is. Look-ahead attempts to instantly change direction \
|
|
||||||
at movement\ncrossings, which means instant changes in the speed of the axes \
|
|
||||||
participating\nin the movement. Define here how big the speed bumps on each \
|
|
||||||
of the axes is\nallowed to be.\n\n\
|
|
||||||
If you want a full stop before and after moving a specific axis, define\n\
|
|
||||||
maximum jerk of this axis to 0. This is often wanted for the Z axis. If you \
|
|
||||||
want\nto ignore jerk on an axis, define it to twice the maximum feedrate of \
|
|
||||||
this axis.\n\nHaving these values too low results in more than necessary \
|
|
||||||
slowdown at\nmovement crossings, but is otherwise harmless. Too high values \
|
|
||||||
can result\nin stepper motors suddenly stalling. If angles between movements \
|
|
||||||
in your\nG-code are small and your printer runs through entire curves full \
|
|
||||||
speed,\nthere's no point in raising the values.\n\n\
|
|
||||||
Units: mm/min\n\
|
|
||||||
Sane values: 0 to 400\n\
|
|
||||||
Valid range: 0 to 65535",
|
|
||||||
|
|
||||||
'INCLUDE_ARDUINO': "Include arduino.h header file in the C++ source code. \
|
|
||||||
This allows you\nto define pins using the atmel/avr conventions (e.g. DI012 \
|
|
||||||
or AI01)",
|
|
||||||
|
|
||||||
'USE_INTERNAL_PULLUPS': "Use Internal Pullups. the ATmega has internal pullup \
|
|
||||||
resistors on it's input pins\nwhich are counterproductive with the commonly \
|
|
||||||
used electronic endstops, so this should be unchecked.\n\For other endstops, \
|
|
||||||
like mechanical ones, you may want to check this.",
|
|
||||||
|
|
||||||
'TX_ENABLE_PIN': "Tx Enable Pin. Not yet used",
|
|
||||||
'RX_ENABLE_PIN': "Rx Enable Pin. Not yet used",
|
|
||||||
|
|
||||||
'X_STEP_PIN': "the pin for the stepper motor step signal",
|
|
||||||
'X_DIR_PIN': "the pin for the stepper motor direction signal",
|
|
||||||
'X_MIN_PIN': "the pin for the endstop at the axis minimum position",
|
|
||||||
'X_MAX_PIN': "the pin for the endstop at the axis maximum position",
|
|
||||||
'X_ENABLE_PIN': "the pin for the stepper motor enable signal",
|
|
||||||
'X_INVERT_DIR': "true or false - invert the stepper motor direction",
|
|
||||||
'X_INVERT_MIN': "true or false - invert the signal received from the minimum endstop",
|
|
||||||
'X_INVERT_MAX': "true or false - invert the signal received from the maximum endstop",
|
|
||||||
'X_INVERT_ENABLE': "true or false - invert the stepper motor enable signal",
|
|
||||||
|
|
||||||
'Y_STEP_PIN': "the pin for the stepper motor step signal",
|
|
||||||
'Y_DIR_PIN': "the pin for the stepper motor direction signal",
|
|
||||||
'Y_MIN_PIN': "the pin for the endstop at the axis minimum position",
|
|
||||||
'Y_MAX_PIN': "the pin for the endstop at the axis maximum position",
|
|
||||||
'Y_ENABLE_PIN': "the pin for the stepper motor enable signal",
|
|
||||||
'Y_INVERT_DIR': "true or false - invert the stepper motor direction",
|
|
||||||
'Y_INVERT_MIN': "true or false - invert the signal received from the minimum endstop",
|
|
||||||
'Y_INVERT_MAX': "true or false - invert the signal received from the maximum endstop",
|
|
||||||
'Y_INVERT_ENABLE': "true or false - invert the stepper motor enable signal",
|
|
||||||
|
|
||||||
'Z_STEP_PIN': "the pin for the stepper motor step signal",
|
|
||||||
'Z_DIR_PIN': "the pin for the stepper motor direction signal",
|
|
||||||
'Z_MIN_PIN': "the pin for the endstop at the axis minimum position",
|
|
||||||
'Z_MAX_PIN': "the pin for the endstop at the axis maximum position",
|
|
||||||
'Z_ENABLE_PIN': "the pin for the stepper motor enable signal",
|
|
||||||
'Z_INVERT_DIR': "true or false - invert the stepper motor direction",
|
|
||||||
'Z_INVERT_MIN': "true or false - invert the signal received from the minimum endstop",
|
|
||||||
'Z_INVERT_MAX': "true or false - invert the signal received from the maximum endstop",
|
|
||||||
'Z_INVERT_ENABLE': "true or false - invert the stepper motor enable signal",
|
|
||||||
|
|
||||||
'E_STEP_PIN': "the pin for the stepper motor step signal",
|
|
||||||
'E_DIR_PIN': "the pin for the stepper motor direction signal",
|
|
||||||
'E_ENABLE_PIN': "the pin for the stepper motor enable signal",
|
|
||||||
'E_INVERT_DIR': "true or false - invert the stepper motor direction",
|
|
||||||
'E_INVERT_ENABLE': "true or false - invert the stepper motor enable signal",
|
|
||||||
|
|
||||||
'PS_ON_PIN': "Which pin is used to turn the power supply off",
|
|
||||||
'PS_MOSFET_PIN': "???",
|
|
||||||
|
|
||||||
'STEPPER_ENABLE_PIN': "???",
|
|
||||||
'STEPPER_INVERT_ENABLE': "???",
|
|
||||||
|
|
||||||
'SD_CARD_DETECT': "the pin used to detect if an SD card has been inserted.",
|
|
||||||
'SD_WRITE_PROTECT': "the pin used to determine if an SD card is write-protected",
|
|
||||||
'DEBUG_LED_PIN': "Enable flashing of a LED during motor stepping.\n\n\
|
|
||||||
Disabled by default. Turning this on this makes the binary a few bytes larger\n\
|
|
||||||
and adds a few cycles to the step timing interrupt. This is also used for\n\
|
|
||||||
for precision profiling",
|
|
||||||
|
|
||||||
'TEMP_HYSTERESIS': "Actual temperature must be target +/- this hysteresis \
|
|
||||||
before target\ntemperature is considered to be achieved. Also, BANG_BANG \
|
|
||||||
tries to stay\nwithin half of this hysteresis. Unit is degrees Celcius",
|
|
||||||
'TEMP_RESIDENCY_TIME': "actual temperature must be close to target (within\n\
|
|
||||||
set temperature +- TEMP_HYSTERESIS) for this long before target is achieved\n\
|
|
||||||
(and a M116 succeeds). Unit is seconds.",
|
|
||||||
'TEMP_EWMA': "Smooth noisy temperature sensors. Good hardware shouldn't be\n\
|
|
||||||
noisy. Set to 1.0 for unfiltered data (and a 140 bytes smaller binary)\n\n\
|
|
||||||
Valid range: 0.001 - 1.0",
|
|
||||||
'TEMP_TYPES': "which temperature sensors are you using? Check every type of \
|
|
||||||
sensor you use\nto enable the appropriate code. Intercom is the gen3-style \
|
|
||||||
separate extruder board. Note\nthat you will not be able to uncheck a sensor \
|
|
||||||
type that is in use",
|
|
||||||
|
|
||||||
'ADDSENSOR': 'Define your temperature sensors. One entry for each sensor, \
|
|
||||||
only limited\nby the number of available ATmega pins.\n\n\
|
|
||||||
Types are only those chosen on the main page.\n\n\
|
|
||||||
The "additional" field is used for TT_THERMISTOR only. It defines the\n\
|
|
||||||
name of the table(s) in ThermistorTable.h to use. Typically, this is\n\
|
|
||||||
THERMISTOR_EXTRUDER for the first or only table, or THERMISTOR_BED for\n\
|
|
||||||
the second table. See also early in ThermistorTable.{single|double}.h,\n\n\
|
|
||||||
For a GEN3 set type to TT_INTERCOM and pin to AIO0. The pin won\'t be used in \
|
|
||||||
this case.',
|
|
||||||
'DELSENSOR': 'Remove the selected temperature sensor from the configuration',
|
|
||||||
|
|
||||||
"HEATER_SANITY_CHECK": "check if heater responds to changes in target \
|
|
||||||
temperature, disable\nand spit errors if not. largely untested, please \
|
|
||||||
comment in forum if this works, or doesn't work for you!",
|
|
||||||
|
|
||||||
'ADDHEATER': "Add a heater to the configuration",
|
|
||||||
'DELHEATER': "Remove a heater from the configuration",
|
|
||||||
|
|
||||||
'BAUD': "Baud rate for the serial RS232 protocol connection to the host. \
|
|
||||||
Usually 115200,\nother common values are 19200, 38400 or 57600. Ignored when \
|
|
||||||
USB_SERIAL is checked.",
|
|
||||||
'USB_SERIAL': "Define this for using USB instead of the serial RS232 protocol. \
|
|
||||||
Works on\nUSB-equipped ATmegas, like the ATmega32U4, only",
|
|
||||||
'XONXOFF': "Xon/Xoff flow control. Redundant when using RepRap Host for \
|
|
||||||
sending GCode,\nbut mandatory when sending GCode files with a plain terminal \
|
|
||||||
emulator, like GtkTerm (Linux),\nCoolTerm (Mac) or HyperTerminal (Windows). \
|
|
||||||
Can also be set in Makefile",
|
|
||||||
|
|
||||||
'MOTHERBOARD': "This is the motherboard, as opposed to the extruder.",
|
|
||||||
'F_CPU': "The CPU clock rate",
|
|
||||||
'EECONFIG': "Enable EEPROM configuration storage.\n\n\
|
|
||||||
Enabled by default. Commenting this out makes the binary several hundred\n\
|
|
||||||
bytes smaller, so you might want to disable EEPROM storage on small MCUs,\n\
|
|
||||||
like the ATmega168.",
|
|
||||||
'DEBUG': "enables extra output, and some extra M-codes.\n\n\
|
|
||||||
WARNING: this WILL break most host-side talkers that expect particular \
|
|
||||||
responses\nfrom firmware such as reprap host and replicatorG. Use with serial \
|
|
||||||
terminal\nor other suitable talker only.",
|
|
||||||
'BANG_BANG': "Drops PID loop from heater control, reduces code size\n\
|
|
||||||
significantly (1300 bytes!)",
|
|
||||||
'BANG_BANG_ON': "PWM value for 'on'",
|
|
||||||
'BANG_BANG_OFF': "PWM value for 'off'",
|
|
||||||
'MOVEBUFFER_SIZE': "Move buffer size, in number of moves\n\nnote that each \
|
|
||||||
move takes a fair chunk of ram (~69 bytes) so don't make the buffer too big.\n\
|
|
||||||
A bigger serial readbuffer may help more than increasing this unless your \
|
|
||||||
gcodes are more than\n70 characters long on average. However, a larger \
|
|
||||||
movebuffer will probably help with lots of \nshort consecutive moves, as each \
|
|
||||||
move takes a bunch of math (hence time) to set up, so a longer\nbuffer allows \
|
|
||||||
more of the math to be done during preceding longer moves",
|
|
||||||
'DC_EXTRUDER': 'If you have a DC motor extruder, configure it as a "heater" \
|
|
||||||
on the heater page,\nand choose the name you used there in this field. You \
|
|
||||||
probably also want to comment out E_STEP_PIN\nand E_DIR_PIN on the Pinouts \
|
|
||||||
page.',
|
|
||||||
'DC_EXTRUDER_PWM': "The PWM value at which to operate the DC Extruder motor",
|
|
||||||
'USE_WATCHDOG': "Teacup implements a watchdog, which has to be reset every \
|
|
||||||
250ms or it will\nreboot the controller. As rebooting (and letting the GCode\
|
|
||||||
sending application trying to\ncontinue the build with a then different Home \
|
|
||||||
point) is probably even worse than just hanging,\nand there is no better \
|
|
||||||
restore code in place, this is disabled for now.",
|
|
||||||
'REFERENCE': "which analog reference to use. see analog.h for choices",
|
|
||||||
'STEP_INTERRUPT_INTERRUPTIBLE': "this option makes the step interrupt \
|
|
||||||
interruptible (nested).\nthis should help immensely with dropped serial \
|
|
||||||
characters, but may also make\ndebugging infuriating due to the complexities \
|
|
||||||
arising from nested interrupts.\n\nnote disable this option if you're using a \
|
|
||||||
'168 or for some reason your ram usage\nis above 90%. This option hugely \
|
|
||||||
increases likelihood of stack smashing.",
|
|
||||||
'TH_COUNT': "Temperature history count. This is how many temperature readings \
|
|
||||||
to keep in\norder to calculate derivative in PID loop. Higher values make PID \
|
|
||||||
derivative term more\nstable at the expense of reaction time",
|
|
||||||
'FAST_PWM': "Teacup offers two PWM frequencies, 76(61) Hz and 78000(62500) \
|
|
||||||
Hz on a\n20(16) MHz electronics. The slower one is the default, as it's the \
|
|
||||||
safer choice.\nThe drawback is in a quiet environment you might notice the \
|
|
||||||
heaters and power supply humming.\n\nUncomment this option if you want to get \
|
|
||||||
rid of this humming or want faster PWM for other reasons.",
|
|
||||||
'ENDSTOP_STEPS': "Number of steps to run into the endstops intentionally\n\n\
|
|
||||||
As Endstops trigger false alarm sometimes, Teacup debounces them by counting \
|
|
||||||
a number of\nconsecutive positives. Valid range is 1...255. Use 4 or less for \
|
|
||||||
reliable endstops, 8 or\neven more for flaky ones.",
|
|
||||||
'CANNED_CYCLE': "G-code commands in this string will be executed over and \
|
|
||||||
over again, without\nuser interaction or even a serial connection. It's \
|
|
||||||
purpose is e.g. for\nexhibitions or when using Teacup for other purposes than \
|
|
||||||
printing. You can\nadd any G-code supported by Teacup.",
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
from configtool.page import Page
|
||||||
|
|
||||||
|
|
||||||
|
class AccelerationPage(wx.Panel, Page):
|
||||||
|
def __init__(self, parent, nb, idPg):
|
||||||
|
wx.Panel.__init__(self, nb, wx.ID_ANY)
|
||||||
|
Page.__init__(self)
|
||||||
|
self.parent = parent
|
||||||
|
self.id = idPg
|
||||||
|
|
||||||
|
self.accTypeKeys = ['ACCELERATION_REPRAP', 'ACCELERATION_RAMPING',
|
||||||
|
'ACCELERATION_TEMPORAL']
|
||||||
|
self.jerkKeys = ['MAX_JERK_X', 'MAX_JERK_Y', 'MAX_JERK_Z', 'MAX_JERK_E']
|
||||||
|
|
||||||
|
self.labels = {'ACCELERATION_REPRAP': "RepRap",
|
||||||
|
'ACCELERATION_RAMPING': "Ramping",
|
||||||
|
'ACCELERATION_TEMPORAL': "Temporal",
|
||||||
|
'ACCELERATION': "Acceleration:",
|
||||||
|
'LOOKAHEAD': "Look Ahead",
|
||||||
|
'MAX_JERK_X': "X:", 'MAX_JERK_Y': "Y:", 'MAX_JERK_Z': "Z:",
|
||||||
|
'MAX_JERK_E': "E:"}
|
||||||
|
|
||||||
|
sz = wx.GridBagSizer()
|
||||||
|
sz.AddSpacer((20, 40), pos = (0, 0))
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "Acceleration Type")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
style = wx.RB_GROUP
|
||||||
|
for k in self.accTypeKeys:
|
||||||
|
rb = self.addRadioButton(k, style, self.onAccTypeSelect)
|
||||||
|
style = 0
|
||||||
|
|
||||||
|
sbox.Add(rb, 1, wx.LEFT + wx.RIGHT, 16)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
self.rbNone = wx.RadioButton(self, wx.ID_ANY, "None", style = style)
|
||||||
|
self.rbNone.SetValue(True)
|
||||||
|
self.Bind(wx.EVT_RADIOBUTTON, self.onAccTypeSelect, self.rbNone)
|
||||||
|
sbox.Add(self.rbNone, 1, wx.LEFT + wx.RIGHT, 16)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
sz.Add(sbox, pos = (1, 1))
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "Ramping Parameters")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
k = 'ACCELERATION'
|
||||||
|
tc = self.addTextCtrl(k, 80, self.onTextCtrlFloat)
|
||||||
|
self.textControls[k].Enable(False)
|
||||||
|
|
||||||
|
sbox.Add(tc)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
k = 'LOOKAHEAD'
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
self.checkBoxes[k].Enable(False)
|
||||||
|
|
||||||
|
sbox.Add(cb, 1, wx.ALIGN_CENTER_HORIZONTAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
sz.Add(sbox, pos = (1, 3))
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "Maximum Jerk")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
for k in self.jerkKeys:
|
||||||
|
tc = self.addTextCtrl(k, 40, self.onTextCtrlInteger)
|
||||||
|
|
||||||
|
sbox.Add(tc)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
sz.AddSpacer((80, 20), pos = (1, 4))
|
||||||
|
sz.Add(sbox, pos = (1, 5))
|
||||||
|
|
||||||
|
self.SetSizer(sz)
|
||||||
|
self.enableAll(False)
|
||||||
|
|
||||||
|
def enableAll(self, flag = True):
|
||||||
|
self.rbNone.Enable(flag)
|
||||||
|
Page.enableAll(self, flag)
|
||||||
|
|
||||||
|
def onAccTypeSelect(self, evt):
|
||||||
|
self.assertModified(True)
|
||||||
|
rb = evt.GetEventObject()
|
||||||
|
label = rb.GetLabel()
|
||||||
|
|
||||||
|
if label == self.labels['ACCELERATION_RAMPING']:
|
||||||
|
ena = True
|
||||||
|
else:
|
||||||
|
ena = False
|
||||||
|
|
||||||
|
self.checkBoxes['LOOKAHEAD'].Enable(ena)
|
||||||
|
self.textControls['ACCELERATION'].Enable(ena)
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def insertValues(self, cfgValues):
|
||||||
|
self.assertValid(True)
|
||||||
|
self.enableAll(True)
|
||||||
|
for k in self.fieldValid.keys():
|
||||||
|
self.fieldValid[k] = True
|
||||||
|
self.checkBoxes['LOOKAHEAD'].Enable(False)
|
||||||
|
self.textControls['ACCELERATION'].Enable(False)
|
||||||
|
for k in self.textControls.keys():
|
||||||
|
if k in cfgValues.keys():
|
||||||
|
self.textControls[k].SetValue(cfgValues[k])
|
||||||
|
else:
|
||||||
|
self.textControls[k].SetValue("")
|
||||||
|
|
||||||
|
for tag in ['ACCELERATION_REPRAP', 'ACCELERATION_RAMPING',
|
||||||
|
'ACCELERATION_TEMPORAL']:
|
||||||
|
if tag in cfgValues.keys() and cfgValues[tag]:
|
||||||
|
self.radioButtons[tag].SetValue(True)
|
||||||
|
if tag == 'ACCELERATION_RAMPING':
|
||||||
|
self.checkBoxes['LOOKAHEAD'].Enable(True)
|
||||||
|
self.textControls['ACCELERATION'].Enable(True)
|
||||||
|
|
||||||
|
k = 'LOOKAHEAD'
|
||||||
|
if k in cfgValues.keys() and cfgValues[k]:
|
||||||
|
self.checkBoxes[k].SetValue(True)
|
||||||
|
else:
|
||||||
|
self.checkBoxes[k].SetValue(False)
|
||||||
|
self.assertModified(False)
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
from configtool.data import pinNames, BSIZESMALL
|
||||||
|
|
||||||
|
|
||||||
|
class AddHeaterDlg(wx.Dialog):
|
||||||
|
def __init__(self, parent, names, pins):
|
||||||
|
wx.Dialog.__init__(self, parent, wx.ID_ANY, "Add heater", size = (400, 204))
|
||||||
|
self.Bind(wx.EVT_CLOSE, self.onCancel)
|
||||||
|
|
||||||
|
self.names = names
|
||||||
|
|
||||||
|
self.nameValid = False
|
||||||
|
|
||||||
|
sz = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
gsz = wx.GridBagSizer()
|
||||||
|
gsz.AddSpacer((20, 20), pos = (0, 0))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Heater Name:", size = (80, -1),
|
||||||
|
style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
|
||||||
|
self.tcName = wx.TextCtrl(self, wx.ID_ANY, "")
|
||||||
|
self.tcName.SetBackgroundColour("pink")
|
||||||
|
self.tcName.Bind(wx.EVT_TEXT, self.onNameEntry)
|
||||||
|
lsz.Add(self.tcName)
|
||||||
|
self.tcName.SetToolTipString("Enter a unique name for this heater.")
|
||||||
|
|
||||||
|
gsz.Add(lsz, pos = (1, 1))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Pin:", size = (80, -1),
|
||||||
|
style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
|
||||||
|
self.chPin = wx.Choice(self, wx.ID_ANY, choices = pins)
|
||||||
|
self.chPin.Bind(wx.EVT_CHOICE, self.onChoice)
|
||||||
|
self.chPin.SetSelection(0)
|
||||||
|
lsz.Add(self.chPin)
|
||||||
|
self.chPin.SetToolTipString("Choose a pin for this heater.")
|
||||||
|
|
||||||
|
gsz.Add(lsz, pos = (3, 1))
|
||||||
|
|
||||||
|
self.cbPwm = wx.CheckBox(self, wx.ID_ANY, "PWM")
|
||||||
|
self.cbPwm.SetToolTipString("Use Pulse Width Modulation in case the "
|
||||||
|
"choosen pin allows to do so.")
|
||||||
|
|
||||||
|
gsz.AddSpacer((50, 15), pos = (1, 2))
|
||||||
|
gsz.Add(self.cbPwm, pos = (1, 3))
|
||||||
|
gsz.AddSpacer((20, 20), pos = (4, 4))
|
||||||
|
|
||||||
|
sz.Add(gsz)
|
||||||
|
sz.AddSpacer((30, 30))
|
||||||
|
|
||||||
|
bsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
|
||||||
|
self.bSave = wx.Button(self, wx.ID_ANY, "Save", size = BSIZESMALL)
|
||||||
|
self.bSave.Bind(wx.EVT_BUTTON, self.onSave)
|
||||||
|
bsz.Add(self.bSave)
|
||||||
|
self.bSave.Enable(False)
|
||||||
|
|
||||||
|
bsz.AddSpacer(30, 100)
|
||||||
|
|
||||||
|
self.bCancel = wx.Button(self, wx.ID_ANY, "Cancel", size = BSIZESMALL)
|
||||||
|
self.bCancel.Bind(wx.EVT_BUTTON, self.onCancel)
|
||||||
|
bsz.Add(self.bCancel)
|
||||||
|
|
||||||
|
sz.Add(bsz, flag = wx.ALIGN_CENTER_HORIZONTAL)
|
||||||
|
self.SetSizer(sz)
|
||||||
|
|
||||||
|
def onNameEntry(self, evt):
|
||||||
|
tc = evt.GetEventObject()
|
||||||
|
w = tc.GetValue().strip()
|
||||||
|
if w == "":
|
||||||
|
self.nameValid = False
|
||||||
|
else:
|
||||||
|
if w in self.names:
|
||||||
|
self.nameValid = False
|
||||||
|
else:
|
||||||
|
self.nameValid = True
|
||||||
|
|
||||||
|
if self.nameValid:
|
||||||
|
tc.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
|
||||||
|
else:
|
||||||
|
tc.SetBackgroundColour("pink")
|
||||||
|
tc.Refresh()
|
||||||
|
|
||||||
|
self.checkDlgValidity()
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def onChoice(self, evt):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def checkDlgValidity(self):
|
||||||
|
if self.nameValid:
|
||||||
|
self.bSave.Enable(True)
|
||||||
|
else:
|
||||||
|
self.bSave.Enable(False)
|
||||||
|
|
||||||
|
def getValues(self):
|
||||||
|
nm = self.tcName.GetValue()
|
||||||
|
pin = pinNames[self.chPin.GetSelection()]
|
||||||
|
if self.cbPwm.IsChecked():
|
||||||
|
pwm = "1"
|
||||||
|
else:
|
||||||
|
pwm = "0"
|
||||||
|
|
||||||
|
return (nm, pin, pwm)
|
||||||
|
|
||||||
|
def onSave(self, evt):
|
||||||
|
self.EndModal(wx.ID_OK)
|
||||||
|
|
||||||
|
def onCancel(self, evt):
|
||||||
|
self.EndModal(wx.ID_CANCEL)
|
||||||
|
|
@ -0,0 +1,174 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
from configtool.data import pinNames, BSIZESMALL
|
||||||
|
|
||||||
|
|
||||||
|
class AddSensorDlg(wx.Dialog):
|
||||||
|
def __init__(self, parent, names, sl, pins):
|
||||||
|
wx.Dialog.__init__(self, parent, wx.ID_ANY, "Add temperature sensor",
|
||||||
|
size = (400, 204))
|
||||||
|
self.Bind(wx.EVT_CLOSE, self.onCancel)
|
||||||
|
|
||||||
|
self.names = names
|
||||||
|
|
||||||
|
self.nameValid = False
|
||||||
|
|
||||||
|
sz = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
|
||||||
|
csz = wx.GridBagSizer()
|
||||||
|
csz.AddSpacer((10, 10), pos = (0, 0))
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "Sensor Type")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
style = wx.RB_GROUP
|
||||||
|
self.rbs = {}
|
||||||
|
for k in sl:
|
||||||
|
rb = wx.RadioButton(self, wx.ID_ANY, k, style = style)
|
||||||
|
self.rbs[k] = rb
|
||||||
|
self.Bind(wx.EVT_RADIOBUTTON, self.onSensorType, rb)
|
||||||
|
style = 0
|
||||||
|
|
||||||
|
sbox.Add(rb, 1, wx.LEFT + wx.RIGHT, 16)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
csz.Add(sbox, pos = (1, 3))
|
||||||
|
|
||||||
|
vsz = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
vsz.AddSpacer((10, 10))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Sensor Name:", size = (80, -1),
|
||||||
|
style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
|
||||||
|
self.tcName = wx.TextCtrl(self, wx.ID_ANY, "")
|
||||||
|
self.tcName.SetBackgroundColour("pink")
|
||||||
|
self.tcName.Bind(wx.EVT_TEXT, self.onNameEntry)
|
||||||
|
lsz.Add(self.tcName)
|
||||||
|
self.tcName.SetToolTipString("Enter a unique name for this sensor.")
|
||||||
|
|
||||||
|
vsz.Add(lsz)
|
||||||
|
vsz.AddSpacer((10, 10))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Pin:", size = (80, -1),
|
||||||
|
style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
|
||||||
|
self.choiceList = pinNames
|
||||||
|
self.chPin = wx.Choice(self, wx.ID_ANY, choices = pins)
|
||||||
|
self.chPin.Bind(wx.EVT_CHOICE, self.onChoice)
|
||||||
|
self.chPin.SetSelection(0)
|
||||||
|
lsz.Add(self.chPin)
|
||||||
|
self.chPin.SetToolTipString("Choose a pin name for this sensor.")
|
||||||
|
|
||||||
|
vsz.Add(lsz)
|
||||||
|
vsz.AddSpacer((10, 10))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Additional:", size = (80, -1),
|
||||||
|
style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
|
||||||
|
self.tcAddtl = wx.TextCtrl(self, wx.ID_ANY, "")
|
||||||
|
self.tcAddtl.Bind(wx.EVT_TEXT, self.onAddtlEntry)
|
||||||
|
self.selectSensorType(sl[0])
|
||||||
|
lsz.Add(self.tcAddtl)
|
||||||
|
self.tcAddtl.SetToolTipString("Enter additional information required "
|
||||||
|
"by the sensor type.")
|
||||||
|
|
||||||
|
vsz.Add(lsz)
|
||||||
|
csz.Add(vsz, pos = (1, 1))
|
||||||
|
|
||||||
|
csz.AddSpacer((10, 10), pos = (1, 4))
|
||||||
|
|
||||||
|
sz.Add(csz)
|
||||||
|
sz.AddSpacer((30, 30))
|
||||||
|
|
||||||
|
bsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
|
||||||
|
self.bSave = wx.Button(self, wx.ID_ANY, "Save", size = BSIZESMALL)
|
||||||
|
self.bSave.Bind(wx.EVT_BUTTON, self.onSave)
|
||||||
|
bsz.Add(self.bSave)
|
||||||
|
self.bSave.Enable(False)
|
||||||
|
|
||||||
|
bsz.AddSpacer(30, 100)
|
||||||
|
|
||||||
|
self.bCancel = wx.Button(self, wx.ID_ANY, "Cancel", size = BSIZESMALL)
|
||||||
|
self.bCancel.Bind(wx.EVT_BUTTON, self.onCancel)
|
||||||
|
bsz.Add(self.bCancel)
|
||||||
|
|
||||||
|
sz.Add(bsz, flag = wx.ALIGN_CENTER_HORIZONTAL)
|
||||||
|
self.SetSizer(sz)
|
||||||
|
|
||||||
|
def onNameEntry(self, evt):
|
||||||
|
tc = evt.GetEventObject()
|
||||||
|
w = tc.GetValue().strip()
|
||||||
|
if w == "":
|
||||||
|
self.nameValid = False
|
||||||
|
else:
|
||||||
|
if w in self.names:
|
||||||
|
self.nameValid = False
|
||||||
|
else:
|
||||||
|
self.nameValid = True
|
||||||
|
|
||||||
|
if self.nameValid:
|
||||||
|
tc.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
|
||||||
|
else:
|
||||||
|
tc.SetBackgroundColour("pink")
|
||||||
|
tc.Refresh()
|
||||||
|
|
||||||
|
self.checkDlgValidity()
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def checkDlgValidity(self):
|
||||||
|
if self.nameValid:
|
||||||
|
self.bSave.Enable(True)
|
||||||
|
else:
|
||||||
|
self.bSave.Enable(False)
|
||||||
|
|
||||||
|
def onAddtlEntry(self, evt):
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def selectSensorType(self, lbl):
|
||||||
|
if lbl == 'TT_THERMISTOR':
|
||||||
|
self.tcAddtl.Enable(True);
|
||||||
|
else:
|
||||||
|
self.tcAddtl.Enable(False);
|
||||||
|
|
||||||
|
def onChoice(self, evt):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def onSensorType(self, evt):
|
||||||
|
rb = evt.GetEventObject()
|
||||||
|
label = rb.GetLabel()
|
||||||
|
|
||||||
|
self.selectSensorType(label)
|
||||||
|
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def getValues(self):
|
||||||
|
nm = self.tcName.GetValue()
|
||||||
|
pin = pinNames[self.chPin.GetSelection()]
|
||||||
|
addtl = self.tcAddtl.GetValue()
|
||||||
|
|
||||||
|
for k in self.rbs:
|
||||||
|
if self.rbs[k].GetValue():
|
||||||
|
stype = k
|
||||||
|
break
|
||||||
|
|
||||||
|
if stype is None:
|
||||||
|
stype = "??"
|
||||||
|
|
||||||
|
if stype in ['TT_THERMISTOR']:
|
||||||
|
return (nm, stype, pin, addtl)
|
||||||
|
else:
|
||||||
|
return (nm, stype, pin)
|
||||||
|
|
||||||
|
|
||||||
|
def onSave(self, evt):
|
||||||
|
self.EndModal(wx.ID_OK)
|
||||||
|
|
||||||
|
def onCancel(self, evt):
|
||||||
|
self.EndModal(wx.ID_CANCEL)
|
||||||
|
|
@ -0,0 +1,515 @@
|
||||||
|
|
||||||
|
import os
|
||||||
|
import wx
|
||||||
|
import re
|
||||||
|
|
||||||
|
from configtool.data import (supportedCPUs, defineValueFormat,
|
||||||
|
defineBoolFormat, defineHeaterFormat, reCommDefBL,
|
||||||
|
reCommDefBoolBL, reHelpTextStart, reHelpTextEnd,
|
||||||
|
reStartSensors, reEndSensors, reStartHeaters,
|
||||||
|
reEndHeaters, reStartProcessors, reEndProcessors,
|
||||||
|
reCandHeatPins, reCandThermPins, reAVR, reDefine,
|
||||||
|
reDefineBL, reDefQS, reDefQSm, reDefQSm2,
|
||||||
|
reDefBool, reDefBoolBL, reDefHT, reDefTS,
|
||||||
|
reHeater, reSensor3, reSensor4)
|
||||||
|
from configtool.pinoutspage import PinoutsPage
|
||||||
|
from configtool.sensorpage import SensorsPage
|
||||||
|
from configtool.heaterspage import HeatersPage
|
||||||
|
from configtool.communicationspage import CommunicationsPage
|
||||||
|
from configtool.cpupage import CpuPage
|
||||||
|
|
||||||
|
|
||||||
|
class BoardPanel(wx.Panel):
|
||||||
|
def __init__(self, parent, nb, folder):
|
||||||
|
wx.Panel.__init__(self, nb, wx.ID_ANY)
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
self.cfgValues = {}
|
||||||
|
self.heaters = []
|
||||||
|
self.sensors = []
|
||||||
|
self.processors = []
|
||||||
|
self.candHeatPins = []
|
||||||
|
self.candThermPins = []
|
||||||
|
self.dir = os.path.join(folder, "config")
|
||||||
|
|
||||||
|
sz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
|
||||||
|
self.nb = wx.Notebook(self, wx.ID_ANY, size = (21, 21),
|
||||||
|
style = wx.BK_DEFAULT)
|
||||||
|
|
||||||
|
self.pages = []
|
||||||
|
self.titles = []
|
||||||
|
self.pageModified = []
|
||||||
|
self.pageValid = []
|
||||||
|
|
||||||
|
self.pgCpu = CpuPage(self, self.nb, len(self.pages))
|
||||||
|
text = "CPU"
|
||||||
|
self.nb.AddPage(self.pgCpu, text)
|
||||||
|
self.pages.append(self.pgCpu)
|
||||||
|
self.titles.append(text)
|
||||||
|
self.pageModified.append(False)
|
||||||
|
self.pageValid.append(True)
|
||||||
|
|
||||||
|
self.pgPins = PinoutsPage(self, self.nb, len(self.pages))
|
||||||
|
text = "Pinouts"
|
||||||
|
self.nb.AddPage(self.pgPins, text)
|
||||||
|
self.pages.append(self.pgPins)
|
||||||
|
self.titles.append(text)
|
||||||
|
self.pageModified.append(False)
|
||||||
|
self.pageValid.append(True)
|
||||||
|
|
||||||
|
self.pgSensors = SensorsPage(self, self.nb, len(self.pages))
|
||||||
|
text = "Temperature Sensors"
|
||||||
|
self.nb.AddPage(self.pgSensors, text)
|
||||||
|
self.pages.append(self.pgSensors)
|
||||||
|
self.titles.append(text)
|
||||||
|
self.pageModified.append(False)
|
||||||
|
self.pageValid.append(True)
|
||||||
|
|
||||||
|
self.pgHeaters = HeatersPage(self, self.nb, len(self.pages))
|
||||||
|
text = "Heaters"
|
||||||
|
self.nb.AddPage(self.pgHeaters, text)
|
||||||
|
self.pages.append(self.pgHeaters)
|
||||||
|
self.titles.append(text)
|
||||||
|
self.pageModified.append(False)
|
||||||
|
self.pageValid.append(True)
|
||||||
|
|
||||||
|
self.pgCommunications = CommunicationsPage(self, self.nb, len(self.pages))
|
||||||
|
text = "Communications"
|
||||||
|
self.nb.AddPage(self.pgCommunications, text)
|
||||||
|
self.pages.append(self.pgCommunications)
|
||||||
|
self.titles.append(text)
|
||||||
|
self.pageModified.append(False)
|
||||||
|
self.pageValid.append(True)
|
||||||
|
|
||||||
|
sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)
|
||||||
|
|
||||||
|
self.SetSizer(sz)
|
||||||
|
|
||||||
|
def assertModified(self, pg, flag = True):
|
||||||
|
self.pageModified[pg] = flag
|
||||||
|
self.modifyTab(pg)
|
||||||
|
|
||||||
|
def isModified(self):
|
||||||
|
return (True in self.pageModified)
|
||||||
|
|
||||||
|
def assertValid(self, pg, flag = True):
|
||||||
|
self.pageValid[pg] = flag
|
||||||
|
self.modifyTab(pg)
|
||||||
|
|
||||||
|
if False in self.pageValid:
|
||||||
|
self.parent.enableSaveBoard(False)
|
||||||
|
else:
|
||||||
|
self.parent.enableSaveBoard(True)
|
||||||
|
|
||||||
|
def modifyTab(self, pg):
|
||||||
|
if self.pageModified[pg] and not self.pageValid[pg]:
|
||||||
|
pfx = "?* "
|
||||||
|
elif self.pageModified[pg]:
|
||||||
|
pfx = "* "
|
||||||
|
elif not self.pageValid[pg]:
|
||||||
|
pfx = "? "
|
||||||
|
else:
|
||||||
|
pfx = ""
|
||||||
|
|
||||||
|
self.nb.SetPageText(pg, pfx + self.titles[pg])
|
||||||
|
|
||||||
|
def setHeaters(self, ht):
|
||||||
|
self.parent.setHeaters(ht)
|
||||||
|
|
||||||
|
def onClose(self, evt):
|
||||||
|
if not self.confirmLoseChanges("exit"):
|
||||||
|
return
|
||||||
|
|
||||||
|
self.Destroy()
|
||||||
|
|
||||||
|
def confirmLoseChanges(self, msg):
|
||||||
|
if True not in self.pageModified:
|
||||||
|
return True
|
||||||
|
|
||||||
|
dlg = wx.MessageDialog(self, "Are you sure you want to " + msg + "?\n"
|
||||||
|
"There are changes to your board "
|
||||||
|
"configuration that will be lost.",
|
||||||
|
"Changes pending",
|
||||||
|
wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
|
||||||
|
rc = dlg.ShowModal()
|
||||||
|
dlg.Destroy()
|
||||||
|
|
||||||
|
if rc != wx.ID_YES:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def onLoadConfig(self, evt):
|
||||||
|
if not self.confirmLoseChanges("load a new board configuration"):
|
||||||
|
return
|
||||||
|
|
||||||
|
wildcard = "Board configuration (board.*.h)|board.*.h"
|
||||||
|
|
||||||
|
dlg = wx.FileDialog(self, message = "Choose a board config file",
|
||||||
|
defaultDir = self.dir, defaultFile = "",
|
||||||
|
wildcard = wildcard, style = wx.OPEN | wx.CHANGE_DIR)
|
||||||
|
|
||||||
|
path = None
|
||||||
|
if dlg.ShowModal() == wx.ID_OK:
|
||||||
|
path = dlg.GetPath()
|
||||||
|
|
||||||
|
dlg.Destroy()
|
||||||
|
if path is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
self.dir = os.path.dirname(path)
|
||||||
|
rc = self.loadConfigFile(path)
|
||||||
|
|
||||||
|
if not rc:
|
||||||
|
dlg = wx.MessageDialog(self, "Unable to process file %s." % path,
|
||||||
|
"File error", wx.OK + wx.ICON_ERROR)
|
||||||
|
dlg.ShowModal()
|
||||||
|
dlg.Destroy()
|
||||||
|
return
|
||||||
|
|
||||||
|
self.parent.enableSaveBoard(True)
|
||||||
|
self.parent.setBoardTabText("Board <%s>" % os.path.basename(path))
|
||||||
|
self.pgHeaters.setCandidatePins(self.candHeatPins)
|
||||||
|
self.pgSensors.setCandidatePins(self.candThermPins)
|
||||||
|
|
||||||
|
for pg in self.pages:
|
||||||
|
pg.insertValues(self.cfgValues)
|
||||||
|
pg.setHelpText(self.helpText)
|
||||||
|
|
||||||
|
self.pgSensors.setSensors(self.sensors)
|
||||||
|
self.pgHeaters.setHeaters(self.heaters)
|
||||||
|
self.pgCpu.setProcessors(self.processors)
|
||||||
|
|
||||||
|
def loadConfigFile(self, fn):
|
||||||
|
try:
|
||||||
|
self.cfgBuffer = list(open(fn))
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.configFile = fn
|
||||||
|
|
||||||
|
self.processors = []
|
||||||
|
self.sensors = []
|
||||||
|
self.heaters = []
|
||||||
|
self.candHeatPins = []
|
||||||
|
self.candThermPins = []
|
||||||
|
gatheringHelpText = False
|
||||||
|
helpTextString = ""
|
||||||
|
helpKey = None
|
||||||
|
|
||||||
|
self.cfgValues = {}
|
||||||
|
self.helpText = {}
|
||||||
|
|
||||||
|
prevLines = ""
|
||||||
|
for ln in self.cfgBuffer:
|
||||||
|
if gatheringHelpText:
|
||||||
|
if reHelpTextEnd.match(ln):
|
||||||
|
gatheringHelpText = False
|
||||||
|
hk = helpKey.split()
|
||||||
|
for k in hk:
|
||||||
|
self.helpText[k] = helpTextString
|
||||||
|
helpTextString = ""
|
||||||
|
helpKey = None
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
helpTextString += ln
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reHelpTextStart.match(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
gatheringHelpText = True
|
||||||
|
helpKey = t[0]
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ln.rstrip().endswith("\\"):
|
||||||
|
prevLines += ln.rstrip()[:-1]
|
||||||
|
continue
|
||||||
|
|
||||||
|
if prevLines != "":
|
||||||
|
ln = prevLines + ln
|
||||||
|
prevLines = ""
|
||||||
|
|
||||||
|
if ln.lstrip().startswith("//"):
|
||||||
|
m = reCandThermPins.match(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 1:
|
||||||
|
self.candThermPins.append(t[0])
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reCandHeatPins.match(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 1:
|
||||||
|
self.candHeatPins.append(t[0])
|
||||||
|
continue
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ln.lstrip().startswith("#if"):
|
||||||
|
m = re.findall(reAVR, ln)
|
||||||
|
inv = []
|
||||||
|
for p in m:
|
||||||
|
if p in supportedCPUs:
|
||||||
|
self.processors.append(p)
|
||||||
|
else:
|
||||||
|
inv.append(p)
|
||||||
|
if len(inv) > 0:
|
||||||
|
if len(inv) == 1:
|
||||||
|
a = " is"
|
||||||
|
b = "it"
|
||||||
|
else:
|
||||||
|
a = "s are"
|
||||||
|
b = "them"
|
||||||
|
dlg = wx.MessageDialog(self,
|
||||||
|
("The following processor type%s not "
|
||||||
|
"supported:\n %s\nPlease add %s to "
|
||||||
|
"\"supportedCPUs\".") %
|
||||||
|
(a, ", ".join(inv), b),
|
||||||
|
"Unsupported processor type",
|
||||||
|
wx.OK + wx.ICON_INFORMATION)
|
||||||
|
|
||||||
|
dlg.ShowModal()
|
||||||
|
dlg.Destroy()
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ln.lstrip().startswith("#define"):
|
||||||
|
m = reDefQS.search(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 2:
|
||||||
|
m = reDefQSm.search(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
tt = re.findall(reDefQSm2, t[1])
|
||||||
|
if len(tt) == 1:
|
||||||
|
self.cfgValues[t[0]] = tt[0]
|
||||||
|
continue
|
||||||
|
elif len(tt) > 1:
|
||||||
|
self.cfgValues[t[0]] = tt
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reDefine.search(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 2:
|
||||||
|
self.cfgValues[t[0]] = t[1]
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reDefBool.search(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 1:
|
||||||
|
self.cfgValues[t[0]] = True
|
||||||
|
|
||||||
|
else:
|
||||||
|
m = reDefTS.search(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 1:
|
||||||
|
s = self.parseSensor(t[0])
|
||||||
|
if s:
|
||||||
|
self.sensors.append(s)
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reDefHT.search(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 1:
|
||||||
|
s = self.parseHeater(t[0])
|
||||||
|
if s:
|
||||||
|
self.heaters.append(s)
|
||||||
|
continue
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def parseSensor(self, s):
|
||||||
|
m = reSensor4.search(s)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 4:
|
||||||
|
return t
|
||||||
|
m = reSensor3.search(s)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 3:
|
||||||
|
return t
|
||||||
|
return None
|
||||||
|
|
||||||
|
def parseHeater(self, s):
|
||||||
|
m = reHeater.search(s)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 3:
|
||||||
|
return t
|
||||||
|
return None
|
||||||
|
|
||||||
|
def onSaveConfig(self, evt):
|
||||||
|
path = self.configFile
|
||||||
|
if self.saveConfigFile(path):
|
||||||
|
dlg = wx.MessageDialog(self, "File %s successfully written." % path,
|
||||||
|
"Save successful", wx.OK + wx.ICON_INFORMATION)
|
||||||
|
else:
|
||||||
|
dlg = wx.MessageDialog(self, "Unable to write to file %s." % path,
|
||||||
|
"File error", wx.OK + wx.ICON_ERROR)
|
||||||
|
dlg.ShowModal()
|
||||||
|
dlg.Destroy()
|
||||||
|
|
||||||
|
|
||||||
|
def onSaveConfigAs(self, evt):
|
||||||
|
wildcard = "Board configuration (board.*.h)|board.*.h"
|
||||||
|
|
||||||
|
dlg = wx.FileDialog(self, message = "Save as ...", defaultDir = self.dir,
|
||||||
|
defaultFile = "", wildcard = wildcard,
|
||||||
|
style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
|
||||||
|
|
||||||
|
val = dlg.ShowModal()
|
||||||
|
|
||||||
|
if val != wx.ID_OK:
|
||||||
|
dlg.Destroy()
|
||||||
|
return
|
||||||
|
|
||||||
|
path = dlg.GetPath()
|
||||||
|
dlg.Destroy()
|
||||||
|
|
||||||
|
if self.saveConfigFile(path):
|
||||||
|
dlg = wx.MessageDialog(self, "File %s successfully written." % path,
|
||||||
|
"Save successful", wx.OK + wx.ICON_INFORMATION)
|
||||||
|
self.parent.setBoardTabText("Board <%s>" % os.path.basename(path))
|
||||||
|
else:
|
||||||
|
dlg = wx.MessageDialog(self, "Unable to write to file %s." % path,
|
||||||
|
"File error", wx.OK + wx.ICON_ERROR)
|
||||||
|
dlg.ShowModal()
|
||||||
|
dlg.Destroy()
|
||||||
|
|
||||||
|
def saveConfigFile(self, path):
|
||||||
|
ext = os.path.splitext(os.path.basename(path))[1]
|
||||||
|
self.dir = os.path.dirname(path)
|
||||||
|
|
||||||
|
if ext == "":
|
||||||
|
path += ".h"
|
||||||
|
|
||||||
|
try:
|
||||||
|
fp = file(path, 'w')
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.configFile = path
|
||||||
|
|
||||||
|
values = {}
|
||||||
|
|
||||||
|
for pg in self.pages:
|
||||||
|
v1 = pg.getValues()
|
||||||
|
for k in v1.keys():
|
||||||
|
values[k] = v1[k]
|
||||||
|
|
||||||
|
self.processors = self.pgCpu.getProcessors()
|
||||||
|
|
||||||
|
|
||||||
|
skipToSensorEnd = False
|
||||||
|
skipToHeaterEnd = False
|
||||||
|
skipToProcessorEnd = False
|
||||||
|
for ln in self.cfgBuffer:
|
||||||
|
m = reStartSensors.match(ln)
|
||||||
|
if m:
|
||||||
|
fp.write(ln)
|
||||||
|
for s in self.sensors:
|
||||||
|
sstr = ", ".join(s)
|
||||||
|
fp.write("DEFINE_TEMP_SENSOR(%s)\n" % sstr)
|
||||||
|
skipToSensorEnd = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if skipToSensorEnd:
|
||||||
|
m = reEndSensors.match(ln)
|
||||||
|
if m:
|
||||||
|
fp.write(ln)
|
||||||
|
skipToSensorEnd = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reStartHeaters.match(ln)
|
||||||
|
if m:
|
||||||
|
fp.write(ln)
|
||||||
|
for s in self.heaters:
|
||||||
|
sstr = ", ".join(s)
|
||||||
|
fp.write("DEFINE_HEATER(%s)\n" % sstr)
|
||||||
|
|
||||||
|
fp.write("\n")
|
||||||
|
for s in self.heaters:
|
||||||
|
fp.write(defineHeaterFormat % (s[0].upper(), s[0]))
|
||||||
|
skipToHeaterEnd = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if skipToHeaterEnd:
|
||||||
|
m = reEndHeaters.match(ln)
|
||||||
|
if m:
|
||||||
|
fp.write(ln)
|
||||||
|
skipToHeaterEnd = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reStartProcessors.match(ln)
|
||||||
|
if m:
|
||||||
|
fp.write(ln)
|
||||||
|
for i in range(len(self.processors)):
|
||||||
|
fp.write("%s#ifndef __AVR_%s__\n" % (i * " ", self.processors[i]))
|
||||||
|
fp.write("%s#error Wrong CPU type.\n" % ((i + 1) * " "))
|
||||||
|
for s in self.processors:
|
||||||
|
fp.write("%s#endif\n" % (i * " "))
|
||||||
|
i -= 1
|
||||||
|
|
||||||
|
skipToProcessorEnd = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if skipToProcessorEnd:
|
||||||
|
m = reEndProcessors.match(ln)
|
||||||
|
if m:
|
||||||
|
fp.write(ln)
|
||||||
|
skipToProcessorEnd = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reDefineBL.match(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 2:
|
||||||
|
if t[0] in values.keys() and values[t[0]] != "":
|
||||||
|
fp.write(defineValueFormat % (t[0], values[t[0]]))
|
||||||
|
else:
|
||||||
|
fp.write("//" + ln)
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reDefBoolBL.match(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 1:
|
||||||
|
if t[0] in values.keys() and values[t[0]]:
|
||||||
|
fp.write(defineBoolFormat % t[0])
|
||||||
|
else:
|
||||||
|
fp.write("//" + ln)
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reCommDefBL.match(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 2:
|
||||||
|
if t[0] in values.keys() and values[t[0]] != "":
|
||||||
|
fp.write(defineValueFormat % (t[0], values[t[0]]))
|
||||||
|
else:
|
||||||
|
fp.write(ln)
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reCommDefBoolBL.match(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 1:
|
||||||
|
if t[0] in values.keys() and values[t[0]]:
|
||||||
|
fp.write(defineBoolFormat % t[0])
|
||||||
|
else:
|
||||||
|
fp.write(ln)
|
||||||
|
continue
|
||||||
|
|
||||||
|
fp.write(ln)
|
||||||
|
|
||||||
|
fp.close()
|
||||||
|
return True
|
||||||
|
|
@ -0,0 +1,251 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
|
||||||
|
from configtool.data import BSIZESMALL, reFloat
|
||||||
|
|
||||||
|
|
||||||
|
class CalcBelt(wx.Dialog):
|
||||||
|
def __init__(self, parent, cbUse):
|
||||||
|
wx.Dialog.__init__(self, parent, wx.ID_ANY,
|
||||||
|
"Steps calculator for belt driven axes",
|
||||||
|
size = (360, 300))
|
||||||
|
self.Bind(wx.EVT_CLOSE, self.onExit)
|
||||||
|
|
||||||
|
self.use = cbUse
|
||||||
|
labelWidth = 110
|
||||||
|
|
||||||
|
sz = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
sz.AddSpacer((10, 10))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Step Angle:", size = (labelWidth, -1),
|
||||||
|
style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
stepAngles = ["1.8 (200 per revolution)", "0.9 (400 per revolution)",
|
||||||
|
"7.5 (48 per revolution)"]
|
||||||
|
self.stepAngleValues = [200, 400, 48]
|
||||||
|
tc = wx.Choice(self, wx.ID_ANY, choices = stepAngles)
|
||||||
|
tc.SetSelection(0)
|
||||||
|
tc.Bind(wx.EVT_CHOICE, self.onChoice)
|
||||||
|
lsz.Add(tc)
|
||||||
|
tc.SetToolTipString("Step angle. Depends on your type of stepper motor.")
|
||||||
|
self.tcStep = tc
|
||||||
|
|
||||||
|
sz.Add(lsz)
|
||||||
|
sz.AddSpacer((10, 10))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Microstepping:",
|
||||||
|
size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
microStepping = ["1 - full step", "1/2 - half step", "1/4 - quarter step",
|
||||||
|
"1/8", "1/16", "1/32", "1/64", "1/128"]
|
||||||
|
self.microSteppingValues = [1, 2, 4, 8, 16, 32, 64, 128]
|
||||||
|
tc = wx.Choice(self, wx.ID_ANY, choices = microStepping)
|
||||||
|
tc.Bind(wx.EVT_CHOICE, self.onChoice)
|
||||||
|
tc.SetSelection(4)
|
||||||
|
lsz.Add(tc)
|
||||||
|
tc.SetToolTipString("Microstepping. Most boards allow to change this by "
|
||||||
|
"setting jumpers. The value here must match the "
|
||||||
|
"setting on the board in conjunction with the type "
|
||||||
|
"of stepper driver chip.")
|
||||||
|
self.tcMicroStepping = tc
|
||||||
|
|
||||||
|
sz.Add(lsz)
|
||||||
|
sz.AddSpacer((10, 10))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Belt Pitch (in mm):",
|
||||||
|
size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
tc = wx.TextCtrl(self, wx.ID_ANY, "2", style = wx.TE_RIGHT)
|
||||||
|
tc.Bind(wx.EVT_TEXT, self.onTextCtrlFloat)
|
||||||
|
lsz.Add(tc)
|
||||||
|
tc.SetToolTipString("Belt pitch. Distance between two teeth on the belt.")
|
||||||
|
self.tcBeltPitch = tc
|
||||||
|
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
beltPresets = ["-", "2mm Pitch (GT2)", "MXL Pitch (2.03mm)",
|
||||||
|
"T2.5 (2.5mm)", "3mm Pitch (GT2, HTD)",
|
||||||
|
"5mm Pitch (T5, GTD, HTD)", "0.2\" XL belt (5.08mm)"]
|
||||||
|
self.beltPresetValues = [-1, 2.0, 2.03, 2.5, 3.0, 5.0, 5.08]
|
||||||
|
tc = wx.Choice(self, wx.ID_ANY, choices = beltPresets)
|
||||||
|
tc.SetSelection(0)
|
||||||
|
tc.Bind(wx.EVT_CHOICE, self.onPresetChoice)
|
||||||
|
lsz.Add(tc)
|
||||||
|
tc.SetToolTipString("Belt pitch presets.")
|
||||||
|
self.tcPresets = tc
|
||||||
|
|
||||||
|
sz.Add(lsz)
|
||||||
|
sz.AddSpacer((10, 10))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Pulley Teeth Count:",
|
||||||
|
size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
tc = wx.TextCtrl(self, wx.ID_ANY, "8", style = wx.TE_RIGHT)
|
||||||
|
tc.Bind(wx.EVT_TEXT, self.onTextCtrlFloat)
|
||||||
|
lsz.Add(tc)
|
||||||
|
tc.SetToolTipString("Pulley teeth count. Count them!")
|
||||||
|
self.tcPulleyTeeth = tc
|
||||||
|
|
||||||
|
sz.Add(lsz)
|
||||||
|
sz.AddSpacer((30, 30))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Result:", size = (labelWidth, -1),
|
||||||
|
style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
tc = wx.StaticText(self, wx.ID_ANY, "", size = (200, -1),
|
||||||
|
style = wx.ALIGN_LEFT)
|
||||||
|
lsz.Add(tc)
|
||||||
|
self.tcResult = tc
|
||||||
|
|
||||||
|
sz.Add(lsz)
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Resolution:", size = (labelWidth, -1),
|
||||||
|
style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
tc = wx.StaticText(self, wx.ID_ANY, "", size = (200, -1),
|
||||||
|
style = wx.ALIGN_LEFT)
|
||||||
|
lsz.Add(tc)
|
||||||
|
self.tcResolution = tc
|
||||||
|
|
||||||
|
sz.Add(lsz)
|
||||||
|
|
||||||
|
sz.AddSpacer((20, 20))
|
||||||
|
|
||||||
|
bsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
b = wx.Button(self, wx.ID_ANY, "Use for X", size = BSIZESMALL)
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.onUseForX, b)
|
||||||
|
bsz.Add(b)
|
||||||
|
self.bUseForX = b
|
||||||
|
bsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
b = wx.Button(self, wx.ID_ANY, "Use for Y", size = BSIZESMALL)
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.onUseForY, b)
|
||||||
|
bsz.Add(b)
|
||||||
|
self.bUseForY = b
|
||||||
|
bsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
b = wx.Button(self, wx.ID_ANY, "Use for Z", size = BSIZESMALL)
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.onUseForZ, b)
|
||||||
|
bsz.Add(b)
|
||||||
|
self.bUseForZ = b
|
||||||
|
bsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
b = wx.Button(self, wx.ID_ANY, "Use for E", size = BSIZESMALL)
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.onUseForE, b)
|
||||||
|
bsz.Add(b)
|
||||||
|
self.bUseForE = b
|
||||||
|
|
||||||
|
sz.Add(bsz)
|
||||||
|
|
||||||
|
self.enableUseButtons(False)
|
||||||
|
|
||||||
|
self.SetSizer(sz)
|
||||||
|
|
||||||
|
self.Fit()
|
||||||
|
|
||||||
|
self.calculate()
|
||||||
|
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
self.tcResult.SetLabel("")
|
||||||
|
self.tcResolution.SetLabel("")
|
||||||
|
self.enableUseButtons(False)
|
||||||
|
s = self.tcStep.GetSelection()
|
||||||
|
sv = self.stepAngleValues[s]
|
||||||
|
|
||||||
|
try:
|
||||||
|
bp = float(self.tcBeltPitch.GetValue())
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
pt = int(self.tcPulleyTeeth.GetValue())
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
|
||||||
|
s = self.tcMicroStepping.GetSelection()
|
||||||
|
msv = self.microSteppingValues[s]
|
||||||
|
|
||||||
|
length = pt * bp
|
||||||
|
steps = sv * msv
|
||||||
|
|
||||||
|
resultmm = steps / length
|
||||||
|
self.result = int(resultmm * 1000.0)
|
||||||
|
|
||||||
|
self.tcResult.SetLabel("%d steps/m (%.3f steps/mm)" %
|
||||||
|
(self.result, resultmm))
|
||||||
|
self.tcResolution.SetLabel("%.3f micrometers" % (length / steps * 1000.0))
|
||||||
|
self.enableUseButtons(True)
|
||||||
|
|
||||||
|
def enableUseButtons(self, flag):
|
||||||
|
self.bUseForX.Enable(flag)
|
||||||
|
self.bUseForY.Enable(flag)
|
||||||
|
self.bUseForZ.Enable(flag)
|
||||||
|
self.bUseForE.Enable(flag)
|
||||||
|
|
||||||
|
def onUseForX(self, evt):
|
||||||
|
self.use('STEPS_PER_M_X', self.result)
|
||||||
|
|
||||||
|
def onUseForY(self, evt):
|
||||||
|
self.use('STEPS_PER_M_Y', self.result)
|
||||||
|
|
||||||
|
def onUseForZ(self, evt):
|
||||||
|
self.use('STEPS_PER_M_Z', self.result)
|
||||||
|
|
||||||
|
def onUseForE(self, evt):
|
||||||
|
self.use('STEPS_PER_M_E', self.result)
|
||||||
|
|
||||||
|
def onPresetChoice(self, evt):
|
||||||
|
s = self.tcPresets.GetSelection()
|
||||||
|
sv = self.beltPresetValues[s]
|
||||||
|
if sv < 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
s = "%f" % sv
|
||||||
|
s = s.rstrip("0")
|
||||||
|
if s[-1] == ".":
|
||||||
|
s += "0"
|
||||||
|
self.tcBeltPitch.SetValue(s)
|
||||||
|
|
||||||
|
def onChoice(self, evt):
|
||||||
|
self.calculate()
|
||||||
|
|
||||||
|
def onTextCtrlFloat(self, evt):
|
||||||
|
tc = evt.GetEventObject()
|
||||||
|
w = tc.GetValue().strip()
|
||||||
|
if w == "":
|
||||||
|
valid = False
|
||||||
|
else:
|
||||||
|
m = reFloat.match(w)
|
||||||
|
if m:
|
||||||
|
valid = True
|
||||||
|
else:
|
||||||
|
valid = False
|
||||||
|
|
||||||
|
if valid:
|
||||||
|
tc.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
|
||||||
|
else:
|
||||||
|
tc.SetBackgroundColour("pink")
|
||||||
|
tc.Refresh()
|
||||||
|
self.calculate()
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def onExit(self, evt):
|
||||||
|
self.EndModal(wx.ID_OK)
|
||||||
|
|
@ -0,0 +1,269 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
from configtool.data import BSIZESMALL, reFloat
|
||||||
|
|
||||||
|
|
||||||
|
class CalcScrew(wx.Dialog):
|
||||||
|
def __init__(self, parent, cbUse):
|
||||||
|
wx.Dialog.__init__(self, parent, wx.ID_ANY,
|
||||||
|
"Steps calculator for screw driven axes",
|
||||||
|
size = (400, 204))
|
||||||
|
self.Bind(wx.EVT_CLOSE, self.onExit)
|
||||||
|
|
||||||
|
self.use = cbUse
|
||||||
|
labelWidth = 110
|
||||||
|
|
||||||
|
sz = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
sz.AddSpacer((10, 10))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Step Angle:", size = (labelWidth, -1),
|
||||||
|
style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
stepAngles = ["1.8 (200 per revolution)", "0.9 (400 per revolution)",
|
||||||
|
"7.5 (48 per revolution)"]
|
||||||
|
self.stepAngleValues = [200, 400, 48]
|
||||||
|
tc = wx.Choice(self, wx.ID_ANY, choices = stepAngles)
|
||||||
|
tc.SetSelection(0)
|
||||||
|
tc.Bind(wx.EVT_CHOICE, self.onChoice)
|
||||||
|
lsz.Add(tc)
|
||||||
|
tc.SetToolTipString("Step angle. Depends on your type of stepper motor.")
|
||||||
|
self.tcStep = tc
|
||||||
|
|
||||||
|
sz.Add(lsz)
|
||||||
|
sz.AddSpacer((10, 10))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Microstepping:",
|
||||||
|
size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
microStepping = ["1 - full step", "1/2 - half step", "1/4 - quarter step",
|
||||||
|
"1/8", "1/16", "1/32", "1/64", "1/128"]
|
||||||
|
self.microSteppingValues = [1, 2, 4, 8, 16, 32, 64, 128]
|
||||||
|
tc = wx.Choice(self, wx.ID_ANY, choices = microStepping)
|
||||||
|
tc.Bind(wx.EVT_CHOICE, self.onChoice)
|
||||||
|
tc.SetSelection(4)
|
||||||
|
lsz.Add(tc)
|
||||||
|
tc.SetToolTipString("Microstepping. Most boards allow to change this by "
|
||||||
|
"setting jumpers. The value here must match the "
|
||||||
|
"setting on the board in conjunction with the type "
|
||||||
|
"of stepper driver chip.")
|
||||||
|
self.tcMicroStepping = tc
|
||||||
|
|
||||||
|
sz.Add(lsz)
|
||||||
|
sz.AddSpacer((10, 10))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Screw Pitch (mm/rev):",
|
||||||
|
size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
tc = wx.TextCtrl(self, wx.ID_ANY, "2", style = wx.TE_RIGHT)
|
||||||
|
tc.Bind(wx.EVT_TEXT, self.onTextCtrlFloat)
|
||||||
|
lsz.Add(tc)
|
||||||
|
tc.SetToolTipString("Screw pitch. Defined by the pitch of the screw.")
|
||||||
|
self.tcScrewPitch = tc
|
||||||
|
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
screwPresets = ["-", "M8 - metric (1.25 mm/rev)", "M6 - metric (1 mm/rev)",
|
||||||
|
"M5 - metric (0.8 mm/rev)", "12 (12 mm/rev)",
|
||||||
|
"16 (16 mm/rev)", "25 (25 mm/rev)",
|
||||||
|
"5/15\"-18 imperial coarse (1.41111 mm/rev)",
|
||||||
|
"3/16\"-20 imperial (1.270 mm/rev)",
|
||||||
|
"1/4\"-16 ACME (1.5875 mm/rev)"]
|
||||||
|
self.screwPresetValues = [-1, 1.25, 1.00, 0.8, 12.0, 16.0, 25.0, 1.41111,
|
||||||
|
1.270, 1.5875]
|
||||||
|
tc = wx.Choice(self, wx.ID_ANY, choices = screwPresets)
|
||||||
|
tc.SetSelection(0)
|
||||||
|
tc.Bind(wx.EVT_CHOICE, self.onPresetChoice)
|
||||||
|
lsz.Add(tc)
|
||||||
|
tc.SetToolTipString("Screw pitch presets.")
|
||||||
|
self.tcPresets = tc
|
||||||
|
|
||||||
|
sz.Add(lsz)
|
||||||
|
sz.AddSpacer((10, 10))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Gear Ratio:", size = (labelWidth, -1),
|
||||||
|
style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
tc = wx.TextCtrl(self, wx.ID_ANY, "1", size = (40, -1), style = wx.TE_RIGHT)
|
||||||
|
tc.Bind(wx.EVT_TEXT, self.onTextCtrlFloat)
|
||||||
|
lsz.Add(tc)
|
||||||
|
tc.SetToolTipString("Gear ratio. 1:1 if there is no gear.")
|
||||||
|
self.tcRatioTop = tc
|
||||||
|
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, ":")
|
||||||
|
lsz.Add(st)
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
tc = wx.TextCtrl(self, wx.ID_ANY, "1", size = (40, -1), style = wx.TE_RIGHT)
|
||||||
|
tc.Bind(wx.EVT_TEXT, self.onTextCtrlFloat)
|
||||||
|
lsz.Add(tc)
|
||||||
|
tc.SetToolTipString("Gear ratio. 1:1 if there is no gear.")
|
||||||
|
self.tcRatioBottom = tc
|
||||||
|
|
||||||
|
sz.Add(lsz)
|
||||||
|
sz.AddSpacer((30, 30))
|
||||||
|
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Result:", size = (labelWidth, -1),
|
||||||
|
style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
tc = wx.StaticText(self, wx.ID_ANY, "", size = (300, -1),
|
||||||
|
style = wx.ALIGN_LEFT)
|
||||||
|
lsz.Add(tc)
|
||||||
|
self.tcResult = tc
|
||||||
|
|
||||||
|
sz.Add(lsz)
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, "Resolution:", size = (labelWidth, -1),
|
||||||
|
style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
lsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
tc = wx.StaticText(self, wx.ID_ANY, "", size = (300, -1),
|
||||||
|
style = wx.ALIGN_LEFT)
|
||||||
|
lsz.Add(tc)
|
||||||
|
self.tcResolution = tc
|
||||||
|
|
||||||
|
sz.Add(lsz)
|
||||||
|
|
||||||
|
sz.AddSpacer((20, 20))
|
||||||
|
|
||||||
|
bsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
b = wx.Button(self, wx.ID_ANY, "Use for X", size = BSIZESMALL)
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.onUseForX, b)
|
||||||
|
bsz.Add(b)
|
||||||
|
self.bUseForX = b
|
||||||
|
bsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
b = wx.Button(self, wx.ID_ANY, "Use for Y", size = BSIZESMALL)
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.onUseForY, b)
|
||||||
|
bsz.Add(b)
|
||||||
|
self.bUseForY = b
|
||||||
|
bsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
b = wx.Button(self, wx.ID_ANY, "Use for Z", size = BSIZESMALL)
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.onUseForZ, b)
|
||||||
|
bsz.Add(b)
|
||||||
|
self.bUseForZ = b
|
||||||
|
bsz.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
b = wx.Button(self, wx.ID_ANY, "Use for E", size = BSIZESMALL)
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.onUseForE, b)
|
||||||
|
bsz.Add(b)
|
||||||
|
self.bUseForE = b
|
||||||
|
|
||||||
|
sz.Add(bsz, flag = wx.ALIGN_CENTER_HORIZONTAL)
|
||||||
|
|
||||||
|
self.enableUseButtons(False)
|
||||||
|
|
||||||
|
self.SetSizer(sz)
|
||||||
|
|
||||||
|
self.Fit()
|
||||||
|
|
||||||
|
self.calculate()
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
self.tcResult.SetLabel("")
|
||||||
|
self.tcResolution.SetLabel("")
|
||||||
|
self.enableUseButtons(False)
|
||||||
|
s = self.tcStep.GetSelection()
|
||||||
|
sv = self.stepAngleValues[s]
|
||||||
|
|
||||||
|
try:
|
||||||
|
sp = float(self.tcScrewPitch.GetValue())
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
ratioA = float(self.tcRatioTop.GetValue())
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
ratioB = float(self.tcRatioBottom.GetValue())
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
|
||||||
|
s = self.tcMicroStepping.GetSelection()
|
||||||
|
msv = self.microSteppingValues[s]
|
||||||
|
|
||||||
|
ratio = ratioA / ratioB
|
||||||
|
steps = sv * msv
|
||||||
|
|
||||||
|
resultmm = steps / sp / ratio
|
||||||
|
self.result = int(resultmm * 1000.0)
|
||||||
|
|
||||||
|
self.tcResult.SetLabel("%d steps/m (%.3f steps/mm)" %
|
||||||
|
(self.result, resultmm))
|
||||||
|
self.tcResolution.SetLabel("%.3f micrometers" % (1.0 / resultmm * 1000.0))
|
||||||
|
self.enableUseButtons(True)
|
||||||
|
|
||||||
|
def enableUseButtons(self, flag):
|
||||||
|
self.bUseForX.Enable(flag)
|
||||||
|
self.bUseForY.Enable(flag)
|
||||||
|
self.bUseForZ.Enable(flag)
|
||||||
|
self.bUseForE.Enable(flag)
|
||||||
|
|
||||||
|
def onUseForX(self, evt):
|
||||||
|
self.use('STEPS_PER_M_X', self.result)
|
||||||
|
|
||||||
|
def onUseForY(self, evt):
|
||||||
|
self.use('STEPS_PER_M_Y', self.result)
|
||||||
|
|
||||||
|
def onUseForZ(self, evt):
|
||||||
|
self.use('STEPS_PER_M_Z', self.result)
|
||||||
|
|
||||||
|
def onUseForE(self, evt):
|
||||||
|
self.use('STEPS_PER_M_E', self.result)
|
||||||
|
|
||||||
|
def onPresetChoice(self, evt):
|
||||||
|
s = self.tcPresets.GetSelection()
|
||||||
|
sv = self.screwPresetValues[s]
|
||||||
|
if sv < 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
s = "%f" % sv
|
||||||
|
s = s.rstrip("0")
|
||||||
|
if s[-1] == ".":
|
||||||
|
s += "0"
|
||||||
|
self.tcScrewPitch.SetValue(s)
|
||||||
|
|
||||||
|
def onChoice(self, evt):
|
||||||
|
self.calculate()
|
||||||
|
|
||||||
|
def onTextCtrlFloat(self, evt):
|
||||||
|
tc = evt.GetEventObject()
|
||||||
|
w = tc.GetValue().strip()
|
||||||
|
if w == "":
|
||||||
|
valid = False
|
||||||
|
else:
|
||||||
|
m = reFloat.match(w)
|
||||||
|
if m:
|
||||||
|
valid = True
|
||||||
|
else:
|
||||||
|
valid = False
|
||||||
|
|
||||||
|
if valid:
|
||||||
|
tc.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
|
||||||
|
else:
|
||||||
|
tc.SetBackgroundColour("pink")
|
||||||
|
tc.Refresh()
|
||||||
|
self.calculate()
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def onExit(self, evt):
|
||||||
|
self.EndModal(wx.ID_OK)
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
from configtool.page import Page
|
||||||
|
|
||||||
|
|
||||||
|
class CommunicationsPage(wx.Panel, Page):
|
||||||
|
def __init__(self, parent, nb, idPg):
|
||||||
|
wx.Panel.__init__(self, nb, wx.ID_ANY)
|
||||||
|
Page.__init__(self)
|
||||||
|
self.parent = parent
|
||||||
|
self.id = idPg
|
||||||
|
self.defaultBaud = '115200'
|
||||||
|
|
||||||
|
self.bauds = ['19200', '38400', '57600', self.defaultBaud]
|
||||||
|
|
||||||
|
self.labels = {'BAUD': "Baud Rate:", 'USB_SERIAL': "USB Serial"}
|
||||||
|
|
||||||
|
sz = wx.GridBagSizer()
|
||||||
|
sz.AddSpacer((20, 40), pos = (0, 0))
|
||||||
|
|
||||||
|
ch = self.addChoice('BAUD', self.bauds, self.bauds.index(self.defaultBaud),
|
||||||
|
60, self.onChoice)
|
||||||
|
sz.Add(ch, pos = (1, 1))
|
||||||
|
|
||||||
|
sz.AddSpacer((100, 10), pos = (1, 2))
|
||||||
|
|
||||||
|
k = 'USB_SERIAL'
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sz.Add(cb, pos = (1, 3))
|
||||||
|
|
||||||
|
self.SetSizer(sz)
|
||||||
|
self.enableAll(False)
|
||||||
|
|
||||||
|
def insertValues(self, cfgValues):
|
||||||
|
self.assertValid(True)
|
||||||
|
self.enableAll(True)
|
||||||
|
for k in self.fieldValid.keys():
|
||||||
|
self.fieldValid[k] = True
|
||||||
|
|
||||||
|
for k in self.checkBoxes.keys():
|
||||||
|
if k in cfgValues.keys() and cfgValues[k]:
|
||||||
|
self.checkBoxes[k].SetValue(True)
|
||||||
|
else:
|
||||||
|
self.checkBoxes[k].SetValue(False)
|
||||||
|
|
||||||
|
self.setChoice('BAUD', cfgValues, self.defaultBaud)
|
||||||
|
|
||||||
|
self.assertModified(False)
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
from configtool.page import Page
|
||||||
|
from configtool.data import supportedCPUs
|
||||||
|
|
||||||
|
|
||||||
|
class CpuPage(wx.Panel, Page):
|
||||||
|
def __init__(self, parent, nb, idPg):
|
||||||
|
wx.Panel.__init__(self, nb, wx.ID_ANY)
|
||||||
|
Page.__init__(self)
|
||||||
|
self.parent = parent
|
||||||
|
self.id = idPg
|
||||||
|
|
||||||
|
self.labels = {'MOTHERBOARD': "Motherboard", 'F_CPU': "CPU Clock Rate:"}
|
||||||
|
self.defaultClock = '16000000UL'
|
||||||
|
self.clocks = ['8000000UL', self.defaultClock, '20000000UL']
|
||||||
|
self.processors = []
|
||||||
|
|
||||||
|
sz = wx.GridBagSizer()
|
||||||
|
sz.AddSpacer((20, 40), pos = (0, 0))
|
||||||
|
|
||||||
|
|
||||||
|
k = 'MOTHERBOARD'
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sz.Add(cb, pos = (1, 1))
|
||||||
|
sz.AddSpacer((100, 10), pos = (1, 2))
|
||||||
|
|
||||||
|
|
||||||
|
k = 'F_CPU'
|
||||||
|
ch = self.addChoice(k, self.clocks, self.clocks.index(self.defaultClock),
|
||||||
|
80, self.onChoice)
|
||||||
|
sz.Add(ch, pos = (1, 3))
|
||||||
|
sz.AddSpacer((100, 10), pos = (1, 4))
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "Processor Type(s)")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
|
||||||
|
ht = "Choose the processor(s) this configuration will work with."
|
||||||
|
for k in supportedCPUs:
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
cb.SetToolTipString(ht)
|
||||||
|
sbox.Add(cb)
|
||||||
|
sbox.AddSpacer((120, 5))
|
||||||
|
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
sz.Add(sbox, pos = (1, 5), span = (3, 1))
|
||||||
|
|
||||||
|
self.SetSizer(sz)
|
||||||
|
self.enableAll(False)
|
||||||
|
|
||||||
|
def setProcessors(self, plist):
|
||||||
|
self.processors = plist
|
||||||
|
for p in supportedCPUs:
|
||||||
|
if p in self.processors:
|
||||||
|
self.checkBoxes[p].SetValue(True)
|
||||||
|
else:
|
||||||
|
self.checkBoxes[p].SetValue(False)
|
||||||
|
|
||||||
|
def getProcessors(self):
|
||||||
|
plist = []
|
||||||
|
for p in supportedCPUs:
|
||||||
|
if self.checkBoxes[p].IsChecked():
|
||||||
|
plist.append(p)
|
||||||
|
|
||||||
|
return plist
|
||||||
|
|
||||||
|
def insertValues(self, cfgValues):
|
||||||
|
self.assertValid(True)
|
||||||
|
self.enableAll(True)
|
||||||
|
for k in self.fieldValid.keys():
|
||||||
|
self.fieldValid[k] = True
|
||||||
|
|
||||||
|
for k in self.checkBoxes.keys():
|
||||||
|
if k in cfgValues.keys() and cfgValues[k]:
|
||||||
|
self.checkBoxes[k].SetValue(True)
|
||||||
|
else:
|
||||||
|
self.checkBoxes[k].SetValue(False)
|
||||||
|
|
||||||
|
self.setChoice('F_CPU', cfgValues, self.defaultClock)
|
||||||
|
|
||||||
|
self.assertModified(False)
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
VERSION = "0.1"
|
||||||
|
|
||||||
|
supportedCPUs = ['ATmega168', 'ATmega328P', 'ATmega644P', 'ATmega644PA',
|
||||||
|
'ATmega1280', 'ATmega1284P', 'ATmega2560', 'AT90USB1286']
|
||||||
|
|
||||||
|
pinNames = ["AIO%d" % x for x in range(16)] + ["DIO%d" % x for x in range(64)]
|
||||||
|
pinNamesWithBlank = ["-"] + pinNames
|
||||||
|
|
||||||
|
BSIZE = (90, 60)
|
||||||
|
BSIZESMALL = (90, 30)
|
||||||
|
|
||||||
|
reDefQSm = re.compile("\s*#define\s+(\S+)\s+(.*)")
|
||||||
|
reDefQSm2 = re.compile("\s*(\"[^\"]*\")")
|
||||||
|
|
||||||
|
reDefine = re.compile("\s*#define\s+(\w+)\s+(\S+)")
|
||||||
|
reDefineBL = re.compile("^\s*#define\s+(\w+)\s+(\S+)")
|
||||||
|
reCommDefBL = re.compile("^\s*//\s*#define\s+(\w+)\s+(\S+)")
|
||||||
|
reDefQS = re.compile("\s*#define\s+(\w+)\s+(\"[^\"]*\")")
|
||||||
|
reDefTS = re.compile("\s*(DEFINE_TEMP_SENSOR\\([^)]*\\))")
|
||||||
|
reDefHT = re.compile("\s*(DEFINE_HEATER\\([^)]*\\))")
|
||||||
|
reDefBool = re.compile("\s*#define\s+(\w+)\s+")
|
||||||
|
reDefBoolBL = re.compile("^\s*#define\s+(\w+)\s+")
|
||||||
|
reCommDefBoolBL = re.compile("^\s*//\s*#define\s+(\S+)\s+")
|
||||||
|
reStartSensors = re.compile("^\s*//\s*DEFINE_TEMP_SENSORS_START")
|
||||||
|
reEndSensors = re.compile("^\s*//\s*DEFINE_TEMP_SENSORS_END")
|
||||||
|
reStartHeaters = re.compile("^\s*//\s*DEFINE_HEATERS_START")
|
||||||
|
reEndHeaters = re.compile("^\s*//\s*DEFINE_HEATERS_END")
|
||||||
|
reStartProcessors = re.compile("^\s*//\s*PROCESSORS_START")
|
||||||
|
reEndProcessors = re.compile("^\s*//\s*PROCESSORS_END")
|
||||||
|
reCandHeatPins = re.compile("^\s*//\s*#define\s+HEATER_PIN\s+(\w+)")
|
||||||
|
reCandThermPins = re.compile("^\s*//\s*#define\s+TEMP_SENSOR_PIN\s+(\w+)")
|
||||||
|
|
||||||
|
reHelpTextStart = re.compile("^\s*/\*\*\s+\\\\def\s+(.*)")
|
||||||
|
reHelpTextEnd = re.compile("^\s*\*/")
|
||||||
|
|
||||||
|
reSensor3 = re.compile(".*\\(\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\\)")
|
||||||
|
reSensor4 = re.compile(".*\\(\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\\)")
|
||||||
|
reHeater = re.compile(".*\\(\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\\)")
|
||||||
|
|
||||||
|
reInteger = re.compile("^\d+U?L?$")
|
||||||
|
reFloat = re.compile("^\d+(\.\d*)?$")
|
||||||
|
|
||||||
|
reAVR = re.compile("__AVR_(\w+)__")
|
||||||
|
|
||||||
|
defineValueFormat = "#define %-24s %s\n"
|
||||||
|
defineBoolFormat = "#define %s\n"
|
||||||
|
defineHeaterFormat = "#define HEATER_%s HEATER_%s\n"
|
||||||
|
defineDCExtruderFormat = "#define %-24s HEATER_%s\n"
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
|
||||||
|
|
||||||
|
class HeaterList(wx.ListCtrl):
|
||||||
|
def __init__(self, parent):
|
||||||
|
self.parent = parent
|
||||||
|
self.currentItem = None
|
||||||
|
wx.ListCtrl.__init__(self, parent, wx.ID_ANY, size = (165 + 4, 100),
|
||||||
|
style = wx.LC_REPORT | wx.LC_VIRTUAL | wx.LC_HRULES |
|
||||||
|
wx.LC_VRULES)
|
||||||
|
|
||||||
|
self.valid = []
|
||||||
|
self.heaterList = []
|
||||||
|
|
||||||
|
self.InsertColumn(0, "Name")
|
||||||
|
self.InsertColumn(1, "Pin")
|
||||||
|
self.InsertColumn(2, "PWM")
|
||||||
|
self.SetColumnWidth(0, 55)
|
||||||
|
self.SetColumnWidth(1, 55)
|
||||||
|
self.SetColumnWidth(2, 55)
|
||||||
|
|
||||||
|
self.SetItemCount(0)
|
||||||
|
|
||||||
|
self.attr2 = wx.ListItemAttr()
|
||||||
|
self.attr2.SetBackgroundColour("light blue")
|
||||||
|
self.attr3 = wx.ListItemAttr()
|
||||||
|
self.attr3.SetBackgroundColour("pink")
|
||||||
|
|
||||||
|
self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
|
||||||
|
self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected)
|
||||||
|
|
||||||
|
def updateList(self, heaterList):
|
||||||
|
self.heaterList = heaterList
|
||||||
|
self.valid = [True] * len(heaterList)
|
||||||
|
self.currentItem = None
|
||||||
|
self.parent.setItemSelected(None)
|
||||||
|
i = self.GetFirstSelected()
|
||||||
|
while i != -1:
|
||||||
|
self.Select(i, False)
|
||||||
|
i = self.GetFirstSelected()
|
||||||
|
|
||||||
|
self.SetItemCount(len(heaterList))
|
||||||
|
|
||||||
|
def setRowValidity(self, i, flag = False):
|
||||||
|
if i < 0 or i >= len(self.heaterList):
|
||||||
|
return
|
||||||
|
|
||||||
|
self.valid[i] = flag
|
||||||
|
self.Refresh()
|
||||||
|
|
||||||
|
def setTableValidity(self, flag = False):
|
||||||
|
for i in range(len(self.heaterList)):
|
||||||
|
self.setRowValidity(i, flag)
|
||||||
|
|
||||||
|
def OnItemSelected(self, event):
|
||||||
|
self.currentItem = event.m_itemIndex
|
||||||
|
self.parent.setItemSelected(self.currentItem)
|
||||||
|
|
||||||
|
def OnItemDeselected(self, event):
|
||||||
|
self.currentItem = None
|
||||||
|
self.parent.setItemSelected(None)
|
||||||
|
|
||||||
|
def getColumnText(self, index, col):
|
||||||
|
item = self.GetItem(index, col)
|
||||||
|
return item.GetText()
|
||||||
|
|
||||||
|
def OnGetItemText(self, item, col):
|
||||||
|
if item < 0 or item >= len(self.heaterList):
|
||||||
|
return "Error - no heaters"
|
||||||
|
|
||||||
|
s = self.heaterList[item]
|
||||||
|
|
||||||
|
if col == 0:
|
||||||
|
return s[0]
|
||||||
|
elif col == 1:
|
||||||
|
return s[1]
|
||||||
|
elif col == 2:
|
||||||
|
if s[2] == "1":
|
||||||
|
return "True"
|
||||||
|
else:
|
||||||
|
return "False"
|
||||||
|
|
||||||
|
def OnGetItemAttr(self, item):
|
||||||
|
if not self.valid[item]:
|
||||||
|
return self.attr3
|
||||||
|
|
||||||
|
if item % 2 == 1:
|
||||||
|
return self.attr2
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
from configtool.page import Page
|
||||||
|
from configtool.data import pinNames, BSIZESMALL
|
||||||
|
from configtool.heaterlist import HeaterList
|
||||||
|
from configtool.addheaterdlg import AddHeaterDlg
|
||||||
|
|
||||||
|
|
||||||
|
class HeatersPage(wx.Panel, Page):
|
||||||
|
def __init__(self, parent, nb, idPg):
|
||||||
|
wx.Panel.__init__(self, nb, wx.ID_ANY)
|
||||||
|
Page.__init__(self)
|
||||||
|
self.parent = parent
|
||||||
|
self.id = idPg
|
||||||
|
|
||||||
|
sz = wx.GridBagSizer()
|
||||||
|
sz.AddSpacer((30, 30), pos = (0, 0))
|
||||||
|
|
||||||
|
self.heaters = []
|
||||||
|
self.validPins = pinNames
|
||||||
|
|
||||||
|
|
||||||
|
self.lb = HeaterList(self)
|
||||||
|
sz.Add(self.lb, pos = (1, 1), span = (1, 3))
|
||||||
|
|
||||||
|
bsz = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
self.bAdd = wx.Button(self, wx.ID_ANY, "Add", size = BSIZESMALL)
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.doAdd, self.bAdd)
|
||||||
|
self.bAdd.SetToolTipString("Add a heater to the configuration.")
|
||||||
|
|
||||||
|
bsz.Add(self.bAdd)
|
||||||
|
|
||||||
|
bsz.AddSpacer((10, 10))
|
||||||
|
self.bDelete = wx.Button(self, wx.ID_ANY, "Delete", size = BSIZESMALL)
|
||||||
|
self.bDelete.Enable(False)
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.doDelete, self.bDelete)
|
||||||
|
bsz.Add(self.bDelete)
|
||||||
|
self.bDelete.SetToolTipString("Remove the selected heater from the "
|
||||||
|
"configuration.")
|
||||||
|
|
||||||
|
sz.Add(bsz, pos = (1, 4))
|
||||||
|
|
||||||
|
self.SetSizer(sz)
|
||||||
|
self.enableAll(False)
|
||||||
|
|
||||||
|
def enableAll(self, flag = True):
|
||||||
|
self.bAdd.Enable(flag)
|
||||||
|
Page.enableAll(self, flag)
|
||||||
|
|
||||||
|
def setItemSelected(self, n):
|
||||||
|
self.selection = n
|
||||||
|
if n is None:
|
||||||
|
self.bDelete.Enable(False)
|
||||||
|
else:
|
||||||
|
self.bDelete.Enable(True)
|
||||||
|
|
||||||
|
def doAdd(self, evt):
|
||||||
|
nm = []
|
||||||
|
for s in self.heaters:
|
||||||
|
nm.append(s[0])
|
||||||
|
|
||||||
|
dlg = AddHeaterDlg(self, nm, self.validPins)
|
||||||
|
rc = dlg.ShowModal()
|
||||||
|
if rc == wx.ID_OK:
|
||||||
|
ht = dlg.getValues()
|
||||||
|
|
||||||
|
dlg.Destroy()
|
||||||
|
|
||||||
|
if rc != wx.ID_OK:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.heaters.append(ht)
|
||||||
|
self.lb.updateList(self.heaters)
|
||||||
|
self.validateTable()
|
||||||
|
self.parent.setHeaters(self.heaters)
|
||||||
|
|
||||||
|
def doDelete(self, evt):
|
||||||
|
if self.selection is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.assertModified(True)
|
||||||
|
|
||||||
|
del self.heaters[self.selection]
|
||||||
|
self.lb.updateList(self.heaters)
|
||||||
|
self.validateTable()
|
||||||
|
self.parent.setHeaters(self.heaters)
|
||||||
|
|
||||||
|
def insertValues(self, cfgValues):
|
||||||
|
self.enableAll(True)
|
||||||
|
for k in self.checkBoxes.keys():
|
||||||
|
if k in cfgValues.keys() and cfgValues[k]:
|
||||||
|
self.checkBoxes[k].SetValue(True)
|
||||||
|
else:
|
||||||
|
self.checkBoxes[k].SetValue(False)
|
||||||
|
|
||||||
|
self.assertModified(False)
|
||||||
|
|
||||||
|
def setHeaters(self, heaters):
|
||||||
|
self.heaters = heaters
|
||||||
|
self.lb.updateList(self.heaters)
|
||||||
|
self.validateTable()
|
||||||
|
self.parent.setHeaters(self.heaters)
|
||||||
|
|
||||||
|
def setCandidatePins(self, plist):
|
||||||
|
if not plist or len(plist) == 0:
|
||||||
|
self.validPins = pinNames
|
||||||
|
else:
|
||||||
|
self.validPins = plist
|
||||||
|
|
||||||
|
self.validateTable()
|
||||||
|
|
||||||
|
def validateTable(self):
|
||||||
|
self.lb.setTableValidity(True)
|
||||||
|
self.setFieldValidity('HEATERLIST', True)
|
||||||
|
for i in range(len(self.heaters)):
|
||||||
|
if self.heaters[i][1] not in self.validPins:
|
||||||
|
self.lb.setRowValidity(i, False)
|
||||||
|
self.setFieldValidity('HEATERLIST', False)
|
||||||
|
|
||||||
|
def setHelpText(self, ht):
|
||||||
|
Page.setHelpText(self, ht)
|
||||||
|
|
||||||
|
k = 'DEFINE_HEATER'
|
||||||
|
if k in ht.keys():
|
||||||
|
self.bAdd.SetToolTipString(ht[k])
|
||||||
|
|
@ -0,0 +1,210 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
from configtool.data import BSIZE
|
||||||
|
from configtool.page import Page
|
||||||
|
from configtool.calcbelt import CalcBelt
|
||||||
|
from configtool.calcscrew import CalcScrew
|
||||||
|
|
||||||
|
|
||||||
|
class MechanicalPage(wx.Panel, Page):
|
||||||
|
def __init__(self, parent, nb, idPg):
|
||||||
|
wx.Panel.__init__(self, nb, wx.ID_ANY)
|
||||||
|
Page.__init__(self)
|
||||||
|
self.id = idPg
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
self.spmKeys = ['STEPS_PER_M_X', 'STEPS_PER_M_Y', 'STEPS_PER_M_Z',
|
||||||
|
'STEPS_PER_M_E']
|
||||||
|
|
||||||
|
self.mfrKeys = ['MAXIMUM_FEEDRATE_X', 'MAXIMUM_FEEDRATE_Y',
|
||||||
|
'MAXIMUM_FEEDRATE_Z', 'MAXIMUM_FEEDRATE_E']
|
||||||
|
|
||||||
|
self.msrKeys = ['SEARCH_FEEDRATE_X', 'SEARCH_FEEDRATE_Y',
|
||||||
|
'SEARCH_FEEDRATE_Z']
|
||||||
|
|
||||||
|
self.eclKeys = ['ENDSTOP_CLEARANCE_X', 'ENDSTOP_CLEARANCE_Y',
|
||||||
|
'ENDSTOP_CLEARANCE_Z']
|
||||||
|
|
||||||
|
self.minmaxKeys = ['X_MIN', 'X_MAX', 'Y_MIN', 'Y_MAX', 'Z_MIN', 'Z_MAX']
|
||||||
|
|
||||||
|
self.kinematicsKeys = ['KINEMATICS_STRAIGHT', 'KINEMATICS_COREXY']
|
||||||
|
|
||||||
|
self.labels = {'STEPS_PER_M_X': "X:", 'STEPS_PER_M_Y': "Y:",
|
||||||
|
'STEPS_PER_M_Z': "Z:", 'STEPS_PER_M_E' : "E:",
|
||||||
|
'MAXIMUM_FEEDRATE_X': "X:", 'MAXIMUM_FEEDRATE_Y': "Y:",
|
||||||
|
'MAXIMUM_FEEDRATE_Z': "Z:", 'MAXIMUM_FEEDRATE_E': "E:",
|
||||||
|
'SEARCH_FEEDRATE_X': "X:", 'SEARCH_FEEDRATE_Y': "Y:",
|
||||||
|
'SEARCH_FEEDRATE_Z': "Z:",
|
||||||
|
'ENDSTOP_CLEARANCE_X': "X:", 'ENDSTOP_CLEARANCE_Y': "Y:",
|
||||||
|
'ENDSTOP_CLEARANCE_Z': "Z:",
|
||||||
|
'X_MIN': "Min X:", 'X_MAX': "Max X:", 'Y_MIN': "Min Y:",
|
||||||
|
'Y_MAX': "Max Y:", 'Z_MIN': "Min Z:", 'Z_MAX': "Max Z:",
|
||||||
|
'E_ABSOLUTE': "Absolute E Coordinates",
|
||||||
|
'KINEMATICS_STRAIGHT': "Straight",
|
||||||
|
'KINEMATICS_COREXY': "CoreXY"}
|
||||||
|
|
||||||
|
labelWidth = 40;
|
||||||
|
|
||||||
|
sz = wx.GridBagSizer()
|
||||||
|
sz.AddSpacer((10, 10), pos = (0, 0))
|
||||||
|
sz.AddSpacer((90, 10), pos = (0, 4))
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "Steps Per Meter")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
for k in self.spmKeys:
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlFloat)
|
||||||
|
sbox.Add(tc)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
sz.Add(sbox, pos = (1, 1))
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "Maximum Feedrate")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
for k in self.mfrKeys:
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlFloat)
|
||||||
|
sbox.Add(tc)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
sz.Add(sbox, pos = (1, 5))
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "Search Feedrate")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
for k in self.msrKeys:
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlFloat)
|
||||||
|
sbox.Add(tc)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
sz.Add(sbox, pos = (1, 7))
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "Endstop Clearance")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
for k in self.eclKeys:
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlFloat)
|
||||||
|
sbox.Add(tc)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
sz.Add(sbox, pos = (3, 5))
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "Travel Limits")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
for k in self.minmaxKeys:
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlFloat)
|
||||||
|
sbox.Add(tc)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
sz.Add(sbox, pos = (3, 7))
|
||||||
|
|
||||||
|
vsz = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "Kinematics")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
style = wx.RB_GROUP
|
||||||
|
for k in self.kinematicsKeys:
|
||||||
|
rb = self.addRadioButton(k, style, self.onKinematicsSelect)
|
||||||
|
style = 0
|
||||||
|
|
||||||
|
sbox.Add(rb, 1, wx.LEFT + wx.RIGHT, 16)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
vsz.Add(sbox, 1, wx.LEFT, 40)
|
||||||
|
|
||||||
|
cb = self.addCheckBox('E_ABSOLUTE', self.onCheckBox)
|
||||||
|
|
||||||
|
vsz.Add(cb, 1, wx.LEFT, 40)
|
||||||
|
|
||||||
|
sz.Add(vsz, pos = (3, 1))
|
||||||
|
|
||||||
|
bsz = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
b = wx.Button(self, wx.ID_ANY, "Calculate\nBelt Driven", size = BSIZE)
|
||||||
|
b.SetToolTipString("Open the calculator for axes that are belt-driven.")
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.onCalcBelt, b)
|
||||||
|
self.bCalcBelt = b
|
||||||
|
|
||||||
|
bsz.Add(b, 1, wx.ALL, 5)
|
||||||
|
b = wx.Button(self, wx.ID_ANY, "Calculate\nScrew Driven", size = BSIZE)
|
||||||
|
bsz.Add(b, 1, wx.ALL, 5)
|
||||||
|
b.SetToolTipString("Open the calculator for axes that are screw-driven.")
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.onCalcScrew, b)
|
||||||
|
self.bCalcScrew = b
|
||||||
|
|
||||||
|
sz.Add(bsz, pos = (1, 3))
|
||||||
|
self.enableAll(False)
|
||||||
|
self.SetSizer(sz)
|
||||||
|
|
||||||
|
def enableAll(self, flag = True):
|
||||||
|
self.bCalcBelt.Enable(flag)
|
||||||
|
self.bCalcScrew.Enable(flag)
|
||||||
|
Page.enableAll(self, flag)
|
||||||
|
|
||||||
|
def onKinematicsSelect(self, evt):
|
||||||
|
self.assertModified(True)
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def onCalcBelt(self, evt):
|
||||||
|
dlg = CalcBelt(self, self.cbCalcBelt)
|
||||||
|
dlg.ShowModal()
|
||||||
|
dlg.Destroy()
|
||||||
|
|
||||||
|
def cbCalcBelt(self, field, value):
|
||||||
|
s = "%d" % value
|
||||||
|
self.textControls[field].SetValue(s)
|
||||||
|
|
||||||
|
def onCalcScrew(self, evt):
|
||||||
|
dlg = CalcScrew(self, self.cbCalcScrew)
|
||||||
|
dlg.ShowModal()
|
||||||
|
dlg.Destroy()
|
||||||
|
|
||||||
|
def cbCalcScrew(self, field, value):
|
||||||
|
s = "%d" % value
|
||||||
|
self.textControls[field].SetValue(s)
|
||||||
|
|
||||||
|
def setHelpText(self, ht):
|
||||||
|
Page.setHelpText(self, ht)
|
||||||
|
if 'KINEMATICS' in ht.keys():
|
||||||
|
for k in self.kinematicsKeys:
|
||||||
|
self.radioButtons[k].SetToolTipString(ht['KINEMATICS'])
|
||||||
|
|
||||||
|
def insertValues(self, cfgValues):
|
||||||
|
self.assertValid(True)
|
||||||
|
for k in self.fieldValid.keys():
|
||||||
|
self.fieldValid[k] = True
|
||||||
|
for k in self.textControls.keys():
|
||||||
|
if k in cfgValues.keys():
|
||||||
|
self.textControls[k].SetValue(cfgValues[k])
|
||||||
|
else:
|
||||||
|
self.textControls[k].SetValue("")
|
||||||
|
|
||||||
|
for k in self.checkBoxes.keys():
|
||||||
|
if k in cfgValues.keys() and cfgValues[k]:
|
||||||
|
self.checkBoxes[k].SetValue(True)
|
||||||
|
else:
|
||||||
|
self.checkBoxes[k].SetValue(False)
|
||||||
|
|
||||||
|
if 'KINEMATICS' in cfgValues.keys():
|
||||||
|
k = cfgValues['KINEMATICS']
|
||||||
|
if k in self.kinematicsKeys:
|
||||||
|
self.radioButtons[k].SetValue(True)
|
||||||
|
else:
|
||||||
|
self.radioButtons[self.kinematicsKeys[0]].SetValue(True)
|
||||||
|
else:
|
||||||
|
self.radioButtons[self.kinematicsKeys[0]].SetValue(True)
|
||||||
|
|
||||||
|
self.assertModified(False)
|
||||||
|
self.enableAll(True)
|
||||||
|
|
||||||
|
def getValues(self):
|
||||||
|
result = Page.getValues(self)
|
||||||
|
|
||||||
|
for tag in self.kinematicsKeys:
|
||||||
|
rb = self.radioButtons[tag]
|
||||||
|
if rb.GetValue():
|
||||||
|
result['KINEMATICS'] = tag
|
||||||
|
break
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
@ -0,0 +1,291 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
from configtool.page import Page
|
||||||
|
from configtool.data import reFloat
|
||||||
|
|
||||||
|
|
||||||
|
class MiscellaneousPage(wx.Panel, Page):
|
||||||
|
def __init__(self, parent, nb, idPg):
|
||||||
|
wx.Panel.__init__(self, nb, wx.ID_ANY)
|
||||||
|
Page.__init__(self)
|
||||||
|
self.parent = parent
|
||||||
|
self.id = idPg
|
||||||
|
|
||||||
|
self.labels = {'USE_INTERNAL_PULLUPS': "Use Internal Pullups",
|
||||||
|
'EECONFIG': "Enable EEPROM Storage",
|
||||||
|
'DEBUG': "Turn on Debugging",
|
||||||
|
'BANG_BANG': "Enable",
|
||||||
|
'BANG_BANG_ON': "On PWM Level:",
|
||||||
|
'BANG_BANG_OFF': "Off PWM Level:",
|
||||||
|
'MOVEBUFFER_SIZE': "Movebuffer Size:",
|
||||||
|
'DC_EXTRUDER': "Heater:", 'DC_EXTRUDER_PWM': "PWM:",
|
||||||
|
'USE_WATCHDOG': "Use the Watchdog Timer",
|
||||||
|
'REFERENCE': "Analog Reference:",
|
||||||
|
'STEP_INTERRUPT_INTERRUPTIBLE': "STEP Interrupt",
|
||||||
|
'TH_COUNT': "Temperature History Size:",
|
||||||
|
'FAST_PWM': "Fast PWM",
|
||||||
|
'ENDSTOP_STEPS': "Endstop Steps:",
|
||||||
|
'PID_SCALE': "PID Scaling Factor:",
|
||||||
|
'TEMP_HYSTERESIS': "Temperature Hysteresis:",
|
||||||
|
'TEMP_RESIDENCY_TIME': "Temperature Residency Time:",
|
||||||
|
'TEMP_EWMA': "Temperature EWMA:",
|
||||||
|
'HEATER_SANITY_CHECK': "Heater Sanity Check"}
|
||||||
|
|
||||||
|
self.heaterNameNone = "<none>"
|
||||||
|
self.heaterNames = [self.heaterNameNone]
|
||||||
|
self.boardHeaters = []
|
||||||
|
self.processors = []
|
||||||
|
|
||||||
|
self.defaultRef = 'REFERENCE_AVCC'
|
||||||
|
self.references = [self.defaultRef, 'REFERENCE_AREF',
|
||||||
|
'REFERENCE_1V1', 'REFERENCE_2V56']
|
||||||
|
|
||||||
|
sz = wx.GridBagSizer()
|
||||||
|
sz.AddSpacer((20, 40), pos = (0, 0))
|
||||||
|
sz.AddSpacer((40, 40), pos = (0, 2))
|
||||||
|
sz.AddSpacer((40, 40), pos = (0, 4))
|
||||||
|
sz.AddSpacer((20, 30), pos = (1, 0))
|
||||||
|
sz.AddSpacer((20, 30), pos = (2, 0))
|
||||||
|
sz.AddSpacer((20, 30), pos = (3, 0))
|
||||||
|
sz.AddSpacer((20, 30), pos = (4, 0))
|
||||||
|
sz.AddSpacer((20, 30), pos = (5, 0))
|
||||||
|
sz.AddSpacer((20, 30), pos = (6, 0))
|
||||||
|
sz.AddSpacer((20, 30), pos = (7, 0))
|
||||||
|
sz.AddSpacer((20, 30), pos = (8, 0))
|
||||||
|
|
||||||
|
labelWidth = 140
|
||||||
|
|
||||||
|
k = 'EECONFIG'
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sz.Add(cb, pos = (1, 1))
|
||||||
|
|
||||||
|
k = 'USE_INTERNAL_PULLUPS'
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sz.Add(cb, pos = (2, 1))
|
||||||
|
|
||||||
|
k = 'DEBUG'
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sz.Add(cb, pos = (3, 1))
|
||||||
|
|
||||||
|
k = 'USE_WATCHDOG'
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sz.Add(cb, pos = (4, 1))
|
||||||
|
|
||||||
|
k = 'STEP_INTERRUPT_INTERRUPTIBLE'
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sz.Add(cb, pos = (5, 1))
|
||||||
|
|
||||||
|
k = 'FAST_PWM'
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sz.Add(cb, pos = (6, 1))
|
||||||
|
|
||||||
|
k = 'XONXOFF'
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sz.Add(cb, pos = (7, 1))
|
||||||
|
|
||||||
|
k = 'HEATER_SANITY_CHECK'
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sz.Add(cb, pos = (8, 1))
|
||||||
|
|
||||||
|
k = 'REFERENCE'
|
||||||
|
ch = self.addChoice(k, self.references,
|
||||||
|
self.references.index(self.defaultRef),
|
||||||
|
labelWidth, self.onChoice)
|
||||||
|
sz.Add(ch, pos = (1, 3))
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "BANG BANG Bed Control")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
k = 'BANG_BANG'
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sbox.Add(cb, 1, wx.LEFT, 60)
|
||||||
|
sbox.AddSpacer((5, 20))
|
||||||
|
|
||||||
|
k = 'BANG_BANG_ON'
|
||||||
|
tc = self.addTextCtrl(k, 80, self.onTextCtrlInteger)
|
||||||
|
sbox.Add(tc)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
k = 'BANG_BANG_OFF'
|
||||||
|
tc = self.addTextCtrl(k, 80, self.onTextCtrlInteger)
|
||||||
|
sbox.Add(tc)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
sz.Add(sbox, pos = (3, 3), span = (4, 1), flag = wx.ALIGN_CENTER_HORIZONTAL)
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "DC Motor Extruder")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
k = 'DC_EXTRUDER'
|
||||||
|
ch = self.addChoice(k, self.heaterNames, 0, 60, self.onChoice)
|
||||||
|
sbox.Add(ch)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
k = 'DC_EXTRUDER_PWM'
|
||||||
|
tc = self.addTextCtrl(k, 60, self.onTextCtrlInteger)
|
||||||
|
sbox.Add(tc)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
sz.Add(sbox, pos = (8,3), flag = wx.ALIGN_CENTER_HORIZONTAL)
|
||||||
|
|
||||||
|
k = 'MOVEBUFFER_SIZE'
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger)
|
||||||
|
sz.Add(tc, pos = (1, 5))
|
||||||
|
|
||||||
|
k = 'TH_COUNT'
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger)
|
||||||
|
sz.Add(tc, pos = (2, 5))
|
||||||
|
|
||||||
|
k = 'ENDSTOP_STEPS'
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger)
|
||||||
|
sz.Add(tc, pos = (3, 5))
|
||||||
|
|
||||||
|
k = 'PID_SCALE'
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger)
|
||||||
|
sz.Add(tc, pos = (4, 5))
|
||||||
|
|
||||||
|
k = 'TEMP_HYSTERESIS'
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlFloat)
|
||||||
|
sz.Add(tc, pos = (6, 5))
|
||||||
|
|
||||||
|
k = 'TEMP_RESIDENCY_TIME'
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger)
|
||||||
|
sz.Add(tc, pos = (7, 5))
|
||||||
|
|
||||||
|
k = 'TEMP_EWMA'
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlEWMA)
|
||||||
|
sz.Add(tc, pos = (8, 5))
|
||||||
|
|
||||||
|
self.SetSizer(sz)
|
||||||
|
self.enableAll(False)
|
||||||
|
|
||||||
|
def onTextCtrlEWMA(self, evt):
|
||||||
|
self.assertModified(True)
|
||||||
|
tc = evt.GetEventObject()
|
||||||
|
name = tc.GetName()
|
||||||
|
w = tc.GetValue().strip()
|
||||||
|
if w == "":
|
||||||
|
valid = True
|
||||||
|
else:
|
||||||
|
m = reFloat.match(w)
|
||||||
|
if m:
|
||||||
|
v = float(w)
|
||||||
|
if v < 0.1 or v > 1.0:
|
||||||
|
valid = False
|
||||||
|
else:
|
||||||
|
valid = True
|
||||||
|
else:
|
||||||
|
valid = False
|
||||||
|
|
||||||
|
self.setFieldValidity(name, valid)
|
||||||
|
|
||||||
|
if valid:
|
||||||
|
tc.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
|
||||||
|
else:
|
||||||
|
tc.SetBackgroundColour("pink")
|
||||||
|
tc.Refresh()
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def setHeaters(self, hlist):
|
||||||
|
k = 'DC_EXTRUDER'
|
||||||
|
v = self.choices[k].GetSelection()
|
||||||
|
currentChoice = self.heaterNames[v]
|
||||||
|
self.boardHeaters = [s[0] for s in hlist]
|
||||||
|
self.heaterNames = [self.heaterNameNone] + self.boardHeaters
|
||||||
|
self.choices[k].Clear()
|
||||||
|
for h in self.heaterNames:
|
||||||
|
self.choices[k].Append(h)
|
||||||
|
self.choiceOptions[k] = self.heaterNames
|
||||||
|
|
||||||
|
try:
|
||||||
|
v = self.heaterNames.index(currentChoice)
|
||||||
|
except:
|
||||||
|
v = 0
|
||||||
|
dlg = wx.MessageDialog(self,
|
||||||
|
"Printer: Miscellaneous tab:\nDC Extruder heater "
|
||||||
|
"\"%s\" not defined for this board. Please check."
|
||||||
|
% currentChoice, "Warning",
|
||||||
|
wx.OK + wx.ICON_WARNING)
|
||||||
|
|
||||||
|
dlg.ShowModal()
|
||||||
|
dlg.Destroy()
|
||||||
|
|
||||||
|
self.choices[k].SetSelection(v)
|
||||||
|
|
||||||
|
def setOriginalHeater(self, h):
|
||||||
|
k = 'DC_EXTRUDER'
|
||||||
|
if h and h.startswith("HEATER_"):
|
||||||
|
hname = h[len("HEATER_"):]
|
||||||
|
else:
|
||||||
|
hname = h
|
||||||
|
if len(self.boardHeaters) != 0:
|
||||||
|
if hname not in self.boardHeaters:
|
||||||
|
dlg = wx.MessageDialog(self,
|
||||||
|
"Printer: Miscellaneous tab:\nDC Extruder "
|
||||||
|
"heater \"%s\" not defined for this board. "
|
||||||
|
"Please check."
|
||||||
|
% hname, "Warning", wx.OK + wx.ICON_WARNING)
|
||||||
|
|
||||||
|
dlg.ShowModal()
|
||||||
|
dlg.Destroy()
|
||||||
|
self.heaterNames = [self.heaterNameNone] + self.boardHeaters
|
||||||
|
else:
|
||||||
|
self.heaterNames = [self.heaterNameNone]
|
||||||
|
if h and h != self.heaterNameNone:
|
||||||
|
self.heaterNames.append(hname)
|
||||||
|
self.choices[k].Clear()
|
||||||
|
for ht in self.heaterNames:
|
||||||
|
self.choices[k].Append(ht)
|
||||||
|
self.choiceOptions[k] = self.heaterNames
|
||||||
|
if hname:
|
||||||
|
try:
|
||||||
|
v = self.heaterNames.index(hname)
|
||||||
|
except:
|
||||||
|
v = 0
|
||||||
|
else:
|
||||||
|
v = 0
|
||||||
|
self.choices[k].SetSelection(v)
|
||||||
|
|
||||||
|
def insertValues(self, cfgValues):
|
||||||
|
self.assertValid(True)
|
||||||
|
for k in self.fieldValid.keys():
|
||||||
|
self.fieldValid[k] = True
|
||||||
|
|
||||||
|
for k in self.checkBoxes.keys():
|
||||||
|
if k in cfgValues.keys() and cfgValues[k]:
|
||||||
|
self.checkBoxes[k].SetValue(True)
|
||||||
|
else:
|
||||||
|
self.checkBoxes[k].SetValue(False)
|
||||||
|
|
||||||
|
for k in self.textControls.keys():
|
||||||
|
if k in cfgValues.keys():
|
||||||
|
self.textControls[k].SetValue(str(cfgValues[k]))
|
||||||
|
else:
|
||||||
|
self.textControls[k].SetValue("")
|
||||||
|
|
||||||
|
self.setChoice('REFERENCE', cfgValues, self.defaultRef)
|
||||||
|
|
||||||
|
self.assertModified(False)
|
||||||
|
self.enableAll(True)
|
||||||
|
|
||||||
|
def getValues(self):
|
||||||
|
result = Page.getValues(self)
|
||||||
|
|
||||||
|
k = 'STEP_INTERRUPT_INTERRUPTIBLE'
|
||||||
|
cb = self.checkBoxes[k]
|
||||||
|
if cb.IsChecked():
|
||||||
|
result[k] = "1"
|
||||||
|
else:
|
||||||
|
result[k] = "0"
|
||||||
|
|
||||||
|
k = "DC_EXTRUDER"
|
||||||
|
s = self.choices[k].GetSelection()
|
||||||
|
v = self.choiceOptions[k][s]
|
||||||
|
if v == self.heaterNameNone:
|
||||||
|
result[k] = ""
|
||||||
|
else:
|
||||||
|
result[k] = "HEATER_%s" % v
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
@ -0,0 +1,235 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
|
||||||
|
from configtool.data import pinNames, pinNamesWithBlank, reInteger, reFloat
|
||||||
|
|
||||||
|
|
||||||
|
class Page:
|
||||||
|
def __init__(self):
|
||||||
|
self.modified = False
|
||||||
|
self.valid = True
|
||||||
|
self.fieldValid = {}
|
||||||
|
self.textControls = {}
|
||||||
|
self.checkBoxes = {}
|
||||||
|
self.radioButtons = {}
|
||||||
|
self.choices = {}
|
||||||
|
self.choiceOptions = {}
|
||||||
|
|
||||||
|
def enableAll(self, flag = True):
|
||||||
|
for c in self.textControls.keys():
|
||||||
|
self.textControls[c].Enable(flag)
|
||||||
|
for c in self.checkBoxes.keys():
|
||||||
|
self.checkBoxes[c].Enable(flag)
|
||||||
|
for c in self.radioButtons.keys():
|
||||||
|
self.radioButtons[c].Enable(flag)
|
||||||
|
for c in self.choices.keys():
|
||||||
|
self.choices[c].Enable(flag)
|
||||||
|
|
||||||
|
def addTextCtrl(self, name, labelWidth, validator):
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, self.labels[name],
|
||||||
|
size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
|
||||||
|
tc = wx.TextCtrl(self, wx.ID_ANY, "", style = wx.TE_RIGHT, name = name)
|
||||||
|
self.fieldValid[name] = True
|
||||||
|
tc.Bind(wx.EVT_TEXT, validator)
|
||||||
|
self.textControls[name] = tc
|
||||||
|
lsz.Add(tc)
|
||||||
|
|
||||||
|
return lsz
|
||||||
|
|
||||||
|
def addCheckBox(self, name, validator):
|
||||||
|
if name in self.labels.keys():
|
||||||
|
lbl = self.labels[name]
|
||||||
|
else:
|
||||||
|
lbl = name
|
||||||
|
cb = wx.CheckBox(self, wx.ID_ANY, lbl)
|
||||||
|
cb.Bind(wx.EVT_CHECKBOX, validator)
|
||||||
|
self.checkBoxes[name] = cb
|
||||||
|
|
||||||
|
return cb
|
||||||
|
|
||||||
|
def addRadioButton(self, name, style, validator):
|
||||||
|
rb = wx.RadioButton(self, wx.ID_ANY, self.labels[name], style = style)
|
||||||
|
self.Bind(wx.EVT_RADIOBUTTON, validator, rb)
|
||||||
|
self.radioButtons[name] = rb
|
||||||
|
|
||||||
|
return rb
|
||||||
|
|
||||||
|
def addChoice(self, name, choices, selection, labelWidth, validator):
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, self.labels[name],
|
||||||
|
size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
|
||||||
|
ch = wx.Choice(self, wx.ID_ANY, choices = choices, name = name)
|
||||||
|
ch.Bind(wx.EVT_CHOICE, validator)
|
||||||
|
ch.SetSelection(selection)
|
||||||
|
lsz.Add(ch)
|
||||||
|
self.choices[name] = ch
|
||||||
|
self.choiceOptions[name] = choices
|
||||||
|
|
||||||
|
return lsz
|
||||||
|
|
||||||
|
def addPinChoice(self, name, choiceVal, allowBlank, labelWidth):
|
||||||
|
lsz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
st = wx.StaticText(self, wx.ID_ANY, self.labels[name],
|
||||||
|
size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
|
||||||
|
lsz.Add(st)
|
||||||
|
|
||||||
|
if allowBlank:
|
||||||
|
opts = pinNamesWithBlank
|
||||||
|
else:
|
||||||
|
opts = pinNames
|
||||||
|
|
||||||
|
ch = wx.Choice(self, wx.ID_ANY, choices = opts, name = name)
|
||||||
|
ch.Bind(wx.EVT_CHOICE, self.onChoice)
|
||||||
|
self.choices[name] = ch
|
||||||
|
self.choiceOptions[name] = opts
|
||||||
|
try:
|
||||||
|
sv = self.pinNames.index(choiceVal)
|
||||||
|
except:
|
||||||
|
sv = 0
|
||||||
|
ch.SetSelection(sv)
|
||||||
|
lsz.Add(ch)
|
||||||
|
|
||||||
|
return lsz
|
||||||
|
|
||||||
|
def setChoice(self, name, cfgValues, default):
|
||||||
|
if name in cfgValues.keys():
|
||||||
|
bv = cfgValues[name]
|
||||||
|
else:
|
||||||
|
bv = default
|
||||||
|
|
||||||
|
try:
|
||||||
|
s = self.choiceOptions[name].index(bv)
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
s = self.choiceOptions[name].index(default)
|
||||||
|
except:
|
||||||
|
s = 0
|
||||||
|
|
||||||
|
self.choices[name].SetSelection(s)
|
||||||
|
|
||||||
|
def onTextCtrlInteger(self, evt):
|
||||||
|
self.assertModified(True)
|
||||||
|
tc = evt.GetEventObject()
|
||||||
|
name = tc.GetName()
|
||||||
|
w = tc.GetValue().strip()
|
||||||
|
if w == "":
|
||||||
|
valid = True
|
||||||
|
else:
|
||||||
|
m = reInteger.match(w)
|
||||||
|
if m:
|
||||||
|
valid = True
|
||||||
|
else:
|
||||||
|
valid = False
|
||||||
|
|
||||||
|
self.setFieldValidity(name, valid)
|
||||||
|
|
||||||
|
if valid:
|
||||||
|
tc.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
|
||||||
|
else:
|
||||||
|
tc.SetBackgroundColour("pink")
|
||||||
|
tc.Refresh()
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def onTextCtrlFloat(self, evt):
|
||||||
|
self.assertModified(True)
|
||||||
|
tc = evt.GetEventObject()
|
||||||
|
name = tc.GetName()
|
||||||
|
w = tc.GetValue().strip()
|
||||||
|
if w == "":
|
||||||
|
valid = True
|
||||||
|
else:
|
||||||
|
m = reFloat.match(w)
|
||||||
|
if m:
|
||||||
|
valid = True
|
||||||
|
else:
|
||||||
|
valid = False
|
||||||
|
|
||||||
|
self.setFieldValidity(name, valid)
|
||||||
|
|
||||||
|
if valid:
|
||||||
|
tc.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
|
||||||
|
else:
|
||||||
|
tc.SetBackgroundColour("pink")
|
||||||
|
tc.Refresh()
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def onTextCtrlPin(self, evt):
|
||||||
|
self.assertModified(True)
|
||||||
|
tc = evt.GetEventObject()
|
||||||
|
self.validatePin(tc)
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def onTextCtrl(self, evt):
|
||||||
|
self.assertModified(True)
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def onChoice(self, evt):
|
||||||
|
self.assertModified(True)
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def onCheckBox(self, evt):
|
||||||
|
self.assertModified(True)
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def setHelpText(self, ht):
|
||||||
|
for k in self.textControls.keys():
|
||||||
|
if k in ht.keys():
|
||||||
|
self.textControls[k].SetToolTipString(ht[k])
|
||||||
|
|
||||||
|
for k in self.checkBoxes.keys():
|
||||||
|
if k in ht.keys():
|
||||||
|
self.checkBoxes[k].SetToolTipString(ht[k])
|
||||||
|
|
||||||
|
for k in self.radioButtons.keys():
|
||||||
|
if k in ht.keys():
|
||||||
|
self.radioButtons[k].SetToolTipString(ht[k])
|
||||||
|
|
||||||
|
for k in self.choices.keys():
|
||||||
|
if k in ht.keys():
|
||||||
|
self.choices[k].SetToolTipString(ht[k])
|
||||||
|
|
||||||
|
def getValues(self):
|
||||||
|
self.assertModified(False)
|
||||||
|
result = {}
|
||||||
|
for k in self.checkBoxes.keys():
|
||||||
|
cb = self.checkBoxes[k]
|
||||||
|
result[k] = cb.IsChecked()
|
||||||
|
|
||||||
|
for k in self.textControls.keys():
|
||||||
|
v = self.textControls[k].GetValue()
|
||||||
|
result[k] = v
|
||||||
|
|
||||||
|
for k in self.radioButtons.keys():
|
||||||
|
result[k] = self.radioButtons[k].GetValue()
|
||||||
|
|
||||||
|
for k in self.choices.keys():
|
||||||
|
v = self.choices[k].GetSelection()
|
||||||
|
result[k] = self.choiceOptions[k][v]
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def assertModified(self, flag):
|
||||||
|
if flag != self.modified:
|
||||||
|
self.parent.assertModified(self.id, flag)
|
||||||
|
self.modified = flag
|
||||||
|
|
||||||
|
def setFieldValidity(self, name, flag):
|
||||||
|
self.fieldValid[name] = flag
|
||||||
|
|
||||||
|
pgValid = True
|
||||||
|
for k in self.fieldValid.keys():
|
||||||
|
if not self.fieldValid[k]:
|
||||||
|
pgValid = False
|
||||||
|
break
|
||||||
|
|
||||||
|
self.assertValid(pgValid)
|
||||||
|
|
||||||
|
def assertValid(self, flag):
|
||||||
|
if flag != self.valid:
|
||||||
|
self.parent.assertValid(self.id, flag)
|
||||||
|
self.valid = flag
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
from configtool.page import Page
|
||||||
|
|
||||||
|
|
||||||
|
class PinoutsPage(wx.Panel, Page):
|
||||||
|
def __init__(self, parent, nb, idPg):
|
||||||
|
wx.Panel.__init__(self, nb, wx.ID_ANY)
|
||||||
|
Page.__init__(self)
|
||||||
|
self.parent = parent
|
||||||
|
self.id = idPg
|
||||||
|
|
||||||
|
pinXkeys = [('X_STEP_PIN', 2), ('X_DIR_PIN', 2), ('X_MIN_PIN', 2),
|
||||||
|
('X_MAX_PIN', 2), ('X_ENABLE_PIN', 2), ('X_INVERT_DIR', 1),
|
||||||
|
('X_INVERT_MIN', 1), ('X_INVERT_MAX', 1),
|
||||||
|
('X_INVERT_ENABLE', 1)]
|
||||||
|
pinYkeys = [('Y_STEP_PIN', 2), ('Y_DIR_PIN', 2), ('Y_MIN_PIN', 2),
|
||||||
|
('Y_MAX_PIN', 2), ('Y_ENABLE_PIN', 2), ('Y_INVERT_DIR', 1),
|
||||||
|
('Y_INVERT_MIN', 1), ('Y_INVERT_MAX', 1),
|
||||||
|
('Y_INVERT_ENABLE', 1)]
|
||||||
|
pinZkeys = [('Z_STEP_PIN', 2), ('Z_DIR_PIN', 2), ('Z_MIN_PIN', 2),
|
||||||
|
('Z_MAX_PIN', 2), ('Z_ENABLE_PIN', 2), ('Z_INVERT_DIR', 1),
|
||||||
|
('Z_INVERT_MIN', 1), ('Z_INVERT_MAX', 1),
|
||||||
|
('Z_INVERT_ENABLE', 1)]
|
||||||
|
pinEkeys = [('E_STEP_PIN', 2), ('E_DIR_PIN', 2), ('E_ENABLE_PIN', 2),
|
||||||
|
('E_INVERT_DIR', 1), ('E_INVERT_ENABLE', 1)]
|
||||||
|
|
||||||
|
self.labels = {'X_STEP_PIN': "Step Pin:", 'X_DIR_PIN': "Direction Pin:",
|
||||||
|
'X_MIN_PIN': "Minimum Pin:", 'X_MAX_PIN': "Maximum Pin:",
|
||||||
|
'X_ENABLE_PIN': "Enable Pin:",
|
||||||
|
'X_INVERT_DIR': "Invert Direction",
|
||||||
|
'X_INVERT_MIN': "Invert Minimum",
|
||||||
|
'X_INVERT_MAX': "Invert Maximum",
|
||||||
|
'X_INVERT_ENABLE': "Invert Enable",
|
||||||
|
|
||||||
|
'Y_STEP_PIN': "Step Pin:", 'Y_DIR_PIN': "Direction Pin:",
|
||||||
|
'Y_MIN_PIN': "Minimum Pin:", 'Y_MAX_PIN': "Maximum Pin:",
|
||||||
|
'Y_ENABLE_PIN': "Enable Pin:",
|
||||||
|
'Y_INVERT_DIR': "Invert Direction",
|
||||||
|
'Y_INVERT_MIN': "Invert Minimum",
|
||||||
|
'Y_INVERT_MAX': "Invert Maximum",
|
||||||
|
'Y_INVERT_ENABLE': "Invert Enable",
|
||||||
|
|
||||||
|
'Z_STEP_PIN': "Step Pin:", 'Z_DIR_PIN': "Direction Pin:",
|
||||||
|
'Z_MIN_PIN': "Minimum Pin:", 'Z_MAX_PIN': "Maximum Pin:",
|
||||||
|
'Z_ENABLE_PIN': "Enable Pin:",
|
||||||
|
'Z_INVERT_DIR': "Invert Direction",
|
||||||
|
'Z_INVERT_MIN': "Invert Minimum",
|
||||||
|
'Z_INVERT_MAX': "Invert Maximum",
|
||||||
|
'Z_INVERT_ENABLE': "Invert Enable",
|
||||||
|
|
||||||
|
'E_STEP_PIN': "Step Pin:", 'E_DIR_PIN': "Direction Pin:",
|
||||||
|
'E_ENABLE_PIN': "Enable Pin:",
|
||||||
|
'E_INVERT_DIR': "Invert Direction",
|
||||||
|
'E_INVERT_ENABLE': "Invert Enable",
|
||||||
|
|
||||||
|
'PS_ON_PIN': "PSU On Pin:",
|
||||||
|
'PS_MOSFET_PIN': "PSU MOSFET Pin:",
|
||||||
|
|
||||||
|
'STEPPER_ENABLE_PIN': "Stepper Enable Pin:",
|
||||||
|
'STEPPER_INVERT_ENABLE': "Stepper Invert Enable",
|
||||||
|
|
||||||
|
'DEBUG_LED_PIN': "Debug LED Pin:"}
|
||||||
|
|
||||||
|
labelWidth = 120
|
||||||
|
|
||||||
|
sz = wx.GridBagSizer()
|
||||||
|
sz.AddSpacer((10, 10), pos = (0, 0))
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "X Axis")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
for k, ctype in pinXkeys:
|
||||||
|
if ctype == 0:
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlPin)
|
||||||
|
sbox.Add(tc)
|
||||||
|
elif ctype == 2:
|
||||||
|
tc = self.addPinChoice(k, "", True, labelWidth)
|
||||||
|
sbox.Add(tc)
|
||||||
|
else:
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sbox.Add(cb, 1, wx.LEFT, 30)
|
||||||
|
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
sz.Add(sbox, pos = (1, 1))
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "Y Axis")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
for k, ctype in pinYkeys:
|
||||||
|
if ctype == 0:
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlPin)
|
||||||
|
sbox.Add(tc)
|
||||||
|
elif ctype == 2:
|
||||||
|
tc = self.addPinChoice(k, "", True, labelWidth)
|
||||||
|
sbox.Add(tc)
|
||||||
|
else:
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sbox.Add(cb, 1, wx.LEFT, 30)
|
||||||
|
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
sz.Add(sbox, pos = (1, 3))
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "Z Axis")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
for k, ctype in pinZkeys:
|
||||||
|
if ctype == 0:
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlPin)
|
||||||
|
sbox.Add(tc)
|
||||||
|
elif ctype == 2:
|
||||||
|
tc = self.addPinChoice(k, "", True, labelWidth)
|
||||||
|
sbox.Add(tc)
|
||||||
|
else:
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sbox.Add(cb, 1, wx.LEFT, 30)
|
||||||
|
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
sz.Add(sbox, pos = (1, 5))
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "E Axis")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
for k, ctype in pinEkeys:
|
||||||
|
if ctype == 0:
|
||||||
|
tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlPin)
|
||||||
|
sbox.Add(tc)
|
||||||
|
elif ctype == 2:
|
||||||
|
tc = self.addPinChoice(k, "", True, labelWidth)
|
||||||
|
sbox.Add(tc)
|
||||||
|
else:
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sbox.Add(cb, 1, wx.LEFT, 30)
|
||||||
|
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
sz.Add(sbox, pos = (1, 7))
|
||||||
|
|
||||||
|
k = "STEPPER_ENABLE_PIN"
|
||||||
|
tc = self.addPinChoice(k, "", True, labelWidth)
|
||||||
|
sz.Add(tc, pos = (3, 1))
|
||||||
|
|
||||||
|
sz.AddSpacer((10, 10), pos = (4, 1))
|
||||||
|
|
||||||
|
k = "STEPPER_INVERT_ENABLE"
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBox)
|
||||||
|
sz.Add(cb, pos = (5, 1), flag = wx.ALIGN_CENTER_HORIZONTAL)
|
||||||
|
|
||||||
|
k = "PS_ON_PIN"
|
||||||
|
tc = self.addPinChoice(k, "", True, labelWidth)
|
||||||
|
sz.Add(tc, pos = (3, 3))
|
||||||
|
|
||||||
|
k = "PS_MOSFET_PIN"
|
||||||
|
tc = self.addPinChoice(k, "", True, labelWidth)
|
||||||
|
sz.Add(tc, pos = (5, 3))
|
||||||
|
|
||||||
|
k = "DEBUG_LED_PIN"
|
||||||
|
tc = self.addPinChoice(k, "", True, labelWidth)
|
||||||
|
sz.Add(tc, pos = (3, 7))
|
||||||
|
|
||||||
|
self.SetSizer(sz)
|
||||||
|
self.enableAll(False)
|
||||||
|
|
||||||
|
def insertValues(self, cfgValues):
|
||||||
|
self.assertValid(True)
|
||||||
|
self.enableAll(True)
|
||||||
|
for k in self.fieldValid.keys():
|
||||||
|
self.fieldValid[k] = True
|
||||||
|
for k in self.textControls.keys():
|
||||||
|
if k in cfgValues.keys():
|
||||||
|
self.textControls[k].SetValue(cfgValues[k])
|
||||||
|
else:
|
||||||
|
self.textControls[k].SetValue("")
|
||||||
|
|
||||||
|
for k in self.checkBoxes.keys():
|
||||||
|
if k in cfgValues.keys() and cfgValues[k]:
|
||||||
|
self.checkBoxes[k].SetValue(True)
|
||||||
|
else:
|
||||||
|
self.checkBoxes[k].SetValue(False)
|
||||||
|
|
||||||
|
for k in self.choices.keys():
|
||||||
|
self.setChoice(k, cfgValues, "-")
|
||||||
|
|
||||||
|
self.assertModified(False)
|
||||||
|
|
||||||
|
def getValues(self):
|
||||||
|
result = Page.getValues(self)
|
||||||
|
|
||||||
|
for k in self.choices.keys():
|
||||||
|
if k in result.keys() and result[k] == "-":
|
||||||
|
result[k] = ""
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
@ -0,0 +1,353 @@
|
||||||
|
|
||||||
|
import os
|
||||||
|
import wx
|
||||||
|
import re
|
||||||
|
|
||||||
|
from configtool.data import (defineValueFormat, defineBoolFormat, reCommDefBL,
|
||||||
|
reCommDefBoolBL, reHelpTextStart, reHelpTextEnd,
|
||||||
|
reDefine, reDefineBL, reDefQS, reDefQSm,
|
||||||
|
reDefQSm2, reDefBool, reDefBoolBL)
|
||||||
|
from configtool.mechanicalpage import MechanicalPage
|
||||||
|
from configtool.accelerationpage import AccelerationPage
|
||||||
|
from configtool.miscellaneouspage import MiscellaneousPage
|
||||||
|
|
||||||
|
|
||||||
|
class PrinterPanel(wx.Panel):
|
||||||
|
def __init__(self, parent, nb, folder):
|
||||||
|
wx.Panel.__init__(self, nb, wx.ID_ANY)
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
self.cfgValues = {}
|
||||||
|
self.heaters = []
|
||||||
|
self.dir = os.path.join(folder, "config")
|
||||||
|
|
||||||
|
sz = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
|
||||||
|
self.nb = wx.Notebook(self, wx.ID_ANY, size = (21, 21),
|
||||||
|
style = wx.BK_DEFAULT)
|
||||||
|
|
||||||
|
self.pages = []
|
||||||
|
self.titles = []
|
||||||
|
self.pageModified = []
|
||||||
|
self.pageValid = []
|
||||||
|
|
||||||
|
self.pgMech = MechanicalPage(self, self.nb, len(self.pages))
|
||||||
|
text = "Mechanical"
|
||||||
|
self.nb.AddPage(self.pgMech, text)
|
||||||
|
self.pages.append(self.pgMech)
|
||||||
|
self.titles.append(text)
|
||||||
|
self.pageModified.append(False)
|
||||||
|
self.pageValid.append(True)
|
||||||
|
|
||||||
|
self.pgAcc = AccelerationPage(self, self.nb, len(self.pages))
|
||||||
|
text = "Acceleration"
|
||||||
|
self.nb.AddPage(self.pgAcc, text)
|
||||||
|
self.pages.append(self.pgAcc)
|
||||||
|
self.titles.append(text)
|
||||||
|
self.pageModified.append(False)
|
||||||
|
self.pageValid.append(True)
|
||||||
|
|
||||||
|
self.pgMiscellaneous = MiscellaneousPage(self, self.nb, len(self.pages))
|
||||||
|
text = "Miscellaneous"
|
||||||
|
self.nb.AddPage(self.pgMiscellaneous, text)
|
||||||
|
self.pages.append(self.pgMiscellaneous)
|
||||||
|
self.titles.append(text)
|
||||||
|
self.pageModified.append(False)
|
||||||
|
self.pageValid.append(True)
|
||||||
|
|
||||||
|
sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)
|
||||||
|
|
||||||
|
self.SetSizer(sz)
|
||||||
|
|
||||||
|
def onPageChange(self, evt):
|
||||||
|
print "printer notebook page changed"
|
||||||
|
print evt.GetSelection()
|
||||||
|
print evt.GetEventObject()
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def checkFocus(self):
|
||||||
|
print "check focus: ", self.nb.GetSelection()
|
||||||
|
|
||||||
|
def assertModified(self, pg, flag = True):
|
||||||
|
self.pageModified[pg] = flag
|
||||||
|
self.modifyTab(pg)
|
||||||
|
|
||||||
|
def isModified(self):
|
||||||
|
return (True in self.pageModified)
|
||||||
|
|
||||||
|
def assertValid(self, pg, flag = True):
|
||||||
|
self.pageValid[pg] = flag
|
||||||
|
self.modifyTab(pg)
|
||||||
|
|
||||||
|
if False in self.pageValid:
|
||||||
|
self.parent.enableSavePrinter(False)
|
||||||
|
else:
|
||||||
|
self.parent.enableSavePrinter(True)
|
||||||
|
|
||||||
|
def modifyTab(self, pg):
|
||||||
|
if self.pageModified[pg] and not self.pageValid[pg]:
|
||||||
|
pfx = "?* "
|
||||||
|
elif self.pageModified[pg]:
|
||||||
|
pfx = "* "
|
||||||
|
elif not self.pageValid[pg]:
|
||||||
|
pfx = "? "
|
||||||
|
else:
|
||||||
|
pfx = ""
|
||||||
|
|
||||||
|
self.nb.SetPageText(pg, pfx + self.titles[pg])
|
||||||
|
|
||||||
|
def setHeaters(self, ht):
|
||||||
|
return self.pgMiscellaneous.setHeaters(ht)
|
||||||
|
|
||||||
|
def onClose(self, evt):
|
||||||
|
if not self.confirmLoseChanges("exit"):
|
||||||
|
return
|
||||||
|
|
||||||
|
self.Destroy()
|
||||||
|
|
||||||
|
def confirmLoseChanges(self, msg):
|
||||||
|
if True not in self.pageModified:
|
||||||
|
return True
|
||||||
|
|
||||||
|
dlg = wx.MessageDialog(self, "Are you sure you want to " + msg + "?\n"
|
||||||
|
"There are changes to your printer "
|
||||||
|
"configuration that will be lost.",
|
||||||
|
"Changes pending",
|
||||||
|
wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
|
||||||
|
rc = dlg.ShowModal()
|
||||||
|
dlg.Destroy()
|
||||||
|
|
||||||
|
if rc != wx.ID_YES:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def onLoadConfig(self, evt):
|
||||||
|
if not self.confirmLoseChanges("load a new printer configuration"):
|
||||||
|
return
|
||||||
|
|
||||||
|
wildcard = "Printer configuration (printer.*.h)|printer.*.h"
|
||||||
|
|
||||||
|
dlg = wx.FileDialog(self, message = "Choose a printer config file",
|
||||||
|
defaultDir = self.dir, defaultFile = "",
|
||||||
|
wildcard = wildcard, style = wx.OPEN | wx.CHANGE_DIR)
|
||||||
|
|
||||||
|
path = None
|
||||||
|
if dlg.ShowModal() == wx.ID_OK:
|
||||||
|
path = dlg.GetPath()
|
||||||
|
|
||||||
|
dlg.Destroy()
|
||||||
|
if path is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.dir = os.path.dirname(path)
|
||||||
|
rc = self.loadConfigFile(path)
|
||||||
|
|
||||||
|
if not rc:
|
||||||
|
dlg = wx.MessageDialog(self, "Unable to process file %s." % path,
|
||||||
|
"File error", wx.OK + wx.ICON_ERROR)
|
||||||
|
dlg.ShowModal()
|
||||||
|
dlg.Destroy()
|
||||||
|
return
|
||||||
|
|
||||||
|
self.parent.enableSavePrinter(True)
|
||||||
|
self.parent.setPrinterTabText("Printer <%s>" % os.path.basename(path))
|
||||||
|
|
||||||
|
for pg in self.pages:
|
||||||
|
pg.insertValues(self.cfgValues)
|
||||||
|
pg.setHelpText(self.helpText)
|
||||||
|
|
||||||
|
k = 'DC_EXTRUDER'
|
||||||
|
if k in self.cfgValues.keys():
|
||||||
|
print "calling orig with (%s)" % self.cfgValues[k]
|
||||||
|
self.pgMiscellaneous.setOriginalHeater(self.cfgValues[k])
|
||||||
|
else:
|
||||||
|
self.pgMiscellaneous.setOriginalHeater(None)
|
||||||
|
|
||||||
|
def loadConfigFile(self, fn):
|
||||||
|
try:
|
||||||
|
self.cfgBuffer = list(open(fn))
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.configFile = fn
|
||||||
|
|
||||||
|
self.processors = []
|
||||||
|
gatheringHelpText = False
|
||||||
|
helpTextString = ""
|
||||||
|
helpKey = None
|
||||||
|
|
||||||
|
self.cfgValues = {}
|
||||||
|
self.helpText = {}
|
||||||
|
|
||||||
|
prevLines = ""
|
||||||
|
for ln in self.cfgBuffer:
|
||||||
|
if gatheringHelpText:
|
||||||
|
if reHelpTextEnd.match(ln):
|
||||||
|
gatheringHelpText = False
|
||||||
|
hk = helpKey.split()
|
||||||
|
for k in hk:
|
||||||
|
self.helpText[k] = helpTextString
|
||||||
|
helpTextString = ""
|
||||||
|
helpKey = None
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
helpTextString += ln
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reHelpTextStart.match(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
gatheringHelpText = True
|
||||||
|
helpKey = t[0]
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ln.rstrip().endswith("\\"):
|
||||||
|
prevLines += ln.rstrip()[:-1]
|
||||||
|
continue
|
||||||
|
|
||||||
|
if prevLines != "":
|
||||||
|
ln = prevLines + ln
|
||||||
|
prevLines = ""
|
||||||
|
|
||||||
|
if ln.lstrip().startswith("//"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ln.lstrip().startswith("#define"):
|
||||||
|
m = reDefQS.search(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 2:
|
||||||
|
m = reDefQSm.search(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
tt = re.findall(reDefQSm2, t[1])
|
||||||
|
if len(tt) == 1:
|
||||||
|
self.cfgValues[t[0]] = tt[0]
|
||||||
|
continue
|
||||||
|
elif len(tt) > 1:
|
||||||
|
self.cfgValues[t[0]] = tt
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reDefine.search(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 2:
|
||||||
|
if t[0] == 'DC_EXTRUDER': print "raw value (%s)" % t[1]
|
||||||
|
self.cfgValues[t[0]] = t[1]
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reDefBool.search(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 1:
|
||||||
|
self.cfgValues[t[0]] = True
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def onSaveConfig(self, evt):
|
||||||
|
path = self.configFile
|
||||||
|
if self.saveConfigFile(path):
|
||||||
|
dlg = wx.MessageDialog(self, "File %s successfully written." % path,
|
||||||
|
"Save successful", wx.OK + wx.ICON_INFORMATION)
|
||||||
|
|
||||||
|
else:
|
||||||
|
dlg = wx.MessageDialog(self, "Unable to write to file %s." % path,
|
||||||
|
"File error", wx.OK + wx.ICON_ERROR)
|
||||||
|
dlg.ShowModal()
|
||||||
|
dlg.Destroy()
|
||||||
|
|
||||||
|
def onSaveConfigAs(self, evt):
|
||||||
|
wildcard = "Printer configuration (printer.*.h)|printer.*.h"
|
||||||
|
|
||||||
|
dlg = wx.FileDialog(self, message = "Save as ...", defaultDir = self.dir,
|
||||||
|
defaultFile = "", wildcard = wildcard,
|
||||||
|
style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
|
||||||
|
|
||||||
|
val = dlg.ShowModal()
|
||||||
|
|
||||||
|
if val != wx.ID_OK:
|
||||||
|
dlg.Destroy()
|
||||||
|
return
|
||||||
|
|
||||||
|
path = dlg.GetPath()
|
||||||
|
dlg.Destroy()
|
||||||
|
|
||||||
|
if self.saveConfigFile(path):
|
||||||
|
dlg = wx.MessageDialog(self, "File %s successfully written." % path,
|
||||||
|
"Save successful", wx.OK + wx.ICON_INFORMATION)
|
||||||
|
self.parent.setPrinterTabText("Printer <%s>" % os.path.basename(path))
|
||||||
|
|
||||||
|
else:
|
||||||
|
dlg = wx.MessageDialog(self, "Unable to write to file %s." % path,
|
||||||
|
"File error", wx.OK + wx.ICON_ERROR)
|
||||||
|
dlg.ShowModal()
|
||||||
|
dlg.Destroy()
|
||||||
|
|
||||||
|
def saveConfigFile(self, path):
|
||||||
|
ext = os.path.splitext(os.path.basename(path))[1]
|
||||||
|
self.dir = os.path.dirname(path)
|
||||||
|
|
||||||
|
if ext == "":
|
||||||
|
path += ".h"
|
||||||
|
|
||||||
|
try:
|
||||||
|
fp = file(path, 'w')
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.configFile = path
|
||||||
|
|
||||||
|
values = {}
|
||||||
|
|
||||||
|
for pg in self.pages:
|
||||||
|
v1 = pg.getValues()
|
||||||
|
for k in v1.keys():
|
||||||
|
values[k] = v1[k]
|
||||||
|
|
||||||
|
for ln in self.cfgBuffer:
|
||||||
|
m = reDefineBL.match(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 2:
|
||||||
|
if t[0] in values.keys() and values[t[0]] != "":
|
||||||
|
fp.write(defineValueFormat % (t[0], values[t[0]]))
|
||||||
|
else:
|
||||||
|
fp.write("//" + ln)
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reDefBoolBL.match(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 1:
|
||||||
|
if t[0] in values.keys() and values[t[0]]:
|
||||||
|
fp.write(defineBoolFormat % t[0])
|
||||||
|
else:
|
||||||
|
fp.write("//" + ln)
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reCommDefBL.match(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 2:
|
||||||
|
if t[0] in values.keys() and values[t[0]] != "":
|
||||||
|
fp.write(defineValueFormat % (t[0], values[t[0]]))
|
||||||
|
else:
|
||||||
|
fp.write(ln)
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = reCommDefBoolBL.match(ln)
|
||||||
|
if m:
|
||||||
|
t = m.groups()
|
||||||
|
if len(t) == 1:
|
||||||
|
if t[0] in values.keys() and values[t[0]]:
|
||||||
|
fp.write(defineBoolFormat % t[0])
|
||||||
|
else:
|
||||||
|
fp.write(ln)
|
||||||
|
continue
|
||||||
|
|
||||||
|
fp.write(ln)
|
||||||
|
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
|
||||||
|
|
||||||
|
class SensorList(wx.ListCtrl):
|
||||||
|
def __init__(self, parent):
|
||||||
|
self.parent = parent
|
||||||
|
self.currentItem = None
|
||||||
|
wx.ListCtrl.__init__(self, parent, wx.ID_ANY, size = (495 + 4, 100),
|
||||||
|
style = wx.LC_REPORT | wx.LC_VIRTUAL |
|
||||||
|
wx.LC_HRULES | wx.LC_VRULES)
|
||||||
|
|
||||||
|
self.valid = []
|
||||||
|
self.sensorList = []
|
||||||
|
|
||||||
|
self.InsertColumn(0, "Name")
|
||||||
|
self.InsertColumn(1, "Sensor Type")
|
||||||
|
self.InsertColumn(2, "Pin")
|
||||||
|
self.InsertColumn(3, "Additional")
|
||||||
|
self.SetColumnWidth(0, 55)
|
||||||
|
self.SetColumnWidth(1, 105)
|
||||||
|
self.SetColumnWidth(2, 55)
|
||||||
|
self.SetColumnWidth(3, 280)
|
||||||
|
|
||||||
|
self.SetItemCount(0)
|
||||||
|
|
||||||
|
self.attr2 = wx.ListItemAttr()
|
||||||
|
self.attr2.SetBackgroundColour("light blue")
|
||||||
|
self.attr3 = wx.ListItemAttr()
|
||||||
|
self.attr3.SetBackgroundColour("pink")
|
||||||
|
|
||||||
|
self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
|
||||||
|
self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected)
|
||||||
|
|
||||||
|
def updateList(self, sensorList):
|
||||||
|
self.sensorList = sensorList
|
||||||
|
self.valid = [True] * len(sensorList)
|
||||||
|
self.currentItem = None
|
||||||
|
self.parent.setItemSelected(None)
|
||||||
|
i = self.GetFirstSelected()
|
||||||
|
while i != -1:
|
||||||
|
self.Select(i, False)
|
||||||
|
i = self.GetFirstSelected()
|
||||||
|
|
||||||
|
self.SetItemCount(len(sensorList))
|
||||||
|
|
||||||
|
def setRowValidity(self, i, flag = False):
|
||||||
|
if i < 0 or i >= len(self.sensorList):
|
||||||
|
return
|
||||||
|
|
||||||
|
self.valid[i] = flag
|
||||||
|
self.Refresh()
|
||||||
|
|
||||||
|
def setTableValidity(self, flag = False):
|
||||||
|
for i in range(len(self.sensorList)):
|
||||||
|
self.setRowValidity(i, flag)
|
||||||
|
|
||||||
|
def OnItemSelected(self, event):
|
||||||
|
self.currentItem = event.m_itemIndex
|
||||||
|
self.parent.setItemSelected(self.currentItem)
|
||||||
|
|
||||||
|
def OnItemDeselected(self, event):
|
||||||
|
self.currentItem = None
|
||||||
|
self.parent.setItemSelected(None)
|
||||||
|
|
||||||
|
def getColumnText(self, index, col):
|
||||||
|
item = self.GetItem(index, col)
|
||||||
|
return item.GetText()
|
||||||
|
|
||||||
|
def OnGetItemText(self, item, col):
|
||||||
|
if item < 0 or item >= len(self.sensorList):
|
||||||
|
return "Error - no sensors"
|
||||||
|
|
||||||
|
s = self.sensorList[item]
|
||||||
|
|
||||||
|
if col == 0:
|
||||||
|
return s[0]
|
||||||
|
elif col == 1:
|
||||||
|
return s[1]
|
||||||
|
elif col == 2:
|
||||||
|
return s[2]
|
||||||
|
elif len(s) == 3:
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
return s[3]
|
||||||
|
|
||||||
|
def OnGetItemAttr(self, item):
|
||||||
|
if not self.valid[item]:
|
||||||
|
return self.attr3
|
||||||
|
|
||||||
|
if item % 2 == 1:
|
||||||
|
return self.attr2
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
@ -0,0 +1,190 @@
|
||||||
|
|
||||||
|
import wx
|
||||||
|
from configtool.page import Page
|
||||||
|
from configtool.data import pinNames, BSIZESMALL
|
||||||
|
from sensorlist import SensorList
|
||||||
|
from addsensordlg import AddSensorDlg
|
||||||
|
|
||||||
|
|
||||||
|
class SensorsPage(wx.Panel, Page):
|
||||||
|
def __init__(self, parent, nb, idPg):
|
||||||
|
wx.Panel.__init__(self, nb, wx.ID_ANY)
|
||||||
|
Page.__init__(self)
|
||||||
|
self.parent = parent
|
||||||
|
self.id = idPg
|
||||||
|
|
||||||
|
self.sensorTypeKeys = ['TEMP_MAX6675', 'TEMP_THERMISTOR', 'TEMP_AD595',
|
||||||
|
'TEMP_PT100', 'TEMP_INTERCOM']
|
||||||
|
self.sensorType = {'TEMP_MAX6675': "TT_MAX6675",
|
||||||
|
'TEMP_THERMISTOR': "TT_THERMISTOR",
|
||||||
|
'TEMP_AD595': "TT_AD595",
|
||||||
|
'TEMP_PT100': "TT_PT100",
|
||||||
|
'TEMP_INTERCOM': "TT_INTERCOM"}
|
||||||
|
self.labels = {'TEMP_MAX6675': "MAX6675", 'TEMP_THERMISTOR': "Thermistor",
|
||||||
|
'TEMP_AD595': "AD595", 'TEMP_PT100': "PT100",
|
||||||
|
'TEMP_INTERCOM': "Intercom"}
|
||||||
|
|
||||||
|
self.validPins = pinNames
|
||||||
|
|
||||||
|
sz = wx.GridBagSizer()
|
||||||
|
sz.AddSpacer((30, 30), pos = (0, 0))
|
||||||
|
|
||||||
|
self.sensors = []
|
||||||
|
|
||||||
|
b = wx.StaticBox(self, wx.ID_ANY, "Sensor Types")
|
||||||
|
sbox = wx.StaticBoxSizer(b, wx.VERTICAL)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
for k in self.sensorTypeKeys:
|
||||||
|
cb = self.addCheckBox(k, self.onCheckBoxSensorType)
|
||||||
|
sbox.Add(cb, 1, wx.LEFT + wx.RIGHT, 10)
|
||||||
|
sbox.AddSpacer((5, 5))
|
||||||
|
|
||||||
|
sz.Add(sbox, pos = (1, 1), span = (5, 1))
|
||||||
|
|
||||||
|
self.lb = SensorList(self)
|
||||||
|
sz.Add(self.lb, pos = (7, 1), span = (1, 3))
|
||||||
|
|
||||||
|
bsz = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
self.bAdd = wx.Button(self, wx.ID_ANY, "Add", size = BSIZESMALL)
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.doAdd, self.bAdd)
|
||||||
|
self.bAdd.Enable(False)
|
||||||
|
self.bAdd.SetToolTipString("Add a sensor to the configuration.")
|
||||||
|
|
||||||
|
bsz.Add(self.bAdd)
|
||||||
|
|
||||||
|
bsz.AddSpacer((10, 10))
|
||||||
|
self.bDelete = wx.Button(self, wx.ID_ANY, "Delete", size = BSIZESMALL)
|
||||||
|
self.bDelete.Enable(False)
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.doDelete, self.bDelete)
|
||||||
|
bsz.Add(self.bDelete)
|
||||||
|
self.bDelete.SetToolTipString("Remove the selected temperature sensor "
|
||||||
|
"from the configuration.")
|
||||||
|
|
||||||
|
sz.Add(bsz, pos = (7, 4))
|
||||||
|
|
||||||
|
self.SetSizer(sz)
|
||||||
|
self.enableAll(False)
|
||||||
|
|
||||||
|
def onCheckBoxSensorType(self, evt):
|
||||||
|
self.assertModified(True)
|
||||||
|
|
||||||
|
ct = 0
|
||||||
|
for tt in self.sensorTypeKeys:
|
||||||
|
if self.checkBoxes[tt].IsChecked():
|
||||||
|
ct += 1
|
||||||
|
|
||||||
|
if ct == 0:
|
||||||
|
self.bAdd.Enable(False)
|
||||||
|
else:
|
||||||
|
self.bAdd.Enable(True)
|
||||||
|
|
||||||
|
evt.Skip()
|
||||||
|
|
||||||
|
def setItemSelected(self, n):
|
||||||
|
self.selection = n
|
||||||
|
if n is None:
|
||||||
|
self.bDelete.Enable(False)
|
||||||
|
else:
|
||||||
|
self.bDelete.Enable(True)
|
||||||
|
|
||||||
|
def doAdd(self, evt):
|
||||||
|
sl = []
|
||||||
|
for tt in self.sensorTypeKeys:
|
||||||
|
if self.checkBoxes[tt].IsChecked():
|
||||||
|
sl.append(self.sensorType[tt])
|
||||||
|
|
||||||
|
nm = []
|
||||||
|
for s in self.sensors:
|
||||||
|
nm.append(s[0])
|
||||||
|
|
||||||
|
dlg = AddSensorDlg(self, nm, sl, self.validPins)
|
||||||
|
rc = dlg.ShowModal()
|
||||||
|
if rc == wx.ID_OK:
|
||||||
|
tt = dlg.getValues()
|
||||||
|
|
||||||
|
dlg.Destroy()
|
||||||
|
|
||||||
|
if rc != wx.ID_OK:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.sensors.append(tt)
|
||||||
|
self.lb.updateList(self.sensors)
|
||||||
|
self.validateTable()
|
||||||
|
self.limitSensorTypeControls()
|
||||||
|
|
||||||
|
def doDelete(self, evt):
|
||||||
|
if self.selection is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.assertModified(True)
|
||||||
|
|
||||||
|
del self.sensors[self.selection]
|
||||||
|
self.lb.updateList(self.sensors)
|
||||||
|
self.validateTable()
|
||||||
|
self.limitSensorTypeControls()
|
||||||
|
|
||||||
|
def limitSensorTypeControls(self):
|
||||||
|
using = {}
|
||||||
|
for s in self.sensors:
|
||||||
|
using[s[1]] = True
|
||||||
|
|
||||||
|
for k in self.sensorTypeKeys:
|
||||||
|
self.checkBoxes[k].Enable(True)
|
||||||
|
|
||||||
|
for tt in using.keys():
|
||||||
|
if not tt.startswith("TT_"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
k = "TEMP_" + tt[3:]
|
||||||
|
if k in self.sensorTypeKeys:
|
||||||
|
self.checkBoxes[k].Enable(False)
|
||||||
|
|
||||||
|
def insertValues(self, cfgValues):
|
||||||
|
self.enableAll(True)
|
||||||
|
for k in self.textControls.keys():
|
||||||
|
if k in cfgValues.keys():
|
||||||
|
self.textControls[k].SetValue(cfgValues[k])
|
||||||
|
else:
|
||||||
|
self.textControls[k].SetValue("")
|
||||||
|
|
||||||
|
for k in self.checkBoxes.keys():
|
||||||
|
if k in cfgValues.keys() and cfgValues[k]:
|
||||||
|
self.checkBoxes[k].SetValue(True)
|
||||||
|
else:
|
||||||
|
self.checkBoxes[k].SetValue(False)
|
||||||
|
|
||||||
|
ct = 0
|
||||||
|
for k in self.sensorTypeKeys:
|
||||||
|
if self.checkBoxes[k].IsChecked(): ct += 1
|
||||||
|
self.bAdd.Enable(ct != 0)
|
||||||
|
|
||||||
|
self.assertModified(False)
|
||||||
|
|
||||||
|
def setSensors(self, sensors):
|
||||||
|
self.sensors = sensors
|
||||||
|
self.lb.updateList(self.sensors)
|
||||||
|
self.validateTable()
|
||||||
|
self.limitSensorTypeControls()
|
||||||
|
|
||||||
|
def setCandidatePins(self, plist):
|
||||||
|
if not plist or len(plist) == 0:
|
||||||
|
self.validPins = pinNames
|
||||||
|
else:
|
||||||
|
self.validPins = plist
|
||||||
|
|
||||||
|
self.validateTable()
|
||||||
|
|
||||||
|
def validateTable(self):
|
||||||
|
self.lb.setTableValidity(True)
|
||||||
|
self.setFieldValidity('SENSORLIST', True)
|
||||||
|
for i in range(len(self.sensors)):
|
||||||
|
if self.sensors[i][2] not in self.validPins:
|
||||||
|
self.lb.setRowValidity(i, False)
|
||||||
|
self.setFieldValidity('SENSORLIST', False)
|
||||||
|
|
||||||
|
def setHelpText(self, ht):
|
||||||
|
Page.setHelpText(self, ht)
|
||||||
|
|
||||||
|
k = 'DEFINE_TEMP_SENSOR'
|
||||||
|
if k in ht.keys():
|
||||||
|
self.bAdd.SetToolTipString(ht[k])
|
||||||
Loading…
Reference in New Issue