2 コミット

作成者 SHA1 メッセージ 日付
  Thomas Buck 924921ebdd whole lot of firmware work. xy table now basically usable. 2年前
  Thomas Buck 0b1d191b71 added simple feet and spacer for plate to hardware design 2年前
19個のファイルの変更1273行の追加805行の削除
  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 ファイルの表示

@@ -247,11 +247,16 @@ draw_pulleys = false;
247 247
 
248 248
 left_support_len = 200;
249 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 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 260
 endstop_pcb_width = 16.0;
256 261
 endstop_pcb_height = 40.0;
257 262
 endstop_pcb_depth = 1.6;
@@ -272,3 +277,15 @@ endstop_pcb_mount_off_d = 18; // TODO was 8
272 277
 endstop_pcb_mount_off_w = endstop_mount_slot_length;
273 278
 
274 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 ファイルの表示

@@ -432,6 +432,31 @@ module y_carriage_posts() {
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 460
 // also used as base for x-carriage
436 461
 // axis = 0 --> all holes, usable for both
437 462
 // axis = 1 --> holes for x-carriage
@@ -505,8 +530,13 @@ module y_carriage(axis = 0) {
505 530
 
506 531
 module y_axis() {
507 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 541
     color("grey")
512 542
     translate([-10, 0, 0])
@@ -594,7 +624,7 @@ module assembly_y_axis_plate() {
594 624
     translate([0, -y_carriage_y / 2 - y_axis_animation_position, 0])
595 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 628
     plate();
599 629
 }
600 630
 
@@ -606,13 +636,27 @@ module assembly_x_axis() {
606 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 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 662
 module assembly() {
@@ -632,7 +676,15 @@ module assembly() {
632 676
             translate([x_axis_rail_len - 20 - right_support_off, -right_support_len - 10, -20])
633 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 688
         } else {
637 689
             color("grey")
638 690
             translate([x_axis_rail_len / 2, 0, -40])
@@ -641,13 +693,21 @@ module assembly() {
641 693
             translate([x_axis_rail_len / 2 - bottom_support_off, -bottom_support_len / 2, 0])
642 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 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 711
     assembly();
652 712
 }
653 713
 
@@ -658,6 +718,7 @@ module xy_table() {
658 718
 //dispenser();
659 719
 //rail_2020_x(100);
660 720
 //rail_wheel();
721
+//rail_foot();
661 722
 
662 723
 //motor_mount(1);
663 724
 //motor_mount(2);
@@ -677,6 +738,7 @@ module xy_table() {
677 738
 //y_carriage(1);
678 739
 //y_carriage(2);
679 740
 //x_carriage();
741
+//carriage_spacer();
680 742
 
681 743
 //y_axis();
682 744
 //x_axis();

+ 3
- 1
include/common.h ファイルの表示

@@ -3,9 +3,11 @@
3 3
 
4 4
 #define CLEAR_STORE_INTERRUPTS() uint8_t prev_int_reg = SREG; cli()
5 5
 #define RESTORE_INTERRUPTS() SREG = prev_int_reg
6
+//#define CLEAR_STORE_INTERRUPTS() cli()
7
+//#define RESTORE_INTERRUPTS() sei()
6 8
 
7 9
 void async_beep(int time, int freq);
8 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 13
 #endif // _COMMON_H_

+ 20
- 6
include/config.h ファイルの表示

@@ -24,6 +24,12 @@
24 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 33
 // xy steps per mm
28 34
 #define XY_BELT_PITCH 2.0
29 35
 #define XY_PULLEY_TEETH 40.0
@@ -67,9 +73,9 @@
67 73
 #define E_MM_TO_PERCENT(x) ((acos((x * 2.0 / E_AXIS_MAX) - 1.0) - PI) * 100.0 / PI)
68 74
 
69 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 80
 // homing speeds
75 81
 #define XY_FAST_HOME_SPEED 25.0 // in mm/s
@@ -100,11 +106,19 @@
100 106
 #define E_HOME_BACK_OFF_TIME (E_BACK_OFF_DISTANCE / E_FAST_HOME_SPEED * 1000)
101 107
 
102 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 112
 #define Z_AXIS_EPSILON 1.0
106 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 124
 #endif // _CONFIG_H_

+ 8
- 8
include/config_pins.h ファイルの表示

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

+ 22
- 5
include/data.h ファイルの表示

@@ -1,22 +1,39 @@
1 1
 #ifndef _DATA_H_
2 2
 #define _DATA_H_
3 3
 
4
-#define DATA_SCHEMA_VERSION 0
4
+#define DATA_SCHEMA_VERSION 1
5 5
 
6 6
 struct data_config_options {
7
+    // in mm/s (%/s for e)
7 8
     float speed_x, speed_y, speed_z, speed_e;
9
+
10
+    // in mm/s^2 (%/s^2 for e)
8 11
     float accel_x, accel_y, accel_z, accel_e;
9 12
 };
10 13
 
11 14
 struct data_config_preset {
15
+    // number of containers
12 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 35
 void data_init(void);
36
+void data_clear(void);
20 37
 void data_eeprom_write(void);
21 38
 
22 39
 bool data_eeprom_read(void);

+ 9
- 2
include/encoder.h ファイルの表示

@@ -2,11 +2,18 @@
2 2
 #define _ENCODER_H_
3 3
 
4 4
 void encoder_init(void);
5
+
5 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 16
 int encoder_change(void);
8 17
 int encoder_rpm(void);
9
-int encoder_click(void);
10
-int kill_switch(void);
11 18
 
12 19
 #endif // _ENCODER_H_

+ 25
- 45
include/statemachine.h ファイルの表示

@@ -5,25 +5,27 @@
5 5
 
6 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 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 17
     int encoder;
20 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 24
 class State {
26 25
 public:
26
+    typedef void(*EnterFuncPtr)(void);
27
+    typedef void(*InFuncPtr)(StateMachineInput smi);
28
+
27 29
     State(State *_parent = NULL);
28 30
     State *getParent(void) { return parent; }
29 31
 
@@ -33,34 +35,24 @@ public:
33 35
     void setTitle(const char *_title) { title = _title; }
34 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 47
     void updateText(void);
59 48
 
60 49
     virtual void enterState(void);
61 50
     virtual void inState(StateMachineInput smi);
62 51
 
63
-private:
52
+protected:
53
+    State *parent;
54
+    State *child;
55
+    const char *title;
64 56
     const char *heading;
65 57
     const char *text;
66 58
     EnterFuncPtr onEnterFunc;
@@ -120,13 +112,10 @@ class StateValue : public State {
120 112
 public:
121 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 117
     typedef void(*UpdateFuncPtr)(T value);
128 118
 
129
-    void onEnter(EnterFuncPtr func);
130 119
     void onLiveUpdate(UpdateFuncPtr func);
131 120
     void onUpdate(UpdateFuncPtr func);
132 121
 
@@ -138,9 +127,6 @@ private:
138 127
 
139 128
     T &value;
140 129
     T min, max;
141
-    const char *heading;
142
-    const char *text;
143
-    EnterFuncPtr onEnterFunc;
144 130
     UpdateFuncPtr updateFunc, updateLiveFunc;
145 131
 };
146 132
 
@@ -151,13 +137,8 @@ public:
151 137
 
152 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 140
     typedef void(*UpdateFuncPtr)(size_t index, T value);
159 141
 
160
-    void onEnter(EnterFuncPtr func);
161 142
     void onLiveUpdate(UpdateFuncPtr func);
162 143
     void onUpdate(UpdateFuncPtr func);
163 144
 
@@ -173,7 +154,6 @@ private:
173 154
     const char *heading;
174 155
     size_t pos;
175 156
     bool editing;
176
-    EnterFuncPtr onEnterFunc;
177 157
     UpdateFuncPtr updateFunc, updateLiveFunc;
178 158
 };
179 159
 

+ 1
- 1
include/states.h ファイルの表示

@@ -9,6 +9,6 @@ void states_run(struct StateMachineInput smi);
9 9
 State *states_get(void);
10 10
 void states_go_to(State *state);
11 11
 
12
-extern StateText sm_error;
12
+extern State sm_error;
13 13
 
14 14
 #endif // _STATES_H_

+ 2
- 1
include/steppers.h ファイルの表示

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

+ 15
- 2
src/common.cpp ファイルの表示

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

+ 33
- 17
src/data.cpp ファイルの表示

@@ -37,20 +37,30 @@ static unsigned int max_presets(void) {
37 37
 }
38 38
 
39 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 46
     uint32_t c = 0;
41 47
 
48
+
42 49
     uint8_t *t = (uint8_t *)data;
43 50
     for (unsigned int i = 0; i < sizeof(struct data_config); i++) {
44 51
         c ^= t[i];
45 52
     }
46 53
 
47 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 56
         for (unsigned int j = 0; j < sizeof(struct data_config_preset); j++) {
50 57
             c ^= t[j];
51 58
         }
52 59
     }
53 60
 
61
+    data->checksum = temp_checksum;
62
+    data->presets = temp_presets;
63
+
54 64
     return c;
55 65
 }
56 66
 
@@ -94,7 +104,6 @@ bool data_eeprom_read(void) {
94 104
 
95 105
     // verify checksum
96 106
     uint32_t read_checksum = config.checksum;
97
-    config.checksum = 0;
98 107
     uint32_t checksum = data_checksum(&config);
99 108
     if (read_checksum == checksum) {
100 109
         // verify version
@@ -112,7 +121,7 @@ bool data_eeprom_read(void) {
112 121
         }
113 122
     } else {
114 123
         Serial.print(F("checksum read="));
115
-        Serial.print(config.checksum);
124
+        Serial.print(read_checksum);
116 125
         Serial.print(F(" calc="));
117 126
         Serial.println(checksum);
118 127
         last_error = "Checksum";
@@ -121,7 +130,6 @@ bool data_eeprom_read(void) {
121 130
 }
122 131
 
123 132
 void data_eeprom_write(void) {
124
-    d.checksum = 0;
125 133
     d.checksum = data_checksum(&d);
126 134
 
127 135
     // write meta-data and settings
@@ -142,6 +150,27 @@ void data_eeprom_write(void) {
142 150
 }
143 151
 
144 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 174
     d.data_schema_version = DATA_SCHEMA_VERSION;
146 175
     d.preset_count = 0;
147 176
     d.checksum = 0;
@@ -155,19 +184,6 @@ void data_init(void) {
155 184
     d.options.accel_y = XY_MAX_ACCEL;
156 185
     d.options.accel_z = Z_MAX_ACCEL;
157 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 189
 struct data_config_options *data_options(void) {

+ 32
- 28
src/encoder.cpp ファイルの表示

@@ -42,32 +42,9 @@ void encoder_run(void) {
42 42
 #ifdef KILL_PIN
43 43
     kill_state = kill.poll();
44 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 48
     int r = click_state;
72 49
 
73 50
     // only return 1 once for each click
@@ -80,10 +57,10 @@ int encoder_click(void) {
80 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 64
 #ifdef KILL_PIN
88 65
 #ifdef DEBUG_ENCODER
89 66
     if (kill_state == 1) {
@@ -91,8 +68,35 @@ int kill_switch(void) {
91 68
     }
92 69
 #endif // DEBUG_ENCODER
93 70
 
94
-    return kill_state;
71
+    return kill_state ? true : false;
95 72
 #else
96
-    return 0;
73
+    return false;
97 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 ファイルの表示

@@ -10,7 +10,8 @@
10 10
 #include "steppers.h"
11 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 16
 void print_data(void) {
16 17
     Serial.println(F("XY:"));
@@ -88,11 +89,29 @@ void print_data(void) {
88 89
     Serial.println(F(" percent/s^2"));
89 90
 
90 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 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 117
 void setup() {
@@ -102,10 +121,6 @@ void setup() {
102 121
     pinMode(BEEPER, OUTPUT);
103 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 124
     Serial.begin(115200);
110 125
     Serial.println(F("Initializing Fuellfix v2"));
111 126
     Serial.print(F("Version: "));
@@ -123,14 +138,14 @@ void setup() {
123 138
     Serial.println(F("Init stepper motors"));
124 139
     steppers_init();
125 140
 
126
-    print_data();
141
+    //print_data();
127 142
 
128 143
     Serial.println(F("ready, showing splash screen"));
129 144
     digitalWrite(LED_PIN, LOW);
130 145
     blocking_beep(100, 2000);
131 146
 
132 147
     // wait some time to show splash screen
133
-    delay(2000);
148
+    while (millis() < 1500) { }
134 149
 
135 150
     Serial.println(F("Init state machine"));
136 151
     states_init();
@@ -138,27 +153,69 @@ void setup() {
138 153
     blocking_beep(100, 2000);
139 154
     Serial.println(F("starting main loop"));
140 155
 
141
-    Timer1.initialize(1000); // 1000us -> 1kHz
156
+    Timer1.initialize(us);
142 157
     Timer1.attachInterrupt(fast_loop);
143 158
 }
144 159
 
145 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 167
     CLEAR_STORE_INTERRUPTS();
149 168
 
150
-    int click = encoder_click();
151 169
     int change = encoder_change();
152 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 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 218
     states_run(smi);
160 219
 
161 220
     lcd_loop();
162
-
163
-    delay(10);
164 221
 }

+ 225
- 0
src/sm_menu.cpp ファイルの表示

@@ -0,0 +1,225 @@
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 ファイルの表示

@@ -0,0 +1,239 @@
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 ファイルの表示

@@ -5,18 +5,14 @@
5 5
 #include "lcd.h"
6 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 10
     if (_parent != NULL) {
10 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 14
     onEnterFunc = []() { };
15
+
20 16
     whenInFunc = [](StateMachineInput smi) {
21 17
         State *s = states_get();
22 18
         if (smi.click && (s != NULL)) {
@@ -29,35 +25,21 @@ StateText::StateText(State *_parent) : State(_parent) {
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 29
     lcd_clear();
30
+
50 31
     if (heading != NULL) {
51 32
         lcd_set_heading(heading);
52 33
     } else if (getTitle() != NULL) {
53 34
         lcd_set_heading(getTitle());
54 35
     }
36
+
55 37
     if (text != NULL) {
56 38
         lcd_set_text(text);
57 39
     }
58 40
 }
59 41
 
60
-void StateText::enterState(void) {
42
+void State::enterState(void) {
61 43
     if (onEnterFunc != NULL) {
62 44
         onEnterFunc();
63 45
     }
@@ -65,480 +47,8 @@ void StateText::enterState(void) {
65 47
     updateText();
66 48
 }
67 49
 
68
-void StateText::inState(struct StateMachineInput smi) {
50
+void State::inState(struct StateMachineInput smi) {
69 51
     if (whenInFunc != NULL) {
70 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 ファイルの表示

@@ -15,23 +15,35 @@
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 23
 StateMenu sm_menu = StateMenu(&sm_do_homing, false);
21 24
 
22 25
 StateMenu sm_auto = StateMenu(&sm_menu);
23 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 39
 StateValues<uint8_t, 2> sm_wiz_count = StateValues<uint8_t, 2>(&sm_wiz_move);
29 40
 StateValues<float, 2> sm_wiz_first_pos = StateValues<float, 2>(&sm_wiz_count);
30 41
 StateValues<float, 2> sm_wiz_last_pos = StateValues<float, 2>(&sm_wiz_first_pos);
31 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 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 48
 StateDynamicMenu sm_mod_preset = StateDynamicMenu(&sm_auto);
37 49
 // TODO modify
@@ -39,16 +51,18 @@ StateDynamicMenu sm_mod_preset = StateDynamicMenu(&sm_auto);
39 51
 StateDynamicMenu sm_del_preset = StateDynamicMenu(&sm_auto);
40 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 54
 StateMenu sm_move = StateMenu(&sm_menu);
44 55
 StateValue<float> sm_move_x = StateValue<float>(&sm_move, move_pos_x, X_AXIS_MIN, X_AXIS_MAX);
45 56
 StateValue<float> sm_move_y = StateValue<float>(&sm_move, move_pos_y, Y_AXIS_MIN, Y_AXIS_MAX);
46 57
 StateValue<float> sm_move_z = StateValue<float>(&sm_move, move_pos_z, Z_AXIS_MIN, Z_AXIS_MAX);
47 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 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 66
 StateValue<float> sm_conf_speed_xy = StateValue<float>(&sm_config, data_options()->speed_x, 1.0, XY_MAX_SPEED);
53 67
 StateValue<float> sm_conf_speed_z = StateValue<float>(&sm_config, data_options()->speed_z, 1.0, Z_MAX_SPEED);
54 68
 StateValue<float> sm_conf_speed_e = StateValue<float>(&sm_config, data_options()->speed_e, 1.0, E_MAX_SPEED);
@@ -56,16 +70,23 @@ StateValue<float> sm_conf_accel_xy = StateValue<float>(&sm_config, data_options(
56 70
 StateValue<float> sm_conf_accel_z = StateValue<float>(&sm_config, data_options()->accel_z, 1.0, Z_MAX_ACCEL);
57 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 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 86
 #endif // ENABLE_MOVEMENT_TEST_STATE
66 87
 
67 88
 #ifdef ENABLE_INPUT_TEST_STATE
68
-StateText sm_input_test = StateText(&sm_menu);
89
+State sm_input_test = State(&sm_debug);
69 90
 #endif // ENABLE_INPUT_TEST_STATE
70 91
 
71 92
 // --------------------------------------
@@ -75,6 +96,7 @@ String strbuf;
75 96
 struct data_config_preset wizard_preset = { .count_x = 1, .count_y = 1 };
76 97
 float wizard_first_x = 0.0, wizard_first_y = 0.0;
77 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 101
 void states_init(void) {
80 102
     // ----------------------------------
@@ -96,7 +118,7 @@ void states_init(void) {
96 118
 
97 119
     sm_do_homing.whenIn([](StateMachineInput smi) {
98 120
 #ifndef DISABLE_HOMING_STATE
99
-        if (smi.motors_done) {
121
+        if (smi.all_motors_done) {
100 122
             if (steppers_homed()) {
101 123
 #endif // DISABLE_HOMING_STATE
102 124
 
@@ -159,16 +181,144 @@ void states_init(void) {
159 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 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 208
     sm_presets.setTitle("Use Preset");
168 209
     sm_presets.setPrefix("Preset ");
169 210
     sm_presets.dataCount([]() {
170 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 323
     sm_new_preset.setTitle("Add new Preset");
174 324
     sm_new_preset.setHeading("Preset Wizard");
@@ -180,7 +330,7 @@ void states_init(void) {
180 330
     });
181 331
     sm_wiz_move.whenIn([](StateMachineInput smi) {
182 332
 #ifndef DISABLE_HOMING_STATE
183
-        if (smi.motors_done) {
333
+        if (smi.all_motors_done) {
184 334
             if (steppers_homed()) {
185 335
 #endif // DISABLE_HOMING_STATE
186 336
                 states_go_to(&sm_wiz_count);
@@ -272,13 +422,18 @@ void states_init(void) {
272 422
     sm_mod_preset.dataCount([]() {
273 423
         return (int)data_preset_count();
274 424
     });
425
+    sm_mod_preset.dataGet(preset_name_func);
275 426
 
276
-    // TODO
277 427
     sm_del_preset.setTitle("Delete Preset");
278 428
     sm_del_preset.setPrefix("Preset ");
279 429
     sm_del_preset.dataCount([]() {
280 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,6 +466,24 @@ void states_init(void) {
311 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 487
     sm_conf_speed_xy.setTitle("XY Speed");
315 488
     sm_conf_speed_xy.onUpdate([](float v) {
316 489
         steppers_set_speed_x(v);
@@ -346,45 +519,97 @@ void states_init(void) {
346 519
     sm_error.setChild(&sm_ask_homing);
347 520
     sm_error.setTitle("Axis Error");
348 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 528
 #ifdef ENABLE_MOVEMENT_TEST_STATE
352 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 549
     sm_move_x_test.setTitle("X Axis");
355 550
     sm_move_x_test.setHeading("X Move Test");
551
+    sm_move_x_test.setText("Moving axis through full range with selected speed.");
356 552
     sm_move_x_test.whenIn([](StateMachineInput smi) {
357 553
         static bool s = false;
358
-        if (smi.motors_done) {
554
+        if (smi.motor_done[X_AXIS]) {
359 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 563
     sm_move_y_test.setTitle("Y Axis");
368 564
     sm_move_y_test.setHeading("Y Move Test");
565
+    sm_move_y_test.setText("Moving axis through full range with selected speed.");
369 566
     sm_move_y_test.whenIn([](StateMachineInput smi) {
370 567
         static bool s = false;
371
-        if (smi.motors_done) {
568
+        if (smi.motor_done[Y_AXIS]) {
372 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 604
 #endif // ENABLE_MOVEMENT_TEST_STATE
380 605
 
381 606
 #ifdef ENABLE_INPUT_TEST_STATE
382 607
     sm_input_test.setTitle("Input Test");
383
-    sm_input_test.setHeading("Input Test");
608
+    sm_input_test.setHeading("Endstop Test");
384 609
 
385 610
     sm_input_test.whenIn([](StateMachineInput smi) {
386 611
         String s = "Endstops: ";
387
-        for (int i = 0; i < 4; i++) {
612
+        for (int i = 0; i < AXIS_COUNT; i++) {
388 613
             if (steppers_home_switch(i)) {
389 614
                 s += '1';
390 615
             } else {
@@ -408,6 +633,10 @@ void states_init(void) {
408 633
 }
409 634
 
410 635
 void states_run(StateMachineInput smi) {
636
+    if (smi.click || smi.kill || (smi.encoder != 0)) {
637
+        last_input = millis();
638
+    }
639
+
411 640
     if (smi.click) {
412 641
         async_beep(ENCODER_CLICK_BEEP_TIME, ENCODER_CLICK_BEEP_FREQ);
413 642
     }
@@ -420,6 +649,18 @@ void states_run(StateMachineInput smi) {
420 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 664
     if (current_state != NULL) {
424 665
         current_state->inState(smi);
425 666
     }
@@ -430,6 +671,8 @@ State *states_get(void) {
430 671
 }
431 672
 
432 673
 void states_go_to(State *state) {
674
+    last_state_change = millis();
675
+
433 676
     current_state = state;
434 677
 
435 678
     if (current_state != NULL) {

+ 189
- 128
src/steppers.cpp ファイルの表示

@@ -14,6 +14,10 @@ static AccelStepper stepper_y(AccelStepper::DRIVER, Y_STEP_PIN, Y_DIR_PIN, 0, 0,
14 14
 static AccelStepper stepper_z(AccelStepper::DRIVER, Z_STEP_PIN, Z_DIR_PIN, 0, 0, false);
15 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 21
 enum stepper_states {
18 22
     step_disabled,
19 23
     step_not_homed,
@@ -35,6 +39,11 @@ enum stepper_states {
35 39
 static volatile stepper_states state = step_disabled;
36 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 47
 void steppers_init(void) {
39 48
     pinMode(X_ENDSTOP_PIN, INPUT_PULLUP);
40 49
     pinMode(Y_ENDSTOP_PIN, INPUT_PULLUP);
@@ -54,6 +63,10 @@ void steppers_init(void) {
54 63
     pinMode(E0_STEP_PIN, OUTPUT);
55 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 70
     stepper_x.setEnablePin(X_ENABLE_PIN);
58 71
     stepper_x.setPinsInverted(false, false, true);
59 72
     steppers_set_speed_x(data_options()->speed_x);
@@ -76,6 +89,7 @@ void steppers_init(void) {
76 89
 }
77 90
 
78 91
 static void steppers_initiate_home(int axis, int phase) {
92
+#if 0
79 93
     Serial.print(F("steppers_initiate_home("));
80 94
     if (axis == 0) {
81 95
         Serial.print('X');
@@ -91,56 +105,81 @@ static void steppers_initiate_home(int axis, int phase) {
91 105
     Serial.print(F(", "));
92 106
     Serial.print(phase);
93 107
     Serial.println(F(")"));
108
+#endif
94 109
 
95 110
     CLEAR_STORE_INTERRUPTS();
96 111
 
97 112
     steppers_home_move_start_time = millis();
98 113
 
99
-    if (axis == 0) {
114
+    if (axis == X_AXIS) {
100 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 131
             state = step_homing_x_back;
106 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 134
             state = step_homing_x_slow;
109 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 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 156
             state = step_homing_y_back;
118 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 159
             state = step_homing_y_slow;
121 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 163
         // z
125
-        if (phase == 0) {
164
+        if (phase == HOME_PHASE_START) {
126 165
             state = step_homing_z_fast;
127 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 168
             state = step_homing_z_back;
130 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 171
             state = step_homing_z_slow;
133 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 175
         // e
137
-        if (phase == 0) {
176
+        if (phase == HOME_PHASE_START) {
138 177
             state = step_homing_e_fast;
139 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 180
             state = step_homing_e_back;
142 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 183
             state = step_homing_e_slow;
145 184
             stepper_e.setSpeed(E_HOMING_DIR * E_AXIS_MOVEMENT_DIR * E_SLOW_HOME_SPEED * E_STEPS_PER_PERCENT);
146 185
         }
@@ -155,13 +194,13 @@ bool steppers_home_switch(int axis) {
155 194
     bool r = true;
156 195
     CLEAR_STORE_INTERRUPTS();
157 196
 
158
-    if (axis == 0) {
197
+    if (axis == X_AXIS) {
159 198
         r = digitalRead(X_ENDSTOP_PIN) == LOW;
160
-    } else if (axis == 1) {
199
+    } else if (axis == Y_AXIS) {
161 200
         r = digitalRead(Y_ENDSTOP_PIN) == LOW;
162
-    } else if (axis == 2) {
201
+    } else if (axis == Z_AXIS) {
163 202
         r = digitalRead(Z_ENDSTOP_PIN) == LOW;
164
-    } else if (axis == 3) {
203
+    } else if (axis == E_AXIS) {
165 204
         r = digitalRead(E_ENDSTOP_PIN) == LOW;
166 205
     } else {
167 206
         Serial.println(F("home_switch error: invalid axis"));
@@ -171,20 +210,35 @@ bool steppers_home_switch(int axis) {
171 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 228
 float steppers_current_pos(int axis) {
175 229
     float r = 0.0;
176 230
     CLEAR_STORE_INTERRUPTS();
177 231
 
178
-    if (axis == 0) {
232
+    if (axis == X_AXIS) {
179 233
         float v = stepper_x.currentPosition();
180 234
         r = v / XY_STEPS_PER_MM / X_AXIS_MOVEMENT_DIR;
181
-    } else if (axis == 1) {
235
+    } else if (axis == Y_AXIS) {
182 236
         float v = stepper_y.currentPosition();
183 237
         r = v / XY_STEPS_PER_MM / Y_AXIS_MOVEMENT_DIR;
184
-    } else if (axis == 2) {
238
+    } else if (axis == Z_AXIS) {
185 239
         float v = stepper_z.currentPosition();
186 240
         r = v / Z_STEPS_PER_MM / Z_AXIS_MOVEMENT_DIR;
187
-    } else if (axis == 3) {
241
+    } else if (axis == E_AXIS) {
188 242
         float v = stepper_e.currentPosition();
189 243
         r = E_PERCENT_TO_MM(v / E_STEPS_PER_PERCENT / E_AXIS_MOVEMENT_DIR);
190 244
     } else {
@@ -195,22 +249,95 @@ float steppers_current_pos(int axis) {
195 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 329
         } else {
203 330
             stepper_x.runSpeed();
204 331
         }
205 332
     } else if (state == step_homing_x_back) {
206 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 336
         } else {
210 337
             stepper_x.runSpeed();
211 338
         }
212 339
     } else if (state == step_homing_x_slow) {
213
-        if (steppers_home_switch(0)) {
340
+        if (steppers_home_switch(X_AXIS)) {
214 341
             stepper_x.setSpeed(0);
215 342
 
216 343
 #if (X_MIN_PIN == -1)
@@ -219,25 +346,25 @@ bool steppers_run(void) {
219 346
             stepper_x.setCurrentPosition(X_AXIS_MIN * XY_STEPS_PER_MM * X_AXIS_MOVEMENT_DIR);
220 347
 #endif
221 348
 
222
-            steppers_initiate_home(1, 0);
349
+            steppers_initiate_home(Y_AXIS, HOME_PHASE_START);
223 350
         } else {
224 351
             stepper_x.runSpeed();
225 352
         }
226 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 356
         } else {
230 357
             stepper_y.runSpeed();
231 358
         }
232 359
     } else if (state == step_homing_y_back) {
233 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 363
         } else {
237 364
             stepper_y.runSpeed();
238 365
         }
239 366
     } else if (state == step_homing_y_slow) {
240
-        if (steppers_home_switch(1)) {
367
+        if (steppers_home_switch(Y_AXIS)) {
241 368
             stepper_y.setSpeed(0);
242 369
 
243 370
 #if (Y_MIN_PIN == -1)
@@ -246,28 +373,27 @@ bool steppers_run(void) {
246 373
             stepper_y.setCurrentPosition(Y_AXIS_MIN * XY_STEPS_PER_MM * Y_AXIS_MOVEMENT_DIR);
247 374
 #endif
248 375
 
249
-            //steppers_initiate_home(3, 0);
376
+            //steppers_initiate_home(E_AXIS, HOME_PHASE_START);
250 377
             // TODO
251 378
             state = step_homed;
252
-            return false;
253 379
         } else {
254 380
             stepper_y.runSpeed();
255 381
         }
256 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 385
         } else {
260 386
             stepper_z.runSpeed();
261 387
         }
262 388
     } else if (state == step_homing_z_back) {
263 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 392
         } else {
267 393
             stepper_z.runSpeed();
268 394
         }
269 395
     } else if (state == step_homing_z_slow) {
270
-        if (steppers_home_switch(2)) {
396
+        if (steppers_home_switch(Z_AXIS)) {
271 397
             stepper_z.setSpeed(0);
272 398
 
273 399
 #if (Z_MIN_PIN == -1)
@@ -276,25 +402,25 @@ bool steppers_run(void) {
276 402
             stepper_z.setCurrentPosition(Z_AXIS_MIN * Z_STEPS_PER_MM * Z_AXIS_MOVEMENT_DIR);
277 403
 #endif
278 404
 
279
-            steppers_initiate_home(0, 0);
405
+            steppers_initiate_home(X_AXIS, HOME_PHASE_START);
280 406
         } else {
281 407
             stepper_z.runSpeed();
282 408
         }
283 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 412
         } else {
287 413
             stepper_e.runSpeed();
288 414
         }
289 415
     } else if (state == step_homing_e_back) {
290 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 419
         } else {
294 420
             stepper_e.runSpeed();
295 421
         }
296 422
     } else if (state == step_homing_e_slow) {
297
-        if (steppers_home_switch(3)) {
423
+        if (steppers_home_switch(E_AXIS)) {
298 424
             stepper_e.setSpeed(0);
299 425
 
300 426
 #if (E_MIN_PIN == -1)
@@ -304,81 +430,10 @@ bool steppers_run(void) {
304 430
 #endif
305 431
 
306 432
             state = step_homed;
307
-            return false;
308 433
         } else {
309 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 439
 bool steppers_homed(void) {
@@ -409,14 +464,16 @@ char steppers_homing_axis(void) {
409 464
 void steppers_start_homing(void) {
410 465
     CLEAR_STORE_INTERRUPTS();
411 466
 
467
+    digitalWrite(FAN_PIN, HIGH);
468
+
412 469
     stepper_x.enableOutputs();
413 470
     stepper_y.enableOutputs();
414 471
     stepper_z.enableOutputs();
415 472
     stepper_e.enableOutputs();
416 473
 
417
-    //steppers_initiate_home(2, 0);
474
+    //steppers_initiate_home(Z_AXIS, HOME_PHASE_START);
418 475
     // TODO
419
-    steppers_initiate_home(0, 0);
476
+    steppers_initiate_home(X_AXIS, HOME_PHASE_START);
420 477
 
421 478
     RESTORE_INTERRUPTS();
422 479
 }
@@ -427,6 +484,8 @@ static int steppers_move_axis(AccelStepper &axis, long pos) {
427 484
     if (state == step_disabled) {
428 485
         Serial.println(F("Enabling stepper drivers"));
429 486
 
487
+        digitalWrite(FAN_PIN, HIGH);
488
+
430 489
         stepper_x.enableOutputs();
431 490
         stepper_y.enableOutputs();
432 491
         stepper_z.enableOutputs();
@@ -567,7 +626,9 @@ void steppers_kill(void) {
567 626
     stepper_z.disableOutputs();
568 627
     stepper_e.disableOutputs();
569 628
 
570
-    state = step_not_homed;
629
+    digitalWrite(FAN_PIN, LOW);
630
+
631
+    state = step_disabled;
571 632
 
572 633
     RESTORE_INTERRUPTS();
573 634
 }

読み込み中…
キャンセル
保存