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 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839
  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. #define ENABLE_MAX_SPEED_ACCEL_STATE
  14. // --------------------------------------
  15. int preset_selection = 0, dispense_off = 0, dispense_count = 0, dispense_index = 0;
  16. float move_pos_x = 0.0, move_pos_y = 0.0, move_pos_z = 0.0, move_pos_e = 0.0;
  17. float mod_count_x, mod_count_y;
  18. float mod_distance_x, mod_distance_y;
  19. float mod_offset_x, mod_offset_y;
  20. float mod_move_z;
  21. float mod_bottom_z, mod_top_z;
  22. float mod_extrusion_length;
  23. float mod_extrusion_bottom_wait;
  24. float mod_extrusion_top_wait;
  25. State sm_ask_homing = State();
  26. State sm_do_homing = State(&sm_ask_homing);
  27. StateMenu sm_menu = StateMenu(&sm_do_homing, false);
  28. StateMenu sm_auto = StateMenu(&sm_menu);
  29. StateDynamicMenu sm_presets = StateDynamicMenu(&sm_auto);
  30. StateValue<int> sm_disp_off = StateValue<int>(&sm_presets, dispense_off, 1, 1);
  31. StateValue<int> sm_disp_cnt = StateValue<int>(&sm_disp_off, dispense_count, 1, 1);
  32. State sm_disp_go = State(&sm_disp_cnt);
  33. State sm_disp_run_z_travel = State(&sm_disp_go);
  34. State sm_disp_run_xy_travel = State(&sm_disp_run_z_travel);
  35. State sm_disp_run_z_disp = State(&sm_disp_run_xy_travel);
  36. // TODO add state for extrusion_bottom_wait
  37. State sm_disp_run = State(&sm_disp_run_z_disp);
  38. State sm_disp_run_back = State(&sm_disp_run);
  39. // TODO add state for extrusion_top_wait
  40. State sm_disp_done = State(&sm_disp_run_back);
  41. State sm_disp_really_done = State(&sm_disp_done);
  42. State sm_new_preset = State(&sm_auto);
  43. State sm_wiz_move = State(&sm_new_preset);
  44. StateValues<uint8_t, 2> sm_wiz_count = StateValues<uint8_t, 2>(&sm_wiz_move);
  45. StateValues<float, 2> sm_wiz_first_pos = StateValues<float, 2>(&sm_wiz_count);
  46. StateValues<float, 2> sm_wiz_last_pos = StateValues<float, 2>(&sm_wiz_first_pos);
  47. // TODO move z above container
  48. // TODO move z inside bottom container
  49. // TODO move z inside top container
  50. // TODO move to extruder depth
  51. State sm_new_preset_done = State(&sm_wiz_last_pos);
  52. StateDynamicMenu sm_mod_preset = StateDynamicMenu(&sm_auto);
  53. StateValues<float, 12> sm_mod_values = StateValues<float, 12>(&sm_mod_preset);
  54. StateDynamicMenu sm_del_preset = StateDynamicMenu(&sm_auto);
  55. // TODO delete yes/no choice
  56. StateMenu sm_move = StateMenu(&sm_menu);
  57. StateValue<float> sm_move_x = StateValue<float>(&sm_move, move_pos_x, X_AXIS_MIN, X_AXIS_MAX);
  58. StateValue<float> sm_move_y = StateValue<float>(&sm_move, move_pos_y, Y_AXIS_MIN, Y_AXIS_MAX);
  59. StateValue<float> sm_move_z = StateValue<float>(&sm_move, move_pos_z, Z_AXIS_MIN, Z_AXIS_MAX);
  60. StateValue<float> sm_move_e = StateValue<float>(&sm_move, move_pos_e, E_AXIS_MIN, E_AXIS_MAX);
  61. State sm_disable_steppers = State(&sm_menu);
  62. StateMenu sm_config = StateMenu(&sm_menu);
  63. State sm_conf_load = State(&sm_config);
  64. State sm_conf_save = State(&sm_config);
  65. State sm_conf_clear = State(&sm_config);
  66. StateValue<float> sm_conf_speed_xy = StateValue<float>(&sm_config, data_options()->speed_x, 1.0, XY_MAX_SPEED);
  67. StateValue<float> sm_conf_speed_z = StateValue<float>(&sm_config, data_options()->speed_z, 1.0, Z_MAX_SPEED);
  68. StateValue<float> sm_conf_speed_e = StateValue<float>(&sm_config, data_options()->speed_e, 1.0, E_MAX_SPEED);
  69. StateValue<float> sm_conf_accel_xy = StateValue<float>(&sm_config, data_options()->accel_x, 1.0, XY_MAX_ACCEL);
  70. StateValue<float> sm_conf_accel_z = StateValue<float>(&sm_config, data_options()->accel_z, 1.0, Z_MAX_ACCEL);
  71. StateValue<float> sm_conf_accel_e = StateValue<float>(&sm_config, data_options()->accel_e, 1.0, E_MAX_ACCEL);
  72. State sm_error = State(NULL);
  73. #if defined(ENABLE_MOVEMENT_TEST_STATE) || defined(ENABLE_INPUT_TEST_STATE) || defined(ENABLE_MAX_SPEED_ACCEL_STATE)
  74. StateMenu sm_debug = StateMenu(&sm_menu);
  75. #endif
  76. #ifdef ENABLE_MOVEMENT_TEST_STATE
  77. StateMenu sm_movement_test = StateMenu(&sm_debug);
  78. State sm_move_xy_test = State(&sm_movement_test);
  79. State sm_move_x_test = State(&sm_movement_test);
  80. State sm_move_y_test = State(&sm_movement_test);
  81. State sm_move_z_test = State(&sm_movement_test);
  82. State sm_move_e_test = State(&sm_movement_test);
  83. #endif // ENABLE_MOVEMENT_TEST_STATE
  84. #ifdef ENABLE_INPUT_TEST_STATE
  85. State sm_input_test = State(&sm_debug);
  86. #endif // ENABLE_INPUT_TEST_STATE
  87. #ifdef ENABLE_MAX_SPEED_ACCEL_STATE
  88. State sm_set_max_speed = State(&sm_debug);
  89. State sm_set_max_accel = State(&sm_debug);
  90. #endif // ENABLE_MAX_SPEED_ACCEL_STATE
  91. // --------------------------------------
  92. State *current_state = NULL;
  93. String strbuf;
  94. struct data_config_preset wizard_preset = { .count_x = 1, .count_y = 1 };
  95. float wizard_first_x = 0.0, wizard_first_y = 0.0;
  96. float wizard_last_x = 0.0, wizard_last_y = 0.0;
  97. unsigned long last_state_change = 0, last_input = 0;
  98. void states_init(void) {
  99. // ----------------------------------
  100. sm_ask_homing.setTitle("Ask for homing");
  101. sm_ask_homing.setHeading("Homing Required!");
  102. sm_ask_homing.setText("Click to home all four axes.");
  103. // ----------------------------------
  104. sm_do_homing.setTitle("Home all axes");
  105. sm_do_homing.setHeading("Homing...");
  106. sm_do_homing.onEnter([]() {
  107. #ifndef DISABLE_HOMING_STATE
  108. steppers_start_homing();
  109. #endif // DISABLE_HOMING_STATE
  110. });
  111. sm_do_homing.whenIn([](StateMachineInput smi) {
  112. #ifndef DISABLE_HOMING_STATE
  113. if (smi.all_motors_done) {
  114. if (steppers_homed()) {
  115. #endif // DISABLE_HOMING_STATE
  116. async_beep(HOMING_BEEP_TIME, HOMING_BEEP_FREQ);
  117. states_go_to(&sm_menu);
  118. #ifndef DISABLE_HOMING_STATE
  119. }
  120. }
  121. #endif // DISABLE_HOMING_STATE
  122. static char last_axis = ' ';
  123. char axis = steppers_homing_axis();
  124. if ((axis != ' ') && (axis != last_axis)) {
  125. last_axis = axis;
  126. strbuf = String(F("Currently homing ")) + axis + String(F(" axis"));
  127. sm_do_homing.setText(strbuf.c_str());
  128. sm_do_homing.updateText();
  129. }
  130. });
  131. // ----------------------------------
  132. sm_menu.setTitle("Main Menu");
  133. sm_menu.addChild(&sm_do_homing, 1);
  134. // ----------------------------------
  135. sm_move.setTitle("Move Axis");
  136. sm_move_x.setTitle("X Axis");
  137. sm_move_x.onEnter([]() {
  138. move_pos_x = steppers_pos_x();
  139. });
  140. sm_move_x.onLiveUpdate([](float v) {
  141. steppers_move_x(v);
  142. });
  143. sm_move_y.setTitle("Y Axis");
  144. sm_move_y.onEnter([]() {
  145. move_pos_y = steppers_pos_y();
  146. });
  147. sm_move_y.onLiveUpdate([](float v) {
  148. steppers_move_y(v);
  149. });
  150. sm_move_z.setTitle("Z Axis");
  151. sm_move_z.onEnter([]() {
  152. move_pos_z = steppers_pos_z();
  153. });
  154. sm_move_z.onLiveUpdate([](float v) {
  155. steppers_move_z(v);
  156. });
  157. sm_move_e.setTitle("E Axis");
  158. sm_move_e.onEnter([]() {
  159. move_pos_e = steppers_pos_e();
  160. });
  161. sm_move_e.onLiveUpdate([](float v) {
  162. steppers_move_e(v);
  163. });
  164. sm_disable_steppers.setTitle("Disable Steppers");
  165. sm_disable_steppers.onEnter([]() {
  166. steppers_kill();
  167. states_go_to(&sm_ask_homing);
  168. });
  169. // ----------------------------------
  170. sm_auto.setTitle("Filling Menu");
  171. auto preset_name_func = [](int i) {
  172. strbuf = String(i + 1);
  173. strbuf += String(F(" ("));
  174. strbuf += String(data_preset(i)->count_x);
  175. strbuf += String(F("*"));
  176. strbuf += String(data_preset(i)->count_y);
  177. strbuf += String(F(" / "));
  178. strbuf += String(data_preset(i)->distance_x);
  179. strbuf += String(F("*"));
  180. strbuf += String(data_preset(i)->distance_y);
  181. strbuf += String(F(")"));
  182. return strbuf.c_str();
  183. };
  184. sm_presets.setTitle("Use Preset");
  185. sm_presets.setPrefix("Preset ");
  186. sm_presets.dataCount([]() {
  187. return (int)data_preset_count();
  188. });
  189. sm_presets.dataGet(preset_name_func);
  190. sm_presets.dataCall([](int i) {
  191. preset_selection = i;
  192. states_go_to(&sm_disp_off);
  193. });
  194. sm_disp_off.setTitle("Offset");
  195. sm_disp_off.setText("Where to start dispensing?");
  196. sm_disp_off.onEnter([]() {
  197. dispense_off = 1;
  198. sm_disp_off.setMax(data_preset(preset_selection)->count_x * data_preset(preset_selection)->count_y);
  199. });
  200. sm_disp_cnt.setTitle("Count");
  201. sm_disp_cnt.setText("How many to fill?");
  202. sm_disp_cnt.onEnter([]() {
  203. dispense_count = data_preset(preset_selection)->count_x * data_preset(preset_selection)->count_y - (dispense_off - 1);
  204. sm_disp_cnt.setMax(dispense_count);
  205. });
  206. sm_disp_go.setTitle("Confirm");
  207. sm_disp_go.onEnter([]() {
  208. dispense_off -= 1;
  209. strbuf = String(F("Filling from ")) + String(dispense_off + 1);
  210. strbuf += String(F(" to ")) + String(dispense_off + dispense_count);
  211. strbuf += String(F("!\nIs this ok?"));
  212. sm_disp_go.setText(strbuf.c_str());
  213. dispense_index = dispense_off;
  214. // TODO allow yes/no choice?
  215. });
  216. sm_disp_run_z_travel.setTitle("Z Travel");
  217. sm_disp_run_z_travel.onEnter([]() {
  218. // TODO move z to travel height
  219. // print status text
  220. strbuf = String(F("Filling ")) + String(dispense_index + 1);
  221. strbuf += String(F(" / ")) + String(data_preset(preset_selection)->count_x * data_preset(preset_selection)->count_y);
  222. sm_disp_run_z_travel.setText(strbuf.c_str());
  223. });
  224. sm_disp_run_z_travel.whenIn([](StateMachineInput smi) {
  225. if (smi.all_motors_done) {
  226. states_go_to(&sm_disp_run_xy_travel);
  227. }
  228. });
  229. sm_disp_run_xy_travel.setTitle("XY Movement");
  230. sm_disp_run_xy_travel.onEnter([]() {
  231. int y = dispense_index / data_preset(preset_selection)->count_x;
  232. int x = dispense_index % data_preset(preset_selection)->count_x;
  233. // keep movements shorter by switching x axis every odd y row
  234. if (y % 2) {
  235. x = data_preset(preset_selection)->count_x - x - 1;
  236. }
  237. Serial.print(F("xy_travel: index="));
  238. Serial.print(dispense_index);
  239. Serial.print(F(" x="));
  240. Serial.print(x);
  241. Serial.print(F(" y="));
  242. Serial.println(y);
  243. float x_pos = data_preset(preset_selection)->offset_x + x * data_preset(preset_selection)->distance_x;
  244. float y_pos = data_preset(preset_selection)->offset_y + y * data_preset(preset_selection)->distance_y;
  245. steppers_move_x(x_pos);
  246. steppers_move_y(y_pos);
  247. // print status text
  248. strbuf = String(F("Filling ")) + String(dispense_index + 1);
  249. strbuf += String(F(" / ")) + String(data_preset(preset_selection)->count_x * data_preset(preset_selection)->count_y);
  250. sm_disp_run_xy_travel.setText(strbuf.c_str());
  251. });
  252. sm_disp_run_xy_travel.whenIn([](StateMachineInput smi) {
  253. if (smi.all_motors_done) {
  254. states_go_to(&sm_disp_run_z_disp);
  255. }
  256. });
  257. sm_disp_run_z_disp.setTitle("Z Dispense");
  258. sm_disp_run_z_disp.onEnter([]() {
  259. // TODO move z to bottom_z
  260. // print status text
  261. strbuf = String(F("Filling ")) + String(dispense_index + 1);
  262. strbuf += String(F(" / ")) + String(data_preset(preset_selection)->count_x * data_preset(preset_selection)->count_y);
  263. sm_disp_run_z_disp.setText(strbuf.c_str());
  264. });
  265. sm_disp_run_z_disp.whenIn([](StateMachineInput smi) {
  266. if (smi.all_motors_done) {
  267. states_go_to(&sm_disp_run);
  268. }
  269. });
  270. sm_disp_run.setTitle("Dispensing");
  271. sm_disp_run.onEnter([]() {
  272. // TODO move z to top_z
  273. // move e to extrusion_length (bottom of press)
  274. steppers_move_e(data_preset(preset_selection)->extrusion_length);
  275. // print status text
  276. strbuf = String(F("Filling ")) + String(dispense_index + 1);
  277. strbuf += String(F(" / ")) + String(data_preset(preset_selection)->count_x * data_preset(preset_selection)->count_y);
  278. sm_disp_run.setText(strbuf.c_str());
  279. });
  280. sm_disp_run.whenIn([](StateMachineInput smi) {
  281. if (smi.all_motors_done) {
  282. states_go_to(&sm_disp_run_back);
  283. }
  284. });
  285. sm_disp_run_back.setTitle("Dispensing Back");
  286. sm_disp_run_back.onEnter([]() {
  287. // move e back to 0 (top)
  288. steppers_move_e(0.0);
  289. // print status text
  290. strbuf = String(F("Filling ")) + String(dispense_index + 1);
  291. strbuf += String(F(" / ")) + String(data_preset(preset_selection)->count_x * data_preset(preset_selection)->count_y);
  292. sm_disp_run_back.setText(strbuf.c_str());
  293. });
  294. sm_disp_run_back.whenIn([](StateMachineInput smi) {
  295. if (smi.all_motors_done) {
  296. dispense_index++;
  297. if (dispense_index >= (dispense_count + dispense_off)) {
  298. states_go_to(&sm_disp_done);
  299. } else {
  300. states_go_to(&sm_disp_run_z_travel);
  301. }
  302. }
  303. });
  304. sm_disp_done.setTitle("Finished");
  305. sm_disp_done.setText("Moving to take-out position.");
  306. sm_disp_done.onEnter([]() {
  307. steppers_move_x(X_AXIS_MAX - 20.0);
  308. steppers_move_y(Y_AXIS_MAX - 20.0);
  309. // TODO move z to travel height
  310. });
  311. sm_disp_done.whenIn([](StateMachineInput smi) {
  312. if (smi.click || smi.all_motors_done) {
  313. states_go_to(&sm_disp_really_done);
  314. }
  315. });
  316. sm_disp_really_done.setTitle("Finished");
  317. sm_disp_really_done.setText("Please remove tray and click to continue.");
  318. sm_disp_really_done.onEnter([]() {
  319. // "stop" steppers without killing them
  320. steppers_move_x(steppers_current_pos(X_AXIS));
  321. steppers_move_y(steppers_current_pos(Y_AXIS));
  322. });
  323. sm_disp_really_done.whenIn([](StateMachineInput smi) {
  324. if (smi.click) {
  325. states_go_to(&sm_auto);
  326. }
  327. });
  328. sm_new_preset.setTitle("Add new Preset");
  329. sm_new_preset.setHeading("Preset Wizard");
  330. sm_new_preset.setText("Moving axes into initial positions. Click to continue.");
  331. sm_wiz_move.setTitle("Initial Movement");
  332. sm_wiz_move.onEnter([]() {
  333. steppers_start_homing();
  334. });
  335. sm_wiz_move.whenIn([](StateMachineInput smi) {
  336. #ifndef DISABLE_HOMING_STATE
  337. if (smi.all_motors_done) {
  338. if (steppers_homed()) {
  339. #endif // DISABLE_HOMING_STATE
  340. states_go_to(&sm_wiz_count);
  341. #ifndef DISABLE_HOMING_STATE
  342. }
  343. }
  344. #endif // DISABLE_HOMING_STATE
  345. static char last_axis = ' ';
  346. char axis = steppers_homing_axis();
  347. if ((axis != ' ') && (axis != last_axis)) {
  348. last_axis = axis;
  349. strbuf = String(F("Currently homing ")) + axis + String(F(" axis"));
  350. sm_wiz_move.setText(strbuf.c_str());
  351. sm_wiz_move.updateText();
  352. }
  353. });
  354. sm_wiz_count.setTitle("Container Count");
  355. sm_wiz_count.setData(0, "X:", &wizard_preset.count_x, 1, 50);
  356. sm_wiz_count.setData(1, "Y:", &wizard_preset.count_y, 1, 100);
  357. sm_wiz_first_pos.setTitle("First Container Position");
  358. sm_wiz_first_pos.setData(0, "X:", &wizard_first_x, X_AXIS_MIN, X_AXIS_MAX);
  359. sm_wiz_first_pos.setData(1, "Y:", &wizard_first_y, Y_AXIS_MIN, Y_AXIS_MAX);
  360. sm_wiz_first_pos.onEnter([]() {
  361. wizard_first_x = steppers_current_pos(0);
  362. wizard_first_y = steppers_current_pos(1);
  363. });
  364. sm_wiz_first_pos.onLiveUpdate([](size_t i, float v) {
  365. if (i == 0) {
  366. steppers_move_x(v);
  367. } else {
  368. steppers_move_y(v);
  369. }
  370. });
  371. sm_wiz_first_pos.onUpdate([](size_t i, float v) {
  372. if (i == 0) {
  373. wizard_preset.offset_x = v;
  374. } else {
  375. wizard_preset.offset_y = v;
  376. }
  377. });
  378. sm_wiz_last_pos.setTitle("Last Container Position");
  379. sm_wiz_last_pos.setData(0, "X:", &wizard_last_x, X_AXIS_MIN, X_AXIS_MAX);
  380. sm_wiz_last_pos.setData(1, "Y:", &wizard_last_y, Y_AXIS_MIN, Y_AXIS_MAX);
  381. sm_wiz_last_pos.onEnter([]() {
  382. wizard_last_x = steppers_current_pos(0);
  383. wizard_last_y = steppers_current_pos(1);
  384. });
  385. sm_wiz_last_pos.onLiveUpdate([](size_t i, float v) {
  386. if (i == 0) {
  387. steppers_move_x(v);
  388. } else {
  389. steppers_move_y(v);
  390. }
  391. });
  392. sm_wiz_last_pos.onUpdate([](size_t i, float v) {
  393. if (i == 0) {
  394. wizard_preset.distance_x = (v - wizard_preset.offset_x) / wizard_preset.count_x;
  395. } else {
  396. wizard_preset.distance_y = (v - wizard_preset.offset_y) / wizard_preset.count_y;
  397. }
  398. });
  399. sm_new_preset_done.setTitle("Preset Wizard Done");
  400. sm_new_preset_done.setHeading("Preset Wizard Done");
  401. sm_new_preset_done.onEnter([]() {
  402. if (!data_preset_add(wizard_preset)) {
  403. strbuf = String(data_eeprom_error()) + F(" Error adding preset!");
  404. sm_new_preset_done.setText(strbuf.c_str());
  405. } else {
  406. strbuf = F("Preset ");
  407. strbuf += String(data_preset_count());
  408. strbuf += F(" has been added! Don't forget to store config to EEPROM to keep it.");
  409. sm_new_preset_done.setText(strbuf.c_str());
  410. }
  411. });
  412. sm_new_preset_done.whenIn([](StateMachineInput smi) {
  413. if (smi.click) {
  414. states_go_to(&sm_auto);
  415. }
  416. });
  417. sm_mod_preset.setTitle("Modify Preset");
  418. sm_mod_preset.setPrefix("Preset ");
  419. sm_mod_preset.dataCount([]() {
  420. return (int)data_preset_count();
  421. });
  422. sm_mod_preset.dataGet(preset_name_func);
  423. sm_mod_preset.dataCall([](int i) {
  424. preset_selection = i;
  425. states_go_to(&sm_mod_values);
  426. });
  427. sm_mod_values.setTitle("Modify Preset");
  428. sm_mod_values.setData(0, "Count X", &mod_count_x, 1, 50);
  429. sm_mod_values.setData(1, "Count Y", &mod_count_y, 1, 100);
  430. sm_mod_values.setData(2, "Distance X", &mod_distance_x, X_AXIS_MIN, X_AXIS_MAX);
  431. sm_mod_values.setData(3, "Distance Y", &mod_distance_y, Y_AXIS_MIN, Y_AXIS_MAX);
  432. sm_mod_values.setData(4, "Offset X", &mod_offset_x, X_AXIS_MIN, X_AXIS_MAX);
  433. sm_mod_values.setData(5, "Offset Y", &mod_offset_y, Y_AXIS_MIN, Y_AXIS_MAX);
  434. sm_mod_values.setData(6, "Travel Z", &mod_move_z, Z_AXIS_MIN, Z_AXIS_MAX);
  435. sm_mod_values.setData(7, "Bottom Z", &mod_bottom_z, Z_AXIS_MIN, Z_AXIS_MAX);
  436. sm_mod_values.setData(8, "Top Z", &mod_top_z, Z_AXIS_MIN, Z_AXIS_MAX);
  437. sm_mod_values.setData(9, "Extrusion Length", &mod_extrusion_length, E_AXIS_MIN, E_AXIS_MAX);
  438. sm_mod_values.setData(10, "Extrusion Bottom", &mod_extrusion_bottom_wait, 0, 10);
  439. sm_mod_values.setData(11, "Extrusion Top", &mod_extrusion_top_wait, 0, 10);
  440. sm_mod_values.onEnter([]() {
  441. mod_count_x = data_preset(preset_selection)->count_x;
  442. mod_count_y = data_preset(preset_selection)->count_y;
  443. mod_distance_x = data_preset(preset_selection)->distance_x;
  444. mod_distance_y = data_preset(preset_selection)->distance_y;
  445. mod_offset_x = data_preset(preset_selection)->offset_x;
  446. mod_offset_y = data_preset(preset_selection)->offset_y;
  447. mod_move_z = data_preset(preset_selection)->move_z;
  448. mod_bottom_z = data_preset(preset_selection)->bottom_z;
  449. mod_top_z = data_preset(preset_selection)->top_z;
  450. mod_extrusion_length = data_preset(preset_selection)->extrusion_length;
  451. mod_extrusion_bottom_wait = data_preset(preset_selection)->extrusion_bottom_wait;
  452. mod_extrusion_top_wait = data_preset(preset_selection)->extrusion_top_wait;
  453. });
  454. sm_mod_values.onUpdate([](size_t i, float v) {
  455. if (i == 0) {
  456. data_preset(preset_selection)->count_x = v;
  457. } else if (i == 1) {
  458. data_preset(preset_selection)->count_y = v;
  459. } else if (i == 2) {
  460. data_preset(preset_selection)->distance_x = v;
  461. } else if (i == 3) {
  462. data_preset(preset_selection)->distance_y = v;
  463. } else if (i == 4) {
  464. data_preset(preset_selection)->offset_x = v;
  465. } else if (i == 5) {
  466. data_preset(preset_selection)->offset_y = v;
  467. } else if (i == 6) {
  468. data_preset(preset_selection)->move_z = v;
  469. } else if (i == 7) {
  470. data_preset(preset_selection)->bottom_z = v;
  471. } else if (i == 8) {
  472. data_preset(preset_selection)->top_z = v;
  473. } else if (i == 9) {
  474. data_preset(preset_selection)->extrusion_length = v;
  475. } else if (i == 10) {
  476. data_preset(preset_selection)->extrusion_bottom_wait = v;
  477. } else if (i == 11) {
  478. data_preset(preset_selection)->extrusion_top_wait = v;
  479. }
  480. });
  481. sm_del_preset.setTitle("Delete Preset");
  482. sm_del_preset.setPrefix("Preset ");
  483. sm_del_preset.dataCount([]() {
  484. return (int)data_preset_count();
  485. });
  486. sm_del_preset.dataGet(preset_name_func);
  487. sm_del_preset.dataCall([](int i) {
  488. data_preset_remove(i);
  489. states_go_to(&sm_auto);
  490. });
  491. // ----------------------------------
  492. sm_config.setTitle("Configuration");
  493. sm_conf_load.setTitle("Load from EEPROM");
  494. sm_conf_load.setHeading("Load from EEPROM");
  495. sm_conf_load.onEnter([]() {
  496. if (!data_eeprom_read()) {
  497. strbuf = String(data_eeprom_error()) + " Error reading configuration!";
  498. sm_conf_load.setText(strbuf.c_str());
  499. } else {
  500. sm_conf_load.setText("Configuration read successful!");
  501. steppers_set_speed_x(data_options()->speed_x);
  502. steppers_set_accel_x(data_options()->accel_x);
  503. steppers_set_speed_y(data_options()->speed_y);
  504. steppers_set_accel_y(data_options()->accel_y);
  505. steppers_set_speed_z(data_options()->speed_z);
  506. steppers_set_accel_z(data_options()->accel_z);
  507. steppers_set_speed_e(data_options()->speed_e);
  508. steppers_set_accel_e(data_options()->accel_e);
  509. }
  510. });
  511. sm_conf_save.setTitle("Store to EEPROM");
  512. sm_conf_save.setHeading("Store to EEPROM");
  513. sm_conf_save.setText("Configuration written to EEPROM!");
  514. sm_conf_save.onEnter([]() {
  515. data_eeprom_write();
  516. });
  517. sm_conf_clear.setTitle("Clear EEPROM & RAM");
  518. sm_conf_clear.setHeading("Clear EEPROM & RAM");
  519. sm_conf_clear.setText("EEPROM and RAM Configuration cleared!");
  520. sm_conf_clear.onEnter([]() {
  521. data_clear();
  522. data_eeprom_write();
  523. // reapply default conf values
  524. steppers_set_speed_x(data_options()->speed_x);
  525. steppers_set_speed_y(data_options()->speed_y);
  526. steppers_set_speed_z(data_options()->speed_z);
  527. steppers_set_speed_e(data_options()->speed_e);
  528. steppers_set_accel_x(data_options()->accel_x);
  529. steppers_set_accel_y(data_options()->accel_y);
  530. steppers_set_accel_z(data_options()->accel_z);
  531. steppers_set_accel_e(data_options()->accel_e);
  532. });
  533. sm_conf_speed_xy.setTitle("XY Speed");
  534. sm_conf_speed_xy.onUpdate([](float v) {
  535. steppers_set_speed_x(v);
  536. steppers_set_speed_y(v);
  537. });
  538. sm_conf_speed_z.setTitle("Z Speed");
  539. sm_conf_speed_z.onUpdate([](float v) {
  540. steppers_set_speed_z(v);
  541. });
  542. sm_conf_speed_e.setTitle("E Speed");
  543. sm_conf_speed_e.onUpdate([](float v) {
  544. steppers_set_speed_e(v);
  545. });
  546. sm_conf_accel_xy.setTitle("XY Acceleration");
  547. sm_conf_accel_xy.onUpdate([](float v) {
  548. steppers_set_accel_x(v);
  549. steppers_set_accel_y(v);
  550. });
  551. sm_conf_accel_z.setTitle("Z Acceleration");
  552. sm_conf_accel_z.onUpdate([](float v) {
  553. steppers_set_accel_z(v);
  554. });
  555. sm_conf_accel_e.setTitle("E Acceleration");
  556. sm_conf_accel_e.onUpdate([](float v) {
  557. steppers_set_accel_e(v);
  558. });
  559. sm_error.setChild(&sm_ask_homing);
  560. sm_error.setTitle("Axis Error");
  561. sm_error.setHeading("Axis Error");
  562. sm_error.setText("An unknown error occured!");
  563. #if defined(ENABLE_MOVEMENT_TEST_STATE) || defined(ENABLE_INPUT_TEST_STATE) || defined(ENABLE_MAX_SPEED_ACCEL_STATE)
  564. sm_debug.setTitle("Debug Menu");
  565. #endif
  566. #ifdef ENABLE_MOVEMENT_TEST_STATE
  567. sm_movement_test.setTitle("Movement Test");
  568. sm_move_xy_test.setTitle("XY Axes");
  569. sm_move_xy_test.setHeading("XY Move Test");
  570. sm_move_xy_test.setText("Moving axis through full range with selected speed.");
  571. sm_move_xy_test.whenIn([](StateMachineInput smi) {
  572. static bool sx = false, sy = false;
  573. if (smi.motor_done[X_AXIS]) {
  574. sx = !sx;
  575. steppers_move_x(sx ? (X_AXIS_MAX - X_AXIS_EPSILON) : (X_AXIS_MIN + X_AXIS_EPSILON));
  576. }
  577. if (smi.motor_done[Y_AXIS]) {
  578. sy = !sy;
  579. steppers_move_y(sy ? (Y_AXIS_MAX - Y_AXIS_EPSILON) : (Y_AXIS_MIN + Y_AXIS_EPSILON));
  580. }
  581. if (smi.click) {
  582. states_go_to(&sm_movement_test);
  583. }
  584. });
  585. sm_move_x_test.setTitle("X Axis");
  586. sm_move_x_test.setHeading("X Move Test");
  587. sm_move_x_test.setText("Moving axis through full range with selected speed.");
  588. sm_move_x_test.whenIn([](StateMachineInput smi) {
  589. static bool s = false;
  590. if (smi.motor_done[X_AXIS]) {
  591. s = !s;
  592. steppers_move_x(s ? (X_AXIS_MAX - X_AXIS_EPSILON) : (X_AXIS_MIN + X_AXIS_EPSILON));
  593. }
  594. if (smi.click) {
  595. states_go_to(&sm_movement_test);
  596. }
  597. });
  598. sm_move_y_test.setTitle("Y Axis");
  599. sm_move_y_test.setHeading("Y Move Test");
  600. sm_move_y_test.setText("Moving axis through full range with selected speed.");
  601. sm_move_y_test.whenIn([](StateMachineInput smi) {
  602. static bool s = false;
  603. if (smi.motor_done[Y_AXIS]) {
  604. s = !s;
  605. steppers_move_y(s ? (Y_AXIS_MAX - Y_AXIS_EPSILON) : (Y_AXIS_MIN + Y_AXIS_EPSILON));
  606. }
  607. if (smi.click) {
  608. states_go_to(&sm_movement_test);
  609. }
  610. });
  611. sm_move_z_test.setTitle("Z Axis");
  612. sm_move_z_test.setHeading("Z Move Test");
  613. sm_move_z_test.setText("Moving axis through full range with selected speed.");
  614. sm_move_z_test.whenIn([](StateMachineInput smi) {
  615. static bool s = false;
  616. if (smi.motor_done[Z_AXIS]) {
  617. s = !s;
  618. steppers_move_z(s ? (Z_AXIS_MAX - Z_AXIS_EPSILON) : (Z_AXIS_MIN + Z_AXIS_EPSILON));
  619. }
  620. if (smi.click) {
  621. states_go_to(&sm_movement_test);
  622. }
  623. });
  624. sm_move_e_test.setTitle("E Axis");
  625. sm_move_e_test.setHeading("E Move Test");
  626. sm_move_e_test.setText("Moving axis through full range with selected speed.");
  627. sm_move_e_test.whenIn([](StateMachineInput smi) {
  628. static bool s = false;
  629. if (smi.motor_done[E_AXIS]) {
  630. s = !s;
  631. steppers_move_e(s ? (E_AXIS_MAX /* - E_AXIS_EPSILON */) : (E_AXIS_MIN /* + E_AXIS_EPSILON */));
  632. }
  633. if (smi.click) {
  634. states_go_to(&sm_movement_test);
  635. }
  636. });
  637. #endif // ENABLE_MOVEMENT_TEST_STATE
  638. #ifdef ENABLE_INPUT_TEST_STATE
  639. sm_input_test.setTitle("Input Test");
  640. sm_input_test.setHeading("Endstop Test");
  641. sm_input_test.whenIn([](StateMachineInput smi) {
  642. String s = "Endstops: ";
  643. for (int i = 0; i < AXIS_COUNT; i++) {
  644. if (steppers_home_switch(i)) {
  645. s += '1';
  646. } else {
  647. s += '0';
  648. }
  649. if (i < 3) {
  650. s += ' ';
  651. }
  652. }
  653. if (s != strbuf) {
  654. strbuf = s;
  655. sm_input_test.setText(strbuf.c_str());
  656. sm_input_test.updateText();
  657. }
  658. });
  659. #endif // ENABLE_INPUT_TEST_STATE
  660. #ifdef ENABLE_MAX_SPEED_ACCEL_STATE
  661. sm_set_max_speed.setTitle("Set Max Speeds");
  662. sm_set_max_speed.setText("Maximum speeds have been set for all axes. Don't forget to store to EEPROM if desired!");
  663. sm_set_max_speed.onEnter([]() {
  664. data_options()->speed_x = XY_MAX_SPEED;
  665. data_options()->speed_y = XY_MAX_SPEED;
  666. data_options()->speed_z = Z_MAX_SPEED;
  667. data_options()->speed_e = E_MAX_SPEED;
  668. steppers_set_speed_x(data_options()->speed_x);
  669. steppers_set_speed_y(data_options()->speed_y);
  670. steppers_set_speed_z(data_options()->speed_z);
  671. steppers_set_speed_e(data_options()->speed_e);
  672. });
  673. sm_set_max_accel.setTitle("Set Max Accels");
  674. sm_set_max_accel.setText("Maximum accelerations have been set for all axes. Don't forget to store to EEPROM if desired!");
  675. sm_set_max_accel.onEnter([]() {
  676. data_options()->accel_x = XY_MAX_ACCEL;
  677. data_options()->accel_y = XY_MAX_ACCEL;
  678. data_options()->accel_z = Z_MAX_ACCEL;
  679. data_options()->accel_e = E_MAX_ACCEL;
  680. steppers_set_accel_x(data_options()->accel_x);
  681. steppers_set_accel_y(data_options()->accel_y);
  682. steppers_set_accel_z(data_options()->accel_z);
  683. steppers_set_accel_e(data_options()->accel_e);
  684. });
  685. #endif // ENABLE_MAX_SPEED_ACCEL_STATE
  686. // ----------------------------------
  687. states_go_to(&sm_ask_homing);
  688. }
  689. void states_run(StateMachineInput smi) {
  690. if (smi.click || smi.kill || (smi.encoder != 0)) {
  691. last_input = millis();
  692. }
  693. if (smi.click) {
  694. async_beep(ENCODER_CLICK_BEEP_TIME, ENCODER_CLICK_BEEP_FREQ);
  695. }
  696. if (smi.kill) {
  697. steppers_kill();
  698. Serial.println(F("Kill button pressed!"));
  699. blocking_beep(KILL_BEEP_TIME, KILL_BEEP_FREQ, KILL_BEEP_REPEAT - 1);
  700. states_go_to(&sm_ask_homing);
  701. return;
  702. }
  703. #if (IDLE_TIMEOUT > 0)
  704. unsigned long last_time = max(last_input, last_state_change);
  705. if ((millis() - last_time) > IDLE_TIMEOUT) {
  706. if (current_state != &sm_ask_homing) {
  707. Serial.println(F("Idle timeout, disabling motors"));
  708. steppers_kill();
  709. states_go_to(&sm_ask_homing);
  710. return;
  711. }
  712. }
  713. #endif // (IDLE_TIMEOUT > 0)
  714. if (current_state != NULL) {
  715. current_state->inState(smi);
  716. }
  717. }
  718. State *states_get(void) {
  719. return current_state;
  720. }
  721. void states_go_to(State *state) {
  722. last_state_change = millis();
  723. current_state = state;
  724. if (current_state != NULL) {
  725. current_state->enterState();
  726. }
  727. }