main.c 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150
  1. /*
  2. * CNC-remote-control
  3. * CPU
  4. *
  5. * Copyright (C) 2009-2016 Michael Buesch <m@bues.ch>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * version 2 as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include "main.h"
  17. #include "debug.h"
  18. #include "util.h"
  19. #include "lcd.h"
  20. #include "override.h"
  21. #include "4094.h"
  22. #include "pdiusb.h"
  23. #include "spi.h"
  24. #include <avr/io.h>
  25. #include <avr/interrupt.h>
  26. #include <avr/wdt.h>
  27. #include <avr/pgmspace.h>
  28. #include <string.h>
  29. enum jog_state {
  30. JOG_STOPPED, /* Not jogging */
  31. JOG_RUNNING_POS, /* Jogging in positive direction */
  32. JOG_RUNNING_NEG, /* Jogging in negative direction */
  33. };
  34. /* Left */
  35. enum softkey0_states {
  36. SK0_AXISPOS, /* Axis position is displayed. */
  37. SK0_VELOCITY, /* Jog velocity is displayed. */
  38. NR_SK0_STATES,
  39. };
  40. /* Right */
  41. enum softkey1_states {
  42. SK1_INCREMENT,
  43. SK1_DEVSTATE,
  44. NR_SK1_STATES,
  45. };
  46. /* The current state */
  47. struct device_state {
  48. bool rapid; /* Rapid-jog on */
  49. bool incremental; /* Incremental-jog on */
  50. fixpt_t increments[6]; /* Possible increments (Modified in IRQ context) */
  51. uint8_t increment_index; /* Selected increment for jog (Modified in IRQ context) */
  52. uint8_t axis; /* Selected axis (enum axis_id) (Modified in IRQ context) */
  53. uint16_t axis_enable_mask; /* Enabled axes (Modified in IRQ context) */
  54. uint8_t jog; /* enum jog_state */
  55. fixpt_t jog_velocity; /* Jogging velocity */
  56. jiffies_t next_jog_keepalife; /* Deadline of next jog keepalife */
  57. uint8_t fo_feedback_percent; /* Feed override feedback percentage */
  58. jiffies_t next_fo_keepalife; /* Deadline of next feed override keepalife */
  59. /* The current axis positions.
  60. * Updated in IRQ context! */
  61. fixpt_t positions[NR_AXIS];
  62. bool spindle_on; /* Spindle state. Changed in IRQ context. */
  63. bool spindle_delayed_on; /* Delayed spindle-on request */
  64. jiffies_t spindle_change_time; /* Deadline for spindle-on */
  65. bool twohand_error; /* Twohand button error */
  66. jiffies_t twohand_error_delay; /* Twohand error delay */
  67. /* Deferred UI update requests. May be accessed in IRQ context. */
  68. bool lcd_need_update;
  69. bool leds_need_update;
  70. /* Button states. Use get_buttons() to access these fields. */
  71. bool button_update_required;
  72. uint16_t buttons;
  73. int8_t jogwheel;
  74. /* Softkey states */
  75. uint8_t softkey[2];
  76. /* Emergency stop state (read only). */
  77. bool estop;
  78. };
  79. static struct device_state state;
  80. /* The "external output-port interface" status. */
  81. typedef uint16_t extports_t;
  82. static extports_t extports;
  83. static char get_axis_name(uint8_t axis)
  84. {
  85. static const char PROGMEM names[] = {
  86. 'X', 'Y', 'Z', 'U', 'V', 'W', 'A', 'B', 'C',
  87. };
  88. if (axis >= ARRAY_SIZE(names))
  89. return '?';
  90. return (char)pgm_read(&names[axis]);
  91. }
  92. static uint8_t find_next_increment_index(uint8_t start)
  93. {
  94. uint8_t i, index;
  95. index = start;
  96. for (i = 0; i < ARRAY_SIZE(state.increments); i++) {
  97. index++;
  98. if (index >= ARRAY_SIZE(state.increments))
  99. index = 0;
  100. if (state.increments[index] != INT32_TO_FIXPT(0)) {
  101. /* Found nonzero. */
  102. return index;
  103. }
  104. }
  105. return start;
  106. }
  107. static fixpt_t current_increment(void)
  108. {
  109. fixpt_t ret;
  110. uint8_t sreg;
  111. sreg = irq_disable_save();
  112. ret = state.increments[state.increment_index];
  113. irq_restore(sreg);
  114. return ret;
  115. }
  116. static void select_next_axis(void)
  117. {
  118. uint8_t sreg, axis;
  119. sreg = irq_disable_save();
  120. BUG_ON(state.axis_enable_mask == 0);
  121. axis = state.axis;
  122. while (1) {
  123. if (++axis >= NR_AXIS)
  124. axis = 0;
  125. if (BIT(axis) & state.axis_enable_mask)
  126. break;
  127. }
  128. state.axis = axis;
  129. irq_restore(sreg);
  130. }
  131. static void select_previous_axis(void)
  132. {
  133. uint8_t sreg, axis;
  134. sreg = irq_disable_save();
  135. BUG_ON(state.axis_enable_mask == 0);
  136. axis = state.axis;
  137. while (1) {
  138. if (axis == 0)
  139. axis = NR_AXIS - 1;
  140. else
  141. axis--;
  142. if (BIT(axis) & state.axis_enable_mask)
  143. break;
  144. }
  145. state.axis = axis;
  146. irq_restore(sreg);
  147. }
  148. void leds_enable(bool enable)
  149. {
  150. sr4094_outen(enable);
  151. }
  152. static inline void extports_commit(void)
  153. {
  154. sr4094_put_data(&extports, sizeof(extports));
  155. }
  156. #define _extports_is_set(state, port_id) \
  157. (!!((state) & (port_id)))
  158. #define _extports_set(state, port_id) do { \
  159. (state) = (extports_t)((state) | (port_id)); \
  160. } while (0)
  161. #define _extports_clear(state, port_id) do { \
  162. (state) = (extports_t)((state) & ~(port_id)); \
  163. } while (0)
  164. static void extports_set(uint16_t extport_id)
  165. {
  166. if (!_extports_is_set(extports, extport_id)) {
  167. _extports_set(extports, extport_id);
  168. extports_commit();
  169. }
  170. }
  171. static void extports_clear(uint16_t extport_id)
  172. {
  173. if (_extports_is_set(extports, extport_id)) {
  174. _extports_clear(extports, extport_id);
  175. extports_commit();
  176. }
  177. }
  178. static void extports_init(void)
  179. {
  180. sr4094_init(&extports, sizeof(extports));
  181. }
  182. static void coprocessor_init(void)
  183. {
  184. uint8_t result;
  185. spi_lowlevel_init();
  186. /* Boot coprocessor application */
  187. spi_slave_select(1);
  188. spi_transfer_slowsync(SPI_CONTROL_ENTERAPP);
  189. spi_slave_select(0);
  190. long_delay_ms(300);
  191. spi_slave_select(1);
  192. spi_transfer_slowsync(SPI_CONTROL_TESTAPP);
  193. result = spi_transfer_slowsync(SPI_CONTROL_NOP);
  194. spi_slave_select(0);
  195. if (result == SPI_RESULT_OK) {
  196. debug_printf("Coprocessor initialized\n");
  197. } else {
  198. debug_printf("Coprocessor init failed (%u)\n", result);
  199. return;
  200. }
  201. GIFR = (1u << SPI_MASTER_TRANSIRQ_INTF);
  202. GICR |= (1u << SPI_MASTER_TRANSIRQ_INT);
  203. }
  204. ISR(SPI_MASTER_TRANSIRQ_VECT)
  205. {
  206. ATOMIC_STORE(state.button_update_required, 1);
  207. }
  208. static struct spi_rx_data {
  209. uint8_t _undefined;
  210. uint8_t low;
  211. uint8_t high;
  212. uint8_t enc;
  213. uint8_t sum;
  214. } __packed spi_rx_data;
  215. /* Commands sent to the coprocessor (in that order).
  216. * Must match struct spi_rx_data. */
  217. static const uint8_t PROGMEM spi_tx_data[] = {
  218. SPI_CONTROL_GETLOW,
  219. SPI_CONTROL_GETHIGH,
  220. SPI_CONTROL_GETENC,
  221. SPI_CONTROL_GETSUM,
  222. SPI_CONTROL_NOP,
  223. };
  224. static void trigger_button_state_fetching(void)
  225. {
  226. BUILD_BUG_ON(sizeof(spi_tx_data) != sizeof(spi_rx_data));
  227. if (!spi_async_running()) {
  228. ATOMIC_STORE(state.button_update_required, 0);
  229. spi_async_start(&spi_rx_data, (const void *)spi_tx_data,
  230. ARRAY_SIZE(spi_tx_data),
  231. SPI_ASYNC_TXPROGMEM, 1);
  232. }
  233. }
  234. /* Runs with IRQs disabled */
  235. void spi_async_done(void)
  236. {
  237. uint8_t expected_sum;
  238. /* We got all spi_rx_data */
  239. expected_sum = spi_rx_data.low ^ spi_rx_data.high ^
  240. spi_rx_data.enc ^ 0xFF;
  241. if (unlikely(spi_rx_data.sum != expected_sum)) {
  242. if (debug_verbose()) {
  243. debug_printf("SPI: button checksum mismatch: "
  244. "was %02X, expected %02X\n",
  245. spi_rx_data.sum, expected_sum);
  246. }
  247. /* Try again */
  248. trigger_button_state_fetching();
  249. return;
  250. }
  251. /* Update state. */
  252. BUG_ON(!irqs_disabled());
  253. state.buttons = spi_rx_data.low | ((uint16_t)spi_rx_data.high << 8);
  254. state.jogwheel = (int8_t)(state.jogwheel + (int8_t)spi_rx_data.enc);
  255. }
  256. /* Spindle state may change at any time before or right after this check */
  257. static inline bool spindle_is_on(void)
  258. {
  259. mb();
  260. return state.spindle_on;
  261. }
  262. static uint16_t get_buttons(int8_t *_jogwheel)
  263. {
  264. uint16_t buttons;
  265. int8_t jogwheel;
  266. uint8_t sreg;
  267. sreg = irq_disable_save();
  268. /* Get the pushbuttons state */
  269. buttons = state.buttons;
  270. /* Get the jogwheel state.
  271. * One "wheel-click" is equivalent to two state increments.
  272. * So we convert the value to "wheel-clicks". */
  273. jogwheel = state.jogwheel / 2;
  274. state.jogwheel %= 2;
  275. irq_restore(sreg);
  276. *_jogwheel = jogwheel;
  277. return buttons;
  278. }
  279. static void do_update_lcd(void)
  280. {
  281. uint8_t sreg;
  282. uint16_t devflags = get_active_devflags();
  283. if (ATOMIC_LOAD(state.estop)) {
  284. lcd_cursor(0, 2);
  285. lcd_put_str("ESTOP ACTIVE");
  286. return;
  287. }
  288. if (state.twohand_error) {
  289. lcd_cursor(0, 1);
  290. lcd_put_str("TWOHAND BUTTON");
  291. lcd_cursor(1, 4);
  292. lcd_put_str("RELEASED!");
  293. return;
  294. }
  295. switch (state.softkey[0]) {
  296. case SK0_AXISPOS: {
  297. uint8_t axis;
  298. fixpt_t pos;
  299. sreg = irq_disable_save();
  300. axis = state.axis;
  301. pos = state.positions[axis];
  302. irq_restore(sreg);
  303. lcd_put_char(get_axis_name(axis));
  304. if (devflags & DEVICE_FLG_G53COORDS)
  305. lcd_put_char('@');
  306. lcd_printf(FIXPT_FMT3, FIXPT_ARG3(pos));
  307. break;
  308. }
  309. case SK0_VELOCITY: {
  310. lcd_printf("Vf" FIXPT_FMT0,
  311. FIXPT_ARG0(state.jog_velocity));
  312. break;
  313. }
  314. default:
  315. BUG_ON(1);
  316. }
  317. switch (state.softkey[1]) {
  318. case SK1_INCREMENT:
  319. lcd_cursor(0, 10);
  320. lcd_printf("i" FIXPT_FMT3, FIXPT_ARG3(current_increment()));
  321. break;
  322. case SK1_DEVSTATE:
  323. lcd_cursor(0, 11);
  324. lcd_put_char(state.jog != JOG_STOPPED ? 'J' : ' ');
  325. lcd_printf("%d%%", state.fo_feedback_percent);
  326. break;
  327. default:
  328. BUG_ON(1);
  329. }
  330. /* Left softkey label */
  331. switch (state.softkey[0]) {
  332. case SK0_AXISPOS:
  333. lcd_cursor(1, 0);
  334. lcd_put_str("Vf");
  335. break;
  336. case SK0_VELOCITY:
  337. lcd_cursor(1, 0);
  338. lcd_put_str("pos");
  339. break;
  340. default:
  341. BUG_ON(1);
  342. }
  343. if (devflags & DEVICE_FLG_ON) {
  344. lcd_cursor(1, 6);
  345. lcd_put_str("[ON]");
  346. } else {
  347. lcd_cursor(1, 5);
  348. lcd_put_str("[OFF]");
  349. }
  350. /* Right softkey label */
  351. switch (state.softkey[1]) {
  352. case SK1_INCREMENT:
  353. lcd_cursor(1, 11);
  354. lcd_put_str("state");
  355. break;
  356. case SK1_DEVSTATE:
  357. lcd_cursor(1, 12);
  358. lcd_put_str("incr");
  359. break;
  360. default:
  361. BUG_ON(1);
  362. }
  363. }
  364. static void update_lcd(void)
  365. {
  366. if (debug_verbose())
  367. debug_printf("Update LCD\n");
  368. lcd_clear_buffer();
  369. do_update_lcd();
  370. lcd_commit();
  371. }
  372. static void update_leds(void)
  373. {
  374. uint16_t devflags = get_active_devflags();
  375. extports_t ext = extports;
  376. if (spindle_is_on())
  377. _extports_set(ext, EXT_LED_SPINDLE);
  378. else
  379. _extports_clear(ext, EXT_LED_SPINDLE);
  380. if (state.rapid)
  381. _extports_set(ext, EXT_LED_JOGRAPID);
  382. else
  383. _extports_clear(ext, EXT_LED_JOGRAPID);
  384. if (state.incremental)
  385. _extports_set(ext, EXT_LED_JOGINC);
  386. else
  387. _extports_clear(ext, EXT_LED_JOGINC);
  388. switch (state.jog) {
  389. case JOG_STOPPED:
  390. _extports_clear(ext, EXT_LED_JOGPOS);
  391. _extports_clear(ext, EXT_LED_JOGNEG);
  392. break;
  393. case JOG_RUNNING_POS:
  394. _extports_set(ext, EXT_LED_JOGPOS);
  395. _extports_clear(ext, EXT_LED_JOGNEG);
  396. break;
  397. case JOG_RUNNING_NEG:
  398. _extports_clear(ext, EXT_LED_JOGPOS);
  399. _extports_set(ext, EXT_LED_JOGNEG);
  400. break;
  401. default:
  402. BUG_ON(1);
  403. }
  404. if (devflags & DEVICE_FLG_ON)
  405. _extports_set(ext, EXT_LED_ONOFF);
  406. else
  407. _extports_clear(ext, EXT_LED_ONOFF);
  408. switch (state.softkey[0]) {
  409. case SK0_AXISPOS:
  410. if (devflags & DEVICE_FLG_G53COORDS)
  411. _extports_set(ext, EXT_LED_TOGGLE);
  412. else
  413. _extports_clear(ext, EXT_LED_TOGGLE);
  414. break;
  415. case SK0_VELOCITY:
  416. _extports_clear(ext, EXT_LED_TOGGLE);
  417. break;
  418. default:
  419. BUG_ON(1);
  420. }
  421. if (extports != ext) {
  422. extports = ext;
  423. extports_commit();
  424. }
  425. }
  426. static void interpret_one_softkey(bool sk, uint8_t index, uint8_t count)
  427. {
  428. uint8_t sk_state;
  429. if (!sk)
  430. return;
  431. /* Key was pressed */
  432. sk_state = state.softkey[index];
  433. sk_state++;
  434. if (sk_state >= count)
  435. sk_state = 0;
  436. state.softkey[index] = sk_state;
  437. update_userinterface();
  438. }
  439. static void interpret_softkeys(bool sk0, bool sk1)
  440. {
  441. interpret_one_softkey(sk0, 0, NR_SK0_STATES);
  442. interpret_one_softkey(sk1, 1, NR_SK1_STATES);
  443. }
  444. static void set_jog_keepalife_deadline(void)
  445. {
  446. state.next_jog_keepalife = get_jiffies() + msec2jiffies(100);
  447. }
  448. static void jog_incremental(int8_t inc_count)
  449. {
  450. struct control_interrupt irq = {
  451. .id = IRQ_JOG,
  452. .flags = IRQ_FLG_DROPPABLE,
  453. };
  454. if (!inc_count)
  455. return;
  456. irq.jog.increment = current_increment();
  457. if (irq.jog.increment == INT32_TO_FIXPT(0))
  458. return;
  459. if (inc_count < 0)
  460. irq.jog.increment = fixpt_neg(irq.jog.increment);
  461. if (abs(inc_count) > 1) {
  462. irq.jog.increment = fixpt_mult(irq.jog.increment,
  463. INT32_TO_FIXPT(abs(inc_count)));
  464. }
  465. irq.jog.axis = state.axis;
  466. irq.jog.flags = state.rapid ? IRQ_JOG_RAPID : 0;
  467. irq.jog.velocity = state.jog_velocity;
  468. send_interrupt(&irq, CONTROL_IRQ_SIZE(jog));
  469. }
  470. static void jog_stop(void)
  471. {
  472. struct control_interrupt irq = {
  473. .id = IRQ_JOG,
  474. .flags = IRQ_FLG_PRIO,
  475. };
  476. if (state.jog == JOG_STOPPED)
  477. return;
  478. irq.jog.axis = state.axis;
  479. irq.jog.flags = IRQ_JOG_CONTINUOUS;
  480. irq.jog.increment = INT32_TO_FIXPT(0);
  481. send_interrupt_count(&irq, CONTROL_IRQ_SIZE(jog), 3);
  482. state.jog = JOG_STOPPED;
  483. }
  484. static void jog(int8_t direction)
  485. {
  486. struct control_interrupt irq = {
  487. .id = IRQ_JOG,
  488. };
  489. if (direction) {
  490. if (state.incremental) {
  491. jog_stop();
  492. jog_incremental(direction > 0 ? 1 : -1);
  493. } else {
  494. /* Positive or negative jog */
  495. irq.flags |= IRQ_FLG_DROPPABLE;
  496. irq.jog.axis = state.axis;
  497. irq.jog.flags = IRQ_JOG_CONTINUOUS;
  498. if (state.rapid)
  499. irq.jog.flags |= IRQ_JOG_RAPID;
  500. irq.jog.velocity = state.jog_velocity;
  501. irq.jog.increment = INT32_TO_FIXPT(direction > 0 ? 1 : -1);
  502. send_interrupt(&irq, CONTROL_IRQ_SIZE(jog));
  503. state.jog = direction > 0 ? JOG_RUNNING_POS : JOG_RUNNING_NEG;
  504. set_jog_keepalife_deadline();
  505. }
  506. } else
  507. jog_stop();
  508. update_userinterface();
  509. }
  510. static void jog_update(void)
  511. {
  512. switch (state.jog) {
  513. case JOG_STOPPED:
  514. jog(0);
  515. break;
  516. case JOG_RUNNING_POS:
  517. jog(1);
  518. break;
  519. case JOG_RUNNING_NEG:
  520. jog(-1);
  521. break;
  522. default:
  523. BUG_ON(1);
  524. }
  525. }
  526. static void handle_jog_keepalife(void)
  527. {
  528. struct control_interrupt irq = {
  529. .id = IRQ_JOG_KEEPALIFE,
  530. .flags = IRQ_FLG_DROPPABLE,
  531. };
  532. if (state.jog == JOG_STOPPED)
  533. return;
  534. if (!devflag_is_set(DEVICE_FLG_ON))
  535. return;
  536. if (time_before(get_jiffies(), state.next_jog_keepalife))
  537. return;
  538. send_interrupt_discard_old(&irq, CONTROL_IRQ_SIZE(jog_keepalife));
  539. set_jog_keepalife_deadline();
  540. }
  541. static void halt_motion(void)
  542. {
  543. struct control_interrupt irq = {
  544. .id = IRQ_HALT,
  545. .flags = IRQ_FLG_PRIO,
  546. };
  547. send_interrupt_count(&irq, CONTROL_IRQ_SIZE(halt), 3);
  548. }
  549. static void interpret_jogwheel(int8_t jogwheel, bool wheel_pressed)
  550. {
  551. fixpt_t mult, increment, velocity;
  552. uint8_t sreg;
  553. if (wheel_pressed) {
  554. /* Select bigger INC step. */
  555. sreg = irq_disable_save();
  556. state.increment_index = find_next_increment_index(state.increment_index);
  557. irq_restore(sreg);
  558. /* Jump to INC state display. */
  559. state.softkey[1] = SK1_INCREMENT;
  560. update_userinterface();
  561. return;
  562. }
  563. if (jogwheel) {
  564. switch (state.softkey[0]) {
  565. case SK0_AXISPOS:
  566. jog_incremental(jogwheel);
  567. break;
  568. case SK0_VELOCITY:
  569. if (state.rapid)
  570. mult = FLOAT_TO_FIXPT(15.0);
  571. else
  572. mult = FLOAT_TO_FIXPT(1.0);
  573. increment = INT32_TO_FIXPT((int32_t)jogwheel);
  574. increment = fixpt_mult(increment, mult);
  575. velocity = state.jog_velocity;
  576. velocity = fixpt_add(velocity, increment);
  577. if (fixpt_is_neg(velocity))
  578. velocity = INT32_TO_FIXPT(0);
  579. if (velocity >= INT32_TO_FIXPT(30000))
  580. velocity = INT32_TO_FIXPT(30000);
  581. state.jog_velocity = velocity;
  582. break;
  583. default:
  584. BUG_ON(1);
  585. }
  586. update_userinterface();
  587. }
  588. }
  589. static void turn_spindle_on(void)
  590. {
  591. struct control_interrupt irq = {
  592. .id = IRQ_SPINDLE,
  593. .flags = IRQ_FLG_DROPPABLE,
  594. };
  595. irq.spindle.state = SPINDLE_CW;
  596. send_interrupt(&irq, CONTROL_IRQ_SIZE(spindle));
  597. }
  598. static void turn_spindle_off(void)
  599. {
  600. struct control_interrupt irq = {
  601. .id = IRQ_SPINDLE,
  602. .flags = IRQ_FLG_PRIO,
  603. };
  604. irq.spindle.state = SPINDLE_OFF;
  605. send_interrupt(&irq, CONTROL_IRQ_SIZE(spindle));
  606. }
  607. static void update_button_led(bool btn_pressed, extports_t ledport)
  608. {
  609. if (btn_pressed)
  610. extports_set(ledport);
  611. else
  612. extports_clear(ledport);
  613. }
  614. static void set_feed_override_keepalife_deadline(void)
  615. {
  616. state.next_fo_keepalife = get_jiffies() + msec2jiffies(100);
  617. }
  618. static void interpret_buttons(void)
  619. {
  620. uint16_t buttons, old_buttons, rising, falling;
  621. int8_t jogwheel;
  622. static uint16_t prev_buttons;
  623. #define rising_edge(btn) (!!(rising & (btn)))
  624. #define falling_edge(btn) (!!(falling & (btn)))
  625. #define pressed(btn) (!!(buttons & (btn)))
  626. #define released(btn) (!pressed(btn))
  627. buttons = get_buttons(&jogwheel);
  628. /* Twohand button */
  629. if (pressed(BTN_TWOHAND)) {
  630. extports_set(EXT_LED_TWOHAND);
  631. } else {
  632. extports_clear(EXT_LED_TWOHAND);
  633. if (devflag_is_set(DEVICE_FLG_TWOHANDEN)) {
  634. /* Security switch is not pressed. Report security
  635. * related buttons as released. */
  636. old_buttons = buttons;
  637. if (!spindle_is_on())
  638. buttons = (uint16_t)(buttons & ~BTN_SPINDLE);
  639. buttons = (uint16_t)(buttons & ~(BTN_JOG_POSITIVE |
  640. BTN_JOG_NEGATIVE));
  641. if (old_buttons != buttons || jogwheel) {
  642. state.twohand_error_delay = get_jiffies() +
  643. msec2jiffies(200);
  644. if (!state.twohand_error) {
  645. state.twohand_error = 1;
  646. update_userinterface();
  647. }
  648. }
  649. jogwheel = 0;
  650. }
  651. }
  652. if (state.twohand_error &&
  653. time_after(get_jiffies(), state.twohand_error_delay)) {
  654. state.twohand_error = 0;
  655. update_userinterface();
  656. }
  657. /* Edge detection */
  658. rising = buttons & ~prev_buttons;
  659. falling = ~buttons & prev_buttons;
  660. /* on/off button */
  661. if (rising_edge(BTN_ONOFF)) {
  662. if (devflag_is_set(DEVICE_FLG_ON)) {
  663. /* Disable device. */
  664. modify_devflags(DEVICE_FLG_ON, 0);
  665. } else {
  666. /* Enable device. */
  667. modify_devflags(DEVICE_FLG_ON, DEVICE_FLG_ON);
  668. set_jog_keepalife_deadline();
  669. set_feed_override_keepalife_deadline();
  670. }
  671. }
  672. /* Spindle button */
  673. if (rising_edge(BTN_SPINDLE)) {
  674. if (spindle_is_on()) {
  675. turn_spindle_off();
  676. } else {
  677. state.spindle_delayed_on = 1;
  678. state.spindle_change_time = get_jiffies() + msec2jiffies(800);
  679. }
  680. }
  681. if (falling_edge(BTN_SPINDLE))
  682. state.spindle_delayed_on = 0;
  683. update_button_led(pressed(BTN_HALT), EXT_LED_HALT);
  684. if (rising_edge(BTN_HALT))
  685. halt_motion();
  686. /* Next axis selection */
  687. update_button_led(pressed(BTN_AXIS_NEXT), EXT_LED_AXIS_NEXT);
  688. update_button_led(pressed(BTN_AXIS_PREV), EXT_LED_AXIS_PREV);
  689. if (rising_edge(BTN_AXIS_NEXT)) {
  690. jog(0);
  691. select_next_axis();
  692. state.softkey[0] = SK0_AXISPOS;
  693. update_userinterface();
  694. }
  695. /* Previous axis selection */
  696. if (rising_edge(BTN_AXIS_PREV)) {
  697. jog(0);
  698. select_previous_axis();
  699. state.softkey[0] = SK0_AXISPOS;
  700. update_userinterface();
  701. }
  702. /* Rapid-move button */
  703. if (rising_edge(BTN_JOG_RAPID)) {
  704. state.rapid = 1;
  705. jog_update();
  706. update_userinterface();
  707. }
  708. if (falling_edge(BTN_JOG_RAPID)) {
  709. state.rapid = 0;
  710. jog_update();
  711. update_userinterface();
  712. }
  713. /* Incremental-button */
  714. if (rising_edge(BTN_JOG_INC)) {
  715. jog(0);
  716. state.incremental = !state.incremental;
  717. update_userinterface();
  718. }
  719. /* Softkeys */
  720. update_button_led(pressed(BTN_SOFT0), EXT_LED_SK0);
  721. update_button_led(pressed(BTN_SOFT1), EXT_LED_SK1);
  722. interpret_softkeys(rising_edge(BTN_SOFT0),
  723. rising_edge(BTN_SOFT1));
  724. /* Jog */
  725. if (rising_edge(BTN_JOG_POSITIVE))
  726. jog(1);
  727. if (rising_edge(BTN_JOG_NEGATIVE))
  728. jog(-1);
  729. if (falling_edge(BTN_JOG_NEGATIVE) ||
  730. falling_edge(BTN_JOG_POSITIVE))
  731. jog(0);
  732. /* Jogwheel. Only if not jogging via buttons. */
  733. if (state.jog == JOG_STOPPED)
  734. interpret_jogwheel(jogwheel, rising_edge(BTN_ENCPUSH));
  735. /* Togglebutton */
  736. if (rising_edge(BTN_TOGGLE)) {
  737. switch (state.softkey[0]) {
  738. case SK0_AXISPOS:
  739. if (devflag_is_set(DEVICE_FLG_G53COORDS)) {
  740. modify_devflags(DEVICE_FLG_G53COORDS,
  741. 0);
  742. } else {
  743. modify_devflags(DEVICE_FLG_G53COORDS,
  744. DEVICE_FLG_G53COORDS);
  745. }
  746. break;
  747. case SK0_VELOCITY:
  748. break;
  749. default:
  750. BUG_ON(1);
  751. }
  752. }
  753. prev_buttons = buttons;
  754. #undef rising_edge
  755. #undef falling_edge
  756. #undef pressed
  757. #undef released
  758. }
  759. static void handle_spindle_change_requests(void)
  760. {
  761. if (state.spindle_delayed_on) {
  762. if (spindle_is_on()) {
  763. state.spindle_delayed_on = 0;
  764. return;
  765. }
  766. if (time_after(get_jiffies(), state.spindle_change_time)) {
  767. turn_spindle_on();
  768. state.spindle_delayed_on = 0;
  769. }
  770. }
  771. }
  772. static void interpret_feed_override(bool force)
  773. {
  774. struct control_interrupt irq = {
  775. .id = IRQ_FEEDOVERRIDE,
  776. .flags = IRQ_FLG_DROPPABLE,
  777. };
  778. uint8_t fostate;
  779. static uint8_t prev_state;
  780. fostate = override_get_pos();
  781. if (fostate != prev_state ||
  782. (devflag_is_set(DEVICE_FLG_ON) &&
  783. time_after(get_jiffies(), state.next_fo_keepalife)) ||
  784. force) {
  785. set_feed_override_keepalife_deadline();
  786. irq.feedoverride.state = fostate;
  787. send_interrupt_discard_old(&irq,
  788. CONTROL_IRQ_SIZE(feedoverride));
  789. }
  790. prev_state = fostate;
  791. }
  792. /* Called in IRQ context! */
  793. void set_axis_enable_mask(uint16_t mask)
  794. {
  795. uint8_t sreg;
  796. BUG_ON(mask == 0);
  797. sreg = irq_disable_save();
  798. if (state.axis_enable_mask != mask) {
  799. state.axis_enable_mask = mask;
  800. if (!(BIT(state.axis) & mask))
  801. state.axis = (uint8_t)(ffs16(mask) - 1u);
  802. update_userinterface();
  803. }
  804. irq_restore(sreg);
  805. }
  806. /* Called in IRQ context! */
  807. void axis_pos_update(uint8_t axis, fixpt_t absolute_pos)
  808. {
  809. uint8_t sreg;
  810. BUG_ON(axis >= ARRAY_SIZE(state.positions));
  811. sreg = irq_disable_save();
  812. if (state.positions[axis] != absolute_pos) {
  813. state.positions[axis] = absolute_pos;
  814. state.lcd_need_update = 1;
  815. }
  816. irq_restore(sreg);
  817. }
  818. /* Called in IRQ context! */
  819. void spindle_state_update(bool on)
  820. {
  821. uint8_t sreg;
  822. sreg = irq_disable_save();
  823. if (state.spindle_on != on) {
  824. state.spindle_on = on;
  825. update_userinterface();
  826. }
  827. irq_restore(sreg);
  828. }
  829. /* Called in IRQ context! */
  830. void feed_override_feedback_update(uint8_t percent)
  831. {
  832. uint8_t sreg;
  833. percent = min(percent, 200);
  834. sreg = irq_disable_save();
  835. if (state.fo_feedback_percent != percent) {
  836. state.fo_feedback_percent = percent;
  837. update_userinterface();
  838. }
  839. irq_restore(sreg);
  840. }
  841. /* Called in IRQ context! */
  842. void set_estop_state(bool asserted)
  843. {
  844. uint8_t sreg;
  845. sreg = irq_disable_save();
  846. if ((bool)ATOMIC_LOAD(state.estop) != asserted) {
  847. ATOMIC_STORE(state.estop, asserted);
  848. update_userinterface();
  849. }
  850. irq_restore(sreg);
  851. }
  852. /* Called in IRQ context! */
  853. bool set_increment_at_index(uint8_t index, fixpt_t increment)
  854. {
  855. uint8_t sreg;
  856. if (index >= ARRAY_SIZE(state.increments))
  857. return 0;
  858. if (fixpt_is_neg(increment) ||
  859. increment > FLOAT_TO_FIXPT(9.999))
  860. return 0;
  861. sreg = irq_disable_save();
  862. state.increments[index] = increment;
  863. if (state.increments[state.increment_index] == INT32_TO_FIXPT(0))
  864. state.increment_index = find_next_increment_index(0);
  865. irq_restore(sreg);
  866. return 1;
  867. }
  868. void update_userinterface(void)
  869. {
  870. mb();
  871. state.lcd_need_update = 1;
  872. state.leds_need_update = 1;
  873. }
  874. static void systimer_init(void)
  875. {
  876. TCCR1A = 0;
  877. TCCR1B = (1 << CS10) | (0 << CS11) | (1 << CS12);
  878. OCR1A = 0;
  879. }
  880. static void handle_debug_ringbuffer(void)
  881. {
  882. struct control_interrupt irq = {
  883. .id = IRQ_LOGMSG,
  884. .flags = IRQ_FLG_DROPPABLE,
  885. };
  886. uint8_t count;
  887. while (debug_ringbuf_count() &&
  888. interrupt_queue_freecount() >= INTERRUPT_QUEUE_MAX_LEN / 2) {
  889. memset(irq.logmsg.msg, 0, sizeof(irq.logmsg.msg));
  890. count = debug_ringbuf_get(irq.logmsg.msg,
  891. sizeof(irq.logmsg.msg));
  892. if (!count)
  893. break;
  894. send_interrupt(&irq, CONTROL_IRQ_SIZE(logmsg));
  895. }
  896. }
  897. void reset_device_state(void)
  898. {
  899. uint8_t i;
  900. memset(&state, 0, sizeof(state));
  901. state.axis = AXIS_X;
  902. state.jog = JOG_STOPPED;
  903. state.jog_velocity = INT32_TO_FIXPT(100);
  904. for (i = 0; i < ARRAY_SIZE(state.positions); i++)
  905. state.positions[i] = INT32_TO_FIXPT(0);
  906. state.softkey[0] = SK0_AXISPOS;
  907. state.softkey[1] = SK1_INCREMENT;
  908. set_axis_enable_mask(BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z) |
  909. BIT(AXIS_A));
  910. reset_devflags();
  911. set_jog_keepalife_deadline();
  912. set_feed_override_keepalife_deadline();
  913. update_userinterface();
  914. interpret_feed_override(1); /* Force-send override state */
  915. }
  916. int main(void) _mainfunc;
  917. int main(void)
  918. {
  919. static jiffies_t next_ms_tick;
  920. jiffies_t j;
  921. irq_disable();
  922. wdt_enable(WDTO_500MS);
  923. debug_init();
  924. GICR = 0;
  925. MCUCR = (0 << ISC11) | (0 << ISC10) |
  926. (1 << ISC01) | (0 << ISC00);
  927. lcd_init();
  928. lcd_printf("CNC-Control %u.%u\nInitializing",
  929. VERSION_MAJOR, VERSION_MINOR);
  930. lcd_commit();
  931. extports_init();
  932. coprocessor_init();
  933. override_init();
  934. pdiusb_init();
  935. systimer_init();
  936. reset_device_state();
  937. irq_enable();
  938. while (1) {
  939. j = get_jiffies();
  940. if (time_after(j, next_ms_tick)) {
  941. next_ms_tick = j + msec2jiffies(1);
  942. spi_async_ms_tick();
  943. }
  944. if (!ATOMIC_LOAD(state.estop)) {
  945. if (ATOMIC_LOAD(state.button_update_required))
  946. trigger_button_state_fetching();
  947. interpret_buttons();
  948. interpret_feed_override(0);
  949. handle_spindle_change_requests();
  950. handle_jog_keepalife();
  951. }
  952. mb();
  953. if (state.lcd_need_update || state.leds_need_update) {
  954. bool lcd, leds;
  955. irq_disable();
  956. lcd = state.lcd_need_update;
  957. leds = state.leds_need_update;
  958. state.lcd_need_update = 0;
  959. state.leds_need_update = 0;
  960. irq_enable();
  961. if (lcd)
  962. update_lcd();
  963. if (leds)
  964. update_leds();
  965. }
  966. if (devflag_is_set(DEVICE_FLG_USBLOGMSG))
  967. handle_debug_ringbuffer();
  968. wdt_reset();
  969. }
  970. }