Browse Source

more work on firmware, support for full graphic smart lcd.

Thomas Buck 3 years ago
parent
commit
fb00cf83a5
14 changed files with 981 additions and 96 deletions
  1. 27
    9
      include/config.h
  2. 23
    1
      include/config_pins.h
  3. 5
    2
      include/data.h
  4. 4
    0
      include/lcd.h
  5. 37
    4
      include/statemachine.h
  6. 12
    0
      include/steppers.h
  7. 17
    2
      platformio.ini
  8. 91
    15
      src/data.cpp
  9. 36
    3
      src/encoder.cpp
  10. 240
    8
      src/lcd.cpp
  11. 6
    8
      src/main.cpp
  12. 223
    13
      src/statemachine.cpp
  13. 141
    14
      src/states.cpp
  14. 119
    17
      src/steppers.cpp

+ 27
- 9
include/config.h View File

@@ -7,19 +7,23 @@
7 7
 
8 8
 #define FIRMWARE_VERSION "0.1"
9 9
 
10
-#define LED_BLINK_INTERVAL 500
10
+#define LED_BLINK_INTERVAL 1000
11 11
 #define DEBOUNCE_DELAY 50
12 12
 
13 13
 #define ENCODER_CLICK_BEEP_FREQ 2000
14 14
 #define ENCODER_CLICK_BEEP_TIME 50
15 15
 
16
+#define HOMING_BEEP_FREQ 3000
17
+#define HOMING_BEEP_TIME 100
18
+
19
+#define KILL_BEEP_FREQ 3000
20
+#define KILL_BEEP_TIME 100
21
+#define KILL_BEEP_REPEAT 5
22
+
16 23
 /***************************************
17 24
  ********** Hardware Settings **********
18 25
  ***************************************/
19 26
 
20
-#define USE_20X4_TEXT_LCD
21
-//#define USE_FULL_GRAPHIC_LCD
22
-
23 27
 // xy steps per mm
24 28
 #define XY_BELT_PITCH 2.0
25 29
 #define XY_PULLEY_TEETH 40.0
@@ -34,9 +38,17 @@
34 38
 #define Z_STEPS_PER_MM (Z_MOTOR_STEPS_PER_REV / Z_ROD_PITCH)
35 39
 
36 40
 // e steps per mm
41
+// 1/2 turn of output is movement range
42
+// gear box factor 3:1 output:input
43
+// 3/2 turns of motor equals 100% movement
44
+// (16 * 200) = 3200 steps for motor turn
45
+// 3200 * 3 / 2 = 4800 steps for 3/2 turn
46
+// 4800 / 100 = 48 steps for one percent of movement
47
+#define GEARBOX_MULT 3
48
+#define OUTPUT_TURN_DIV 2
37 49
 #define E_MICRO_STEPS 16.0
38 50
 #define E_MOTOR_STEPS_PER_REV (200.0 * E_MICRO_STEPS)
39
-#define E_STEPS_PER_MM (E_MOTOR_STEPS_PER_REV / 42) // TODO
51
+#define E_STEPS_PER_PERCENT (E_MOTOR_STEPS_PER_REV * GEARBOX_MULT / OUTPUT_TURN_DIV / 100.0)
40 52
 
41 53
 // travel lengths
42 54
 #define X_AXIS_MIN -5.0 // in mm
@@ -48,23 +60,29 @@
48 60
 #define E_AXIS_MIN 0.0 // in mm
49 61
 #define E_AXIS_MAX 6.0 // in mm
50 62
 
63
+//   0 degree =   0 percent =  pi = 0mm
64
+// 180 degree = 100 percent = 2pi = 6mm
65
+// (cos(pi + x / 100 * pi) + 1) / 2 * 6mm
66
+#define E_PERCENT_TO_MM(x) ((cos(PI + (x * PI / 100.0)) + 1.0) / 2.0 * E_AXIS_MAX)
67
+#define E_MM_TO_PERCENT(x) ((acos((x * 2.0 / E_AXIS_MAX) - 1.0) - PI) * 100.0 / PI)
68
+
51 69
 // maximum speeds
52 70
 #define XY_MAX_SPEED 50.0 // in mm/s
53 71
 #define Z_MAX_SPEED 20.0 // in mm/s
54
-#define E_MAX_SPEED 10.0 // in mm/s
72
+#define E_MAX_SPEED 50.0 // in percent/s
55 73
 
56 74
 // homing speeds
57 75
 #define XY_FAST_HOME_SPEED 2.5 // in mm/s
58 76
 #define XY_SLOW_HOME_SPEED 1.0 // in mm/s
59 77
 #define Z_FAST_HOME_SPEED 2.0 // in mm/s
60 78
 #define Z_SLOW_HOME_SPEED 1.0 // in mm/s
61
-#define E_FAST_HOME_SPEED 0.1 // in mm/s
62
-#define E_SLOW_HOME_SPEED 0.05 // in mm/s
79
+#define E_FAST_HOME_SPEED 10.0 // in percent/s
80
+#define E_SLOW_HOME_SPEED 5.0 // in percent/s
63 81
 
64 82
 // accelerations
65 83
 #define XY_MAX_ACCEL 100.0 // in mm/s^2
66 84
 #define Z_MAX_ACCEL 50.0 // in mm/s^2
67
-#define E_MAX_ACCEL 20.0 // in mm/s^2
85
+#define E_MAX_ACCEL 1000.0 // in percent/s^2
68 86
 
69 87
 // axis movement directions (1.0 normal, -1.0 inverted)
70 88
 #define X_AXIS_MOVEMENT_DIR 1.0

+ 23
- 1
include/config_pins.h View File

@@ -81,7 +81,23 @@
81 81
 
82 82
 #ifdef USE_FULL_GRAPHIC_LCD
83 83
 
84
-// TODO
84
+// based on https://reprap.org/wiki/RepRapDiscount_Full_Graphic_Smart_Controller
85
+
86
+// STOP / KILL button
87
+#define KILL_PIN 41
88
+
89
+// lcd pins
90
+#define LCD_PINS_CS 16
91
+#define LCD_PINS_MOSI 17
92
+#define LCD_PINS_SCK 23
93
+
94
+// encoder pins
95
+#define BTN_EN1 31
96
+#define BTN_EN2 33
97
+#define BTN_ENC 35
98
+
99
+// beeper
100
+#define BEEPER 37
85 101
 
86 102
 #endif // USE_FULL_GRAPHIC_LCD
87 103
 
@@ -134,3 +150,9 @@
134 150
 #define E_HOMING_DIR -1.0
135 151
 #define E_ENDSTOP_PIN E_MIN_PIN
136 152
 #endif
153
+
154
+#ifdef KILL_PIN
155
+#if (KILL_PIN == -1)
156
+#undef KILL_PIN
157
+#endif
158
+#endif // KILL_PIN

+ 5
- 2
include/data.h View File

@@ -19,11 +19,14 @@ struct data_config_preset {
19 19
 void data_init(void);
20 20
 void data_eeprom_write(void);
21 21
 
22
+bool data_eeprom_read(void);
23
+const char *data_eeprom_error(void);
24
+
22 25
 struct data_config_options *data_options(void);
23 26
 
24 27
 unsigned int data_preset_count(void);
25 28
 struct data_config_preset *data_preset(unsigned int i);
26
-void data_preset_add(struct data_config_preset preset);
27
-void data_preset_remove(unsigned int i);
29
+bool data_preset_add(struct data_config_preset preset);
30
+bool data_preset_remove(unsigned int i);
28 31
 
29 32
 #endif // _DATA_H_

+ 4
- 0
include/lcd.h View File

@@ -2,9 +2,13 @@
2 2
 #define _LCD_H_
3 3
 
4 4
 void lcd_init(void);
5
+void lcd_loop(void);
5 6
 
6 7
 void lcd_clear(void);
7 8
 void lcd_set_heading(const char *heading);
8 9
 void lcd_set_text(const char *text);
10
+void lcd_set_menu_text(int line, const char *text);
11
+
12
+int lcd_text_lines(void);
9 13
 
10 14
 #endif // _LCD_H_

+ 37
- 4
include/statemachine.h View File

@@ -3,6 +3,14 @@
3 3
 
4 4
 #include <Array.h>
5 5
 
6
+#define STATE_ARRAY_SIZE 42
7
+
8
+template <typename T, size_t N>
9
+void array_print(Array<T, N> *arr);
10
+
11
+template <typename T, size_t N>
12
+void array_insert_at_pos(Array<T, N> *arr, T value, size_t pos);
13
+
6 14
 struct StateMachineInput {
7 15
     StateMachineInput(int c, int e, int k, int m)
8 16
             : click(c), encoder(e), kill(k), motors_done(m) { };
@@ -58,7 +66,7 @@ private:
58 66
 
59 67
 class StateMenu : public State {
60 68
 public:
61
-    StateMenu(State *_parent = NULL);
69
+    StateMenu(State *_parent = NULL, bool _show_parent = true);
62 70
     virtual void setChild(State *_child);
63 71
 
64 72
     void addChild(State *_child, int pos = -1);
@@ -67,8 +75,11 @@ public:
67 75
     virtual void inState(StateMachineInput smi);
68 76
 
69 77
 private:
70
-    int menuPos;
71
-    Array<State *, 42> children;
78
+    void display(void);
79
+
80
+    bool show_parent;
81
+    int menuPos, menuOff;
82
+    Array<State *, STATE_ARRAY_SIZE> children;
72 83
 };
73 84
 
74 85
 class StateDynamicMenu : public State {
@@ -93,8 +104,30 @@ private:
93 104
     GetFuncPtr getFunc;
94 105
     CallFuncPtr callFunc;
95 106
 
107
+    int menuPos, menuOff;
96 108
     int count;
97
-    Array<const char *, 42> contents;
109
+    Array<const char *, STATE_ARRAY_SIZE> contents;
110
+};
111
+
112
+template <typename T>
113
+class StateValue : public State {
114
+public:
115
+    StateValue(State *_parent, T &_value, T _min, T _max);
116
+
117
+    typedef void(*UpdateFuncPtr)(T value);
118
+
119
+    void onUpdate(UpdateFuncPtr func);
120
+
121
+    virtual void enterState(void);
122
+    virtual void inState(StateMachineInput smi);
123
+
124
+private:
125
+    void display(void);
126
+
127
+    T &value;
128
+    T min, max;
129
+    UpdateFuncPtr updateFunc;
98 130
 };
99 131
 
132
+
100 133
 #endif // _STATE_MACHINE_H_

+ 12
- 0
include/steppers.h View File

@@ -12,4 +12,16 @@ int steppers_move_y(long pos);
12 12
 int steppers_move_z(long pos);
13 13
 int steppers_move_e(long pos);
14 14
 
15
+void steppers_kill(void);
16
+
17
+void steppers_set_speed_x(float speed);
18
+void steppers_set_speed_y(float speed);
19
+void steppers_set_speed_z(float speed);
20
+void steppers_set_speed_e(float speed);
21
+
22
+void steppers_set_accel_x(float accel);
23
+void steppers_set_accel_y(float accel);
24
+void steppers_set_accel_z(float accel);
25
+void steppers_set_accel_e(float accel);
26
+
15 27
 #endif // _STEPPERS_H_

+ 17
- 2
platformio.ini View File

@@ -9,12 +9,13 @@
9 9
 ; https://docs.platformio.org/page/projectconf.html
10 10
 
11 11
 [platformio]
12
-default_envs = arduino
12
+default_envs = ramps_lcd2004, ramps_lcd12864
13 13
 
14
-[env:arduino]
14
+[env:ramps_lcd2004]
15 15
 platform = atmelavr
16 16
 board = megaatmega2560
17 17
 framework = arduino
18
+build_flags = -D USE_20X4_TEXT_LCD -Wno-sign-compare
18 19
 upload_port = /dev/ttyUSB1
19 20
 monitor_port = /dev/ttyUSB1
20 21
 monitor_speed = 115200
@@ -23,3 +24,17 @@ lib_deps =
23 24
     https://github.com/waspinator/AccelStepper
24 25
     https://github.com/mathertel/RotaryEncoder
25 26
     https://github.com/janelia-arduino/Array
27
+
28
+[env:ramps_lcd12864]
29
+platform = atmelavr
30
+board = megaatmega2560
31
+framework = arduino
32
+build_flags = -D USE_FULL_GRAPHIC_LCD -Wno-sign-compare
33
+upload_port = /dev/ttyUSB1
34
+monitor_port = /dev/ttyUSB1
35
+monitor_speed = 115200
36
+lib_deps =
37
+    u8g2
38
+    https://github.com/waspinator/AccelStepper
39
+    https://github.com/mathertel/RotaryEncoder
40
+    https://github.com/janelia-arduino/Array

+ 91
- 15
src/data.cpp View File

@@ -5,7 +5,9 @@
5 5
 #include "config_pins.h"
6 6
 #include "data.h"
7 7
 
8
+// TODO make defines platform specific
8 9
 #define EEPROM_SIZE 4096
10
+#define RAM_SIZE (8192 / 2)
9 11
 
10 12
 struct data_config {
11 13
     uint8_t data_schema_version;
@@ -16,12 +18,24 @@ struct data_config {
16 18
 };
17 19
 
18 20
 static struct data_config d;
21
+static const char *last_error = "";
19 22
 
20
-static unsigned int max_presets(void) {
23
+static unsigned int max_presets_eeprom(void) {
21 24
     unsigned int s = EEPROM_SIZE - sizeof(struct data_config) + sizeof(struct data_config_preset *);
22 25
     return s / sizeof(struct data_config_preset);
23 26
 }
24 27
 
28
+static unsigned int max_presets_ram(void) {
29
+    unsigned int s = RAM_SIZE - sizeof(struct data_config) + sizeof(struct data_config_preset *);
30
+    return s / sizeof(struct data_config_preset);
31
+}
32
+
33
+static unsigned int max_presets(void) {
34
+    unsigned int eeprom = max_presets_eeprom();
35
+    unsigned int ram = max_presets_ram();
36
+    return (eeprom < ram) ? eeprom : ram;
37
+}
38
+
25 39
 static uint32_t data_checksum(struct data_config *data) {
26 40
     uint32_t c = 0;
27 41
 
@@ -40,7 +54,11 @@ static uint32_t data_checksum(struct data_config *data) {
40 54
     return c;
41 55
 }
42 56
 
43
-static bool data_eeprom_read(void) {
57
+const char *data_eeprom_error(void) {
58
+    return last_error;
59
+}
60
+
61
+bool data_eeprom_read(void) {
44 62
     struct data_config config;
45 63
     uint8_t *data = (uint8_t *)&config;
46 64
 
@@ -51,14 +69,14 @@ static bool data_eeprom_read(void) {
51 69
     }
52 70
 
53 71
     if (config.preset_count > 0) {
54
-        config.presets = (struct data_config_preset *)malloc(config.preset_count * sizeof(struct data_config_preset));
55
-        if (config.presets == NULL) {
56
-            Serial.print(F("Alloc "));
72
+        if (config.preset_count > max_presets()) {
73
+            last_error = "Preset";
57 74
             return false;
58 75
         }
59 76
 
60
-        if (config.preset_count > max_presets()) {
61
-            Serial.print(F("Preset "));
77
+        config.presets = (struct data_config_preset *)malloc(config.preset_count * sizeof(struct data_config_preset));
78
+        if (config.presets == NULL) {
79
+            last_error = "Alloc";
62 80
             return false;
63 81
         }
64 82
 
@@ -75,8 +93,10 @@ static bool data_eeprom_read(void) {
75 93
     }
76 94
 
77 95
     // verify checksum
96
+    uint32_t read_checksum = config.checksum;
97
+    config.checksum = 0;
78 98
     uint32_t checksum = data_checksum(&config);
79
-    if (config.checksum == checksum) {
99
+    if (read_checksum == checksum) {
80 100
         // verify version
81 101
         if (config.data_schema_version == DATA_SCHEMA_VERSION) {
82 102
             if (d.presets != NULL) {
@@ -84,18 +104,24 @@ static bool data_eeprom_read(void) {
84 104
             }
85 105
             d = config;
86 106
 
107
+            last_error = "";
87 108
             return true;
88 109
         } else {
89
-            Serial.print(F("Version "));
110
+            last_error = "Version";
90 111
             return false;
91 112
         }
92 113
     } else {
93
-        Serial.print(F("Checksum "));
114
+        Serial.print("read=");
115
+        Serial.print(config.checksum);
116
+        Serial.print(" calc=");
117
+        Serial.println(checksum);
118
+        last_error = "Checksum";
94 119
         return false;
95 120
     }
96 121
 }
97 122
 
98 123
 void data_eeprom_write(void) {
124
+    d.checksum = 0;
99 125
     d.checksum = data_checksum(&d);
100 126
 
101 127
     // write meta-data and settings
@@ -132,9 +158,13 @@ void data_init(void) {
132 158
 
133 159
     d.presets = NULL;
134 160
 
161
+    Serial.print(F("EEPROM max presets: "));
162
+    Serial.println(max_presets());
163
+
135 164
     Serial.print(F("EEPROM read... "));
136 165
     if (!data_eeprom_read()) {
137
-        Serial.println(F("Error"));
166
+        Serial.print(last_error);
167
+        Serial.println(F(" Error"));
138 168
     } else {
139 169
         Serial.println(F("Ok"));
140 170
     }
@@ -155,10 +185,56 @@ struct data_config_preset *data_preset(unsigned int i) {
155 185
     return NULL;
156 186
 }
157 187
 
158
-void data_preset_add(struct data_config_preset preset) {
159
-
188
+bool data_preset_add(struct data_config_preset preset) {
189
+    if ((d.preset_count == 0) || (d.presets == NULL)) {
190
+        d.preset_count = 1;
191
+        d.presets = (struct data_config_preset *)malloc(d.preset_count * sizeof(struct data_config_preset));
192
+        if (d.presets == NULL) {
193
+            d.preset_count = 0;
194
+            last_error = "Alloc";
195
+            return false;
196
+        } else {
197
+            d.presets[d.preset_count - 1] = preset;
198
+            return true;
199
+        }
200
+    } else if (d.preset_count < max_presets()) {
201
+        d.preset_count += 1;
202
+        struct data_config_preset *new_mem = (struct data_config_preset *)realloc(d.presets, d.preset_count * sizeof(struct data_config_preset));
203
+        if (new_mem == NULL) {
204
+            d.preset_count -= 1;
205
+            last_error = "Realloc";
206
+            return false;
207
+        } else {
208
+            d.presets = new_mem;
209
+            d.presets[d.preset_count - 1] = preset;
210
+            return true;
211
+        }
212
+    } else {
213
+        return false;
214
+    }
160 215
 }
161 216
 
162
-void data_preset_remove(unsigned int i) {
163
-
217
+bool data_preset_remove(unsigned int i) {
218
+    if (d.preset_count == 1) {
219
+        d.preset_count = 0;
220
+        free(d.presets);
221
+        d.presets = NULL;
222
+        return true;
223
+    } else if (d.preset_count > 1) {
224
+        for (int j = i; j < (d.preset_count - 1); j++) {
225
+            d.presets[j] = d.presets[j + 1];
226
+        }
227
+        d.preset_count -= 1;
228
+        struct data_config_preset *new_mem = (struct data_config_preset *)realloc(d.presets, d.preset_count * sizeof(struct data_config_preset));
229
+        if (new_mem == NULL) {
230
+            d.preset_count += 1;
231
+            last_error = "Realloc";
232
+            return false;
233
+        } else {
234
+            d.presets = new_mem;
235
+            return true;
236
+        }
237
+    } else {
238
+        return true; // nothing to delete
239
+    }
164 240
 }

+ 36
- 3
src/encoder.cpp View File

@@ -6,19 +6,26 @@
6 6
 #include "debounce.h"
7 7
 #include "encoder.h"
8 8
 
9
+//#define DEBUG_ENCODER
10
+
9 11
 static Debouncer click(BTN_ENC);
10 12
 static int click_state = 0;
11 13
 static bool ignore_until_next_unclick = false;
12 14
 
15
+#ifdef KILL_PIN
13 16
 static Debouncer kill(KILL_PIN);
14 17
 static int kill_state = 0;
18
+#endif // KILL_PIN
15 19
 
16
-static RotaryEncoder encoder(BTN_EN1, BTN_EN2, RotaryEncoder::LatchMode::TWO03);
20
+static RotaryEncoder encoder(BTN_EN1, BTN_EN2, RotaryEncoder::LatchMode::FOUR3);
17 21
 static int pos = 0;
18 22
 
19 23
 void encoder_init(void) {
20
-    pinMode(BTN_ENC, INPUT);
21
-    pinMode(KILL_PIN, INPUT);
24
+    pinMode(BTN_ENC, INPUT_PULLUP);
25
+
26
+#ifdef KILL_PIN
27
+    pinMode(KILL_PIN, INPUT_PULLUP);
28
+#endif // KILL_PIN
22 29
 }
23 30
 
24 31
 void encoder_run(void) {
@@ -32,7 +39,9 @@ void encoder_run(void) {
32 39
         click_state = cs;
33 40
     }
34 41
 
42
+#ifdef KILL_PIN
35 43
     kill_state = kill.poll();
44
+#endif // KILL_PIN
36 45
 
37 46
     encoder.tick();
38 47
 }
@@ -41,6 +50,16 @@ int encoder_change(void) {
41 50
     int new_pos = encoder.getPosition();
42 51
     int diff = new_pos - pos;
43 52
     pos = new_pos;
53
+
54
+#ifdef DEBUG_ENCODER
55
+    if (diff != 0) {
56
+        Serial.print("encoder_change: ");
57
+        Serial.print(diff);
58
+        Serial.print(" ticks: ");
59
+        Serial.println(new_pos);
60
+    }
61
+#endif // DEBUG_ENCODER
62
+
44 63
     return diff;
45 64
 }
46 65
 
@@ -51,11 +70,25 @@ int encoder_click(void) {
51 70
     if (r == 1) {
52 71
         click_state = 0;
53 72
         ignore_until_next_unclick = true;
73
+
74
+#ifdef DEBUG_ENCODER
75
+        Serial.println("encoder_click: 1");
76
+#endif // DEBUG_ENCODER
54 77
     }
55 78
 
56 79
     return r;
57 80
 }
58 81
 
59 82
 int kill_switch(void) {
83
+#ifdef KILL_PIN
84
+#ifdef DEBUG_ENCODER
85
+    if (kill_state == 1) {
86
+        Serial.println("kill_switch: 1");
87
+    }
88
+#endif // DEBUG_ENCODER
89
+
60 90
     return kill_state;
91
+#else
92
+    return 0;
93
+#endif // KILL_PIN
61 94
 }

+ 240
- 8
src/lcd.cpp View File

@@ -9,14 +9,155 @@
9 9
 #endif
10 10
 
11 11
 #ifdef USE_20X4_TEXT_LCD
12
+
12 13
 #include <LiquidCrystal.h>
14
+
15
+#define LCD_HEADING_LINES 1
16
+#define LCD_HEADING_WIDTH 20
17
+#define LCD_TEXT_LINES 3
18
+#define LCD_TEXT_WIDTH 20
19
+
13 20
 LiquidCrystal lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5, LCD_PINS_D6, LCD_PINS_D7);
21
+
14 22
 #endif // USE_20X4_TEXT_LCD
15 23
 
16 24
 #ifdef USE_FULL_GRAPHIC_LCD
17
-// TODO
25
+
26
+#include <U8g2lib.h>
27
+
28
+#define LCD_HEADING_LINES 1
29
+#define LCD_HEADING_WIDTH 15
30
+#define LCD_TEXT_LINES 5
31
+#define LCD_TEXT_WIDTH 25
32
+
33
+#define LCD_HEADING_FONT u8g2_font_torussansbold8_8r
34
+#define LCD_TEXT_FONT u8g2_font_5x7_tr
35
+
36
+#define LCD_HEADING_TEXT_OFFSET 3
37
+#define LCD_HEADING_HEIGHT 8
38
+#define LCD_TEXT_HEIGHT 9
39
+
40
+U8G2_ST7920_128X64_1_SW_SPI lcd(U8G2_R0, LCD_PINS_SCK, LCD_PINS_MOSI, LCD_PINS_CS);
41
+
18 42
 #endif // USE_FULL_GRAPHIC_LCD
19 43
 
44
+String heading[LCD_HEADING_LINES];
45
+String text[LCD_TEXT_LINES];
46
+
47
+String heading_pre, heading_post;
48
+String text_pre, text_post;
49
+int heading_direction, text_direction;
50
+
51
+String menu_pre[LCD_TEXT_LINES], menu_post[LCD_TEXT_LINES];
52
+int menu_dir[LCD_TEXT_LINES];
53
+
54
+boolean redraw = false;
55
+
56
+enum lcd_text_mode {
57
+    lcd_mode_none,
58
+    lcd_mode_multiline,
59
+    lcd_mode_menu
60
+};
61
+enum lcd_text_mode text_mode = lcd_mode_none;
62
+
63
+#define SCROLL_DELAY 500
64
+unsigned long last_scroll_time = 0;
65
+
66
+void lcd_shorten_multiline(String s[], int n, int w, String *remainder) {
67
+    // if a line is longer then w, take end off and put in front of next line
68
+    String for_next_line = "";
69
+    for (int i = 0; i < n; i++) {
70
+        s[i] = for_next_line + s[i];
71
+        for_next_line = "";
72
+        if (s[i].length() > w) {
73
+            for_next_line = s[i].substring(w);
74
+            s[i] = s[i].substring(0, w);
75
+        }
76
+    }
77
+
78
+    // if something remains at end, store remainder, if given, otherwise leave at last line
79
+    if (remainder != NULL) {
80
+        *remainder = for_next_line;
81
+    } else {
82
+        s[n - 1] = s[n - 1] + for_next_line;
83
+    }
84
+
85
+    last_scroll_time = millis();
86
+}
87
+
88
+void lcd_scroll_multiline(String s[], int n, int w, String &pre, String &post, int &dir) {
89
+    if (dir == 0) {
90
+        // switch directions if done scrolling in current direction
91
+        if (post.length() == 0) {
92
+            dir = 1;
93
+            return;
94
+        }
95
+
96
+        // take first char of first line, append to pre
97
+        pre = pre + s[0][0];
98
+        s[0] = s[0].substring(1);
99
+
100
+        // shift now empty spot to the left through lines
101
+        for (int i = 1; i < n; i++) {
102
+            s[i - 1] = s[i - 1] + s[i][0];
103
+            s[i] = s[i].substring(1);
104
+        }
105
+
106
+        // fill empty spot at end of last line with first char of post
107
+        s[n - 1] = s[n - 1] + post[0];
108
+        post = post.substring(1);
109
+    } else {
110
+        // switch directions if done scrolling in current direction
111
+        if (pre.length() == 0) {
112
+            dir = 0;
113
+            return;
114
+        }
115
+
116
+        // take last char of last line, prepend to post
117
+        post = s[n - 1][s[n - 1].length() - 1] + post;
118
+        s[n - 1] = s[n - 1].substring(0, s[n - 1].length() - 1);
119
+
120
+        // shift now empty sport to the right through lines
121
+        for (int i = n - 1; i >= 1; i--) {
122
+            s[i] = s[i - 1][s[i - 1].length() - 1] + s[i];
123
+            s[i - 1] = s[i - 1].substring(0, s[i - 1].length() - 1);
124
+        }
125
+
126
+        // fill empty spot at beginning with last char of pre
127
+        s[0] = pre[pre.length() - 1] + s[0];
128
+        pre = pre.substring(0, pre.length() - 1);
129
+    }
130
+
131
+    redraw = true;
132
+}
133
+
134
+void lcd_scrolling(void) {
135
+    if (text_mode != lcd_mode_none) {
136
+        if ((heading_pre.length() > 0) || (heading_post.length() > 0)) {
137
+            lcd_scroll_multiline(heading, LCD_HEADING_LINES, LCD_HEADING_WIDTH,
138
+                                 heading_pre, heading_post, heading_direction);
139
+        }
140
+    }
141
+
142
+    if (text_mode == lcd_mode_multiline) {
143
+        if ((text_pre.length() > 0) || (text_post.length() > 0)) {
144
+            lcd_scroll_multiline(text, LCD_TEXT_LINES, LCD_TEXT_WIDTH,
145
+                                 text_pre, text_post, text_direction);
146
+        }
147
+    } else if (text_mode == lcd_mode_menu) {
148
+        for (int i = 0; i < LCD_TEXT_LINES; i++) {
149
+            if ((menu_pre[i].length() > 0) || (menu_post[i].length() > 0)) {
150
+                lcd_scroll_multiline(text + i, 1, LCD_TEXT_WIDTH,
151
+                                     menu_pre[i], menu_post[i], menu_dir[i]);
152
+            }
153
+        }
154
+    }
155
+}
156
+
157
+int lcd_text_lines(void) {
158
+    return LCD_TEXT_LINES;
159
+}
160
+
20 161
 void lcd_init(void) {
21 162
 #ifdef USE_20X4_TEXT_LCD
22 163
     lcd.begin(20, 4);
@@ -28,30 +169,121 @@ void lcd_init(void) {
28 169
     lcd.print(F(FIRMWARE_VERSION));
29 170
     lcd.print(F("made by: xythobuz.de"));
30 171
 #endif // USE_20X4_TEXT_LCD
172
+
173
+#ifdef USE_FULL_GRAPHIC_LCD
174
+    lcd.begin();
175
+
176
+    lcd.firstPage();
177
+    do {
178
+        lcd.setFont(u8g2_font_luBS12_tr);
179
+        lcd.drawStr(0, 14 * 1, "Fuellfix v2");
180
+        lcd.drawStr(0, 14 * 2, "Initializing");
181
+
182
+        lcd.setFont(u8g2_font_t0_12b_tr);
183
+        lcd.drawStr(0, 14 * 2 + 8 + 12 * 1, "Software Version " FIRMWARE_VERSION);
184
+        lcd.drawStr(0, 14 * 2 + 8 + 12 * 2, "made by: xythobuz.de");
185
+    } while (lcd.nextPage());
186
+#endif // USE_FULL_GRAPHIC_LCD
187
+}
188
+
189
+void lcd_loop(void) {
190
+    if ((millis() - last_scroll_time) >= SCROLL_DELAY) {
191
+        last_scroll_time = millis();
192
+        lcd_scrolling();
193
+    }
194
+
195
+#ifdef USE_FULL_GRAPHIC_LCD
196
+    if (redraw) {
197
+        lcd.firstPage();
198
+        do {
199
+            lcd.setFont(LCD_HEADING_FONT);
200
+            for (int i = 0; i < LCD_HEADING_LINES; i++) {
201
+                lcd.drawStr(0, LCD_HEADING_HEIGHT * (i + 1), heading[i].c_str());
202
+            }
203
+
204
+            lcd.setFont(LCD_TEXT_FONT);
205
+            for (int i = 0; i < LCD_TEXT_LINES; i++) {
206
+                lcd.drawStr(0, LCD_HEADING_HEIGHT * LCD_HEADING_LINES + LCD_HEADING_TEXT_OFFSET + LCD_TEXT_HEIGHT * (i + 1), text[i].c_str());
207
+            }
208
+        } while (lcd.nextPage());
209
+        redraw = false;
210
+    }
211
+#endif // USE_FULL_GRAPHIC_LCD
31 212
 }
32 213
 
33 214
 void lcd_clear(void) {
34 215
     Serial.println();
35 216
 
217
+    text_mode = lcd_mode_none;
218
+
36 219
 #ifdef USE_20X4_TEXT_LCD
37 220
     lcd.clear();
38 221
 #endif // USE_20X4_TEXT_LCD
222
+
223
+#ifdef USE_FULL_GRAPHIC_LCD
224
+    for (int i = 0; i < LCD_HEADING_LINES; i++) {
225
+        heading[i] = "";
226
+    }
227
+    for (int i = 0; i < LCD_TEXT_LINES; i++) {
228
+        text[i] = "";
229
+    }
230
+    redraw = true;
231
+#endif // USE_FULL_GRAPHIC_LCD
39 232
 }
40 233
 
41
-void lcd_set_heading(const char *heading) {
42
-    Serial.println(heading);
234
+void lcd_set_heading(const char *h) {
235
+    Serial.println(h);
43 236
 
44 237
 #ifdef USE_20X4_TEXT_LCD
45 238
     lcd.setCursor(0, 0);
46
-    lcd.print(heading);
239
+    lcd.print(h);
47 240
 #endif // USE_20X4_TEXT_LCD
241
+
242
+#ifdef USE_FULL_GRAPHIC_LCD
243
+    heading[0] = h;
244
+    heading_pre = "";
245
+    heading_direction = 0;
246
+    lcd_shorten_multiline(heading, LCD_HEADING_LINES, LCD_HEADING_WIDTH, &heading_post);
247
+    redraw = true;
248
+#endif // USE_FULL_GRAPHIC_LCD
249
+}
250
+
251
+void lcd_set_text(const char *t) {
252
+    Serial.println(t);
253
+
254
+    text_mode = lcd_mode_multiline;
255
+
256
+#ifdef USE_20X4_TEXT_LCD
257
+    lcd.setCursor(0, LCD_HEADING_LINES);
258
+    lcd.print(t);
259
+#endif // USE_20X4_TEXT_LCD
260
+
261
+#ifdef USE_FULL_GRAPHIC_LCD
262
+    text[0] = t;
263
+    text_pre = "";
264
+    text_direction = 0;
265
+    lcd_shorten_multiline(text, LCD_TEXT_LINES, LCD_TEXT_WIDTH, &text_post);
266
+    redraw = true;
267
+#endif // USE_FULL_GRAPHIC_LCD
48 268
 }
49 269
 
50
-void lcd_set_text(const char *text) {
51
-    Serial.println(text);
270
+void lcd_set_menu_text(int line, const char *t) {
271
+    Serial.print(line);
272
+    Serial.print(": ");
273
+    Serial.println(t);
274
+
275
+    text_mode = lcd_mode_menu;
52 276
 
53 277
 #ifdef USE_20X4_TEXT_LCD
54
-    lcd.setCursor(0, 1);
55
-    lcd.print(text);
278
+    lcd.setCursor(0, LCD_HEADING_LINES + line);
279
+    lcd.print(t);
56 280
 #endif // USE_20X4_TEXT_LCD
281
+
282
+#ifdef USE_FULL_GRAPHIC_LCD
283
+    text[line] = t;
284
+    menu_pre[line] = "";
285
+    menu_dir[line] = 0;
286
+    lcd_shorten_multiline(text + line, 1, LCD_TEXT_WIDTH, menu_post + line);
287
+    redraw = true;
288
+#endif // USE_FULL_GRAPHIC_LCD
57 289
 }

+ 6
- 8
src/main.cpp View File

@@ -98,16 +98,16 @@ void setup() {
98 98
     Serial.println(F(" mm"));
99 99
 
100 100
     Serial.print(F("\t"));
101
-    Serial.print(E_STEPS_PER_MM);
102
-    Serial.println(F(" steps/mm"));
101
+    Serial.print(E_STEPS_PER_PERCENT);
102
+    Serial.println(F(" steps/percent"));
103 103
 
104 104
     Serial.print(F("\t"));
105 105
     Serial.print(E_MAX_SPEED);
106
-    Serial.println(F(" mm/s"));
106
+    Serial.println(F(" percent/s"));
107 107
 
108 108
     Serial.print(F("\t"));
109 109
     Serial.print(E_MAX_ACCEL);
110
-    Serial.println(F(" mm/s^2"));
110
+    Serial.println(F(" percent/s^2"));
111 111
 
112 112
     Serial.println();
113 113
 
@@ -136,10 +136,8 @@ void loop() {
136 136
     int click = encoder_click();
137 137
     int kill = kill_switch();
138 138
 
139
-    if (click) {
140
-        async_beep(ENCODER_CLICK_BEEP_TIME, ENCODER_CLICK_BEEP_FREQ);
141
-    }
142
-
143 139
     struct StateMachineInput smi(click, encoder_change(), kill, !still_running);
144 140
     states_run(smi);
141
+
142
+    lcd_loop();
145 143
 }

+ 223
- 13
src/statemachine.cpp View File

@@ -14,13 +14,17 @@ State::State(State *_parent) : parent(_parent), child(NULL), title("no title") {
14 14
 // --------------------------------------
15 15
 
16 16
 StateText::StateText(State *_parent) : State(_parent) {
17
-    heading = "";
18
-    text = "";
17
+    heading = "no heading";
18
+    text = "text missing";
19 19
     onEnterFunc = []() { };
20 20
     whenInFunc = [](StateMachineInput smi) {
21 21
         State *s = states_get();
22
-        if (smi.click && (s != NULL) && (s->getChild() != NULL)) {
23
-            states_go_to(s->getChild());
22
+        if (smi.click && (s != NULL)) {
23
+            if (s->getChild() != NULL) {
24
+                states_go_to(s->getChild());
25
+            } else if (s->getParent() != NULL) {
26
+                states_go_to(s->getParent());
27
+            }
24 28
         }
25 29
     };
26 30
 }
@@ -42,21 +46,27 @@ void StateText::whenIn(InFuncPtr func) {
42 46
 }
43 47
 
44 48
 void StateText::enterState(void) {
49
+    if (onEnterFunc != NULL) {
50
+        onEnterFunc();
51
+    }
52
+
45 53
     lcd_clear();
46 54
     lcd_set_heading(heading);
47 55
     lcd_set_text(text);
48
-
49
-    onEnterFunc();
50 56
 }
51 57
 
52 58
 void StateText::inState(struct StateMachineInput smi) {
53
-    whenInFunc(smi);
59
+    if (whenInFunc != NULL) {
60
+        whenInFunc(smi);
61
+    }
54 62
 }
55 63
 
56 64
 // --------------------------------------
57 65
 
58
-StateMenu::StateMenu(State *_parent) : State(_parent) {
66
+StateMenu::StateMenu(State *_parent, bool _show_parent) : State(_parent) {
67
+    show_parent = _show_parent;
59 68
     menuPos = 0;
69
+    menuOff = 0;
60 70
 }
61 71
 
62 72
 void StateMenu::setChild(State *_child) {
@@ -67,21 +77,84 @@ void StateMenu::addChild(State *_child, int pos) {
67 77
     if (pos < 0) {
68 78
         setChild(_child);
69 79
     } else {
70
-        // TODO insert child at pos in children
80
+        array_insert_at_pos(&children, _child, pos);
71 81
     }
72 82
 }
73 83
 
74 84
 void StateMenu::enterState(void) {
75
-    menuPos = 0;
85
+    display();
86
+}
87
+
88
+void StateMenu::display(void) {
89
+    lcd_clear();
90
+    lcd_set_heading(getTitle());
91
+
92
+    int size = children.size();
93
+    if (show_parent) {
94
+        size++;
95
+    }
96
+
97
+    for (int i = menuOff; (i < menuOff + lcd_text_lines()) && (i < size); i++) {
98
+        String s = "";
99
+        if (i == menuPos) {
100
+            s += "> ";
101
+        } else {
102
+            s += "  ";
103
+        }
104
+        if (i == children.size()) {
105
+            s += getParent()->getTitle();
106
+        } else {
107
+            s += children.at(i)->getTitle();
108
+        }
109
+        lcd_set_menu_text(i - menuOff, s.c_str());
110
+    }
76 111
 }
77 112
 
78 113
 void StateMenu::inState(struct StateMachineInput smi) {
114
+    int size = children.size();
115
+    if (show_parent) {
116
+        size++;
117
+    }
118
+
119
+    if (smi.encoder != 0) {
120
+        menuPos -= smi.encoder;
121
+
122
+        while (menuPos < 0) {
123
+            menuPos += size;
124
+        }
125
+
126
+        while (menuPos >= size) {
127
+            menuPos -= size;
128
+        }
79 129
 
130
+        while (menuPos < menuOff) {
131
+            menuOff--;
132
+        }
133
+
134
+        while (menuPos >= (menuOff + lcd_text_lines())) {
135
+            menuOff++;
136
+        }
137
+
138
+        display();
139
+    }
140
+
141
+    if (smi.click) {
142
+        if (menuPos == children.size()) {
143
+            menuPos = 0;
144
+            menuOff = 0;
145
+            states_go_to(getParent());
146
+        } else {
147
+            states_go_to(children.at(menuPos));
148
+        }
149
+    }
80 150
 }
81 151
 
82 152
 // --------------------------------------
83 153
 
84
-StateDynamicMenu::StateDynamicMenu(State *_parent = NULL) : State(_parent) { }
154
+StateDynamicMenu::StateDynamicMenu(State *_parent) : State(_parent) {
155
+    menuPos = 0;
156
+    menuOff = 0;
157
+}
85 158
 
86 159
 void StateDynamicMenu::dataCount(CountFuncPtr count) {
87 160
     countFunc = count;
@@ -96,20 +169,157 @@ void StateDynamicMenu::dataCall(CallFuncPtr call) {
96 169
 }
97 170
 
98 171
 void StateDynamicMenu::display(void) {
172
+    lcd_clear();
173
+    lcd_set_heading(getTitle());
99 174
 
175
+    for (int i = menuOff; (i < menuOff + lcd_text_lines()) && (i < count + 1); i++) {
176
+        String s = "";
177
+        if (i == menuPos) {
178
+            s += "> ";
179
+        } else {
180
+            s += "  ";
181
+        }
182
+        if (i == count) {
183
+            s += getParent()->getTitle();
184
+        } else {
185
+            s += contents.at(i);
186
+        }
187
+        lcd_set_menu_text(i - menuOff, s.c_str());
188
+    }
100 189
 }
101 190
 
102 191
 void StateDynamicMenu::enterState(void) {
103 192
     // cache all entries on entering state
104
-    count = countFunc();
193
+    if (countFunc != NULL) {
194
+        count = countFunc();
195
+    } else {
196
+        count = 0;
197
+    }
105 198
     contents.clear();
106 199
     for (int i = 0; i < count; i++) {
107
-        contents.push_back(getFunc(i));
200
+        if (getFunc != NULL) {
201
+            contents.push_back(getFunc(i));
202
+        } else {
203
+            contents.push_back("no get func");
204
+        }
108 205
     }
109 206
 
110 207
     display();
111 208
 }
112 209
 
113 210
 void StateDynamicMenu::inState(StateMachineInput smi) {
211
+    if (smi.encoder != 0) {
212
+        menuPos -= smi.encoder;
213
+
214
+        while (menuPos < 0) {
215
+            menuPos += count + 1;
216
+        }
217
+
218
+        while (menuPos >= count + 1) {
219
+            menuPos -= count + 1;
220
+        }
221
+
222
+        while (menuPos < menuOff) {
223
+            menuOff--;
224
+        }
225
+
226
+        while (menuPos >= (menuOff + lcd_text_lines())) {
227
+            menuOff++;
228
+        }
229
+
230
+        display();
231
+    }
232
+
233
+    if (smi.click) {
234
+        if (menuPos == count) {
235
+            menuPos = 0;
236
+            menuOff = 0;
237
+            states_go_to(getParent());
238
+        } else {
239
+            if (callFunc != NULL) {
240
+                callFunc(menuPos);
241
+            }
242
+        }
243
+    }
244
+}
245
+
246
+// --------------------------------------
247
+
248
+template <typename T>
249
+StateValue<T>::StateValue(State *_parent, T &_value, T _min, T _max) : State(_parent), value(_value) {
250
+    min = _min;
251
+    max = _max;
252
+    updateFunc = NULL;
253
+}
254
+
255
+template <typename T>
256
+void StateValue<T>::onUpdate(UpdateFuncPtr func) {
257
+    updateFunc = func;
258
+}
259
+
260
+template <typename T>
261
+void StateValue<T>::display(void) {
262
+    String s = String(min) + " .. " + String(value) + " .. " + String(max);
263
+    lcd_set_text(s.c_str());
264
+}
265
+
266
+template <typename T>
267
+void StateValue<T>::enterState(void) {
268
+    lcd_clear();
269
+    lcd_set_heading(getTitle());
270
+
271
+    display();
272
+}
273
+
274
+template <typename T>
275
+void StateValue<T>::inState(StateMachineInput smi) {
276
+    if (smi.encoder != 0) {
277
+        value -= smi.encoder;
278
+        if (value < min) {
279
+            value = min;
280
+        }
281
+        if (value > max) {
282
+            value = max;
283
+        }
284
+        display();
285
+    }
286
+    if (smi.click) {
287
+        if (updateFunc != NULL) {
288
+            updateFunc(value);
289
+        }
290
+        states_go_to(getParent());
291
+    }
292
+}
293
+
294
+template class StateValue<float>;
295
+
296
+// --------------------------------------
297
+
298
+template <typename T, size_t N>
299
+void array_print(Array<T, N> *arr) {
300
+    Serial.print("Array length: ");
301
+    Serial.print(arr->size());
302
+    Serial.println(" contents:");
303
+    for (int i = 0; i < arr->size(); i++) {
304
+        Serial.print(i);
305
+        Serial.print(": ");
306
+        Serial.println(arr->at(i)->getTitle());
307
+    }
308
+}
309
+
310
+template <typename T, size_t N>
311
+void array_insert_at_pos(Array<T, N> *arr, T value, size_t pos) {
312
+    // make additional space
313
+    arr->push_back(value);
314
+
315
+    if ((pos >= arr->max_size()) || (pos >= arr->size())) {
316
+        // we can not shift it to the given position
317
+        return;
318
+    }
319
+
320
+    for (int i = arr->size() - 2; i >= pos; i--) {
321
+        arr->at(i + 1) = arr->at(i);
322
+    }
114 323
 
324
+    arr->at(pos) = value;
115 325
 }

+ 141
- 14
src/states.cpp View File

@@ -13,43 +13,58 @@
13 13
 
14 14
 StateText sm_ask_homing = StateText();
15 15
 StateText sm_do_homing = StateText(&sm_ask_homing);
16
-StateMenu sm_menu = StateMenu(&sm_do_homing);
16
+StateMenu sm_menu = StateMenu(&sm_do_homing, false);
17 17
 
18 18
 StateMenu sm_auto = StateMenu(&sm_menu);
19 19
 StateDynamicMenu sm_presets = StateDynamicMenu(&sm_auto);
20
-StateDynamicMenu sm_new_preset = StateDynamicMenu(&sm_auto);
20
+StateText sm_new_preset = StateText(&sm_auto);
21 21
 StateDynamicMenu sm_mod_preset = StateDynamicMenu(&sm_auto);
22 22
 StateDynamicMenu sm_del_preset = StateDynamicMenu(&sm_auto);
23 23
 
24
-StateMenu sm_config = StateMenu(&sm_menu);
24
+StateMenu sm_move = StateMenu(&sm_menu);
25
+StateText sm_move_x = StateText(&sm_move);
26
+StateText sm_move_y = StateText(&sm_move);
27
+StateText sm_move_z = StateText(&sm_move);
28
+StateText sm_move_e = StateText(&sm_move);
25 29
 
30
+StateMenu sm_config = StateMenu(&sm_menu);
31
+StateText sm_conf_load = StateText(&sm_config);
32
+StateText sm_conf_save = StateText(&sm_config);
33
+StateValue<float> sm_conf_speed_xy = StateValue<float>(&sm_config, data_options()->speed_x, 1.0, XY_MAX_SPEED);
34
+StateValue<float> sm_conf_speed_z = StateValue<float>(&sm_config, data_options()->speed_z, 1.0, Z_MAX_SPEED);
35
+StateValue<float> sm_conf_speed_e = StateValue<float>(&sm_config, data_options()->speed_e, 1.0, E_MAX_SPEED);
36
+StateValue<float> sm_conf_accel_xy = StateValue<float>(&sm_config, data_options()->accel_x, 1.0, XY_MAX_ACCEL);
37
+StateValue<float> sm_conf_accel_z = StateValue<float>(&sm_config, data_options()->accel_z, 1.0, Z_MAX_ACCEL);
38
+StateValue<float> sm_conf_accel_e = StateValue<float>(&sm_config, data_options()->accel_e, 1.0, E_MAX_ACCEL);
26 39
 
27 40
 // --------------------------------------
28 41
 
29 42
 State *current_state = NULL;
43
+String strbuf;
30 44
 
31 45
 void states_init(void) {
32 46
     // ----------------------------------
33 47
 
48
+    sm_ask_homing.setTitle("Ask for homing");
34 49
     sm_ask_homing.setHeading("Homing Required!");
35 50
     sm_ask_homing.setText("Click to home all four axes.");
36 51
 
37 52
     // ----------------------------------
38 53
 
39 54
     sm_do_homing.setTitle("Home all axes");
40
-    sm_do_homing.setHeading("Homing");
55
+    sm_do_homing.setHeading("Homing...");
41 56
 
42 57
     sm_do_homing.onEnter([]() {
43
-        steppers_start_homing();
58
+        //steppers_start_homing();
44 59
     });
45 60
 
46 61
     sm_do_homing.whenIn([](StateMachineInput smi) {
47
-        if (smi.motors_done) {
48
-            if (steppers_homed()) {
49
-                async_beep(100, 2000);
62
+        //if (smi.motors_done) {
63
+        //    if (steppers_homed()) {
64
+                async_beep(HOMING_BEEP_TIME, HOMING_BEEP_FREQ);
50 65
                 states_go_to(&sm_menu);
51
-            }
52
-        }
66
+        //    }
67
+        //}
53 68
 
54 69
         // TODO update text with current axis
55 70
     });
@@ -61,10 +76,18 @@ void states_init(void) {
61 76
 
62 77
     // ----------------------------------
63 78
 
79
+    sm_move.setTitle("Move Axis");
80
+
81
+    sm_move_x.setTitle("X Axis");
82
+    sm_move_y.setTitle("Y Axis");
83
+    sm_move_z.setTitle("Z Axis");
84
+    sm_move_e.setTitle("E Axis");
85
+
86
+    // ----------------------------------
87
+
64 88
     sm_auto.setTitle("Filling Menu");
65
-    sm_auto.setChild(&sm_menu);
66 89
 
67
-    sm_presets.setTitle("Presets");
90
+    sm_presets.setTitle("Use Preset");
68 91
     sm_presets.dataCount([]() {
69 92
         return (int)data_preset_count();
70 93
     });
@@ -73,16 +96,108 @@ void states_init(void) {
73 96
         // dynamically. need to have a name stored
74 97
         // somewhere, in data/eeprom, for each preset
75 98
         // that we can pass here
99
+        return "foo";
100
+    });
101
+
102
+    sm_new_preset.setTitle("Add new Preset");
103
+    sm_new_preset.setHeading("Add new Preset");
104
+    sm_new_preset.onEnter([]() {
105
+        struct data_config_preset preset;
106
+        if (!data_preset_add(preset)) {
107
+            strbuf = String(data_eeprom_error()) + " Error adding preset!";
108
+            sm_new_preset.setText(strbuf.c_str());
109
+        } else {
110
+            strbuf = "Preset " + String(data_preset_count()) + " has been added!";
111
+            sm_new_preset.setText(strbuf.c_str());
112
+        }
76 113
     });
77 114
 
78
-    sm_new_preset.setTitle("New Preset");
79 115
     sm_mod_preset.setTitle("Modify Preset");
116
+    sm_mod_preset.dataCount([]() {
117
+        return (int)data_preset_count();
118
+    });
119
+    sm_mod_preset.dataGet([](int i) {
120
+        // TODO can not build a name string here
121
+        // dynamically. need to have a name stored
122
+        // somewhere, in data/eeprom, for each preset
123
+        // that we can pass here
124
+        return "foo";
125
+    });
126
+
80 127
     sm_del_preset.setTitle("Delete Preset");
128
+    sm_del_preset.dataCount([]() {
129
+        return (int)data_preset_count();
130
+    });
131
+    sm_del_preset.dataGet([](int i) {
132
+        // TODO can not build a name string here
133
+        // dynamically. need to have a name stored
134
+        // somewhere, in data/eeprom, for each preset
135
+        // that we can pass here
136
+        return "foo";
137
+    });
81 138
 
82 139
     // ----------------------------------
83 140
 
84 141
     sm_config.setTitle("Configuration");
85
-    sm_auto.setChild(&sm_menu);
142
+
143
+    sm_conf_load.setTitle("Load from EEPROM");
144
+    sm_conf_load.setHeading("Load from EEPROM");
145
+    sm_conf_load.onEnter([]() {
146
+        if (!data_eeprom_read()) {
147
+            strbuf = String(data_eeprom_error()) + " Error reading configuration!";
148
+            sm_conf_load.setText(strbuf.c_str());
149
+        } else {
150
+            sm_conf_load.setText("Configuration read successful!");
151
+
152
+            steppers_set_speed_x(data_options()->speed_x);
153
+            steppers_set_accel_x(data_options()->accel_x);
154
+            steppers_set_speed_y(data_options()->speed_y);
155
+            steppers_set_accel_y(data_options()->accel_y);
156
+            steppers_set_speed_z(data_options()->speed_z);
157
+            steppers_set_accel_z(data_options()->accel_z);
158
+            steppers_set_speed_e(data_options()->speed_e);
159
+            steppers_set_accel_e(data_options()->accel_e);
160
+        }
161
+    });
162
+
163
+    sm_conf_save.setTitle("Store to EEPROM");
164
+    sm_conf_save.setHeading("Store to EEPROM");
165
+    sm_conf_save.setText("Configuration written to EEPROM!");
166
+    sm_conf_save.onEnter([]() {
167
+        data_eeprom_write();
168
+    });
169
+
170
+    sm_conf_speed_xy.setTitle("XY Speed");
171
+    sm_conf_speed_xy.onUpdate([](float v) {
172
+        steppers_set_speed_x(v);
173
+        steppers_set_speed_y(v);
174
+    });
175
+
176
+    sm_conf_speed_z.setTitle("Z Speed");
177
+    sm_conf_speed_z.onUpdate([](float v) {
178
+        steppers_set_speed_z(v);
179
+    });
180
+
181
+    sm_conf_speed_e.setTitle("E Speed");
182
+    sm_conf_speed_e.onUpdate([](float v) {
183
+        steppers_set_speed_e(v);
184
+    });
185
+
186
+    sm_conf_accel_xy.setTitle("XY Acceleration");
187
+    sm_conf_accel_xy.onUpdate([](float v) {
188
+        steppers_set_accel_x(v);
189
+        steppers_set_accel_y(v);
190
+    });
191
+
192
+    sm_conf_accel_z.setTitle("Z Acceleration");
193
+    sm_conf_accel_z.onUpdate([](float v) {
194
+        steppers_set_accel_z(v);
195
+    });
196
+
197
+    sm_conf_accel_e.setTitle("E Acceleration");
198
+    sm_conf_accel_e.onUpdate([](float v) {
199
+        steppers_set_accel_e(v);
200
+    });
86 201
 
87 202
     // ----------------------------------
88 203
 
@@ -90,6 +205,18 @@ void states_init(void) {
90 205
 }
91 206
 
92 207
 void states_run(StateMachineInput smi) {
208
+    if (smi.click) {
209
+        async_beep(ENCODER_CLICK_BEEP_TIME, ENCODER_CLICK_BEEP_FREQ);
210
+    }
211
+
212
+    if (smi.kill) {
213
+        steppers_kill();
214
+        Serial.println("Kill button pressed!");
215
+        blocking_beep(KILL_BEEP_TIME, KILL_BEEP_FREQ, KILL_BEEP_REPEAT - 1);
216
+        states_go_to(&sm_ask_homing);
217
+        return;
218
+    }
219
+
93 220
     if (current_state != NULL) {
94 221
         current_state->inState(smi);
95 222
     }

+ 119
- 17
src/steppers.cpp View File

@@ -4,6 +4,7 @@
4 4
 #include "config.h"
5 5
 #include "config_pins.h"
6 6
 #include "lcd.h"
7
+#include "data.h"
7 8
 #include "steppers.h"
8 9
 
9 10
 static AccelStepper stepper_x(AccelStepper::DRIVER, X_STEP_PIN, X_DIR_PIN, 0, 0, false);
@@ -33,10 +34,10 @@ static stepper_states state = step_disabled;
33 34
 static unsigned long steppers_home_move_start_time = 0;
34 35
 
35 36
 void steppers_init(void) {
36
-    pinMode(X_ENDSTOP_PIN, INPUT);
37
-    pinMode(Y_ENDSTOP_PIN, INPUT);
38
-    pinMode(Z_ENDSTOP_PIN, INPUT);
39
-    pinMode(E_ENDSTOP_PIN, INPUT);
37
+    pinMode(X_ENDSTOP_PIN, INPUT_PULLUP);
38
+    pinMode(Y_ENDSTOP_PIN, INPUT_PULLUP);
39
+    pinMode(Z_ENDSTOP_PIN, INPUT_PULLUP);
40
+    pinMode(E_ENDSTOP_PIN, INPUT_PULLUP);
40 41
 
41 42
     pinMode(X_ENABLE_PIN, OUTPUT);
42 43
     pinMode(X_STEP_PIN, OUTPUT);
@@ -53,19 +54,20 @@ void steppers_init(void) {
53 54
 
54 55
     stepper_x.setEnablePin(X_ENABLE_PIN);
55 56
     stepper_x.setMaxSpeed(XY_MAX_SPEED * XY_STEPS_PER_MM);
56
-    stepper_x.setAcceleration(XY_MAX_ACCEL * XY_STEPS_PER_MM);
57
+    steppers_set_speed_x(data_options()->speed_x);
58
+    steppers_set_accel_x(data_options()->accel_x);
57 59
 
58 60
     stepper_y.setEnablePin(Y_ENABLE_PIN);
59
-    stepper_y.setMaxSpeed(XY_MAX_SPEED * XY_STEPS_PER_MM);
60
-    stepper_y.setAcceleration(XY_MAX_ACCEL * XY_STEPS_PER_MM);
61
+    steppers_set_speed_y(data_options()->speed_y);
62
+    steppers_set_accel_y(data_options()->accel_y);
61 63
 
62 64
     stepper_z.setEnablePin(Z_ENABLE_PIN);
63
-    stepper_z.setMaxSpeed(Z_MAX_SPEED * Z_STEPS_PER_MM);
64
-    stepper_z.setAcceleration(Z_MAX_ACCEL * Z_STEPS_PER_MM);
65
+    steppers_set_speed_z(data_options()->speed_z);
66
+    steppers_set_accel_z(data_options()->accel_z);
65 67
 
66 68
     stepper_e.setEnablePin(E0_ENABLE_PIN);
67
-    stepper_e.setMaxSpeed(E_MAX_SPEED * E_STEPS_PER_MM);
68
-    stepper_e.setAcceleration(E_MAX_ACCEL * E_STEPS_PER_MM);
69
+    steppers_set_speed_e(data_options()->speed_e);
70
+    steppers_set_accel_e(data_options()->accel_e);
69 71
 }
70 72
 
71 73
 static void steppers_initiate_home(int axis, int phase) {
@@ -111,13 +113,13 @@ static void steppers_initiate_home(int axis, int phase) {
111 113
         // e
112 114
         if (phase == 0) {
113 115
             state = step_homing_e_fast;
114
-            stepper_e.setSpeed(E_HOMING_DIR * E_AXIS_MOVEMENT_DIR * E_FAST_HOME_SPEED * E_STEPS_PER_MM);
116
+            stepper_e.setSpeed(E_HOMING_DIR * E_AXIS_MOVEMENT_DIR * E_FAST_HOME_SPEED * E_STEPS_PER_PERCENT);
115 117
         } else if (phase == 1) {
116 118
             state = step_homing_e_back;
117
-            stepper_e.setSpeed(-1.0 * E_HOMING_DIR * E_AXIS_MOVEMENT_DIR * E_FAST_HOME_SPEED * E_STEPS_PER_MM);
119
+            stepper_e.setSpeed(-1.0 * E_HOMING_DIR * E_AXIS_MOVEMENT_DIR * E_FAST_HOME_SPEED * E_STEPS_PER_PERCENT);
118 120
         } else if (phase == 2) {
119 121
             state = step_homing_e_slow;
120
-            stepper_e.setSpeed(E_HOMING_DIR * E_AXIS_MOVEMENT_DIR * E_SLOW_HOME_SPEED * E_STEPS_PER_MM);
122
+            stepper_e.setSpeed(E_HOMING_DIR * E_AXIS_MOVEMENT_DIR * E_SLOW_HOME_SPEED * E_STEPS_PER_PERCENT);
121 123
         }
122 124
     } else {
123 125
         Serial.println(F("home_init error: invalid axis"));
@@ -155,6 +157,7 @@ bool steppers_run(void) {
155 157
         }
156 158
     } else if (state == step_homing_x_slow) {
157 159
         if (steppers_home_switch(0)) {
160
+            stepper_x.setSpeed(0);
158 161
             steppers_initiate_home(1, 0);
159 162
         } else {
160 163
             stepper_x.runSpeed();
@@ -174,6 +177,7 @@ bool steppers_run(void) {
174 177
         }
175 178
     } else if (state == step_homing_y_slow) {
176 179
         if (steppers_home_switch(1)) {
180
+            stepper_y.setSpeed(0);
177 181
             steppers_initiate_home(3, 0);
178 182
         } else {
179 183
             stepper_y.runSpeed();
@@ -193,6 +197,7 @@ bool steppers_run(void) {
193 197
         }
194 198
     } else if (state == step_homing_z_slow) {
195 199
         if (steppers_home_switch(2)) {
200
+            stepper_z.setSpeed(0);
196 201
             steppers_initiate_home(0, 0);
197 202
         } else {
198 203
             stepper_z.runSpeed();
@@ -212,10 +217,11 @@ bool steppers_run(void) {
212 217
         }
213 218
     } else if (state == step_homing_e_slow) {
214 219
         if (steppers_home_switch(3)) {
220
+            stepper_e.setSpeed(0);
215 221
             state = step_homed;
216 222
             return false;
217 223
         } else {
218
-            stepper_z.runSpeed();
224
+            stepper_e.runSpeed();
219 225
         }
220 226
     } else if (state != step_disabled) {
221 227
         for (int i = 0; i < 4; i++) {
@@ -332,7 +338,9 @@ int steppers_move_e(long pos) {
332 338
     Serial.print(F("Moving E to "));
333 339
     Serial.print(pos);
334 340
     Serial.print(F(" mm ("));
335
-    Serial.print(pos * E_STEPS_PER_MM * E_AXIS_MOVEMENT_DIR);
341
+    Serial.print(E_MM_TO_PERCENT(pos));
342
+    Serial.println(F("% = "));
343
+    Serial.print(E_MM_TO_PERCENT(pos) * E_STEPS_PER_PERCENT * E_AXIS_MOVEMENT_DIR);
336 344
     Serial.println(F(" steps)"));
337 345
 
338 346
     if (pos < E_AXIS_MIN) {
@@ -345,5 +353,99 @@ int steppers_move_e(long pos) {
345 353
         return -1;
346 354
     }
347 355
 
348
-    return steppers_move_axis(stepper_e, pos * E_STEPS_PER_MM * E_AXIS_MOVEMENT_DIR);
356
+    return steppers_move_axis(stepper_e, E_MM_TO_PERCENT(pos) * E_STEPS_PER_PERCENT * E_AXIS_MOVEMENT_DIR);
357
+}
358
+
359
+void steppers_kill(void) {
360
+    stepper_x.setCurrentPosition(0);
361
+    stepper_y.setCurrentPosition(0);
362
+    stepper_z.setCurrentPosition(0);
363
+    stepper_e.setCurrentPosition(0);
364
+
365
+    stepper_x.disableOutputs();
366
+    stepper_y.disableOutputs();
367
+    stepper_z.disableOutputs();
368
+    stepper_e.disableOutputs();
369
+
370
+    state = step_not_homed;
371
+}
372
+
373
+void steppers_set_speed_x(float speed) {
374
+    if (speed < 0.0) {
375
+        speed = 0.0;
376
+    }
377
+    if (speed > XY_MAX_SPEED) {
378
+        speed = XY_MAX_SPEED;
379
+    }
380
+    stepper_x.setMaxSpeed(speed * XY_STEPS_PER_MM);
381
+}
382
+
383
+void steppers_set_speed_y(float speed) {
384
+    if (speed < 0.0) {
385
+        speed = 0.0;
386
+    }
387
+    if (speed > XY_MAX_SPEED) {
388
+        speed = XY_MAX_SPEED;
389
+    }
390
+    stepper_y.setMaxSpeed(speed * XY_STEPS_PER_MM);
391
+}
392
+
393
+void steppers_set_speed_z(float speed) {
394
+    if (speed < 0.0) {
395
+        speed = 0.0;
396
+    }
397
+    if (speed > Z_MAX_SPEED) {
398
+        speed = Z_MAX_SPEED;
399
+    }
400
+    stepper_z.setMaxSpeed(speed * Z_STEPS_PER_MM);
401
+}
402
+
403
+void steppers_set_speed_e(float speed) {
404
+    if (speed < 0.0) {
405
+        speed = 0.0;
406
+    }
407
+    if (speed > E_MAX_SPEED) {
408
+        speed = E_MAX_SPEED;
409
+    }
410
+    stepper_e.setMaxSpeed(speed * E_STEPS_PER_PERCENT);
411
+}
412
+
413
+void steppers_set_accel_x(float accel) {
414
+    if (accel < 0.0) {
415
+        accel = 0.0;
416
+    }
417
+    if (accel > XY_MAX_ACCEL) {
418
+        accel = XY_MAX_ACCEL;
419
+    }
420
+    stepper_x.setAcceleration(accel * XY_STEPS_PER_MM);
421
+}
422
+
423
+void steppers_set_accel_y(float accel) {
424
+    if (accel < 0.0) {
425
+        accel = 0.0;
426
+    }
427
+    if (accel > XY_MAX_ACCEL) {
428
+        accel = XY_MAX_ACCEL;
429
+    }
430
+    stepper_y.setAcceleration(accel * XY_STEPS_PER_MM);
431
+}
432
+
433
+void steppers_set_accel_z(float accel) {
434
+    if (accel < 0.0) {
435
+        accel = 0.0;
436
+    }
437
+    if (accel > Z_MAX_ACCEL) {
438
+        accel = Z_MAX_ACCEL;
439
+    }
440
+    stepper_z.setAcceleration(accel * Z_STEPS_PER_MM);
441
+}
442
+
443
+void steppers_set_accel_e(float accel) {
444
+    if (accel < 0.0) {
445
+        accel = 0.0;
446
+    }
447
+    if (accel > E_MAX_ACCEL) {
448
+        accel = E_MAX_ACCEL;
449
+    }
450
+    stepper_e.setAcceleration(accel * E_STEPS_PER_PERCENT);
349 451
 }

Loading…
Cancel
Save