2 Commits

Author SHA1 Message Date
  Thomas Buck 924921ebdd whole lot of firmware work. xy table now basically usable. 2 years ago
  Thomas Buck 0b1d191b71 added simple feet and spacer for plate to hardware design 2 years ago
19 changed files with 1273 additions and 805 deletions
  1. 19
    2
      hardware/config.scad
  2. 74
    12
      hardware/table.scad
  3. 3
    1
      include/common.h
  4. 20
    6
      include/config.h
  5. 8
    8
      include/config_pins.h
  6. 22
    5
      include/data.h
  7. 9
    2
      include/encoder.h
  8. 25
    45
      include/statemachine.h
  9. 1
    1
      include/states.h
  10. 2
    1
      include/steppers.h
  11. 15
    2
      src/common.cpp
  12. 33
    17
      src/data.cpp
  13. 32
    28
      src/encoder.cpp
  14. 74
    17
      src/main.cpp
  15. 225
    0
      src/sm_menu.cpp
  16. 239
    0
      src/sm_value.cpp
  17. 8
    498
      src/statemachine.cpp
  18. 275
    32
      src/states.cpp
  19. 189
    128
      src/steppers.cpp

+ 19
- 2
hardware/config.scad View File

247
 
247
 
248
 left_support_len = 200;
248
 left_support_len = 200;
249
 left_support_off = 50;
249
 left_support_off = 50;
250
-right_support_len = 200;
251
-right_support_off = 50;
250
+right_support_len = left_support_len;
251
+right_support_off = left_support_off;
252
 
252
 
253
 echo("distance between bottom support rails", x_axis_rail_len - left_support_off - right_support_off - 40, -left_support_off, -right_support_off);
253
 echo("distance between bottom support rails", x_axis_rail_len - left_support_off - right_support_off - 40, -left_support_off, -right_support_off);
254
 
254
 
255
+bottom_support_len = 500;
256
+bottom_support_off = 80;
257
+
258
+use_double_supports = false;
259
+
255
 endstop_pcb_width = 16.0;
260
 endstop_pcb_width = 16.0;
256
 endstop_pcb_height = 40.0;
261
 endstop_pcb_height = 40.0;
257
 endstop_pcb_depth = 1.6;
262
 endstop_pcb_depth = 1.6;
272
 endstop_pcb_mount_off_w = endstop_mount_slot_length;
277
 endstop_pcb_mount_off_w = endstop_mount_slot_length;
273
 
278
 
274
 use_endstop_mount_v2 = false;
279
 use_endstop_mount_v2 = false;
280
+
281
+foot_screw_dia = 5.3;
282
+foot_screw_head_dia = 10.0;
283
+foot_screw_head_height = 7.0;
284
+foot_nut_base_dia = foot_screw_head_dia;
285
+foot_dia_add = 10.0;
286
+foot_dia = max(foot_screw_dia, foot_screw_head_dia) + foot_dia_add;
287
+
288
+carriage_spacer_height = 5;
289
+carriage_spacer_cut = 4;
290
+carriage_spacer_cut_x = y_carriage_x / 2 - carriage_spacer_cut;
291
+carriage_spacer_cut_y = y_carriage_y / 2 - carriage_spacer_cut;

+ 74
- 12
hardware/table.scad View File

432
     }
432
     }
433
 }
433
 }
434
 
434
 
435
+module carriage_spacer() {
436
+    difference() {
437
+        cube([y_carriage_x, y_carriage_y, carriage_spacer_height]);
438
+        
439
+        translate([y_carriage_x / 2, y_carriage_y / 2, 0])
440
+        plate_holes(carriage_spacer_height);
441
+        
442
+        translate([carriage_spacer_cut_x / 2 * sqrt(2) + y_carriage_x / 2, -1, -1])
443
+        rotate([0, -90, 45])
444
+        prism(carriage_spacer_height + 2, carriage_spacer_cut_x, carriage_spacer_cut_x);
445
+        
446
+        translate([-carriage_spacer_cut_x / 2 * sqrt(2) + y_carriage_x / 2, y_carriage_y + 1, -1])
447
+        rotate([0, -90, 225])
448
+        prism(carriage_spacer_height + 2, carriage_spacer_cut_x, carriage_spacer_cut_x);
449
+        
450
+        translate([-1, y_carriage_y / 2 - carriage_spacer_cut_y / 2 * sqrt(2), -1])
451
+        rotate([0, -90, -45])
452
+        prism(carriage_spacer_height + 2, carriage_spacer_cut_y, carriage_spacer_cut_y);
453
+        
454
+        translate([y_carriage_x + 1, y_carriage_y / 2 + carriage_spacer_cut_y / 2 * sqrt(2), -1])
455
+        rotate([0, -90, -225])
456
+        prism(carriage_spacer_height + 2, carriage_spacer_cut_y, carriage_spacer_cut_y);
457
+    }
458
+}
459
+
435
 // also used as base for x-carriage
460
 // also used as base for x-carriage
436
 // axis = 0 --> all holes, usable for both
461
 // axis = 0 --> all holes, usable for both
437
 // axis = 1 --> holes for x-carriage
462
 // axis = 1 --> holes for x-carriage
505
 
530
 
506
 module y_axis() {
531
 module y_axis() {
507
     translate([y_carriage_x / 2, y_axis_animation_position, 20 + y_carriage_h + y_carriage_rail_dist])
532
     translate([y_carriage_x / 2, y_axis_animation_position, 20 + y_carriage_h + y_carriage_rail_dist])
508
-    rotate([0, 180, 0])
509
-    y_carriage(2);
533
+    rotate([0, 180, 0]) {
534
+        y_carriage(2);
535
+        
536
+        color("cyan")
537
+        translate([0, 0, -carriage_spacer_height - 0.01])
538
+        carriage_spacer();
539
+    }
510
     
540
     
511
     color("grey")
541
     color("grey")
512
     translate([-10, 0, 0])
542
     translate([-10, 0, 0])
594
     translate([0, -y_carriage_y / 2 - y_axis_animation_position, 0])
624
     translate([0, -y_carriage_y / 2 - y_axis_animation_position, 0])
595
     y_axis();
625
     y_axis();
596
     
626
     
597
-    %translate([-plate_x / 2, -plate_y / 2, 20 + y_carriage_h + y_carriage_rail_dist])
627
+    %translate([-plate_x / 2, -plate_y / 2, 20 + y_carriage_h + y_carriage_rail_dist + carriage_spacer_height])
598
     plate();
628
     plate();
599
 }
629
 }
600
 
630
 
606
     assembly_y_axis_plate();
636
     assembly_y_axis_plate();
607
 }
637
 }
608
 
638
 
609
-bottom_support_len = 500;
610
-bottom_support_off = 80;
611
-
612
-use_double_supports = false;
613
-
614
 module rail_foot() {
639
 module rail_foot() {
615
-    
640
+    difference() {
641
+        union() {
642
+            sphere(d = foot_dia);
643
+            
644
+            translate([0, 0, foot_dia / 2])
645
+            sphere(d = foot_nut_base_dia);
646
+        }
647
+        
648
+        translate([-foot_dia / 2 - 1, -foot_dia / 2 - 1, -foot_dia / 2 - 1])
649
+        cube([foot_dia + 2, foot_dia + 2, foot_dia / 2 + 1]);
650
+        
651
+        translate([-foot_nut_base_dia / 2 - 1, -foot_nut_base_dia / 2 - 1, foot_dia / 2])
652
+        cube([foot_nut_base_dia + 2, foot_nut_base_dia + 2, foot_nut_base_dia / 2 + 1]);
653
+        
654
+        translate([0, 0, -1])
655
+        cylinder(d = foot_screw_dia, h = foot_dia / 2 + 2);
656
+        
657
+        translate([0, 0, -1])
658
+        cylinder(d = foot_screw_head_dia, h = foot_screw_head_height + 1);
659
+    }
616
 }
660
 }
617
 
661
 
618
 module assembly() {
662
 module assembly() {
632
             translate([x_axis_rail_len - 20 - right_support_off, -right_support_len - 10, -20])
676
             translate([x_axis_rail_len - 20 - right_support_off, -right_support_len - 10, -20])
633
             rail_2020_y(right_support_len, "right support");
677
             rail_2020_y(right_support_len, "right support");
634
             
678
             
635
-            // TODO feet
679
+            for (i = [0, 1])
680
+            for (j = [1, -1])
681
+            translate([i * x_axis_rail_len - (i * 2 - 1) * (right_support_off + 10), j * (right_support_len - 10), -40 - 0]) {
682
+                %color("grey")
683
+                cylinder(d = 5.0, h = 25);
684
+                
685
+                %color("green")
686
+                rail_foot();
687
+            }
636
         } else {
688
         } else {
637
             color("grey")
689
             color("grey")
638
             translate([x_axis_rail_len / 2, 0, -40])
690
             translate([x_axis_rail_len / 2, 0, -40])
641
             translate([x_axis_rail_len / 2 - bottom_support_off, -bottom_support_len / 2, 0])
693
             translate([x_axis_rail_len / 2 - bottom_support_off, -bottom_support_len / 2, 0])
642
             rail_2020_y(bottom_support_len, "bottom supports");
694
             rail_2020_y(bottom_support_len, "bottom supports");
643
             
695
             
644
-            // TODO feet
696
+            for (i = [0, 1])
697
+            for (j = [1, -1])
698
+            translate([i * x_axis_rail_len - (i * 2 - 1) * (bottom_support_off - 10), j * (bottom_support_len / 2 - 40), -40 - 20]) {
699
+                %color("grey")
700
+                cylinder(d = 5.0, h = 25);
701
+                
702
+                %color("green")
703
+                rail_foot();
704
+            }
645
         }
705
         }
646
     }
706
     }
647
 }
707
 }
648
 
708
 
649
 module xy_table() {
709
 module xy_table() {
650
-    translate([-point_that_reaches_everywhere_x, -point_that_reaches_everywhere_y, -40 + -40 + (y_carriage_rail_dist + y_carriage_h) * -2 + -plate_z])
710
+    translate([-point_that_reaches_everywhere_x, -point_that_reaches_everywhere_y, -40 + -40 + (y_carriage_rail_dist + y_carriage_h) * -2 + -plate_z - carriage_spacer_height])
651
     assembly();
711
     assembly();
652
 }
712
 }
653
 
713
 
658
 //dispenser();
718
 //dispenser();
659
 //rail_2020_x(100);
719
 //rail_2020_x(100);
660
 //rail_wheel();
720
 //rail_wheel();
721
+//rail_foot();
661
 
722
 
662
 //motor_mount(1);
723
 //motor_mount(1);
663
 //motor_mount(2);
724
 //motor_mount(2);
677
 //y_carriage(1);
738
 //y_carriage(1);
678
 //y_carriage(2);
739
 //y_carriage(2);
679
 //x_carriage();
740
 //x_carriage();
741
+//carriage_spacer();
680
 
742
 
681
 //y_axis();
743
 //y_axis();
682
 //x_axis();
744
 //x_axis();

+ 3
- 1
include/common.h View File

3
 
3
 
4
 #define CLEAR_STORE_INTERRUPTS() uint8_t prev_int_reg = SREG; cli()
4
 #define CLEAR_STORE_INTERRUPTS() uint8_t prev_int_reg = SREG; cli()
5
 #define RESTORE_INTERRUPTS() SREG = prev_int_reg
5
 #define RESTORE_INTERRUPTS() SREG = prev_int_reg
6
+//#define CLEAR_STORE_INTERRUPTS() cli()
7
+//#define RESTORE_INTERRUPTS() sei()
6
 
8
 
7
 void async_beep(int time, int freq);
9
 void async_beep(int time, int freq);
8
 void blocking_beep(int time, int freq, int repeat = 0);
10
 void blocking_beep(int time, int freq, int repeat = 0);
9
-void common_run(unsigned long t);
11
+void common_run(void);
10
 
12
 
11
 #endif // _COMMON_H_
13
 #endif // _COMMON_H_

+ 20
- 6
include/config.h View File

24
  ********** Hardware Settings **********
24
  ********** Hardware Settings **********
25
  ***************************************/
25
  ***************************************/
26
 
26
 
27
+#define AXIS_COUNT 4
28
+#define X_AXIS 0
29
+#define Y_AXIS 1
30
+#define Z_AXIS 2
31
+#define E_AXIS 3
32
+
27
 // xy steps per mm
33
 // xy steps per mm
28
 #define XY_BELT_PITCH 2.0
34
 #define XY_BELT_PITCH 2.0
29
 #define XY_PULLEY_TEETH 40.0
35
 #define XY_PULLEY_TEETH 40.0
67
 #define E_MM_TO_PERCENT(x) ((acos((x * 2.0 / E_AXIS_MAX) - 1.0) - PI) * 100.0 / PI)
73
 #define E_MM_TO_PERCENT(x) ((acos((x * 2.0 / E_AXIS_MAX) - 1.0) - PI) * 100.0 / PI)
68
 
74
 
69
 // maximum speeds
75
 // maximum speeds
70
-#define XY_MAX_SPEED 50.0 // in mm/s
71
-#define Z_MAX_SPEED 20.0 // in mm/s
72
-#define E_MAX_SPEED 50.0 // in percent/s
76
+#define XY_MAX_SPEED 50.0 // in mm/s --> 50mm/s = 2000steps/s
77
+#define Z_MAX_SPEED 1.2 // in mm/s --> 20mm/s = 32000steps/s
78
+#define E_MAX_SPEED 30.0 // in percent/s --> 50%/s = 2400steps/s
73
 
79
 
74
 // homing speeds
80
 // homing speeds
75
 #define XY_FAST_HOME_SPEED 25.0 // in mm/s
81
 #define XY_FAST_HOME_SPEED 25.0 // in mm/s
100
 #define E_HOME_BACK_OFF_TIME (E_BACK_OFF_DISTANCE / E_FAST_HOME_SPEED * 1000)
106
 #define E_HOME_BACK_OFF_TIME (E_BACK_OFF_DISTANCE / E_FAST_HOME_SPEED * 1000)
101
 
107
 
102
 // epsilon around expected endstop position where we dont abort on hits
108
 // epsilon around expected endstop position where we dont abort on hits
103
-#define X_AXIS_EPSILON 20.0 // TODO
104
-#define Y_AXIS_EPSILON 20.0 // TODO
109
+// if you need to increase this value, try to reduce play in your axis
110
+#define X_AXIS_EPSILON 1.0
111
+#define Y_AXIS_EPSILON 1.0
105
 #define Z_AXIS_EPSILON 1.0
112
 #define Z_AXIS_EPSILON 1.0
106
 #define E_AXIS_EPSILON 1.0
113
 #define E_AXIS_EPSILON 1.0
107
 
114
 
108
-#define ENCODER_RPM_VALUE_FACTOR 10.0
115
+#define ENCODER_RPM_VALUE_FACTOR 2.0
116
+#define IDLE_TIMEOUT (5UL * 60UL * 1000UL) // ms, 0 to disable
117
+
118
+// TimerOne freq for steppers
119
+#define XY_MAX_HZ (XY_MAX_SPEED * XY_STEPS_PER_MM)
120
+#define Z_MAX_HZ (Z_MAX_SPEED * Z_STEPS_PER_MM)
121
+#define E_MAX_HZ (E_MAX_SPEED * E_STEPS_PER_PERCENT)
122
+#define MAX_SAMPLE_FREQ 2500
109
 
123
 
110
 #endif // _CONFIG_H_
124
 #endif // _CONFIG_H_

+ 8
- 8
include/config_pins.h View File

120
 #endif
120
 #endif
121
 
121
 
122
 #if (X_MIN_PIN == -1)
122
 #if (X_MIN_PIN == -1)
123
-#define X_HOMING_DIR 1.0
123
+#define X_HOMING_DIR 1
124
 #define X_ENDSTOP_PIN X_MAX_PIN
124
 #define X_ENDSTOP_PIN X_MAX_PIN
125
 #else
125
 #else
126
-#define X_HOMING_DIR -1.0
126
+#define X_HOMING_DIR -1
127
 #define X_ENDSTOP_PIN X_MIN_PIN
127
 #define X_ENDSTOP_PIN X_MIN_PIN
128
 #endif
128
 #endif
129
 
129
 
130
 #if (Y_MIN_PIN == -1)
130
 #if (Y_MIN_PIN == -1)
131
-#define Y_HOMING_DIR 1.0
131
+#define Y_HOMING_DIR 1
132
 #define Y_ENDSTOP_PIN Y_MAX_PIN
132
 #define Y_ENDSTOP_PIN Y_MAX_PIN
133
 #else
133
 #else
134
-#define Y_HOMING_DIR -1.0
134
+#define Y_HOMING_DIR -1
135
 #define Y_ENDSTOP_PIN Y_MIN_PIN
135
 #define Y_ENDSTOP_PIN Y_MIN_PIN
136
 #endif
136
 #endif
137
 
137
 
138
 #if (Z_MIN_PIN == -1)
138
 #if (Z_MIN_PIN == -1)
139
-#define Z_HOMING_DIR 1.0
139
+#define Z_HOMING_DIR 1
140
 #define Z_ENDSTOP_PIN Z_MAX_PIN
140
 #define Z_ENDSTOP_PIN Z_MAX_PIN
141
 #else
141
 #else
142
-#define Z_HOMING_DIR -1.0
142
+#define Z_HOMING_DIR -1
143
 #define Z_ENDSTOP_PIN Z_MIN_PIN
143
 #define Z_ENDSTOP_PIN Z_MIN_PIN
144
 #endif
144
 #endif
145
 
145
 
146
 #if (E_MIN_PIN == -1)
146
 #if (E_MIN_PIN == -1)
147
-#define E_HOMING_DIR 1.0
147
+#define E_HOMING_DIR 1
148
 #define E_ENDSTOP_PIN E_MAX_PIN
148
 #define E_ENDSTOP_PIN E_MAX_PIN
149
 #else
149
 #else
150
-#define E_HOMING_DIR -1.0
150
+#define E_HOMING_DIR -1
151
 #define E_ENDSTOP_PIN E_MIN_PIN
151
 #define E_ENDSTOP_PIN E_MIN_PIN
152
 #endif
152
 #endif
153
 
153
 

+ 22
- 5
include/data.h View File

1
 #ifndef _DATA_H_
1
 #ifndef _DATA_H_
2
 #define _DATA_H_
2
 #define _DATA_H_
3
 
3
 
4
-#define DATA_SCHEMA_VERSION 0
4
+#define DATA_SCHEMA_VERSION 1
5
 
5
 
6
 struct data_config_options {
6
 struct data_config_options {
7
+    // in mm/s (%/s for e)
7
     float speed_x, speed_y, speed_z, speed_e;
8
     float speed_x, speed_y, speed_z, speed_e;
9
+
10
+    // in mm/s^2 (%/s^2 for e)
8
     float accel_x, accel_y, accel_z, accel_e;
11
     float accel_x, accel_y, accel_z, accel_e;
9
 };
12
 };
10
 
13
 
11
 struct data_config_preset {
14
 struct data_config_preset {
15
+    // number of containers
12
     uint8_t count_x, count_y;
16
     uint8_t count_x, count_y;
13
-    float distance_x, distance_y;
14
-    float offset_x, offset_y;
15
-    float top_z, bottom_z;
16
-    float extrusion;
17
+
18
+    // distance between containers
19
+    float distance_x, distance_y; // in mm
20
+
21
+    // offset of first container
22
+    float offset_x, offset_y; // in mm
23
+
24
+    // height for moves between extrusions
25
+    float move_z; // in mm
26
+
27
+    // height while extruding
28
+    float bottom_z, top_z; // in mm
29
+
30
+    float extrusion_length; // in mm
31
+    float extrusion_bottom_wait; // in s
32
+    float extrusion_top_wait; // in s
17
 };
33
 };
18
 
34
 
19
 void data_init(void);
35
 void data_init(void);
36
+void data_clear(void);
20
 void data_eeprom_write(void);
37
 void data_eeprom_write(void);
21
 
38
 
22
 bool data_eeprom_read(void);
39
 bool data_eeprom_read(void);

+ 9
- 2
include/encoder.h View File

2
 #define _ENCODER_H_
2
 #define _ENCODER_H_
3
 
3
 
4
 void encoder_init(void);
4
 void encoder_init(void);
5
+
5
 void encoder_run(void);
6
 void encoder_run(void);
6
 
7
 
8
+bool encoder_click(void);
9
+bool kill_switch(void);
10
+
11
+// --------------------------------------
12
+
13
+void encoder_run_fast(void);
14
+
15
+// disable interrupts while reading these
7
 int encoder_change(void);
16
 int encoder_change(void);
8
 int encoder_rpm(void);
17
 int encoder_rpm(void);
9
-int encoder_click(void);
10
-int kill_switch(void);
11
 
18
 
12
 #endif // _ENCODER_H_
19
 #endif // _ENCODER_H_

+ 25
- 45
include/statemachine.h View File

5
 
5
 
6
 #define STATE_ARRAY_SIZE 42
6
 #define STATE_ARRAY_SIZE 42
7
 
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
-
14
 struct StateMachineInput {
8
 struct StateMachineInput {
15
-    StateMachineInput(int c, int e, int r, int k, int m)
16
-            : click(c), encoder(e), rpm(r), kill(k), motors_done(m) { };
17
-
18
-    int click;
9
+    StateMachineInput(bool c, int e, int r, bool k, bool *m, bool am)
10
+            : click(c), encoder(e), rpm(r), kill(k), all_motors_done(am) {
11
+        for (int i = 0; i < AXIS_COUNT; i++) {
12
+            motor_done[i] = m[i];
13
+        }
14
+    };
15
+
16
+    bool click;
19
     int encoder;
17
     int encoder;
20
     int rpm;
18
     int rpm;
21
-    int kill;
22
-    int motors_done;
19
+    bool kill;
20
+    bool motor_done[AXIS_COUNT];
21
+    bool all_motors_done;
23
 };
22
 };
24
 
23
 
25
 class State {
24
 class State {
26
 public:
25
 public:
26
+    typedef void(*EnterFuncPtr)(void);
27
+    typedef void(*InFuncPtr)(StateMachineInput smi);
28
+
27
     State(State *_parent = NULL);
29
     State(State *_parent = NULL);
28
     State *getParent(void) { return parent; }
30
     State *getParent(void) { return parent; }
29
 
31
 
33
     void setTitle(const char *_title) { title = _title; }
35
     void setTitle(const char *_title) { title = _title; }
34
     const char *getTitle(void) { return title; }
36
     const char *getTitle(void) { return title; }
35
 
37
 
36
-    virtual void enterState(void) = 0;
37
-    virtual void inState(StateMachineInput smi) = 0;
38
-
39
-private:
40
-    State *parent;
41
-    State *child;
42
-    const char *title;
43
-};
44
-
45
-class StateText : public State {
46
-public:
47
-    StateText(State *_parent = NULL);
48
-
49
-    void setHeading(const char *_heading);
50
-    void setText(const char *_text);
38
+    void setHeading(const char *_heading) { heading = _heading; }
39
+    const char *getHeading(void) { return heading; }
51
 
40
 
52
-    typedef void(*EnterFuncPtr)(void);
53
-    typedef void(*InFuncPtr)(StateMachineInput smi);
41
+    void setText(const char *_text) { text = _text; }
42
+    const char *getText(void) { return text; }
54
 
43
 
55
-    void onEnter(EnterFuncPtr func);
56
-    void whenIn(InFuncPtr func);
44
+    void onEnter(EnterFuncPtr func) { onEnterFunc = func; }
45
+    void whenIn(InFuncPtr func) { whenInFunc = func; }
57
 
46
 
58
     void updateText(void);
47
     void updateText(void);
59
 
48
 
60
     virtual void enterState(void);
49
     virtual void enterState(void);
61
     virtual void inState(StateMachineInput smi);
50
     virtual void inState(StateMachineInput smi);
62
 
51
 
63
-private:
52
+protected:
53
+    State *parent;
54
+    State *child;
55
+    const char *title;
64
     const char *heading;
56
     const char *heading;
65
     const char *text;
57
     const char *text;
66
     EnterFuncPtr onEnterFunc;
58
     EnterFuncPtr onEnterFunc;
120
 public:
112
 public:
121
     StateValue(State *_parent, T &_value, T _min, T _max);
113
     StateValue(State *_parent, T &_value, T _min, T _max);
122
 
114
 
123
-    void setHeading(const char *_heading);
124
-    void setText(const char *_text);
115
+    void setMax(T _max);
125
 
116
 
126
-    typedef void(*EnterFuncPtr)(void);
127
     typedef void(*UpdateFuncPtr)(T value);
117
     typedef void(*UpdateFuncPtr)(T value);
128
 
118
 
129
-    void onEnter(EnterFuncPtr func);
130
     void onLiveUpdate(UpdateFuncPtr func);
119
     void onLiveUpdate(UpdateFuncPtr func);
131
     void onUpdate(UpdateFuncPtr func);
120
     void onUpdate(UpdateFuncPtr func);
132
 
121
 
138
 
127
 
139
     T &value;
128
     T &value;
140
     T min, max;
129
     T min, max;
141
-    const char *heading;
142
-    const char *text;
143
-    EnterFuncPtr onEnterFunc;
144
     UpdateFuncPtr updateFunc, updateLiveFunc;
130
     UpdateFuncPtr updateFunc, updateLiveFunc;
145
 };
131
 };
146
 
132
 
151
 
137
 
152
     void setData(size_t index, const char *name, T *value, T min, T max);
138
     void setData(size_t index, const char *name, T *value, T min, T max);
153
 
139
 
154
-    void setHeading(const char *_heading);
155
-    void setText(const char *_text);
156
-
157
-    typedef void(*EnterFuncPtr)(void);
158
     typedef void(*UpdateFuncPtr)(size_t index, T value);
140
     typedef void(*UpdateFuncPtr)(size_t index, T value);
159
 
141
 
160
-    void onEnter(EnterFuncPtr func);
161
     void onLiveUpdate(UpdateFuncPtr func);
142
     void onLiveUpdate(UpdateFuncPtr func);
162
     void onUpdate(UpdateFuncPtr func);
143
     void onUpdate(UpdateFuncPtr func);
163
 
144
 
173
     const char *heading;
154
     const char *heading;
174
     size_t pos;
155
     size_t pos;
175
     bool editing;
156
     bool editing;
176
-    EnterFuncPtr onEnterFunc;
177
     UpdateFuncPtr updateFunc, updateLiveFunc;
157
     UpdateFuncPtr updateFunc, updateLiveFunc;
178
 };
158
 };
179
 
159
 

+ 1
- 1
include/states.h View File

9
 State *states_get(void);
9
 State *states_get(void);
10
 void states_go_to(State *state);
10
 void states_go_to(State *state);
11
 
11
 
12
-extern StateText sm_error;
12
+extern State sm_error;
13
 
13
 
14
 #endif // _STATES_H_
14
 #endif // _STATES_H_

+ 2
- 1
include/steppers.h View File

2
 #define _STEPPERS_H_
2
 #define _STEPPERS_H_
3
 
3
 
4
 void steppers_init(void);
4
 void steppers_init(void);
5
-bool steppers_run(void);
5
+void steppers_run(void);
6
 
6
 
7
 bool steppers_homed(void);
7
 bool steppers_homed(void);
8
 char steppers_homing_axis(void);
8
 char steppers_homing_axis(void);
9
 void steppers_start_homing(void);
9
 void steppers_start_homing(void);
10
 
10
 
11
+bool stepper_reached_target(int axis);
11
 float steppers_current_pos(int axis);
12
 float steppers_current_pos(int axis);
12
 
13
 
13
 // target pos
14
 // target pos

+ 15
- 2
src/common.cpp View File

3
 #include "config.h"
3
 #include "config.h"
4
 #include "config_pins.h"
4
 #include "config_pins.h"
5
 
5
 
6
+//#define DISABLE_BEEPING
7
+
6
 unsigned long last_led_blink_time = 0;
8
 unsigned long last_led_blink_time = 0;
9
+
10
+#ifndef DISABLE_BEEPING
7
 unsigned long beep_stop_time = 0;
11
 unsigned long beep_stop_time = 0;
12
+#endif // DISABLE_BEEPING
8
 
13
 
9
 void async_beep(int time, int freq) {
14
 void async_beep(int time, int freq) {
15
+#ifndef DISABLE_BEEPING
10
     beep_stop_time = millis() + time;
16
     beep_stop_time = millis() + time;
11
     tone(BEEPER, freq);
17
     tone(BEEPER, freq);
18
+#endif // DISABLE_BEEPING
12
 }
19
 }
13
 
20
 
14
 void blocking_beep(int time, int freq, int repeat = 0) {
21
 void blocking_beep(int time, int freq, int repeat = 0) {
22
+#ifndef DISABLE_BEEPING
15
     for (int i = 0; i <= repeat; i++) {
23
     for (int i = 0; i <= repeat; i++) {
16
         tone(BEEPER, freq);
24
         tone(BEEPER, freq);
17
         delay(time);
25
         delay(time);
21
             delay(time);
29
             delay(time);
22
         }
30
         }
23
     }
31
     }
32
+#endif // DISABLE_BEEPING
24
 }
33
 }
25
 
34
 
26
-void common_run(unsigned long t) {
35
+void common_run(void) {
36
+    unsigned long t = millis();
37
+
38
+#ifndef DISABLE_BEEPING
27
     // stop async beep
39
     // stop async beep
28
     if ((beep_stop_time > 0)  && (t > beep_stop_time)) {
40
     if ((beep_stop_time > 0)  && (t > beep_stop_time)) {
29
         noTone(BEEPER);
41
         noTone(BEEPER);
30
         beep_stop_time = 0;
42
         beep_stop_time = 0;
31
     }
43
     }
44
+#endif // DISABLE_BEEPING
32
 
45
 
33
     // blink heartbeat LED
46
     // blink heartbeat LED
34
     if ((t - last_led_blink_time) >= LED_BLINK_INTERVAL) {
47
     if ((t - last_led_blink_time) >= LED_BLINK_INTERVAL) {
35
-        last_led_blink_time = millis();
48
+        last_led_blink_time = t;
36
         digitalWrite(LED_PIN, !digitalRead(LED_PIN));
49
         digitalWrite(LED_PIN, !digitalRead(LED_PIN));
37
     }
50
     }
38
 }
51
 }

+ 33
- 17
src/data.cpp View File

37
 }
37
 }
38
 
38
 
39
 static uint32_t data_checksum(struct data_config *data) {
39
 static uint32_t data_checksum(struct data_config *data) {
40
+    uint32_t temp_checksum = data->checksum;
41
+    data->checksum = 0;
42
+
43
+    struct data_config_preset *temp_presets = data->presets;
44
+    data->presets = NULL;
45
+
40
     uint32_t c = 0;
46
     uint32_t c = 0;
41
 
47
 
48
+
42
     uint8_t *t = (uint8_t *)data;
49
     uint8_t *t = (uint8_t *)data;
43
     for (unsigned int i = 0; i < sizeof(struct data_config); i++) {
50
     for (unsigned int i = 0; i < sizeof(struct data_config); i++) {
44
         c ^= t[i];
51
         c ^= t[i];
45
     }
52
     }
46
 
53
 
47
     for (unsigned int i = 0; i < data->preset_count; i++) {
54
     for (unsigned int i = 0; i < data->preset_count; i++) {
48
-        t = (uint8_t *)(&data->presets[i]);
55
+        t = (uint8_t *)(temp_presets + i);
49
         for (unsigned int j = 0; j < sizeof(struct data_config_preset); j++) {
56
         for (unsigned int j = 0; j < sizeof(struct data_config_preset); j++) {
50
             c ^= t[j];
57
             c ^= t[j];
51
         }
58
         }
52
     }
59
     }
53
 
60
 
61
+    data->checksum = temp_checksum;
62
+    data->presets = temp_presets;
63
+
54
     return c;
64
     return c;
55
 }
65
 }
56
 
66
 
94
 
104
 
95
     // verify checksum
105
     // verify checksum
96
     uint32_t read_checksum = config.checksum;
106
     uint32_t read_checksum = config.checksum;
97
-    config.checksum = 0;
98
     uint32_t checksum = data_checksum(&config);
107
     uint32_t checksum = data_checksum(&config);
99
     if (read_checksum == checksum) {
108
     if (read_checksum == checksum) {
100
         // verify version
109
         // verify version
112
         }
121
         }
113
     } else {
122
     } else {
114
         Serial.print(F("checksum read="));
123
         Serial.print(F("checksum read="));
115
-        Serial.print(config.checksum);
124
+        Serial.print(read_checksum);
116
         Serial.print(F(" calc="));
125
         Serial.print(F(" calc="));
117
         Serial.println(checksum);
126
         Serial.println(checksum);
118
         last_error = "Checksum";
127
         last_error = "Checksum";
121
 }
130
 }
122
 
131
 
123
 void data_eeprom_write(void) {
132
 void data_eeprom_write(void) {
124
-    d.checksum = 0;
125
     d.checksum = data_checksum(&d);
133
     d.checksum = data_checksum(&d);
126
 
134
 
127
     // write meta-data and settings
135
     // write meta-data and settings
142
 }
150
 }
143
 
151
 
144
 void data_init(void) {
152
 void data_init(void) {
153
+    d.presets = NULL;
154
+    data_clear();
155
+
156
+    Serial.print(F("EEPROM max presets: "));
157
+    Serial.println(max_presets());
158
+
159
+    Serial.print(F("EEPROM read... "));
160
+    if (!data_eeprom_read()) {
161
+        Serial.print(last_error);
162
+        Serial.println(F(" Error"));
163
+    } else {
164
+        Serial.println(F("Ok"));
165
+    }
166
+}
167
+
168
+void data_clear(void) {
169
+    if (d.presets != NULL) {
170
+        free(d.presets);
171
+        d.presets = NULL;
172
+    }
173
+
145
     d.data_schema_version = DATA_SCHEMA_VERSION;
174
     d.data_schema_version = DATA_SCHEMA_VERSION;
146
     d.preset_count = 0;
175
     d.preset_count = 0;
147
     d.checksum = 0;
176
     d.checksum = 0;
155
     d.options.accel_y = XY_MAX_ACCEL;
184
     d.options.accel_y = XY_MAX_ACCEL;
156
     d.options.accel_z = Z_MAX_ACCEL;
185
     d.options.accel_z = Z_MAX_ACCEL;
157
     d.options.accel_e = E_MAX_ACCEL;
186
     d.options.accel_e = E_MAX_ACCEL;
158
-
159
-    d.presets = NULL;
160
-
161
-    Serial.print(F("EEPROM max presets: "));
162
-    Serial.println(max_presets());
163
-
164
-    Serial.print(F("EEPROM read... "));
165
-    if (!data_eeprom_read()) {
166
-        Serial.print(last_error);
167
-        Serial.println(F(" Error"));
168
-    } else {
169
-        Serial.println(F("Ok"));
170
-    }
171
 }
187
 }
172
 
188
 
173
 struct data_config_options *data_options(void) {
189
 struct data_config_options *data_options(void) {

+ 32
- 28
src/encoder.cpp View File

42
 #ifdef KILL_PIN
42
 #ifdef KILL_PIN
43
     kill_state = kill.poll();
43
     kill_state = kill.poll();
44
 #endif // KILL_PIN
44
 #endif // KILL_PIN
45
-
46
-    encoder.tick();
47
-}
48
-
49
-int encoder_change(void) {
50
-    int new_pos = encoder.getPosition();
51
-    int diff = new_pos - pos;
52
-    pos = new_pos;
53
-
54
-#ifdef DEBUG_ENCODER
55
-    if (diff != 0) {
56
-        Serial.print(F("encoder_change: "));
57
-        Serial.print(diff);
58
-        Serial.print(F(" ticks: "));
59
-        Serial.println(new_pos);
60
-    }
61
-#endif // DEBUG_ENCODER
62
-
63
-    return diff;
64
-}
65
-
66
-int encoder_rpm(void) {
67
-    return encoder.getRPM();
68
 }
45
 }
69
 
46
 
70
-int encoder_click(void) {
47
+bool encoder_click(void) {
71
     int r = click_state;
48
     int r = click_state;
72
 
49
 
73
     // only return 1 once for each click
50
     // only return 1 once for each click
80
 #endif // DEBUG_ENCODER
57
 #endif // DEBUG_ENCODER
81
     }
58
     }
82
 
59
 
83
-    return r;
60
+    return r ? true : false;
84
 }
61
 }
85
 
62
 
86
-int kill_switch(void) {
63
+bool kill_switch(void) {
87
 #ifdef KILL_PIN
64
 #ifdef KILL_PIN
88
 #ifdef DEBUG_ENCODER
65
 #ifdef DEBUG_ENCODER
89
     if (kill_state == 1) {
66
     if (kill_state == 1) {
91
     }
68
     }
92
 #endif // DEBUG_ENCODER
69
 #endif // DEBUG_ENCODER
93
 
70
 
94
-    return kill_state;
71
+    return kill_state ? true : false;
95
 #else
72
 #else
96
-    return 0;
73
+    return false;
97
 #endif // KILL_PIN
74
 #endif // KILL_PIN
98
 }
75
 }
76
+
77
+// --------------------------------------
78
+
79
+void encoder_run_fast(void) {
80
+    encoder.tick();
81
+}
82
+
83
+int encoder_change(void) {
84
+    int new_pos = encoder.getPosition();
85
+    int diff = new_pos - pos;
86
+    pos = new_pos;
87
+
88
+#ifdef DEBUG_ENCODER
89
+    if (diff != 0) {
90
+        Serial.print(F("encoder_change: "));
91
+        Serial.print(diff);
92
+        Serial.print(F(" ticks: "));
93
+        Serial.println(new_pos);
94
+    }
95
+#endif // DEBUG_ENCODER
96
+
97
+    return diff;
98
+}
99
+
100
+int encoder_rpm(void) {
101
+    return encoder.getRPM();
102
+}

+ 74
- 17
src/main.cpp View File

10
 #include "steppers.h"
10
 #include "steppers.h"
11
 #include "states.h"
11
 #include "states.h"
12
 
12
 
13
-static volatile bool still_running = false;
13
+const static float hz = min(max(max(XY_MAX_HZ, Z_MAX_HZ), E_MAX_HZ), MAX_SAMPLE_FREQ);
14
+const static float us = (1000.0 * 1000.0) / hz;
14
 
15
 
15
 void print_data(void) {
16
 void print_data(void) {
16
     Serial.println(F("XY:"));
17
     Serial.println(F("XY:"));
88
     Serial.println(F(" percent/s^2"));
89
     Serial.println(F(" percent/s^2"));
89
 
90
 
90
     Serial.println();
91
     Serial.println();
92
+
93
+    // ----------------------------------
94
+
95
+    Serial.print(F("XY max move freq: "));
96
+    Serial.print(XY_MAX_HZ);
97
+    Serial.println(F("hz"));
98
+    Serial.print(F("Z max move freq: "));
99
+    Serial.print(Z_MAX_HZ);
100
+    Serial.println(F("hz"));
101
+    Serial.print(F("E max move freq: "));
102
+    Serial.print(E_MAX_HZ);
103
+    Serial.println(F("hz"));
104
+
105
+    Serial.print(F("Sample Freq: "));
106
+    Serial.print(hz);
107
+    Serial.print(F("Hz = "));
108
+    Serial.print(us);
109
+    Serial.println(F("us"));
91
 }
110
 }
92
 
111
 
93
 void fast_loop(void) {
112
 void fast_loop(void) {
94
-    still_running = steppers_run();
95
-    encoder_run();
113
+    steppers_run();
114
+    encoder_run_fast();
96
 }
115
 }
97
 
116
 
98
 void setup() {
117
 void setup() {
102
     pinMode(BEEPER, OUTPUT);
121
     pinMode(BEEPER, OUTPUT);
103
     blocking_beep(100, 1000);
122
     blocking_beep(100, 1000);
104
 
123
 
105
-    // turn on fan connected to D8 for electronics
106
-    pinMode(FAN_PIN, OUTPUT);
107
-    digitalWrite(FAN_PIN, HIGH);
108
-
109
     Serial.begin(115200);
124
     Serial.begin(115200);
110
     Serial.println(F("Initializing Fuellfix v2"));
125
     Serial.println(F("Initializing Fuellfix v2"));
111
     Serial.print(F("Version: "));
126
     Serial.print(F("Version: "));
123
     Serial.println(F("Init stepper motors"));
138
     Serial.println(F("Init stepper motors"));
124
     steppers_init();
139
     steppers_init();
125
 
140
 
126
-    print_data();
141
+    //print_data();
127
 
142
 
128
     Serial.println(F("ready, showing splash screen"));
143
     Serial.println(F("ready, showing splash screen"));
129
     digitalWrite(LED_PIN, LOW);
144
     digitalWrite(LED_PIN, LOW);
130
     blocking_beep(100, 2000);
145
     blocking_beep(100, 2000);
131
 
146
 
132
     // wait some time to show splash screen
147
     // wait some time to show splash screen
133
-    delay(2000);
148
+    while (millis() < 1500) { }
134
 
149
 
135
     Serial.println(F("Init state machine"));
150
     Serial.println(F("Init state machine"));
136
     states_init();
151
     states_init();
138
     blocking_beep(100, 2000);
153
     blocking_beep(100, 2000);
139
     Serial.println(F("starting main loop"));
154
     Serial.println(F("starting main loop"));
140
 
155
 
141
-    Timer1.initialize(1000); // 1000us -> 1kHz
156
+    Timer1.initialize(us);
142
     Timer1.attachInterrupt(fast_loop);
157
     Timer1.attachInterrupt(fast_loop);
143
 }
158
 }
144
 
159
 
145
 void loop() {
160
 void loop() {
146
-    common_run(millis());
161
+    common_run();
162
+    encoder_run();
163
+
164
+    bool click = encoder_click();
165
+    bool kill = kill_switch();
147
 
166
 
148
     CLEAR_STORE_INTERRUPTS();
167
     CLEAR_STORE_INTERRUPTS();
149
 
168
 
150
-    int click = encoder_click();
151
     int change = encoder_change();
169
     int change = encoder_change();
152
     int rpm = encoder_rpm();
170
     int rpm = encoder_rpm();
153
-    int kill = kill_switch();
154
-    bool motors_done = !still_running;
171
+
172
+    bool motor_done[AXIS_COUNT];
173
+    bool all_done = true;
174
+    for (int i = 0; i < AXIS_COUNT; i++) {
175
+        motor_done[i] = stepper_reached_target(i);
176
+        if (!motor_done[i]) {
177
+            all_done = false;
178
+        }
179
+    }
155
 
180
 
156
     RESTORE_INTERRUPTS();
181
     RESTORE_INTERRUPTS();
157
 
182
 
158
-    struct StateMachineInput smi(click, change, rpm, kill, motors_done);
183
+    // allow rudimentary control over serial
184
+    // with enter and w/s or arrow up/down for encoder
185
+    // and q/k/space keys for kill
186
+    static int ser_state = 0;
187
+    while (Serial.available()) {
188
+        int c = Serial.read();
189
+        if (ser_state == 0) {
190
+            if (c == '\n') {
191
+                click = 1;
192
+            } else if ((c == 'q') || (c == 'Q') || (c == 'k') || (c == 'K') || (c == ' ')) {
193
+                kill = 1;
194
+            } else if ((c == 'w') || (c == 'W')) {
195
+                change = 1;
196
+            } else if ((c == 's') || (c == 'S')) {
197
+                change = -1;
198
+            } else if (c == '\e') {
199
+                ser_state = 1;
200
+            }
201
+        } else if (ser_state == 1) {
202
+            if (c == '[') {
203
+                ser_state = 2;
204
+            } else {
205
+                ser_state = 0;
206
+            }
207
+        } else if (ser_state == 2) {
208
+            if (c == 'A') {
209
+                change = 1;
210
+            } else if (c == 'B') {
211
+                change = -1;
212
+            }
213
+            ser_state = 0;
214
+        }
215
+    }
216
+
217
+    struct StateMachineInput smi(click, change, rpm, kill, motor_done, all_done);
159
     states_run(smi);
218
     states_run(smi);
160
 
219
 
161
     lcd_loop();
220
     lcd_loop();
162
-
163
-    delay(10);
164
 }
221
 }

+ 225
- 0
src/sm_menu.cpp View File

1
+#include <Arduino.h>
2
+
3
+#include "config.h"
4
+#include "config_pins.h"
5
+#include "lcd.h"
6
+#include "states.h"
7
+
8
+template <typename T, size_t N>
9
+void array_print(Array<T, N> *arr) {
10
+    Serial.print(F("Array length: "));
11
+    Serial.print(arr->size());
12
+    Serial.println(F(" contents:"));
13
+    for (int i = 0; i < arr->size(); i++) {
14
+        Serial.print(i);
15
+        Serial.print(F(": "));
16
+        Serial.println(arr->at(i)->getTitle());
17
+    }
18
+}
19
+
20
+template <typename T, size_t N>
21
+void array_insert_at_pos(Array<T, N> *arr, T value, size_t pos) {
22
+    // make additional space
23
+    arr->push_back(value);
24
+
25
+    if ((pos >= arr->max_size()) || (pos >= arr->size())) {
26
+        // we can not shift it to the given position
27
+        return;
28
+    }
29
+
30
+    for (int i = arr->size() - 2; i >= pos; i--) {
31
+        arr->at(i + 1) = arr->at(i);
32
+    }
33
+
34
+    arr->at(pos) = value;
35
+}
36
+
37
+// --------------------------------------
38
+
39
+StateMenu::StateMenu(State *_parent, bool _show_parent) : State(_parent) {
40
+    show_parent = _show_parent;
41
+    menuPos = 0;
42
+    menuOff = 0;
43
+}
44
+
45
+void StateMenu::setChild(State *_child) {
46
+    children.push_back(_child);
47
+}
48
+
49
+void StateMenu::addChild(State *_child, int pos) {
50
+    if (pos < 0) {
51
+        setChild(_child);
52
+    } else {
53
+        array_insert_at_pos(&children, _child, pos);
54
+    }
55
+}
56
+
57
+void StateMenu::enterState(void) {
58
+    display();
59
+}
60
+
61
+void StateMenu::display(void) {
62
+    lcd_clear();
63
+    lcd_set_heading(getTitle());
64
+
65
+    int size = children.size();
66
+    if (show_parent) {
67
+        size++;
68
+    }
69
+
70
+    for (int i = menuOff; (i < menuOff + lcd_text_lines()) && (i < size); i++) {
71
+        String s;
72
+        if (i == menuPos) {
73
+            s = F("> ");
74
+        } else {
75
+            s = F("  ");
76
+        }
77
+        if (i == children.size()) {
78
+            s += getParent()->getTitle();
79
+        } else {
80
+            s += children.at(i)->getTitle();
81
+        }
82
+        lcd_set_menu_text(i - menuOff, s.c_str());
83
+    }
84
+}
85
+
86
+void StateMenu::inState(struct StateMachineInput smi) {
87
+    int size = children.size();
88
+    if (show_parent) {
89
+        size++;
90
+    }
91
+
92
+    if (smi.encoder != 0) {
93
+        menuPos -= smi.encoder;
94
+
95
+        while (menuPos < 0) {
96
+            menuPos += size;
97
+        }
98
+
99
+        while (menuPos >= size) {
100
+            menuPos -= size;
101
+        }
102
+
103
+        while (menuPos < menuOff) {
104
+            menuOff--;
105
+        }
106
+
107
+        while (menuPos >= (menuOff + lcd_text_lines())) {
108
+            menuOff++;
109
+        }
110
+
111
+        display();
112
+    }
113
+
114
+    if (smi.click) {
115
+        if (menuPos == children.size()) {
116
+            menuPos = 0;
117
+            menuOff = 0;
118
+            states_go_to(getParent());
119
+        } else {
120
+            states_go_to(children.at(menuPos));
121
+        }
122
+    }
123
+}
124
+
125
+// --------------------------------------
126
+
127
+StateDynamicMenu::StateDynamicMenu(State *_parent) : State(_parent) {
128
+    menuPos = 0;
129
+    menuOff = 0;
130
+    prefix = "";
131
+    countFunc = NULL;
132
+    getFunc = NULL;
133
+    callFunc = NULL;
134
+}
135
+
136
+void StateDynamicMenu::dataCount(CountFuncPtr count) {
137
+    countFunc = count;
138
+}
139
+
140
+void StateDynamicMenu::dataGet(GetFuncPtr get) {
141
+    getFunc = get;
142
+}
143
+
144
+void StateDynamicMenu::dataCall(CallFuncPtr call) {
145
+    callFunc = call;
146
+}
147
+
148
+void StateDynamicMenu::display(void) {
149
+    lcd_clear();
150
+    lcd_set_heading(getTitle());
151
+
152
+    for (int i = menuOff; (i < menuOff + lcd_text_lines()) && (i < count + 1); i++) {
153
+        String s;
154
+        if (i == menuPos) {
155
+            s = F("> ");
156
+        } else {
157
+            s = F("  ");
158
+        }
159
+        if (i == count) {
160
+            s += getParent()->getTitle();
161
+        } else {
162
+            s += contents.at(i);
163
+        }
164
+        lcd_set_menu_text(i - menuOff, s.c_str());
165
+    }
166
+}
167
+
168
+void StateDynamicMenu::setPrefix(String pre) {
169
+    prefix = pre;
170
+}
171
+
172
+void StateDynamicMenu::enterState(void) {
173
+    // cache all entries on entering state
174
+    if (countFunc != NULL) {
175
+        count = countFunc();
176
+    } else {
177
+        count = 0;
178
+    }
179
+    contents.clear();
180
+    for (int i = 0; i < count; i++) {
181
+        if (getFunc != NULL) {
182
+            contents.push_back(prefix + String(getFunc(i)));
183
+        } else {
184
+            contents.push_back(prefix + String(i + 1));
185
+        }
186
+    }
187
+
188
+    display();
189
+}
190
+
191
+void StateDynamicMenu::inState(StateMachineInput smi) {
192
+    if (smi.encoder != 0) {
193
+        menuPos -= smi.encoder;
194
+
195
+        while (menuPos < 0) {
196
+            menuPos += count + 1;
197
+        }
198
+
199
+        while (menuPos >= count + 1) {
200
+            menuPos -= count + 1;
201
+        }
202
+
203
+        while (menuPos < menuOff) {
204
+            menuOff--;
205
+        }
206
+
207
+        while (menuPos >= (menuOff + lcd_text_lines())) {
208
+            menuOff++;
209
+        }
210
+
211
+        display();
212
+    }
213
+
214
+    if (smi.click) {
215
+        if (menuPos == count) {
216
+            menuPos = 0;
217
+            menuOff = 0;
218
+            states_go_to(getParent());
219
+        } else {
220
+            if (callFunc != NULL) {
221
+                callFunc(menuPos);
222
+            }
223
+        }
224
+    }
225
+}

+ 239
- 0
src/sm_value.cpp View File

1
+#include <Arduino.h>
2
+
3
+#include "config.h"
4
+#include "config_pins.h"
5
+#include "lcd.h"
6
+#include "states.h"
7
+
8
+template <typename T>
9
+StateValue<T>::StateValue(State *_parent, T &_value, T _min, T _max) : State(_parent), value(_value) {
10
+    min = _min;
11
+    max = _max;
12
+    heading = NULL;
13
+    text = NULL;
14
+    onEnterFunc = NULL;
15
+    updateFunc = NULL;
16
+    updateLiveFunc = NULL;
17
+}
18
+
19
+template <typename T>
20
+void StateValue<T>::setMax(T _max) {
21
+    max = _max;
22
+}
23
+
24
+template <typename T>
25
+void StateValue<T>::onUpdate(UpdateFuncPtr func) {
26
+    updateFunc = func;
27
+}
28
+
29
+template <typename T>
30
+void StateValue<T>::onLiveUpdate(UpdateFuncPtr func) {
31
+    updateLiveFunc = func;
32
+}
33
+
34
+template <typename T>
35
+void StateValue<T>::display(void) {
36
+    lcd_clear();
37
+    if (heading == NULL) {
38
+        lcd_set_heading(getTitle());
39
+    } else {
40
+        lcd_set_heading(heading);
41
+    }
42
+
43
+    String s = String(min) + F(" .. ") + String(value) + F(" .. ") + String(max);
44
+
45
+    if (text != NULL) {
46
+        s = text + String(F("\n")) + s;
47
+    }
48
+
49
+    lcd_set_text(s.c_str());
50
+}
51
+
52
+
53
+template <typename T>
54
+void StateValue<T>::enterState(void) {
55
+    if (onEnterFunc != NULL) {
56
+        onEnterFunc();
57
+    }
58
+    display();
59
+}
60
+
61
+template <typename T>
62
+void StateValue<T>::inState(StateMachineInput smi) {
63
+    if (smi.encoder != 0) {
64
+        float vf = smi.encoder;
65
+        vf *= 1.0 + ((float)smi.rpm / ENCODER_RPM_VALUE_FACTOR);
66
+        int v = vf;
67
+        value -= v;
68
+        if (value < min) {
69
+            value = min;
70
+        }
71
+        if (value > max) {
72
+            value = max;
73
+        }
74
+        if (updateLiveFunc != NULL) {
75
+            updateLiveFunc(value);
76
+        }
77
+        display();
78
+    }
79
+    if (smi.click) {
80
+        if (updateFunc != NULL) {
81
+            updateFunc(value);
82
+        }
83
+        if (getChild() != NULL) {
84
+            states_go_to(getChild());
85
+        } else if (getParent() != NULL) {
86
+            states_go_to(getParent());
87
+        }
88
+    }
89
+}
90
+
91
+template class StateValue<int>;
92
+template class StateValue<float>;
93
+
94
+// --------------------------------------
95
+
96
+template <typename T, size_t N>
97
+StateValues<T, N>::StateValues(State *_parent) : State(_parent) {
98
+    heading = NULL;
99
+    onEnterFunc = NULL;
100
+    updateFunc = NULL;
101
+    updateLiveFunc = NULL;
102
+    pos = 0;
103
+    editing = false;
104
+}
105
+
106
+template <typename T, size_t N>
107
+void StateValues<T, N>::setData(size_t index, const char *name, T *value, T min, T max) {
108
+    if (index >= N) {
109
+        return;
110
+    }
111
+    values[index] = value;
112
+    mins[index] = min;
113
+    maxs[index] = max;
114
+    texts[index] = name;
115
+}
116
+
117
+template <typename T, size_t N>
118
+void StateValues<T, N>::onUpdate(UpdateFuncPtr func) {
119
+    updateFunc = func;
120
+}
121
+
122
+template <typename T, size_t N>
123
+void StateValues<T, N>::onLiveUpdate(UpdateFuncPtr func) {
124
+    updateLiveFunc = func;
125
+}
126
+
127
+template <typename T, size_t N>
128
+void StateValues<T, N>::display(void) {
129
+    lcd_clear();
130
+
131
+    if (heading == NULL) {
132
+        lcd_set_heading(getTitle());
133
+    } else {
134
+        lcd_set_heading(heading);
135
+    }
136
+
137
+    for (size_t i = 0; i < (N + 1); i++) {
138
+        String s;
139
+
140
+        if (i == pos) {
141
+            if (editing) {
142
+                s = F("# ");
143
+            } else {
144
+                s = F("> ");
145
+            }
146
+        } else {
147
+            s = F("  ");
148
+        }
149
+
150
+        if (i < N) {
151
+            s += texts[i] + String(*(values[i])) + F(" (") + String(mins[i]) + F("/") + String(maxs[i]) + F(")");
152
+        } else {
153
+            if (getChild() != NULL) {
154
+                s += F("Continue");
155
+            } else {
156
+                s += F("Done");
157
+            }
158
+        }
159
+
160
+        lcd_set_menu_text(i, s.c_str());
161
+    }
162
+}
163
+
164
+template <typename T, size_t N>
165
+void StateValues<T, N>::enterState(void) {
166
+    pos = 0;
167
+    if (onEnterFunc != NULL) {
168
+        onEnterFunc();
169
+    }
170
+    display();
171
+}
172
+
173
+template <typename T, size_t N>
174
+void StateValues<T, N>::inState(StateMachineInput smi) {
175
+    if (editing) {
176
+        if (smi.encoder != 0) {
177
+            float vf = smi.encoder;
178
+            vf *= 1.0 + ((float)smi.rpm / ENCODER_RPM_VALUE_FACTOR);
179
+            int v = vf;
180
+            *(values[pos]) -= v;
181
+
182
+            if (*(values[pos]) < mins[pos]) {
183
+                *(values[pos]) = mins[pos];
184
+            }
185
+
186
+            if (*(values[pos]) > maxs[pos]) {
187
+                *(values[pos]) = maxs[pos];
188
+            }
189
+
190
+            if (updateLiveFunc != NULL) {
191
+                updateLiveFunc(pos, *(values[pos]));
192
+            }
193
+
194
+            display();
195
+        }
196
+        if (smi.click) {
197
+            editing = false;
198
+            display();
199
+        }
200
+    } else {
201
+        if (smi.encoder != 0) {
202
+            int tmp = pos;
203
+            tmp -= smi.encoder;
204
+
205
+            while (tmp < 0) {
206
+                tmp += N + 1;
207
+            }
208
+
209
+            while (tmp >= (N + 1)) {
210
+                tmp -= N + 1;
211
+            }
212
+
213
+            pos = tmp;
214
+
215
+            display();
216
+        }
217
+        if (smi.click) {
218
+            if (pos < N) {
219
+                editing = true;
220
+                display();
221
+            } else {
222
+                if (updateFunc != NULL) {
223
+                    for (size_t i = 0; i < N; i++) {
224
+                        updateFunc(i, *(values[i]));
225
+                    }
226
+                }
227
+
228
+                if (getChild() != NULL) {
229
+                    states_go_to(getChild());
230
+                } else if (getParent() != NULL) {
231
+                    states_go_to(getParent());
232
+                }
233
+            }
234
+        }
235
+    }
236
+}
237
+
238
+template class StateValues<uint8_t, 2>;
239
+template class StateValues<float, 2>;

+ 8
- 498
src/statemachine.cpp View File

5
 #include "lcd.h"
5
 #include "lcd.h"
6
 #include "states.h"
6
 #include "states.h"
7
 
7
 
8
-State::State(State *_parent) : parent(_parent), child(NULL), title("no title") {
8
+State::State(State *_parent)
9
+        : parent(_parent), child(NULL), title(""), heading(""), text("") {
9
     if (_parent != NULL) {
10
     if (_parent != NULL) {
10
         _parent->setChild(this);
11
         _parent->setChild(this);
11
     }
12
     }
12
-}
13
-
14
-// --------------------------------------
15
 
13
 
16
-StateText::StateText(State *_parent) : State(_parent) {
17
-    heading = "no heading";
18
-    text = "text missing";
19
     onEnterFunc = []() { };
14
     onEnterFunc = []() { };
15
+
20
     whenInFunc = [](StateMachineInput smi) {
16
     whenInFunc = [](StateMachineInput smi) {
21
         State *s = states_get();
17
         State *s = states_get();
22
         if (smi.click && (s != NULL)) {
18
         if (smi.click && (s != NULL)) {
29
     };
25
     };
30
 }
26
 }
31
 
27
 
32
-void StateText::setHeading(const char *_heading) {
33
-    heading = _heading;
34
-}
35
-
36
-void StateText::setText(const char *_text) {
37
-    text = _text;
38
-}
39
-
40
-void StateText::onEnter(EnterFuncPtr func) {
41
-    onEnterFunc = func;
42
-}
43
-
44
-void StateText::whenIn(InFuncPtr func) {
45
-    whenInFunc = func;
46
-}
47
-
48
-void StateText::updateText(void) {
28
+void State::updateText(void) {
49
     lcd_clear();
29
     lcd_clear();
30
+
50
     if (heading != NULL) {
31
     if (heading != NULL) {
51
         lcd_set_heading(heading);
32
         lcd_set_heading(heading);
52
     } else if (getTitle() != NULL) {
33
     } else if (getTitle() != NULL) {
53
         lcd_set_heading(getTitle());
34
         lcd_set_heading(getTitle());
54
     }
35
     }
36
+
55
     if (text != NULL) {
37
     if (text != NULL) {
56
         lcd_set_text(text);
38
         lcd_set_text(text);
57
     }
39
     }
58
 }
40
 }
59
 
41
 
60
-void StateText::enterState(void) {
42
+void State::enterState(void) {
61
     if (onEnterFunc != NULL) {
43
     if (onEnterFunc != NULL) {
62
         onEnterFunc();
44
         onEnterFunc();
63
     }
45
     }
65
     updateText();
47
     updateText();
66
 }
48
 }
67
 
49
 
68
-void StateText::inState(struct StateMachineInput smi) {
50
+void State::inState(struct StateMachineInput smi) {
69
     if (whenInFunc != NULL) {
51
     if (whenInFunc != NULL) {
70
         whenInFunc(smi);
52
         whenInFunc(smi);
71
     }
53
     }
72
 }
54
 }
73
-
74
-// --------------------------------------
75
-
76
-StateMenu::StateMenu(State *_parent, bool _show_parent) : State(_parent) {
77
-    show_parent = _show_parent;
78
-    menuPos = 0;
79
-    menuOff = 0;
80
-}
81
-
82
-void StateMenu::setChild(State *_child) {
83
-    children.push_back(_child);
84
-}
85
-
86
-void StateMenu::addChild(State *_child, int pos) {
87
-    if (pos < 0) {
88
-        setChild(_child);
89
-    } else {
90
-        array_insert_at_pos(&children, _child, pos);
91
-    }
92
-}
93
-
94
-void StateMenu::enterState(void) {
95
-    display();
96
-}
97
-
98
-void StateMenu::display(void) {
99
-    lcd_clear();
100
-    lcd_set_heading(getTitle());
101
-
102
-    int size = children.size();
103
-    if (show_parent) {
104
-        size++;
105
-    }
106
-
107
-    for (int i = menuOff; (i < menuOff + lcd_text_lines()) && (i < size); i++) {
108
-        String s;
109
-        if (i == menuPos) {
110
-            s = F("> ");
111
-        } else {
112
-            s = F("  ");
113
-        }
114
-        if (i == children.size()) {
115
-            s += getParent()->getTitle();
116
-        } else {
117
-            s += children.at(i)->getTitle();
118
-        }
119
-        lcd_set_menu_text(i - menuOff, s.c_str());
120
-    }
121
-}
122
-
123
-void StateMenu::inState(struct StateMachineInput smi) {
124
-    int size = children.size();
125
-    if (show_parent) {
126
-        size++;
127
-    }
128
-
129
-    if (smi.encoder != 0) {
130
-        menuPos -= smi.encoder;
131
-
132
-        while (menuPos < 0) {
133
-            menuPos += size;
134
-        }
135
-
136
-        while (menuPos >= size) {
137
-            menuPos -= size;
138
-        }
139
-
140
-        while (menuPos < menuOff) {
141
-            menuOff--;
142
-        }
143
-
144
-        while (menuPos >= (menuOff + lcd_text_lines())) {
145
-            menuOff++;
146
-        }
147
-
148
-        display();
149
-    }
150
-
151
-    if (smi.click) {
152
-        if (menuPos == children.size()) {
153
-            menuPos = 0;
154
-            menuOff = 0;
155
-            states_go_to(getParent());
156
-        } else {
157
-            states_go_to(children.at(menuPos));
158
-        }
159
-    }
160
-}
161
-
162
-// --------------------------------------
163
-
164
-StateDynamicMenu::StateDynamicMenu(State *_parent) : State(_parent) {
165
-    menuPos = 0;
166
-    menuOff = 0;
167
-    prefix = "";
168
-    countFunc = NULL;
169
-    getFunc = NULL;
170
-    callFunc = NULL;
171
-}
172
-
173
-void StateDynamicMenu::dataCount(CountFuncPtr count) {
174
-    countFunc = count;
175
-}
176
-
177
-void StateDynamicMenu::dataGet(GetFuncPtr get) {
178
-    getFunc = get;
179
-}
180
-
181
-void StateDynamicMenu::dataCall(CallFuncPtr call) {
182
-    callFunc = call;
183
-}
184
-
185
-void StateDynamicMenu::display(void) {
186
-    lcd_clear();
187
-    lcd_set_heading(getTitle());
188
-
189
-    for (int i = menuOff; (i < menuOff + lcd_text_lines()) && (i < count + 1); i++) {
190
-        String s;
191
-        if (i == menuPos) {
192
-            s = F("> ");
193
-        } else {
194
-            s = F("  ");
195
-        }
196
-        if (i == count) {
197
-            s += getParent()->getTitle();
198
-        } else {
199
-            s += contents.at(i);
200
-        }
201
-        lcd_set_menu_text(i - menuOff, s.c_str());
202
-    }
203
-}
204
-
205
-void StateDynamicMenu::setPrefix(String pre) {
206
-    prefix = pre;
207
-}
208
-
209
-void StateDynamicMenu::enterState(void) {
210
-    // cache all entries on entering state
211
-    if (countFunc != NULL) {
212
-        count = countFunc();
213
-    } else {
214
-        count = 0;
215
-    }
216
-    contents.clear();
217
-    for (int i = 0; i < count; i++) {
218
-        if (getFunc != NULL) {
219
-            contents.push_back(prefix + String(getFunc(i)));
220
-        } else {
221
-            contents.push_back(prefix + String(i + 1));
222
-        }
223
-    }
224
-
225
-    display();
226
-}
227
-
228
-void StateDynamicMenu::inState(StateMachineInput smi) {
229
-    if (smi.encoder != 0) {
230
-        menuPos -= smi.encoder;
231
-
232
-        while (menuPos < 0) {
233
-            menuPos += count + 1;
234
-        }
235
-
236
-        while (menuPos >= count + 1) {
237
-            menuPos -= count + 1;
238
-        }
239
-
240
-        while (menuPos < menuOff) {
241
-            menuOff--;
242
-        }
243
-
244
-        while (menuPos >= (menuOff + lcd_text_lines())) {
245
-            menuOff++;
246
-        }
247
-
248
-        display();
249
-    }
250
-
251
-    if (smi.click) {
252
-        if (menuPos == count) {
253
-            menuPos = 0;
254
-            menuOff = 0;
255
-            states_go_to(getParent());
256
-        } else {
257
-            if (callFunc != NULL) {
258
-                callFunc(menuPos);
259
-            }
260
-        }
261
-    }
262
-}
263
-
264
-// --------------------------------------
265
-
266
-template <typename T>
267
-StateValue<T>::StateValue(State *_parent, T &_value, T _min, T _max) : State(_parent), value(_value) {
268
-    min = _min;
269
-    max = _max;
270
-    heading = NULL;
271
-    text = NULL;
272
-    onEnterFunc = NULL;
273
-    updateFunc = NULL;
274
-    updateLiveFunc = NULL;
275
-}
276
-
277
-template <typename T>
278
-void StateValue<T>::setHeading(const char *_heading) {
279
-    heading = _heading;
280
-}
281
-
282
-template <typename T>
283
-void StateValue<T>::setText(const char *_text) {
284
-    text = _text;
285
-}
286
-
287
-template <typename T>
288
-void StateValue<T>::onEnter(EnterFuncPtr func) {
289
-    onEnterFunc = func;
290
-}
291
-
292
-template <typename T>
293
-void StateValue<T>::onUpdate(UpdateFuncPtr func) {
294
-    updateFunc = func;
295
-}
296
-
297
-template <typename T>
298
-void StateValue<T>::onLiveUpdate(UpdateFuncPtr func) {
299
-    updateLiveFunc = func;
300
-}
301
-
302
-template <typename T>
303
-void StateValue<T>::display(void) {
304
-    lcd_clear();
305
-    if (heading == NULL) {
306
-        lcd_set_heading(getTitle());
307
-    } else {
308
-        lcd_set_heading(heading);
309
-    }
310
-
311
-    String s = String(min) + F(" .. ") + String(value) + F(" .. ") + String(max);
312
-
313
-    if (text != NULL) {
314
-        s = text + String(F("\n")) + s;
315
-    }
316
-
317
-    lcd_set_text(s.c_str());
318
-}
319
-
320
-
321
-template <typename T>
322
-void StateValue<T>::enterState(void) {
323
-    if (onEnterFunc != NULL) {
324
-        onEnterFunc();
325
-    }
326
-    display();
327
-}
328
-
329
-template <typename T>
330
-void StateValue<T>::inState(StateMachineInput smi) {
331
-    if (smi.encoder != 0) {
332
-        float vf = smi.encoder;
333
-        vf *= 1.0 + ((float)smi.rpm / ENCODER_RPM_VALUE_FACTOR);
334
-        int v = vf;
335
-        value -= v;
336
-        if (value < min) {
337
-            value = min;
338
-        }
339
-        if (value > max) {
340
-            value = max;
341
-        }
342
-        if (updateLiveFunc != NULL) {
343
-            updateLiveFunc(value);
344
-        }
345
-        display();
346
-    }
347
-    if (smi.click) {
348
-        if (updateFunc != NULL) {
349
-            updateFunc(value);
350
-        }
351
-        states_go_to(getParent());
352
-    }
353
-}
354
-
355
-template class StateValue<int>;
356
-template class StateValue<float>;
357
-
358
-// --------------------------------------
359
-
360
-template <typename T, size_t N>
361
-StateValues<T, N>::StateValues(State *_parent) : State(_parent) {
362
-    heading = NULL;
363
-    onEnterFunc = NULL;
364
-    updateFunc = NULL;
365
-    updateLiveFunc = NULL;
366
-    pos = 0;
367
-    editing = false;
368
-}
369
-
370
-template <typename T, size_t N>
371
-void StateValues<T, N>::setData(size_t index, const char *name, T *value, T min, T max) {
372
-    if (index >= N) {
373
-        return;
374
-    }
375
-    values[index] = value;
376
-    mins[index] = min;
377
-    maxs[index] = max;
378
-    texts[index] = name;
379
-}
380
-
381
-template <typename T, size_t N>
382
-void StateValues<T, N>::setHeading(const char *_heading) {
383
-    heading = _heading;
384
-}
385
-
386
-template <typename T, size_t N>
387
-void StateValues<T, N>::onEnter(EnterFuncPtr func) {
388
-    onEnterFunc = func;
389
-}
390
-
391
-template <typename T, size_t N>
392
-void StateValues<T, N>::onUpdate(UpdateFuncPtr func) {
393
-    updateFunc = func;
394
-}
395
-
396
-template <typename T, size_t N>
397
-void StateValues<T, N>::onLiveUpdate(UpdateFuncPtr func) {
398
-    updateLiveFunc = func;
399
-}
400
-
401
-template <typename T, size_t N>
402
-void StateValues<T, N>::display(void) {
403
-    lcd_clear();
404
-
405
-    if (heading == NULL) {
406
-        lcd_set_heading(getTitle());
407
-    } else {
408
-        lcd_set_heading(heading);
409
-    }
410
-
411
-    for (size_t i = 0; i < (N + 1); i++) {
412
-        String s;
413
-
414
-        if (i == pos) {
415
-            if (editing) {
416
-                s = F("# ");
417
-            } else {
418
-                s = F("> ");
419
-            }
420
-        } else {
421
-            s = F("  ");
422
-        }
423
-
424
-        if (i < N) {
425
-            s += texts[i] + String(*(values[i])) + F(" (") + String(mins[i]) + F("/") + String(maxs[i]) + F(")");
426
-        } else {
427
-            if (getChild() != NULL) {
428
-                s += F("Continue");
429
-            } else {
430
-                s += F("Done");
431
-            }
432
-        }
433
-
434
-        lcd_set_menu_text(i, s.c_str());
435
-    }
436
-}
437
-
438
-template <typename T, size_t N>
439
-void StateValues<T, N>::enterState(void) {
440
-    pos = 0;
441
-    if (onEnterFunc != NULL) {
442
-        onEnterFunc();
443
-    }
444
-    display();
445
-}
446
-
447
-template <typename T, size_t N>
448
-void StateValues<T, N>::inState(StateMachineInput smi) {
449
-    if (editing) {
450
-        if (smi.encoder != 0) {
451
-            float vf = smi.encoder;
452
-            vf *= 1.0 + ((float)smi.rpm / ENCODER_RPM_VALUE_FACTOR);
453
-            int v = vf;
454
-            *(values[pos]) -= v;
455
-
456
-            if (*(values[pos]) < mins[pos]) {
457
-                *(values[pos]) = mins[pos];
458
-            }
459
-
460
-            if (*(values[pos]) > maxs[pos]) {
461
-                *(values[pos]) = maxs[pos];
462
-            }
463
-
464
-            if (updateLiveFunc != NULL) {
465
-                updateLiveFunc(pos, *(values[pos]));
466
-            }
467
-
468
-            display();
469
-        }
470
-        if (smi.click) {
471
-            editing = false;
472
-            display();
473
-        }
474
-    } else {
475
-        if (smi.encoder != 0) {
476
-            int tmp = pos;
477
-            tmp -= smi.encoder;
478
-
479
-            while (tmp < 0) {
480
-                tmp += N + 1;
481
-            }
482
-
483
-            while (tmp >= (N + 1)) {
484
-                tmp -= N + 1;
485
-            }
486
-
487
-            pos = tmp;
488
-
489
-            display();
490
-        }
491
-        if (smi.click) {
492
-            if (pos < N) {
493
-                editing = true;
494
-                display();
495
-            } else {
496
-                if (updateFunc != NULL) {
497
-                    for (size_t i = 0; i < N; i++) {
498
-                        updateFunc(i, *(values[i]));
499
-                    }
500
-                }
501
-
502
-                if (getChild() != NULL) {
503
-                    states_go_to(getChild());
504
-                } else if (getParent() != NULL) {
505
-                    states_go_to(getParent());
506
-                }
507
-            }
508
-        }
509
-    }
510
-}
511
-
512
-template class StateValues<uint8_t, 2>;
513
-template class StateValues<float, 2>;
514
-
515
-// --------------------------------------
516
-
517
-template <typename T, size_t N>
518
-void array_print(Array<T, N> *arr) {
519
-    Serial.print(F("Array length: "));
520
-    Serial.print(arr->size());
521
-    Serial.println(F(" contents:"));
522
-    for (int i = 0; i < arr->size(); i++) {
523
-        Serial.print(i);
524
-        Serial.print(F(": "));
525
-        Serial.println(arr->at(i)->getTitle());
526
-    }
527
-}
528
-
529
-template <typename T, size_t N>
530
-void array_insert_at_pos(Array<T, N> *arr, T value, size_t pos) {
531
-    // make additional space
532
-    arr->push_back(value);
533
-
534
-    if ((pos >= arr->max_size()) || (pos >= arr->size())) {
535
-        // we can not shift it to the given position
536
-        return;
537
-    }
538
-
539
-    for (int i = arr->size() - 2; i >= pos; i--) {
540
-        arr->at(i + 1) = arr->at(i);
541
-    }
542
-
543
-    arr->at(pos) = value;
544
-}

+ 275
- 32
src/states.cpp View File

15
 
15
 
16
 // --------------------------------------
16
 // --------------------------------------
17
 
17
 
18
-StateText sm_ask_homing = StateText();
19
-StateText sm_do_homing = StateText(&sm_ask_homing);
18
+int preset_selection = 0, dispense_off = 0,  dispense_count = 0, dispense_index = 0;
19
+float move_pos_x = 0.0, move_pos_y = 0.0, move_pos_z = 0.0, move_pos_e = 0.0;
20
+
21
+State sm_ask_homing = State();
22
+State sm_do_homing = State(&sm_ask_homing);
20
 StateMenu sm_menu = StateMenu(&sm_do_homing, false);
23
 StateMenu sm_menu = StateMenu(&sm_do_homing, false);
21
 
24
 
22
 StateMenu sm_auto = StateMenu(&sm_menu);
25
 StateMenu sm_auto = StateMenu(&sm_menu);
23
 StateDynamicMenu sm_presets = StateDynamicMenu(&sm_auto);
26
 StateDynamicMenu sm_presets = StateDynamicMenu(&sm_auto);
24
-// TODO dispense
25
 
27
 
26
-StateText sm_new_preset = StateText(&sm_auto);
27
-StateText sm_wiz_move = StateText(&sm_new_preset);
28
+StateValue<int> sm_disp_off = StateValue<int>(&sm_presets, dispense_off, 1, 1);
29
+StateValue<int> sm_disp_cnt = StateValue<int>(&sm_disp_off, dispense_count, 1, 1);
30
+State sm_disp_go = State(&sm_disp_cnt);
31
+State sm_disp_run_z_travel = State(&sm_disp_go);
32
+State sm_disp_run_xy_travel = State(&sm_disp_run_z_travel);
33
+State sm_disp_run_z_disp = State(&sm_disp_run_xy_travel);
34
+State sm_disp_run = State(&sm_disp_run_z_disp);
35
+State sm_disp_done = State(&sm_disp_run);
36
+
37
+State sm_new_preset = State(&sm_auto);
38
+State sm_wiz_move = State(&sm_new_preset);
28
 StateValues<uint8_t, 2> sm_wiz_count = StateValues<uint8_t, 2>(&sm_wiz_move);
39
 StateValues<uint8_t, 2> sm_wiz_count = StateValues<uint8_t, 2>(&sm_wiz_move);
29
 StateValues<float, 2> sm_wiz_first_pos = StateValues<float, 2>(&sm_wiz_count);
40
 StateValues<float, 2> sm_wiz_first_pos = StateValues<float, 2>(&sm_wiz_count);
30
 StateValues<float, 2> sm_wiz_last_pos = StateValues<float, 2>(&sm_wiz_first_pos);
41
 StateValues<float, 2> sm_wiz_last_pos = StateValues<float, 2>(&sm_wiz_first_pos);
31
 // TODO move z above container
42
 // TODO move z above container
32
-// TODO move z inside container
43
+// TODO move z inside bottom container
44
+// TODO move z inside top container
33
 // TODO move to extruder depth
45
 // TODO move to extruder depth
34
-StateText sm_new_preset_done = StateText(&sm_wiz_last_pos);
46
+State sm_new_preset_done = State(&sm_wiz_last_pos);
35
 
47
 
36
 StateDynamicMenu sm_mod_preset = StateDynamicMenu(&sm_auto);
48
 StateDynamicMenu sm_mod_preset = StateDynamicMenu(&sm_auto);
37
 // TODO modify
49
 // TODO modify
39
 StateDynamicMenu sm_del_preset = StateDynamicMenu(&sm_auto);
51
 StateDynamicMenu sm_del_preset = StateDynamicMenu(&sm_auto);
40
 // TODO delete
52
 // TODO delete
41
 
53
 
42
-float move_pos_x = 0.0, move_pos_y = 0.0, move_pos_z = 0.0, move_pos_e = 0.0;
43
 StateMenu sm_move = StateMenu(&sm_menu);
54
 StateMenu sm_move = StateMenu(&sm_menu);
44
 StateValue<float> sm_move_x = StateValue<float>(&sm_move, move_pos_x, X_AXIS_MIN, X_AXIS_MAX);
55
 StateValue<float> sm_move_x = StateValue<float>(&sm_move, move_pos_x, X_AXIS_MIN, X_AXIS_MAX);
45
 StateValue<float> sm_move_y = StateValue<float>(&sm_move, move_pos_y, Y_AXIS_MIN, Y_AXIS_MAX);
56
 StateValue<float> sm_move_y = StateValue<float>(&sm_move, move_pos_y, Y_AXIS_MIN, Y_AXIS_MAX);
46
 StateValue<float> sm_move_z = StateValue<float>(&sm_move, move_pos_z, Z_AXIS_MIN, Z_AXIS_MAX);
57
 StateValue<float> sm_move_z = StateValue<float>(&sm_move, move_pos_z, Z_AXIS_MIN, Z_AXIS_MAX);
47
 StateValue<float> sm_move_e = StateValue<float>(&sm_move, move_pos_e, E_AXIS_MIN, E_AXIS_MAX);
58
 StateValue<float> sm_move_e = StateValue<float>(&sm_move, move_pos_e, E_AXIS_MIN, E_AXIS_MAX);
48
 
59
 
60
+State sm_disable_steppers = State(&sm_menu);
61
+
49
 StateMenu sm_config = StateMenu(&sm_menu);
62
 StateMenu sm_config = StateMenu(&sm_menu);
50
-StateText sm_conf_load = StateText(&sm_config);
51
-StateText sm_conf_save = StateText(&sm_config);
63
+State sm_conf_load = State(&sm_config);
64
+State sm_conf_save = State(&sm_config);
65
+State sm_conf_clear = State(&sm_config);
52
 StateValue<float> sm_conf_speed_xy = StateValue<float>(&sm_config, data_options()->speed_x, 1.0, XY_MAX_SPEED);
66
 StateValue<float> sm_conf_speed_xy = StateValue<float>(&sm_config, data_options()->speed_x, 1.0, XY_MAX_SPEED);
53
 StateValue<float> sm_conf_speed_z = StateValue<float>(&sm_config, data_options()->speed_z, 1.0, Z_MAX_SPEED);
67
 StateValue<float> sm_conf_speed_z = StateValue<float>(&sm_config, data_options()->speed_z, 1.0, Z_MAX_SPEED);
54
 StateValue<float> sm_conf_speed_e = StateValue<float>(&sm_config, data_options()->speed_e, 1.0, E_MAX_SPEED);
68
 StateValue<float> sm_conf_speed_e = StateValue<float>(&sm_config, data_options()->speed_e, 1.0, E_MAX_SPEED);
56
 StateValue<float> sm_conf_accel_z = StateValue<float>(&sm_config, data_options()->accel_z, 1.0, Z_MAX_ACCEL);
70
 StateValue<float> sm_conf_accel_z = StateValue<float>(&sm_config, data_options()->accel_z, 1.0, Z_MAX_ACCEL);
57
 StateValue<float> sm_conf_accel_e = StateValue<float>(&sm_config, data_options()->accel_e, 1.0, E_MAX_ACCEL);
71
 StateValue<float> sm_conf_accel_e = StateValue<float>(&sm_config, data_options()->accel_e, 1.0, E_MAX_ACCEL);
58
 
72
 
59
-StateText sm_error = StateText(NULL);
73
+State sm_error = State(NULL);
74
+
75
+#if defined(ENABLE_MOVEMENT_TEST_STATE) || defined(ENABLE_INPUT_TEST_STATE)
76
+StateMenu sm_debug = StateMenu(&sm_menu);
77
+#endif
60
 
78
 
61
 #ifdef ENABLE_MOVEMENT_TEST_STATE
79
 #ifdef ENABLE_MOVEMENT_TEST_STATE
62
-StateMenu sm_movement_test = StateMenu(&sm_menu);
63
-StateText sm_move_x_test = StateText(&sm_movement_test);
64
-StateText sm_move_y_test = StateText(&sm_movement_test);
80
+StateMenu sm_movement_test = StateMenu(&sm_debug);
81
+State sm_move_xy_test = State(&sm_movement_test);
82
+State sm_move_x_test = State(&sm_movement_test);
83
+State sm_move_y_test = State(&sm_movement_test);
84
+State sm_move_z_test = State(&sm_movement_test);
85
+State sm_move_e_test = State(&sm_movement_test);
65
 #endif // ENABLE_MOVEMENT_TEST_STATE
86
 #endif // ENABLE_MOVEMENT_TEST_STATE
66
 
87
 
67
 #ifdef ENABLE_INPUT_TEST_STATE
88
 #ifdef ENABLE_INPUT_TEST_STATE
68
-StateText sm_input_test = StateText(&sm_menu);
89
+State sm_input_test = State(&sm_debug);
69
 #endif // ENABLE_INPUT_TEST_STATE
90
 #endif // ENABLE_INPUT_TEST_STATE
70
 
91
 
71
 // --------------------------------------
92
 // --------------------------------------
75
 struct data_config_preset wizard_preset = { .count_x = 1, .count_y = 1 };
96
 struct data_config_preset wizard_preset = { .count_x = 1, .count_y = 1 };
76
 float wizard_first_x = 0.0, wizard_first_y = 0.0;
97
 float wizard_first_x = 0.0, wizard_first_y = 0.0;
77
 float wizard_last_x = 0.0, wizard_last_y = 0.0;
98
 float wizard_last_x = 0.0, wizard_last_y = 0.0;
99
+unsigned long last_state_change = 0, last_input = 0;
78
 
100
 
79
 void states_init(void) {
101
 void states_init(void) {
80
     // ----------------------------------
102
     // ----------------------------------
96
 
118
 
97
     sm_do_homing.whenIn([](StateMachineInput smi) {
119
     sm_do_homing.whenIn([](StateMachineInput smi) {
98
 #ifndef DISABLE_HOMING_STATE
120
 #ifndef DISABLE_HOMING_STATE
99
-        if (smi.motors_done) {
121
+        if (smi.all_motors_done) {
100
             if (steppers_homed()) {
122
             if (steppers_homed()) {
101
 #endif // DISABLE_HOMING_STATE
123
 #endif // DISABLE_HOMING_STATE
102
 
124
 
159
         steppers_move_e(v);
181
         steppers_move_e(v);
160
     });
182
     });
161
 
183
 
184
+    sm_disable_steppers.setTitle("Disable Steppers");
185
+    sm_disable_steppers.onEnter([]() {
186
+        steppers_kill();
187
+        states_go_to(&sm_ask_homing);
188
+    });
189
+
162
     // ----------------------------------
190
     // ----------------------------------
163
 
191
 
164
     sm_auto.setTitle("Filling Menu");
192
     sm_auto.setTitle("Filling Menu");
165
 
193
 
166
-    // TODO
194
+    auto preset_name_func = [](int i) {
195
+        strbuf = String(i + 1);
196
+        strbuf += String(F(" ("));
197
+        strbuf += String(data_preset(i)->count_x);
198
+        strbuf += String(F("*"));
199
+        strbuf += String(data_preset(i)->count_y);
200
+        strbuf += String(F(" / "));
201
+        strbuf += String(data_preset(i)->distance_x);
202
+        strbuf += String(F("*"));
203
+        strbuf += String(data_preset(i)->distance_y);
204
+        strbuf += String(F(")"));
205
+        return strbuf.c_str();
206
+    };
207
+
167
     sm_presets.setTitle("Use Preset");
208
     sm_presets.setTitle("Use Preset");
168
     sm_presets.setPrefix("Preset ");
209
     sm_presets.setPrefix("Preset ");
169
     sm_presets.dataCount([]() {
210
     sm_presets.dataCount([]() {
170
         return (int)data_preset_count();
211
         return (int)data_preset_count();
171
     });
212
     });
213
+    sm_presets.dataGet(preset_name_func);
214
+    sm_presets.dataCall([](int i) {
215
+        preset_selection = i;
216
+        states_go_to(&sm_disp_off);
217
+    });
218
+
219
+    sm_disp_off.setTitle("Offset");
220
+    sm_disp_off.setText("Where to start dispensing?");
221
+    sm_disp_off.onEnter([]() {
222
+        dispense_off = 1;
223
+        sm_disp_off.setMax(data_preset(preset_selection)->count_x * data_preset(preset_selection)->count_y);
224
+    });
225
+
226
+    sm_disp_cnt.setTitle("Count");
227
+    sm_disp_cnt.setText("How many to fill?");
228
+    sm_disp_cnt.onEnter([]() {
229
+        dispense_count = data_preset(preset_selection)->count_x * data_preset(preset_selection)->count_y - (dispense_off - 1);
230
+        sm_disp_cnt.setMax(dispense_count);
231
+    });
232
+
233
+    sm_disp_go.setTitle("Confirm");
234
+    sm_disp_go.onEnter([]() {
235
+        dispense_off -= 1;
236
+        strbuf = String(F("Filling from ")) + String(dispense_off + 1);
237
+        strbuf += String(F(" to ")) + String(dispense_off + dispense_count);
238
+        strbuf += String(F("!\nIs this ok?"));
239
+        sm_disp_go.setText(strbuf.c_str());
240
+
241
+        dispense_index = dispense_off;
242
+
243
+        // TODO allow yes/no choice?
244
+    });
245
+
246
+    sm_disp_run_z_travel.setTitle("Z Travel");
247
+    sm_disp_run_z_travel.onEnter([]() {
248
+        // TODO move z to travel height
249
+    });
250
+    sm_disp_run_z_travel.whenIn([](StateMachineInput smi) {
251
+        // TODO update status screen
252
+
253
+        if (smi.all_motors_done) {
254
+            states_go_to(&sm_disp_run_xy_travel);
255
+        }
256
+    });
257
+
258
+    sm_disp_run_xy_travel.setTitle("XY Movement");
259
+    sm_disp_run_xy_travel.onEnter([]() {
260
+        int y = dispense_index / data_preset(preset_selection)->count_x;
261
+        int x = dispense_index % data_preset(preset_selection)->count_x;
262
+
263
+        Serial.print(F("xy_travel: index="));
264
+        Serial.print(dispense_index);
265
+        Serial.print(F(" x="));
266
+        Serial.print(x);
267
+        Serial.print(F(" y="));
268
+        Serial.println(y);
269
+
270
+        float x_pos = data_preset(preset_selection)->offset_x + x * data_preset(preset_selection)->distance_x;
271
+        float y_pos = data_preset(preset_selection)->offset_y + y * data_preset(preset_selection)->distance_y;
272
+
273
+        steppers_move_x(x_pos);
274
+        steppers_move_y(y_pos);
275
+    });
276
+    sm_disp_run_xy_travel.whenIn([](StateMachineInput smi) {
277
+        // TODO update status screen
278
+
279
+        if (smi.all_motors_done) {
280
+            states_go_to(&sm_disp_run_z_disp);
281
+        }
282
+    });
283
+
284
+    sm_disp_run_z_disp.setTitle("Z Dispense");
285
+    sm_disp_run_z_disp.onEnter([]() {
286
+        // TODO move z to dispension height
287
+    });
288
+    sm_disp_run_z_disp.whenIn([](StateMachineInput smi) {
289
+        // TODO update status screen
290
+
291
+        if (smi.all_motors_done) {
292
+            states_go_to(&sm_disp_run);
293
+        }
294
+    });
295
+
296
+    sm_disp_run.setTitle("Dispensing");
297
+    sm_disp_run.onEnter([]() {
298
+        // TODO start dispensing with e and moving z up
299
+    });
300
+    sm_disp_run.whenIn([](StateMachineInput smi) {
301
+        // TODO update status screen
302
+
303
+        if (smi.all_motors_done) {
304
+            dispense_index++;
305
+            if (dispense_index >= (dispense_count + dispense_off)) {
306
+                states_go_to(&sm_disp_done);
307
+            } else {
308
+                states_go_to(&sm_disp_run_z_travel);
309
+            }
310
+        }
311
+    });
312
+
313
+    sm_disp_done.setTitle("Finished");
314
+    sm_disp_done.onEnter([]() {
315
+        // TODO show end screen, "stats"
316
+    });
317
+    sm_disp_done.whenIn([](StateMachineInput smi) {
318
+        if (smi.click) {
319
+            states_go_to(&sm_auto);
320
+        }
321
+    });
172
 
322
 
173
     sm_new_preset.setTitle("Add new Preset");
323
     sm_new_preset.setTitle("Add new Preset");
174
     sm_new_preset.setHeading("Preset Wizard");
324
     sm_new_preset.setHeading("Preset Wizard");
180
     });
330
     });
181
     sm_wiz_move.whenIn([](StateMachineInput smi) {
331
     sm_wiz_move.whenIn([](StateMachineInput smi) {
182
 #ifndef DISABLE_HOMING_STATE
332
 #ifndef DISABLE_HOMING_STATE
183
-        if (smi.motors_done) {
333
+        if (smi.all_motors_done) {
184
             if (steppers_homed()) {
334
             if (steppers_homed()) {
185
 #endif // DISABLE_HOMING_STATE
335
 #endif // DISABLE_HOMING_STATE
186
                 states_go_to(&sm_wiz_count);
336
                 states_go_to(&sm_wiz_count);
272
     sm_mod_preset.dataCount([]() {
422
     sm_mod_preset.dataCount([]() {
273
         return (int)data_preset_count();
423
         return (int)data_preset_count();
274
     });
424
     });
425
+    sm_mod_preset.dataGet(preset_name_func);
275
 
426
 
276
-    // TODO
277
     sm_del_preset.setTitle("Delete Preset");
427
     sm_del_preset.setTitle("Delete Preset");
278
     sm_del_preset.setPrefix("Preset ");
428
     sm_del_preset.setPrefix("Preset ");
279
     sm_del_preset.dataCount([]() {
429
     sm_del_preset.dataCount([]() {
280
         return (int)data_preset_count();
430
         return (int)data_preset_count();
281
     });
431
     });
432
+    sm_del_preset.dataGet(preset_name_func);
433
+    sm_del_preset.dataCall([](int i) {
434
+        data_preset_remove(i);
435
+        states_go_to(&sm_auto);
436
+    });
282
 
437
 
283
     // ----------------------------------
438
     // ----------------------------------
284
 
439
 
311
         data_eeprom_write();
466
         data_eeprom_write();
312
     });
467
     });
313
 
468
 
469
+    sm_conf_clear.setTitle("Clear EEPROM & RAM");
470
+    sm_conf_clear.setHeading("Clear EEPROM & RAM");
471
+    sm_conf_clear.setText("EEPROM and RAM Configuration cleared!");
472
+    sm_conf_clear.onEnter([]() {
473
+        data_clear();
474
+        data_eeprom_write();
475
+
476
+        // reapply default conf values
477
+        steppers_set_speed_x(data_options()->speed_x);
478
+        steppers_set_speed_y(data_options()->speed_y);
479
+        steppers_set_speed_z(data_options()->speed_z);
480
+        steppers_set_speed_e(data_options()->speed_e);
481
+        steppers_set_accel_x(data_options()->accel_x);
482
+        steppers_set_accel_y(data_options()->accel_y);
483
+        steppers_set_accel_z(data_options()->accel_z);
484
+        steppers_set_accel_e(data_options()->accel_e);
485
+    });
486
+
314
     sm_conf_speed_xy.setTitle("XY Speed");
487
     sm_conf_speed_xy.setTitle("XY Speed");
315
     sm_conf_speed_xy.onUpdate([](float v) {
488
     sm_conf_speed_xy.onUpdate([](float v) {
316
         steppers_set_speed_x(v);
489
         steppers_set_speed_x(v);
346
     sm_error.setChild(&sm_ask_homing);
519
     sm_error.setChild(&sm_ask_homing);
347
     sm_error.setTitle("Axis Error");
520
     sm_error.setTitle("Axis Error");
348
     sm_error.setHeading("Axis Error");
521
     sm_error.setHeading("Axis Error");
349
-    sm_error.setText("Endstop has been hit!");
522
+    sm_error.setText("An unknown error occured!");
523
+
524
+#if defined(ENABLE_MOVEMENT_TEST_STATE) || defined(ENABLE_INPUT_TEST_STATE)
525
+    sm_debug.setTitle("Debug Menu");
526
+#endif
350
 
527
 
351
 #ifdef ENABLE_MOVEMENT_TEST_STATE
528
 #ifdef ENABLE_MOVEMENT_TEST_STATE
352
     sm_movement_test.setTitle("Movement Test");
529
     sm_movement_test.setTitle("Movement Test");
353
 
530
 
531
+    sm_move_xy_test.setTitle("XY Axes");
532
+    sm_move_xy_test.setHeading("XY Move Test");
533
+    sm_move_xy_test.setText("Moving axis through full range with selected speed.");
534
+    sm_move_xy_test.whenIn([](StateMachineInput smi) {
535
+        static bool sx = false, sy = false;
536
+        if (smi.motor_done[X_AXIS]) {
537
+            sx = !sx;
538
+            steppers_move_x(sx ? (X_AXIS_MAX - X_AXIS_EPSILON) : (X_AXIS_MIN + X_AXIS_EPSILON));
539
+        }
540
+        if (smi.motor_done[Y_AXIS]) {
541
+            sy = !sy;
542
+            steppers_move_y(sy ? (Y_AXIS_MAX - Y_AXIS_EPSILON) : (Y_AXIS_MIN + Y_AXIS_EPSILON));
543
+        }
544
+        if (smi.click) {
545
+            states_go_to(&sm_movement_test);
546
+        }
547
+    });
548
+
354
     sm_move_x_test.setTitle("X Axis");
549
     sm_move_x_test.setTitle("X Axis");
355
     sm_move_x_test.setHeading("X Move Test");
550
     sm_move_x_test.setHeading("X Move Test");
551
+    sm_move_x_test.setText("Moving axis through full range with selected speed.");
356
     sm_move_x_test.whenIn([](StateMachineInput smi) {
552
     sm_move_x_test.whenIn([](StateMachineInput smi) {
357
         static bool s = false;
553
         static bool s = false;
358
-        if (smi.motors_done) {
554
+        if (smi.motor_done[X_AXIS]) {
359
             s = !s;
555
             s = !s;
360
-            steppers_move_x(s ? (X_AXIS_MAX - 10.0) : (X_AXIS_MIN + 10.0));
361
-            if (smi.click) {
362
-                states_go_to(&sm_movement_test);
363
-            }
556
+            steppers_move_x(s ? (X_AXIS_MAX - X_AXIS_EPSILON) : (X_AXIS_MIN + X_AXIS_EPSILON));
557
+        }
558
+        if (smi.click) {
559
+            states_go_to(&sm_movement_test);
364
         }
560
         }
365
     });
561
     });
366
 
562
 
367
     sm_move_y_test.setTitle("Y Axis");
563
     sm_move_y_test.setTitle("Y Axis");
368
     sm_move_y_test.setHeading("Y Move Test");
564
     sm_move_y_test.setHeading("Y Move Test");
565
+    sm_move_y_test.setText("Moving axis through full range with selected speed.");
369
     sm_move_y_test.whenIn([](StateMachineInput smi) {
566
     sm_move_y_test.whenIn([](StateMachineInput smi) {
370
         static bool s = false;
567
         static bool s = false;
371
-        if (smi.motors_done) {
568
+        if (smi.motor_done[Y_AXIS]) {
372
             s = !s;
569
             s = !s;
373
-            steppers_move_y(s ? (Y_AXIS_MAX - 10.0) : (Y_AXIS_MIN + 10.0));
374
-            if (smi.click) {
375
-                states_go_to(&sm_movement_test);
376
-            }
570
+            steppers_move_y(s ? (Y_AXIS_MAX - Y_AXIS_EPSILON) : (Y_AXIS_MIN + Y_AXIS_EPSILON));
571
+        }
572
+        if (smi.click) {
573
+            states_go_to(&sm_movement_test);
574
+        }
575
+    });
576
+
577
+    sm_move_z_test.setTitle("Z Axis");
578
+    sm_move_z_test.setHeading("Z Move Test");
579
+    sm_move_z_test.setText("Moving axis through full range with selected speed.");
580
+    sm_move_z_test.whenIn([](StateMachineInput smi) {
581
+        static bool s = false;
582
+        if (smi.motor_done[Z_AXIS]) {
583
+            s = !s;
584
+            steppers_move_z(s ? (Z_AXIS_MAX - Z_AXIS_EPSILON) : (Z_AXIS_MIN + Z_AXIS_EPSILON));
585
+        }
586
+        if (smi.click) {
587
+            states_go_to(&sm_movement_test);
588
+        }
589
+    });
590
+
591
+    sm_move_e_test.setTitle("E Axis");
592
+    sm_move_e_test.setHeading("E Move Test");
593
+    sm_move_e_test.setText("Moving axis through full range with selected speed.");
594
+    sm_move_e_test.whenIn([](StateMachineInput smi) {
595
+        static bool s = false;
596
+        if (smi.motor_done[E_AXIS]) {
597
+            s = !s;
598
+            steppers_move_e(s ? (E_AXIS_MAX - E_AXIS_EPSILON) : (E_AXIS_MIN + E_AXIS_EPSILON));
599
+        }
600
+        if (smi.click) {
601
+            states_go_to(&sm_movement_test);
377
         }
602
         }
378
     });
603
     });
379
 #endif // ENABLE_MOVEMENT_TEST_STATE
604
 #endif // ENABLE_MOVEMENT_TEST_STATE
380
 
605
 
381
 #ifdef ENABLE_INPUT_TEST_STATE
606
 #ifdef ENABLE_INPUT_TEST_STATE
382
     sm_input_test.setTitle("Input Test");
607
     sm_input_test.setTitle("Input Test");
383
-    sm_input_test.setHeading("Input Test");
608
+    sm_input_test.setHeading("Endstop Test");
384
 
609
 
385
     sm_input_test.whenIn([](StateMachineInput smi) {
610
     sm_input_test.whenIn([](StateMachineInput smi) {
386
         String s = "Endstops: ";
611
         String s = "Endstops: ";
387
-        for (int i = 0; i < 4; i++) {
612
+        for (int i = 0; i < AXIS_COUNT; i++) {
388
             if (steppers_home_switch(i)) {
613
             if (steppers_home_switch(i)) {
389
                 s += '1';
614
                 s += '1';
390
             } else {
615
             } else {
408
 }
633
 }
409
 
634
 
410
 void states_run(StateMachineInput smi) {
635
 void states_run(StateMachineInput smi) {
636
+    if (smi.click || smi.kill || (smi.encoder != 0)) {
637
+        last_input = millis();
638
+    }
639
+
411
     if (smi.click) {
640
     if (smi.click) {
412
         async_beep(ENCODER_CLICK_BEEP_TIME, ENCODER_CLICK_BEEP_FREQ);
641
         async_beep(ENCODER_CLICK_BEEP_TIME, ENCODER_CLICK_BEEP_FREQ);
413
     }
642
     }
420
         return;
649
         return;
421
     }
650
     }
422
 
651
 
652
+#if (IDLE_TIMEOUT > 0)
653
+    unsigned long last_time = max(last_input, last_state_change);
654
+    if ((millis() - last_time) > IDLE_TIMEOUT) {
655
+        if (current_state != &sm_ask_homing) {
656
+            Serial.println(F("Idle timeout, disabling motors"));
657
+            steppers_kill();
658
+            states_go_to(&sm_ask_homing);
659
+            return;
660
+        }
661
+    }
662
+#endif // (IDLE_TIMEOUT > 0)
663
+
423
     if (current_state != NULL) {
664
     if (current_state != NULL) {
424
         current_state->inState(smi);
665
         current_state->inState(smi);
425
     }
666
     }
430
 }
671
 }
431
 
672
 
432
 void states_go_to(State *state) {
673
 void states_go_to(State *state) {
674
+    last_state_change = millis();
675
+
433
     current_state = state;
676
     current_state = state;
434
 
677
 
435
     if (current_state != NULL) {
678
     if (current_state != NULL) {

+ 189
- 128
src/steppers.cpp View File

14
 static AccelStepper stepper_z(AccelStepper::DRIVER, Z_STEP_PIN, Z_DIR_PIN, 0, 0, false);
14
 static AccelStepper stepper_z(AccelStepper::DRIVER, Z_STEP_PIN, Z_DIR_PIN, 0, 0, false);
15
 static AccelStepper stepper_e(AccelStepper::DRIVER, E0_STEP_PIN, E0_DIR_PIN, 0, 0, false);
15
 static AccelStepper stepper_e(AccelStepper::DRIVER, E0_STEP_PIN, E0_DIR_PIN, 0, 0, false);
16
 
16
 
17
+#define HOME_PHASE_START 0
18
+#define HOME_PHASE_BACK 1
19
+#define HOME_PHASE_FINE 2
20
+
17
 enum stepper_states {
21
 enum stepper_states {
18
     step_disabled,
22
     step_disabled,
19
     step_not_homed,
23
     step_not_homed,
35
 static volatile stepper_states state = step_disabled;
39
 static volatile stepper_states state = step_disabled;
36
 static volatile unsigned long steppers_home_move_start_time = 0;
40
 static volatile unsigned long steppers_home_move_start_time = 0;
37
 
41
 
42
+static volatile bool x_finished = true;
43
+static volatile bool y_finished = true;
44
+static volatile bool z_finished = true;
45
+static volatile bool e_finished = true;
46
+
38
 void steppers_init(void) {
47
 void steppers_init(void) {
39
     pinMode(X_ENDSTOP_PIN, INPUT_PULLUP);
48
     pinMode(X_ENDSTOP_PIN, INPUT_PULLUP);
40
     pinMode(Y_ENDSTOP_PIN, INPUT_PULLUP);
49
     pinMode(Y_ENDSTOP_PIN, INPUT_PULLUP);
54
     pinMode(E0_STEP_PIN, OUTPUT);
63
     pinMode(E0_STEP_PIN, OUTPUT);
55
     pinMode(E0_DIR_PIN, OUTPUT);
64
     pinMode(E0_DIR_PIN, OUTPUT);
56
 
65
 
66
+    // fan connected to D8 for electronics
67
+    pinMode(FAN_PIN, OUTPUT);
68
+    digitalWrite(FAN_PIN, LOW);
69
+
57
     stepper_x.setEnablePin(X_ENABLE_PIN);
70
     stepper_x.setEnablePin(X_ENABLE_PIN);
58
     stepper_x.setPinsInverted(false, false, true);
71
     stepper_x.setPinsInverted(false, false, true);
59
     steppers_set_speed_x(data_options()->speed_x);
72
     steppers_set_speed_x(data_options()->speed_x);
76
 }
89
 }
77
 
90
 
78
 static void steppers_initiate_home(int axis, int phase) {
91
 static void steppers_initiate_home(int axis, int phase) {
92
+#if 0
79
     Serial.print(F("steppers_initiate_home("));
93
     Serial.print(F("steppers_initiate_home("));
80
     if (axis == 0) {
94
     if (axis == 0) {
81
         Serial.print('X');
95
         Serial.print('X');
91
     Serial.print(F(", "));
105
     Serial.print(F(", "));
92
     Serial.print(phase);
106
     Serial.print(phase);
93
     Serial.println(F(")"));
107
     Serial.println(F(")"));
108
+#endif
94
 
109
 
95
     CLEAR_STORE_INTERRUPTS();
110
     CLEAR_STORE_INTERRUPTS();
96
 
111
 
97
     steppers_home_move_start_time = millis();
112
     steppers_home_move_start_time = millis();
98
 
113
 
99
-    if (axis == 0) {
114
+    if (axis == X_AXIS) {
100
         // x
115
         // x
101
-        if (phase == 0) {
102
-            state = step_homing_x_fast;
103
-            stepper_x.setSpeed(X_HOMING_DIR * X_AXIS_MOVEMENT_DIR * XY_FAST_HOME_SPEED * XY_STEPS_PER_MM);
104
-        } else if (phase == 1) {
116
+        if (phase == HOME_PHASE_START) {
117
+            if (steppers_home_switch(axis)) {
118
+#if (X_MIN_PIN == -1)
119
+                stepper_x.setCurrentPosition(X_AXIS_MAX * XY_STEPS_PER_MM * X_AXIS_MOVEMENT_DIR);
120
+#else
121
+                stepper_x.setCurrentPosition(X_AXIS_MIN * XY_STEPS_PER_MM * X_AXIS_MOVEMENT_DIR);
122
+#endif
123
+
124
+                // TODO order of homing
125
+                steppers_initiate_home(Y_AXIS, HOME_PHASE_START);
126
+            } else {
127
+                state = step_homing_x_fast;
128
+                stepper_x.setSpeed(X_HOMING_DIR * X_AXIS_MOVEMENT_DIR * XY_FAST_HOME_SPEED * XY_STEPS_PER_MM);
129
+            }
130
+        } else if (phase == HOME_PHASE_BACK) {
105
             state = step_homing_x_back;
131
             state = step_homing_x_back;
106
             stepper_x.setSpeed(-1.0 * X_HOMING_DIR * X_AXIS_MOVEMENT_DIR * XY_FAST_HOME_SPEED * XY_STEPS_PER_MM);
132
             stepper_x.setSpeed(-1.0 * X_HOMING_DIR * X_AXIS_MOVEMENT_DIR * XY_FAST_HOME_SPEED * XY_STEPS_PER_MM);
107
-        } else if (phase == 2) {
133
+        } else if (phase == HOME_PHASE_FINE) {
108
             state = step_homing_x_slow;
134
             state = step_homing_x_slow;
109
             stepper_x.setSpeed(X_HOMING_DIR * X_AXIS_MOVEMENT_DIR * XY_SLOW_HOME_SPEED * XY_STEPS_PER_MM);
135
             stepper_x.setSpeed(X_HOMING_DIR * X_AXIS_MOVEMENT_DIR * XY_SLOW_HOME_SPEED * XY_STEPS_PER_MM);
110
         }
136
         }
111
-    } else if (axis == 1) {
137
+    } else if (axis == Y_AXIS) {
112
         // y
138
         // y
113
-        if (phase == 0) {
114
-            state = step_homing_y_fast;
115
-            stepper_y.setSpeed(Y_HOMING_DIR * Y_AXIS_MOVEMENT_DIR * XY_FAST_HOME_SPEED * XY_STEPS_PER_MM);
116
-        } else if (phase == 1) {
139
+        if (phase == HOME_PHASE_START) {
140
+            if (steppers_home_switch(axis)) {
141
+
142
+#if (Y_MIN_PIN == -1)
143
+                stepper_y.setCurrentPosition(Y_AXIS_MAX * XY_STEPS_PER_MM * Y_AXIS_MOVEMENT_DIR);
144
+#else
145
+                stepper_y.setCurrentPosition(Y_AXIS_MIN * XY_STEPS_PER_MM * Y_AXIS_MOVEMENT_DIR);
146
+#endif
147
+
148
+                // TODO order of homing
149
+                //steppers_initiate_home(Z_AXIS, HOME_PHASE_START);
150
+                state = step_homed;
151
+            } else {
152
+                state = step_homing_y_fast;
153
+                stepper_y.setSpeed(Y_HOMING_DIR * Y_AXIS_MOVEMENT_DIR * XY_FAST_HOME_SPEED * XY_STEPS_PER_MM);
154
+            }
155
+        } else if (phase == HOME_PHASE_BACK) {
117
             state = step_homing_y_back;
156
             state = step_homing_y_back;
118
             stepper_y.setSpeed(-1.0 * Y_HOMING_DIR * Y_AXIS_MOVEMENT_DIR * XY_FAST_HOME_SPEED * XY_STEPS_PER_MM);
157
             stepper_y.setSpeed(-1.0 * Y_HOMING_DIR * Y_AXIS_MOVEMENT_DIR * XY_FAST_HOME_SPEED * XY_STEPS_PER_MM);
119
-        } else if (phase == 2) {
158
+        } else if (phase == HOME_PHASE_FINE) {
120
             state = step_homing_y_slow;
159
             state = step_homing_y_slow;
121
             stepper_y.setSpeed(Y_HOMING_DIR * Y_AXIS_MOVEMENT_DIR * XY_SLOW_HOME_SPEED * XY_STEPS_PER_MM);
160
             stepper_y.setSpeed(Y_HOMING_DIR * Y_AXIS_MOVEMENT_DIR * XY_SLOW_HOME_SPEED * XY_STEPS_PER_MM);
122
         }
161
         }
123
-    } else if (axis == 2) {
162
+    } else if (axis == Z_AXIS) {
124
         // z
163
         // z
125
-        if (phase == 0) {
164
+        if (phase == HOME_PHASE_START) {
126
             state = step_homing_z_fast;
165
             state = step_homing_z_fast;
127
             stepper_z.setSpeed(Z_HOMING_DIR * Z_AXIS_MOVEMENT_DIR * Z_FAST_HOME_SPEED * Z_STEPS_PER_MM);
166
             stepper_z.setSpeed(Z_HOMING_DIR * Z_AXIS_MOVEMENT_DIR * Z_FAST_HOME_SPEED * Z_STEPS_PER_MM);
128
-        } else if (phase == 1) {
167
+        } else if (phase == HOME_PHASE_BACK) {
129
             state = step_homing_z_back;
168
             state = step_homing_z_back;
130
             stepper_z.setSpeed(-1.0 * Z_HOMING_DIR * Z_AXIS_MOVEMENT_DIR * Z_FAST_HOME_SPEED * Z_STEPS_PER_MM);
169
             stepper_z.setSpeed(-1.0 * Z_HOMING_DIR * Z_AXIS_MOVEMENT_DIR * Z_FAST_HOME_SPEED * Z_STEPS_PER_MM);
131
-        } else if (phase == 2) {
170
+        } else if (phase == HOME_PHASE_FINE) {
132
             state = step_homing_z_slow;
171
             state = step_homing_z_slow;
133
             stepper_z.setSpeed(Z_HOMING_DIR * Z_AXIS_MOVEMENT_DIR * Z_SLOW_HOME_SPEED * Z_STEPS_PER_MM);
172
             stepper_z.setSpeed(Z_HOMING_DIR * Z_AXIS_MOVEMENT_DIR * Z_SLOW_HOME_SPEED * Z_STEPS_PER_MM);
134
         }
173
         }
135
-    } else if (axis == 3) {
174
+    } else if (axis == E_AXIS) {
136
         // e
175
         // e
137
-        if (phase == 0) {
176
+        if (phase == HOME_PHASE_START) {
138
             state = step_homing_e_fast;
177
             state = step_homing_e_fast;
139
             stepper_e.setSpeed(E_HOMING_DIR * E_AXIS_MOVEMENT_DIR * E_FAST_HOME_SPEED * E_STEPS_PER_PERCENT);
178
             stepper_e.setSpeed(E_HOMING_DIR * E_AXIS_MOVEMENT_DIR * E_FAST_HOME_SPEED * E_STEPS_PER_PERCENT);
140
-        } else if (phase == 1) {
179
+        } else if (phase == HOME_PHASE_BACK) {
141
             state = step_homing_e_back;
180
             state = step_homing_e_back;
142
             stepper_e.setSpeed(-1.0 * E_HOMING_DIR * E_AXIS_MOVEMENT_DIR * E_FAST_HOME_SPEED * E_STEPS_PER_PERCENT);
181
             stepper_e.setSpeed(-1.0 * E_HOMING_DIR * E_AXIS_MOVEMENT_DIR * E_FAST_HOME_SPEED * E_STEPS_PER_PERCENT);
143
-        } else if (phase == 2) {
182
+        } else if (phase == HOME_PHASE_FINE) {
144
             state = step_homing_e_slow;
183
             state = step_homing_e_slow;
145
             stepper_e.setSpeed(E_HOMING_DIR * E_AXIS_MOVEMENT_DIR * E_SLOW_HOME_SPEED * E_STEPS_PER_PERCENT);
184
             stepper_e.setSpeed(E_HOMING_DIR * E_AXIS_MOVEMENT_DIR * E_SLOW_HOME_SPEED * E_STEPS_PER_PERCENT);
146
         }
185
         }
155
     bool r = true;
194
     bool r = true;
156
     CLEAR_STORE_INTERRUPTS();
195
     CLEAR_STORE_INTERRUPTS();
157
 
196
 
158
-    if (axis == 0) {
197
+    if (axis == X_AXIS) {
159
         r = digitalRead(X_ENDSTOP_PIN) == LOW;
198
         r = digitalRead(X_ENDSTOP_PIN) == LOW;
160
-    } else if (axis == 1) {
199
+    } else if (axis == Y_AXIS) {
161
         r = digitalRead(Y_ENDSTOP_PIN) == LOW;
200
         r = digitalRead(Y_ENDSTOP_PIN) == LOW;
162
-    } else if (axis == 2) {
201
+    } else if (axis == Z_AXIS) {
163
         r = digitalRead(Z_ENDSTOP_PIN) == LOW;
202
         r = digitalRead(Z_ENDSTOP_PIN) == LOW;
164
-    } else if (axis == 3) {
203
+    } else if (axis == E_AXIS) {
165
         r = digitalRead(E_ENDSTOP_PIN) == LOW;
204
         r = digitalRead(E_ENDSTOP_PIN) == LOW;
166
     } else {
205
     } else {
167
         Serial.println(F("home_switch error: invalid axis"));
206
         Serial.println(F("home_switch error: invalid axis"));
171
     return r;
210
     return r;
172
 }
211
 }
173
 
212
 
213
+bool stepper_reached_target(int axis) {
214
+    if (axis == X_AXIS) {
215
+        return x_finished;
216
+    } else if (axis == Y_AXIS) {
217
+        return y_finished;
218
+    } else if (axis == Z_AXIS) {
219
+        return z_finished;
220
+    } else if (axis == E_AXIS) {
221
+        return e_finished;
222
+    } else {
223
+        Serial.println(F("stepper_reached_target error: invalid axis"));
224
+        return false;
225
+    }
226
+}
227
+
174
 float steppers_current_pos(int axis) {
228
 float steppers_current_pos(int axis) {
175
     float r = 0.0;
229
     float r = 0.0;
176
     CLEAR_STORE_INTERRUPTS();
230
     CLEAR_STORE_INTERRUPTS();
177
 
231
 
178
-    if (axis == 0) {
232
+    if (axis == X_AXIS) {
179
         float v = stepper_x.currentPosition();
233
         float v = stepper_x.currentPosition();
180
         r = v / XY_STEPS_PER_MM / X_AXIS_MOVEMENT_DIR;
234
         r = v / XY_STEPS_PER_MM / X_AXIS_MOVEMENT_DIR;
181
-    } else if (axis == 1) {
235
+    } else if (axis == Y_AXIS) {
182
         float v = stepper_y.currentPosition();
236
         float v = stepper_y.currentPosition();
183
         r = v / XY_STEPS_PER_MM / Y_AXIS_MOVEMENT_DIR;
237
         r = v / XY_STEPS_PER_MM / Y_AXIS_MOVEMENT_DIR;
184
-    } else if (axis == 2) {
238
+    } else if (axis == Z_AXIS) {
185
         float v = stepper_z.currentPosition();
239
         float v = stepper_z.currentPosition();
186
         r = v / Z_STEPS_PER_MM / Z_AXIS_MOVEMENT_DIR;
240
         r = v / Z_STEPS_PER_MM / Z_AXIS_MOVEMENT_DIR;
187
-    } else if (axis == 3) {
241
+    } else if (axis == E_AXIS) {
188
         float v = stepper_e.currentPosition();
242
         float v = stepper_e.currentPosition();
189
         r = E_PERCENT_TO_MM(v / E_STEPS_PER_PERCENT / E_AXIS_MOVEMENT_DIR);
243
         r = E_PERCENT_TO_MM(v / E_STEPS_PER_PERCENT / E_AXIS_MOVEMENT_DIR);
190
     } else {
244
     } else {
195
     return r;
249
     return r;
196
 }
250
 }
197
 
251
 
198
-bool steppers_run(void) {
199
-    if (state == step_homing_x_fast) {
200
-        if (steppers_home_switch(0)) {
201
-            steppers_initiate_home(0, 1);
252
+// TODO split into separate run funcs for running and homing
253
+// TODO only enable timer1 when either homing or moving
254
+// TODO disable timer1 when no longer homing/moving
255
+// TODO (when timer is disabled, still call in normal loop?)
256
+
257
+void steppers_run(void) {
258
+    if ((state == step_homed) || (state == step_not_homed)) {
259
+        for (int i = 0; i < AXIS_COUNT; i++) {
260
+#if 0
261
+            Serial.print(i);
262
+            Serial.print(": ");
263
+            Serial.println(steppers_current_pos(i));
264
+#endif
265
+
266
+            if (steppers_home_switch(i)) {
267
+                float compare = 0.0, epsilon = 0.0;
268
+                if (i == X_AXIS) {
269
+                    epsilon = X_AXIS_EPSILON;
270
+    #if (X_HOMING_DIR == 1)
271
+                    compare = X_AXIS_MAX;
272
+    #else
273
+                    compare = X_AXIS_MIN;
274
+    #endif
275
+                } else if (i == Y_AXIS) {
276
+                    epsilon = Y_AXIS_EPSILON;
277
+    #if (Y_HOMING_DIR == 1)
278
+                    compare = Y_AXIS_MAX;
279
+    #else
280
+                    compare = Y_AXIS_MIN;
281
+    #endif
282
+                } else if (i == Z_AXIS) {
283
+                    epsilon = Z_AXIS_EPSILON;
284
+    #if (Z_HOMING_DIR == 1)
285
+                    compare = Z_AXIS_MAX;
286
+    #else
287
+                    compare = Z_AXIS_MIN;
288
+    #endif
289
+                } else if (i == E_AXIS) {
290
+                    epsilon = E_AXIS_EPSILON;
291
+    #if (E_HOMING_DIR == 1)
292
+                    compare = E_AXIS_MAX;
293
+    #else
294
+                    compare = E_AXIS_MIN;
295
+    #endif
296
+                }
297
+
298
+                if (fabs(steppers_current_pos(i) - compare) > epsilon) {
299
+#if 0
300
+                    Serial.print(F("Endstop hit at "));
301
+                    Serial.println(steppers_current_pos(i));
302
+#endif
303
+
304
+                    steppers_kill();
305
+
306
+                    if (i == X_AXIS) {
307
+                        sm_error.setText("Enstop hit on X axis");
308
+                    } else if (i == Y_AXIS) {
309
+                        sm_error.setText("Enstop hit on Y axis");
310
+                    } else if (i == Z_AXIS) {
311
+                        sm_error.setText("Enstop hit on Z axis");
312
+                    } else if (i == E_AXIS) {
313
+                        sm_error.setText("Enstop hit on E axis");
314
+                    } else {
315
+                        sm_error.setText("Enstop hit on unknown axis");
316
+                    }
317
+                    states_go_to(&sm_error);
318
+                }
319
+            }
320
+        }
321
+
322
+        x_finished = !stepper_x.run();
323
+        y_finished = !stepper_y.run();
324
+        z_finished = !stepper_z.run();
325
+        e_finished = !stepper_e.run();
326
+    } else if (state == step_homing_x_fast) {
327
+        if (steppers_home_switch(X_AXIS)) {
328
+            steppers_initiate_home(X_AXIS, HOME_PHASE_BACK);
202
         } else {
329
         } else {
203
             stepper_x.runSpeed();
330
             stepper_x.runSpeed();
204
         }
331
         }
205
     } else if (state == step_homing_x_back) {
332
     } else if (state == step_homing_x_back) {
206
         unsigned long end_time = steppers_home_move_start_time + XY_HOME_BACK_OFF_TIME;
333
         unsigned long end_time = steppers_home_move_start_time + XY_HOME_BACK_OFF_TIME;
207
-        if ((!steppers_home_switch(0)) && (millis() >= end_time)) {
208
-            steppers_initiate_home(0, 2);
334
+        if ((!steppers_home_switch(X_AXIS)) && (millis() >= end_time)) {
335
+            steppers_initiate_home(X_AXIS, HOME_PHASE_FINE);
209
         } else {
336
         } else {
210
             stepper_x.runSpeed();
337
             stepper_x.runSpeed();
211
         }
338
         }
212
     } else if (state == step_homing_x_slow) {
339
     } else if (state == step_homing_x_slow) {
213
-        if (steppers_home_switch(0)) {
340
+        if (steppers_home_switch(X_AXIS)) {
214
             stepper_x.setSpeed(0);
341
             stepper_x.setSpeed(0);
215
 
342
 
216
 #if (X_MIN_PIN == -1)
343
 #if (X_MIN_PIN == -1)
219
             stepper_x.setCurrentPosition(X_AXIS_MIN * XY_STEPS_PER_MM * X_AXIS_MOVEMENT_DIR);
346
             stepper_x.setCurrentPosition(X_AXIS_MIN * XY_STEPS_PER_MM * X_AXIS_MOVEMENT_DIR);
220
 #endif
347
 #endif
221
 
348
 
222
-            steppers_initiate_home(1, 0);
349
+            steppers_initiate_home(Y_AXIS, HOME_PHASE_START);
223
         } else {
350
         } else {
224
             stepper_x.runSpeed();
351
             stepper_x.runSpeed();
225
         }
352
         }
226
     } else if (state == step_homing_y_fast) {
353
     } else if (state == step_homing_y_fast) {
227
-        if (steppers_home_switch(1)) {
228
-            steppers_initiate_home(1, 1);
354
+        if (steppers_home_switch(Y_AXIS)) {
355
+            steppers_initiate_home(Y_AXIS, HOME_PHASE_BACK);
229
         } else {
356
         } else {
230
             stepper_y.runSpeed();
357
             stepper_y.runSpeed();
231
         }
358
         }
232
     } else if (state == step_homing_y_back) {
359
     } else if (state == step_homing_y_back) {
233
         unsigned long end_time = steppers_home_move_start_time + XY_HOME_BACK_OFF_TIME;
360
         unsigned long end_time = steppers_home_move_start_time + XY_HOME_BACK_OFF_TIME;
234
-        if ((!steppers_home_switch(1)) && (millis() >= end_time)) {
235
-            steppers_initiate_home(1, 2);
361
+        if ((!steppers_home_switch(Y_AXIS)) && (millis() >= end_time)) {
362
+            steppers_initiate_home(Y_AXIS, HOME_PHASE_FINE);
236
         } else {
363
         } else {
237
             stepper_y.runSpeed();
364
             stepper_y.runSpeed();
238
         }
365
         }
239
     } else if (state == step_homing_y_slow) {
366
     } else if (state == step_homing_y_slow) {
240
-        if (steppers_home_switch(1)) {
367
+        if (steppers_home_switch(Y_AXIS)) {
241
             stepper_y.setSpeed(0);
368
             stepper_y.setSpeed(0);
242
 
369
 
243
 #if (Y_MIN_PIN == -1)
370
 #if (Y_MIN_PIN == -1)
246
             stepper_y.setCurrentPosition(Y_AXIS_MIN * XY_STEPS_PER_MM * Y_AXIS_MOVEMENT_DIR);
373
             stepper_y.setCurrentPosition(Y_AXIS_MIN * XY_STEPS_PER_MM * Y_AXIS_MOVEMENT_DIR);
247
 #endif
374
 #endif
248
 
375
 
249
-            //steppers_initiate_home(3, 0);
376
+            //steppers_initiate_home(E_AXIS, HOME_PHASE_START);
250
             // TODO
377
             // TODO
251
             state = step_homed;
378
             state = step_homed;
252
-            return false;
253
         } else {
379
         } else {
254
             stepper_y.runSpeed();
380
             stepper_y.runSpeed();
255
         }
381
         }
256
     } else if (state == step_homing_z_fast) {
382
     } else if (state == step_homing_z_fast) {
257
-        if (steppers_home_switch(2)) {
258
-            steppers_initiate_home(2, 1);
383
+        if (steppers_home_switch(Z_AXIS)) {
384
+            steppers_initiate_home(Z_AXIS, HOME_PHASE_BACK);
259
         } else {
385
         } else {
260
             stepper_z.runSpeed();
386
             stepper_z.runSpeed();
261
         }
387
         }
262
     } else if (state == step_homing_z_back) {
388
     } else if (state == step_homing_z_back) {
263
         unsigned long end_time = steppers_home_move_start_time + Z_HOME_BACK_OFF_TIME;
389
         unsigned long end_time = steppers_home_move_start_time + Z_HOME_BACK_OFF_TIME;
264
-        if ((!steppers_home_switch(2)) && (millis() >= end_time)) {
265
-            steppers_initiate_home(2, 2);
390
+        if ((!steppers_home_switch(Z_AXIS)) && (millis() >= end_time)) {
391
+            steppers_initiate_home(Z_AXIS, HOME_PHASE_FINE);
266
         } else {
392
         } else {
267
             stepper_z.runSpeed();
393
             stepper_z.runSpeed();
268
         }
394
         }
269
     } else if (state == step_homing_z_slow) {
395
     } else if (state == step_homing_z_slow) {
270
-        if (steppers_home_switch(2)) {
396
+        if (steppers_home_switch(Z_AXIS)) {
271
             stepper_z.setSpeed(0);
397
             stepper_z.setSpeed(0);
272
 
398
 
273
 #if (Z_MIN_PIN == -1)
399
 #if (Z_MIN_PIN == -1)
276
             stepper_z.setCurrentPosition(Z_AXIS_MIN * Z_STEPS_PER_MM * Z_AXIS_MOVEMENT_DIR);
402
             stepper_z.setCurrentPosition(Z_AXIS_MIN * Z_STEPS_PER_MM * Z_AXIS_MOVEMENT_DIR);
277
 #endif
403
 #endif
278
 
404
 
279
-            steppers_initiate_home(0, 0);
405
+            steppers_initiate_home(X_AXIS, HOME_PHASE_START);
280
         } else {
406
         } else {
281
             stepper_z.runSpeed();
407
             stepper_z.runSpeed();
282
         }
408
         }
283
     } else if (state == step_homing_e_fast) {
409
     } else if (state == step_homing_e_fast) {
284
-        if (steppers_home_switch(3)) {
285
-            steppers_initiate_home(3, 1);
410
+        if (steppers_home_switch(E_AXIS)) {
411
+            steppers_initiate_home(E_AXIS, HOME_PHASE_BACK);
286
         } else {
412
         } else {
287
             stepper_e.runSpeed();
413
             stepper_e.runSpeed();
288
         }
414
         }
289
     } else if (state == step_homing_e_back) {
415
     } else if (state == step_homing_e_back) {
290
         unsigned long end_time = steppers_home_move_start_time + E_HOME_BACK_OFF_TIME;
416
         unsigned long end_time = steppers_home_move_start_time + E_HOME_BACK_OFF_TIME;
291
-        if ((!steppers_home_switch(3)) && (millis() >= end_time)) {
292
-            steppers_initiate_home(3, 2);
417
+        if ((!steppers_home_switch(E_AXIS)) && (millis() >= end_time)) {
418
+            steppers_initiate_home(E_AXIS, HOME_PHASE_FINE);
293
         } else {
419
         } else {
294
             stepper_e.runSpeed();
420
             stepper_e.runSpeed();
295
         }
421
         }
296
     } else if (state == step_homing_e_slow) {
422
     } else if (state == step_homing_e_slow) {
297
-        if (steppers_home_switch(3)) {
423
+        if (steppers_home_switch(E_AXIS)) {
298
             stepper_e.setSpeed(0);
424
             stepper_e.setSpeed(0);
299
 
425
 
300
 #if (E_MIN_PIN == -1)
426
 #if (E_MIN_PIN == -1)
304
 #endif
430
 #endif
305
 
431
 
306
             state = step_homed;
432
             state = step_homed;
307
-            return false;
308
         } else {
433
         } else {
309
             stepper_e.runSpeed();
434
             stepper_e.runSpeed();
310
         }
435
         }
311
-    } else if (state != step_disabled) {
312
-        if (state == step_homed) {
313
-            for (int i = 0; i < 4; i++) {
314
-                Serial.print(i);
315
-                Serial.print(": ");
316
-                Serial.println(steppers_current_pos(i));
317
-
318
-                float compare = 0.0, epsilon = 0.0;
319
-                if (i == 0) {
320
-                    epsilon = X_AXIS_EPSILON;
321
-#if (X_MIN_PIN == -1)
322
-                    compare = X_AXIS_MAX;
323
-#else
324
-                    compare = X_AXIS_MIN;
325
-#endif
326
-                } else if (i == 1) {
327
-                    epsilon = Y_AXIS_EPSILON;
328
-#if (Y_MIN_PIN == -1)
329
-                    compare = Y_AXIS_MAX;
330
-#else
331
-                    compare = Y_AXIS_MIN;
332
-#endif
333
-                } else if (i == 2) {
334
-                    epsilon = Z_AXIS_EPSILON;
335
-#if (Z_MIN_PIN == -1)
336
-                    compare = Z_AXIS_MAX;
337
-#else
338
-                    compare = Z_AXIS_MIN;
339
-#endif
340
-                } else if (i == 3) {
341
-                    epsilon = E_AXIS_EPSILON;
342
-#if (E_MIN_PIN == -1)
343
-                    compare = E_AXIS_MAX;
344
-#else
345
-                    compare = E_AXIS_MIN;
346
-#endif
347
-                }
348
-
349
-                if (fabs(steppers_current_pos(i) - compare) > epsilon) {
350
-                    if (steppers_home_switch(i)) {
351
-                        Serial.print(F("Endstop hit at "));
352
-                        Serial.println(steppers_current_pos(i));
353
-
354
-                        steppers_kill();
355
-
356
-                        if (i == 0) {
357
-                            sm_error.setText("Enstop hit on X axis");
358
-                        } else if (i == 1) {
359
-                            sm_error.setText("Enstop hit on Y axis");
360
-                        } else if (i == 2) {
361
-                            sm_error.setText("Enstop hit on Z axis");
362
-                        } else if (i == 3) {
363
-                            sm_error.setText("Enstop hit on E axis");
364
-                        } else {
365
-                            sm_error.setText("Enstop hit on unknown axis");
366
-                        }
367
-                        states_go_to(&sm_error);
368
-                    }
369
-                }
370
-            }
371
-        }
372
-
373
-        boolean x = stepper_x.run();
374
-        boolean y = stepper_y.run();
375
-        boolean z = stepper_z.run();
376
-        boolean e = stepper_e.run();
377
-
378
-        return x || y || z || e;
379
     }
436
     }
380
-
381
-    return true;
382
 }
437
 }
383
 
438
 
384
 bool steppers_homed(void) {
439
 bool steppers_homed(void) {
409
 void steppers_start_homing(void) {
464
 void steppers_start_homing(void) {
410
     CLEAR_STORE_INTERRUPTS();
465
     CLEAR_STORE_INTERRUPTS();
411
 
466
 
467
+    digitalWrite(FAN_PIN, HIGH);
468
+
412
     stepper_x.enableOutputs();
469
     stepper_x.enableOutputs();
413
     stepper_y.enableOutputs();
470
     stepper_y.enableOutputs();
414
     stepper_z.enableOutputs();
471
     stepper_z.enableOutputs();
415
     stepper_e.enableOutputs();
472
     stepper_e.enableOutputs();
416
 
473
 
417
-    //steppers_initiate_home(2, 0);
474
+    //steppers_initiate_home(Z_AXIS, HOME_PHASE_START);
418
     // TODO
475
     // TODO
419
-    steppers_initiate_home(0, 0);
476
+    steppers_initiate_home(X_AXIS, HOME_PHASE_START);
420
 
477
 
421
     RESTORE_INTERRUPTS();
478
     RESTORE_INTERRUPTS();
422
 }
479
 }
427
     if (state == step_disabled) {
484
     if (state == step_disabled) {
428
         Serial.println(F("Enabling stepper drivers"));
485
         Serial.println(F("Enabling stepper drivers"));
429
 
486
 
487
+        digitalWrite(FAN_PIN, HIGH);
488
+
430
         stepper_x.enableOutputs();
489
         stepper_x.enableOutputs();
431
         stepper_y.enableOutputs();
490
         stepper_y.enableOutputs();
432
         stepper_z.enableOutputs();
491
         stepper_z.enableOutputs();
567
     stepper_z.disableOutputs();
626
     stepper_z.disableOutputs();
568
     stepper_e.disableOutputs();
627
     stepper_e.disableOutputs();
569
 
628
 
570
-    state = step_not_homed;
629
+    digitalWrite(FAN_PIN, LOW);
630
+
631
+    state = step_disabled;
571
 
632
 
572
     RESTORE_INTERRUPTS();
633
     RESTORE_INTERRUPTS();
573
 }
634
 }

Loading…
Cancel
Save