No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

states.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. #include <Arduino.h>
  2. #include "config.h"
  3. #include "config_pins.h"
  4. #include "data.h"
  5. #include "common.h"
  6. #include "lcd.h"
  7. #include "steppers.h"
  8. #include "statemachine.h"
  9. #include "states.h"
  10. //#define DISABLE_HOMING_STATE
  11. #define ENABLE_MOVEMENT_TEST_STATE
  12. #define ENABLE_INPUT_TEST_STATE
  13. // --------------------------------------
  14. StateText sm_ask_homing = StateText();
  15. StateText sm_do_homing = StateText(&sm_ask_homing);
  16. StateMenu sm_menu = StateMenu(&sm_do_homing, false);
  17. StateMenu sm_auto = StateMenu(&sm_menu);
  18. StateDynamicMenu sm_presets = StateDynamicMenu(&sm_auto);
  19. // TODO dispense
  20. StateText sm_new_preset = StateText(&sm_auto);
  21. StateText sm_wiz_move = StateText(&sm_new_preset);
  22. StateValues<uint8_t, 2> sm_wiz_count = StateValues<uint8_t, 2>(&sm_wiz_move);
  23. StateValues<float, 2> sm_wiz_first_pos = StateValues<float, 2>(&sm_wiz_count);
  24. StateValues<float, 2> sm_wiz_last_pos = StateValues<float, 2>(&sm_wiz_first_pos);
  25. // TODO move z above container
  26. // TODO move z inside container
  27. // TODO move to extruder depth
  28. StateText sm_new_preset_done = StateText(&sm_wiz_last_pos);
  29. StateDynamicMenu sm_mod_preset = StateDynamicMenu(&sm_auto);
  30. // TODO modify
  31. StateDynamicMenu sm_del_preset = StateDynamicMenu(&sm_auto);
  32. // TODO delete
  33. float move_pos_x = 0.0, move_pos_y = 0.0, move_pos_z = 0.0, move_pos_e = 0.0;
  34. StateMenu sm_move = StateMenu(&sm_menu);
  35. StateValue<float> sm_move_x = StateValue<float>(&sm_move, move_pos_x, X_AXIS_MIN, X_AXIS_MAX);
  36. StateValue<float> sm_move_y = StateValue<float>(&sm_move, move_pos_y, Y_AXIS_MIN, Y_AXIS_MAX);
  37. StateValue<float> sm_move_z = StateValue<float>(&sm_move, move_pos_z, Z_AXIS_MIN, Z_AXIS_MAX);
  38. StateValue<float> sm_move_e = StateValue<float>(&sm_move, move_pos_e, E_AXIS_MIN, E_AXIS_MAX);
  39. StateMenu sm_config = StateMenu(&sm_menu);
  40. StateText sm_conf_load = StateText(&sm_config);
  41. StateText sm_conf_save = StateText(&sm_config);
  42. StateValue<float> sm_conf_speed_xy = StateValue<float>(&sm_config, data_options()->speed_x, 1.0, XY_MAX_SPEED);
  43. StateValue<float> sm_conf_speed_z = StateValue<float>(&sm_config, data_options()->speed_z, 1.0, Z_MAX_SPEED);
  44. StateValue<float> sm_conf_speed_e = StateValue<float>(&sm_config, data_options()->speed_e, 1.0, E_MAX_SPEED);
  45. StateValue<float> sm_conf_accel_xy = StateValue<float>(&sm_config, data_options()->accel_x, 1.0, XY_MAX_ACCEL);
  46. StateValue<float> sm_conf_accel_z = StateValue<float>(&sm_config, data_options()->accel_z, 1.0, Z_MAX_ACCEL);
  47. StateValue<float> sm_conf_accel_e = StateValue<float>(&sm_config, data_options()->accel_e, 1.0, E_MAX_ACCEL);
  48. StateText sm_error = StateText(NULL);
  49. #ifdef ENABLE_MOVEMENT_TEST_STATE
  50. StateMenu sm_movement_test = StateMenu(&sm_menu);
  51. StateText sm_move_x_test = StateText(&sm_movement_test);
  52. StateText sm_move_y_test = StateText(&sm_movement_test);
  53. #endif // ENABLE_MOVEMENT_TEST_STATE
  54. #ifdef ENABLE_INPUT_TEST_STATE
  55. StateText sm_input_test = StateText(&sm_menu);
  56. #endif // ENABLE_INPUT_TEST_STATE
  57. // --------------------------------------
  58. State *current_state = NULL;
  59. String strbuf;
  60. struct data_config_preset wizard_preset = { .count_x = 1, .count_y = 1 };
  61. float wizard_first_x = 0.0, wizard_first_y = 0.0;
  62. float wizard_last_x = 0.0, wizard_last_y = 0.0;
  63. void states_init(void) {
  64. // ----------------------------------
  65. sm_ask_homing.setTitle("Ask for homing");
  66. sm_ask_homing.setHeading("Homing Required!");
  67. sm_ask_homing.setText("Click to home all four axes.");
  68. // ----------------------------------
  69. sm_do_homing.setTitle("Home all axes");
  70. sm_do_homing.setHeading("Homing...");
  71. sm_do_homing.onEnter([]() {
  72. #ifndef DISABLE_HOMING_STATE
  73. steppers_start_homing();
  74. #endif // DISABLE_HOMING_STATE
  75. });
  76. sm_do_homing.whenIn([](StateMachineInput smi) {
  77. #ifndef DISABLE_HOMING_STATE
  78. if (smi.motors_done) {
  79. if (steppers_homed()) {
  80. #endif // DISABLE_HOMING_STATE
  81. async_beep(HOMING_BEEP_TIME, HOMING_BEEP_FREQ);
  82. states_go_to(&sm_menu);
  83. #ifndef DISABLE_HOMING_STATE
  84. }
  85. }
  86. #endif // DISABLE_HOMING_STATE
  87. static char last_axis = ' ';
  88. char axis = steppers_homing_axis();
  89. if ((axis != ' ') && (axis != last_axis)) {
  90. last_axis = axis;
  91. strbuf = String(F("Currently homing ")) + axis + String(F(" axis"));
  92. sm_do_homing.setText(strbuf.c_str());
  93. sm_do_homing.updateText();
  94. }
  95. });
  96. // ----------------------------------
  97. sm_menu.setTitle("Main Menu");
  98. sm_menu.addChild(&sm_do_homing, 1);
  99. // ----------------------------------
  100. sm_move.setTitle("Move Axis");
  101. sm_move_x.setTitle("X Axis");
  102. sm_move_x.onEnter([]() {
  103. move_pos_x = steppers_pos_x();
  104. });
  105. sm_move_x.onLiveUpdate([](float v) {
  106. steppers_move_x(v);
  107. });
  108. sm_move_y.setTitle("Y Axis");
  109. sm_move_y.onEnter([]() {
  110. move_pos_y = steppers_pos_y();
  111. });
  112. sm_move_y.onLiveUpdate([](float v) {
  113. steppers_move_y(v);
  114. });
  115. sm_move_z.setTitle("Z Axis");
  116. sm_move_z.onEnter([]() {
  117. move_pos_z = steppers_pos_z();
  118. });
  119. sm_move_z.onLiveUpdate([](float v) {
  120. steppers_move_z(v);
  121. });
  122. sm_move_e.setTitle("E Axis");
  123. sm_move_e.onEnter([]() {
  124. move_pos_e = steppers_pos_e();
  125. });
  126. sm_move_e.onLiveUpdate([](float v) {
  127. steppers_move_e(v);
  128. });
  129. // ----------------------------------
  130. sm_auto.setTitle("Filling Menu");
  131. // TODO
  132. sm_presets.setTitle("Use Preset");
  133. sm_presets.setPrefix("Preset ");
  134. sm_presets.dataCount([]() {
  135. return (int)data_preset_count();
  136. });
  137. sm_new_preset.setTitle("Add new Preset");
  138. sm_new_preset.setHeading("Preset Wizard");
  139. sm_new_preset.setText("Moving axes into initial positions. Click to continue.");
  140. sm_wiz_move.setTitle("Initial Movement");
  141. sm_wiz_move.onEnter([]() {
  142. steppers_start_homing();
  143. });
  144. sm_wiz_move.whenIn([](StateMachineInput smi) {
  145. #ifndef DISABLE_HOMING_STATE
  146. if (smi.motors_done) {
  147. if (steppers_homed()) {
  148. #endif // DISABLE_HOMING_STATE
  149. states_go_to(&sm_wiz_count);
  150. #ifndef DISABLE_HOMING_STATE
  151. }
  152. }
  153. #endif // DISABLE_HOMING_STATE
  154. static char last_axis = ' ';
  155. char axis = steppers_homing_axis();
  156. if ((axis != ' ') && (axis != last_axis)) {
  157. last_axis = axis;
  158. strbuf = String(F("Currently homing ")) + axis + String(F(" axis"));
  159. sm_wiz_move.setText(strbuf.c_str());
  160. sm_wiz_move.updateText();
  161. }
  162. });
  163. sm_wiz_count.setTitle("Container Count");
  164. sm_wiz_count.setData(0, "X: ", &wizard_preset.count_x, 1, 50);
  165. sm_wiz_count.setData(1, "Y: ", &wizard_preset.count_y, 1, 100);
  166. sm_wiz_first_pos.setTitle("First Container Position");
  167. sm_wiz_first_pos.setData(0, "X: ", &wizard_first_x, X_AXIS_MIN, X_AXIS_MAX);
  168. sm_wiz_first_pos.setData(1, "Y: ", &wizard_first_y, Y_AXIS_MIN, Y_AXIS_MAX);
  169. sm_wiz_first_pos.onEnter([]() {
  170. wizard_first_x = steppers_current_pos(0);
  171. wizard_first_y = steppers_current_pos(1);
  172. });
  173. sm_wiz_first_pos.onLiveUpdate([](size_t i, float v) {
  174. if (i == 0) {
  175. steppers_move_x(v);
  176. } else {
  177. steppers_move_y(v);
  178. }
  179. });
  180. sm_wiz_first_pos.onUpdate([](size_t i, float v) {
  181. if (i == 0) {
  182. wizard_preset.offset_x = v;
  183. } else {
  184. wizard_preset.offset_y = v;
  185. }
  186. });
  187. sm_wiz_last_pos.setTitle("Last Container Position");
  188. sm_wiz_last_pos.setData(0, "X: ", &wizard_last_x, X_AXIS_MIN, X_AXIS_MAX);
  189. sm_wiz_last_pos.setData(1, "Y: ", &wizard_last_y, Y_AXIS_MIN, Y_AXIS_MAX);
  190. sm_wiz_last_pos.onEnter([]() {
  191. wizard_last_x = steppers_current_pos(0);
  192. wizard_last_y = steppers_current_pos(1);
  193. });
  194. sm_wiz_last_pos.onLiveUpdate([](size_t i, float v) {
  195. if (i == 0) {
  196. steppers_move_x(v);
  197. } else {
  198. steppers_move_y(v);
  199. }
  200. });
  201. sm_wiz_last_pos.onUpdate([](size_t i, float v) {
  202. if (i == 0) {
  203. wizard_preset.distance_x = (v - wizard_preset.offset_x) / wizard_preset.count_x;
  204. } else {
  205. wizard_preset.distance_y = (v - wizard_preset.offset_y) / wizard_preset.count_y;
  206. }
  207. });
  208. sm_new_preset_done.setTitle("Preset Wizard Done");
  209. sm_new_preset_done.setHeading("Preset Wizard Done");
  210. sm_new_preset_done.onEnter([]() {
  211. if (!data_preset_add(wizard_preset)) {
  212. strbuf = String(data_eeprom_error()) + F(" Error adding preset!");
  213. sm_new_preset_done.setText(strbuf.c_str());
  214. } else {
  215. strbuf = F("Preset ");
  216. strbuf += String(data_preset_count());
  217. strbuf += F(" has been added! Don't forget to store config to EEPROM to keep it.");
  218. sm_new_preset_done.setText(strbuf.c_str());
  219. }
  220. });
  221. sm_new_preset_done.whenIn([](StateMachineInput smi) {
  222. if (smi.click) {
  223. states_go_to(&sm_auto);
  224. }
  225. });
  226. // TODO
  227. sm_mod_preset.setTitle("Modify Preset");
  228. sm_mod_preset.setPrefix("Preset ");
  229. sm_mod_preset.dataCount([]() {
  230. return (int)data_preset_count();
  231. });
  232. // TODO
  233. sm_del_preset.setTitle("Delete Preset");
  234. sm_del_preset.setPrefix("Preset ");
  235. sm_del_preset.dataCount([]() {
  236. return (int)data_preset_count();
  237. });
  238. // ----------------------------------
  239. sm_config.setTitle("Configuration");
  240. sm_conf_load.setTitle("Load from EEPROM");
  241. sm_conf_load.setHeading("Load from EEPROM");
  242. sm_conf_load.onEnter([]() {
  243. if (!data_eeprom_read()) {
  244. strbuf = String(data_eeprom_error()) + " Error reading configuration!";
  245. sm_conf_load.setText(strbuf.c_str());
  246. } else {
  247. sm_conf_load.setText("Configuration read successful!");
  248. steppers_set_speed_x(data_options()->speed_x);
  249. steppers_set_accel_x(data_options()->accel_x);
  250. steppers_set_speed_y(data_options()->speed_y);
  251. steppers_set_accel_y(data_options()->accel_y);
  252. steppers_set_speed_z(data_options()->speed_z);
  253. steppers_set_accel_z(data_options()->accel_z);
  254. steppers_set_speed_e(data_options()->speed_e);
  255. steppers_set_accel_e(data_options()->accel_e);
  256. }
  257. });
  258. sm_conf_save.setTitle("Store to EEPROM");
  259. sm_conf_save.setHeading("Store to EEPROM");
  260. sm_conf_save.setText("Configuration written to EEPROM!");
  261. sm_conf_save.onEnter([]() {
  262. data_eeprom_write();
  263. });
  264. sm_conf_speed_xy.setTitle("XY Speed");
  265. sm_conf_speed_xy.onUpdate([](float v) {
  266. steppers_set_speed_x(v);
  267. steppers_set_speed_y(v);
  268. });
  269. sm_conf_speed_z.setTitle("Z Speed");
  270. sm_conf_speed_z.onUpdate([](float v) {
  271. steppers_set_speed_z(v);
  272. });
  273. sm_conf_speed_e.setTitle("E Speed");
  274. sm_conf_speed_e.onUpdate([](float v) {
  275. steppers_set_speed_e(v);
  276. });
  277. sm_conf_accel_xy.setTitle("XY Acceleration");
  278. sm_conf_accel_xy.onUpdate([](float v) {
  279. steppers_set_accel_x(v);
  280. steppers_set_accel_y(v);
  281. });
  282. sm_conf_accel_z.setTitle("Z Acceleration");
  283. sm_conf_accel_z.onUpdate([](float v) {
  284. steppers_set_accel_z(v);
  285. });
  286. sm_conf_accel_e.setTitle("E Acceleration");
  287. sm_conf_accel_e.onUpdate([](float v) {
  288. steppers_set_accel_e(v);
  289. });
  290. sm_error.setChild(&sm_ask_homing);
  291. sm_error.setTitle("Axis Error");
  292. sm_error.setHeading("Axis Error");
  293. sm_error.setText("Endstop has been hit!");
  294. #ifdef ENABLE_MOVEMENT_TEST_STATE
  295. sm_movement_test.setTitle("Movement Test");
  296. sm_move_x_test.setTitle("X Axis");
  297. sm_move_x_test.setHeading("X Move Test");
  298. sm_move_x_test.whenIn([](StateMachineInput smi) {
  299. static bool s = false;
  300. if (smi.motors_done) {
  301. s = !s;
  302. steppers_move_x(s ? (X_AXIS_MAX - 10.0) : (X_AXIS_MIN + 10.0));
  303. if (smi.click) {
  304. states_go_to(&sm_movement_test);
  305. }
  306. }
  307. });
  308. sm_move_y_test.setTitle("Y Axis");
  309. sm_move_y_test.setHeading("Y Move Test");
  310. sm_move_y_test.whenIn([](StateMachineInput smi) {
  311. static bool s = false;
  312. if (smi.motors_done) {
  313. s = !s;
  314. steppers_move_y(s ? (Y_AXIS_MAX - 10.0) : (Y_AXIS_MIN + 10.0));
  315. if (smi.click) {
  316. states_go_to(&sm_movement_test);
  317. }
  318. }
  319. });
  320. #endif // ENABLE_MOVEMENT_TEST_STATE
  321. #ifdef ENABLE_INPUT_TEST_STATE
  322. sm_input_test.setTitle("Input Test");
  323. sm_input_test.setHeading("Input Test");
  324. sm_input_test.whenIn([](StateMachineInput smi) {
  325. String s = "Endstops: ";
  326. for (int i = 0; i < 4; i++) {
  327. if (steppers_home_switch(i)) {
  328. s += '1';
  329. } else {
  330. s += '0';
  331. }
  332. if (i < 3) {
  333. s += ' ';
  334. }
  335. }
  336. if (s != strbuf) {
  337. strbuf = s;
  338. sm_input_test.setText(strbuf.c_str());
  339. sm_input_test.updateText();
  340. }
  341. });
  342. #endif // ENABLE_INPUT_TEST_STATE
  343. // ----------------------------------
  344. states_go_to(&sm_ask_homing);
  345. }
  346. void states_run(StateMachineInput smi) {
  347. if (smi.click) {
  348. async_beep(ENCODER_CLICK_BEEP_TIME, ENCODER_CLICK_BEEP_FREQ);
  349. }
  350. if (smi.kill) {
  351. steppers_kill();
  352. Serial.println(F("Kill button pressed!"));
  353. blocking_beep(KILL_BEEP_TIME, KILL_BEEP_FREQ, KILL_BEEP_REPEAT - 1);
  354. states_go_to(&sm_ask_homing);
  355. return;
  356. }
  357. if (current_state != NULL) {
  358. current_state->inState(smi);
  359. }
  360. }
  361. State *states_get(void) {
  362. return current_state;
  363. }
  364. void states_go_to(State *state) {
  365. current_state = state;
  366. if (current_state != NULL) {
  367. current_state->enterState();
  368. }
  369. }