machine_interface.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /*
  2. * CNC-remote-control
  3. * Machine interface
  4. *
  5. * Copyright (C) 2011 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 "machine_interface.h"
  17. #include "machine_interface_internal.h"
  18. #include "usb.h"
  19. #include "usb_application.h"
  20. #include "util.h"
  21. #include "main.h"
  22. #include "pdiusb.h"
  23. #include "debug.h"
  24. #include "lcd.h"
  25. #include "tiny-list.h"
  26. #include <avr/wdt.h>
  27. #include <string.h>
  28. struct tx_queue_entry {
  29. struct control_interrupt buffer;
  30. uint8_t size;
  31. uint8_t count;
  32. struct tiny_list list;
  33. };
  34. static struct tx_queue_entry tx_queue_entry_buffer[INTERRUPT_QUEUE_MAX_LEN];
  35. static struct tiny_list tx_queued;
  36. static struct tiny_list tx_free;
  37. static uint8_t tx_free_count;
  38. static bool irq_queue_overflow;
  39. static uint8_t irq_sequence_number;
  40. uint16_t active_devflags;
  41. uint8_t interrupt_queue_freecount(void)
  42. {
  43. return ATOMIC_LOAD(tx_free_count);
  44. }
  45. static void tqentry_free(struct tx_queue_entry *e)
  46. {
  47. tlist_move_tail(&e->list, &tx_free);
  48. tx_free_count++;
  49. }
  50. static struct tx_queue_entry * tqentry_alloc(void)
  51. {
  52. struct tx_queue_entry *e;
  53. if (tlist_is_empty(&tx_free))
  54. return NULL;
  55. e = tlist_last_entry(&tx_free, struct tx_queue_entry, list);
  56. tlist_move_tail(&e->list, &tx_queued);
  57. tx_free_count--;
  58. return e;
  59. }
  60. void usb_app_reset(void)
  61. {
  62. uint8_t sreg, i;
  63. struct tx_queue_entry *e;
  64. sreg = irq_disable_save();
  65. memset(tx_queue_entry_buffer, 0, sizeof(tx_queue_entry_buffer));
  66. tlist_init(&tx_queued);
  67. tlist_init(&tx_free);
  68. for (i = 0; i < ARRAY_SIZE(tx_queue_entry_buffer); i++) {
  69. e = &tx_queue_entry_buffer[i];
  70. tlist_add_tail(&e->list, &tx_free);
  71. }
  72. tx_free_count = ARRAY_SIZE(tx_queue_entry_buffer);
  73. irq_queue_overflow = 0;
  74. irq_sequence_number = 0;
  75. irq_restore(sreg);
  76. }
  77. void usb_app_highpower(bool granted)
  78. {
  79. leds_enable(granted);
  80. }
  81. uint16_t get_active_devflags(void)
  82. {
  83. uint16_t flags;
  84. uint8_t sreg;
  85. sreg = irq_disable_save();
  86. flags = active_devflags;
  87. irq_restore(sreg);
  88. return flags;
  89. }
  90. static uint16_t do_modify_devflags(uint16_t mask, uint16_t set)
  91. {
  92. uint8_t sreg;
  93. uint16_t flags;
  94. sreg = irq_disable_save();
  95. flags = active_devflags;
  96. flags |= mask & set;
  97. flags &= ~mask | set;
  98. if (flags != active_devflags) {
  99. active_devflags = flags;
  100. update_userinterface();
  101. }
  102. irq_restore(sreg);
  103. return flags;
  104. }
  105. void reset_devflags(void)
  106. {
  107. do_modify_devflags(0xFFFF, 0);
  108. }
  109. void modify_devflags(uint16_t mask, uint16_t set)
  110. {
  111. struct control_interrupt irq = {
  112. .id = IRQ_DEVFLAGS,
  113. };
  114. uint8_t sreg;
  115. sreg = irq_disable_save();
  116. irq.devflags.flags = do_modify_devflags(mask, set);
  117. send_interrupt_discard_old(&irq, CONTROL_IRQ_SIZE(devflags));
  118. irq_restore(sreg);
  119. }
  120. static noreturn void enter_bootloader(void)
  121. {
  122. debug_printf("Entering bootloader...\n");
  123. irq_disable();
  124. wdt_reset();
  125. pdiusb_exit();
  126. /* Jump to bootloader code */
  127. __asm__ __volatile__(
  128. "ijmp\n"
  129. : /* None */
  130. : [_Z] "z" (BOOT_OFFSET / 2)
  131. );
  132. unreachable();
  133. }
  134. static int8_t rx_raw_message(const void *msg, uint8_t ctl_size,
  135. void *reply_buf, uint8_t reply_buf_size)
  136. {
  137. const struct control_message *ctl = msg;
  138. struct control_reply *reply = reply_buf;
  139. if (reply_buf_size < CONTROL_REPLY_MAX_SIZE)
  140. return -1;
  141. if (ctl_size < CONTROL_MSG_HDR_SIZE)
  142. goto err_size;
  143. if (ctl->flags & CONTROL_FLG_BOOTLOADER)
  144. goto err_context;
  145. switch (ctl->id) {
  146. case CONTROL_PING:
  147. break;
  148. case CONTROL_RESET: {
  149. reset_device_state();
  150. break;
  151. }
  152. case CONTROL_DEVFLAGS: {
  153. uint16_t flags;
  154. if (ctl_size < CONTROL_MSG_SIZE(devflags))
  155. goto err_size;
  156. flags = do_modify_devflags(ctl->devflags.mask,
  157. ctl->devflags.set);
  158. init_control_reply(reply, REPLY_VAL16, 0, ctl->seqno);
  159. reply->val16.value = flags;
  160. return CONTROL_REPLY_SIZE(val16);
  161. }
  162. case CONTROL_AXISUPDATE: {
  163. if (ctl_size < CONTROL_MSG_SIZE(axisupdate))
  164. goto err_size;
  165. if (ctl->axisupdate.axis >= NR_AXIS)
  166. goto err_inval;
  167. axis_pos_update(ctl->axisupdate.axis, ctl->axisupdate.pos);
  168. break;
  169. }
  170. case CONTROL_SPINDLEUPDATE: {
  171. if (ctl_size < CONTROL_MSG_SIZE(spindleupdate))
  172. goto err_size;
  173. spindle_state_update(ctl->spindleupdate.state == SPINDLE_CW);
  174. break;
  175. }
  176. case CONTROL_FOUPDATE: {
  177. if (ctl_size < CONTROL_MSG_SIZE(feedoverride))
  178. goto err_size;
  179. feed_override_feedback_update(ctl->feedoverride.percent);
  180. break;
  181. }
  182. case CONTROL_AXISENABLE: {
  183. if (ctl_size < CONTROL_MSG_SIZE(axisenable))
  184. goto err_size;
  185. if (!ctl->axisenable.mask)
  186. goto err_inval;
  187. set_axis_enable_mask(ctl->axisenable.mask);
  188. break;
  189. }
  190. case CONTROL_ESTOPUPDATE: {
  191. if (ctl_size < CONTROL_MSG_SIZE(estopupdate))
  192. goto err_size;
  193. set_estop_state(!!ctl->estopupdate.asserted);
  194. break;
  195. }
  196. case CONTROL_SETINCREMENT: {
  197. if (ctl_size < CONTROL_MSG_SIZE(setincrement))
  198. goto err_size;
  199. if (!set_increment_at_index(ctl->setincrement.index,
  200. ctl->setincrement.increment))
  201. goto err_inval;
  202. break;
  203. }
  204. case CONTROL_ENTERBOOT: {
  205. if (ctl_size < CONTROL_MSG_SIZE(enterboot))
  206. goto err_size;
  207. if (!control_enterboot_magic_ok(ctl))
  208. goto err_inval;
  209. switch (ctl->enterboot.target) {
  210. case TARGET_CPU:
  211. lcd_clear_buffer();
  212. lcd_printf("BOOTLOADER");
  213. lcd_commit();
  214. enter_bootloader();
  215. break;
  216. case TARGET_COPROC:
  217. default:
  218. goto err_context;
  219. }
  220. break;
  221. }
  222. case CONTROL_EXITBOOT:
  223. break;
  224. default:
  225. goto err_command;
  226. }
  227. init_control_reply(reply, REPLY_OK, 0, ctl->seqno);
  228. return CONTROL_REPLY_SIZE(ok);
  229. err_command:
  230. reply->error.code = CTLERR_COMMAND;
  231. goto error;
  232. err_inval:
  233. reply->error.code = CTLERR_INVAL;
  234. goto error;
  235. err_size:
  236. reply->error.code = CTLERR_SIZE;
  237. goto error;
  238. err_context:
  239. reply->error.code = CTLERR_CONTEXT;
  240. goto error;
  241. error:
  242. init_control_reply(reply, REPLY_ERROR, 0, ctl->seqno);
  243. return CONTROL_REPLY_SIZE(error);
  244. }
  245. uint8_t usb_app_control_setup_rx(struct usb_ctrl *ctl, uint8_t *reply_buf)
  246. {
  247. DBG(usb_printstr("USB-APP: Received control frame"));
  248. return USB_APP_UNHANDLED;
  249. }
  250. uint8_t usb_app_ep1_rx(uint8_t *data, uint8_t size,
  251. uint8_t *reply_buf)
  252. {
  253. DBG(usb_printstr("USB-APP: Received EP1 frame"));
  254. return USB_APP_UNHANDLED;
  255. }
  256. uint8_t usb_app_ep2_rx(uint8_t *data, uint8_t size,
  257. uint8_t *reply_buf)
  258. {
  259. int8_t res;
  260. DBG(usb_printstr("USB-APP: Received EP2 frame"));
  261. res = rx_raw_message(data, size, reply_buf, USBCFG_EP1_MAXSIZE);
  262. if (res < 0)
  263. return USB_APP_UNHANDLED;
  264. return (uint8_t)res;
  265. }
  266. /* Interrupt endpoint */
  267. uint8_t usb_app_ep1_tx_poll(void *buffer)
  268. {
  269. struct tx_queue_entry *e;
  270. struct control_interrupt *irqbuf = buffer;
  271. uint8_t ret_size, sreg;
  272. sreg = irq_disable_save();
  273. if (tlist_is_empty(&tx_queued)) {
  274. irq_restore(sreg);
  275. return 0; /* Zero length reply */
  276. }
  277. e = tlist_first_entry(&tx_queued, struct tx_queue_entry, list);
  278. BUILD_BUG_ON(sizeof(e->buffer) > USBCFG_EP1_MAXSIZE);
  279. memcpy(irqbuf, &e->buffer, e->size);
  280. ret_size = e->size;
  281. irqbuf->seqno = irq_sequence_number++;
  282. if (unlikely(irq_queue_overflow)) {
  283. irq_queue_overflow = 0;
  284. irqbuf->flags |= IRQ_FLG_TXQOVR;
  285. }
  286. if (--e->count == 0)
  287. tqentry_free(e);
  288. irq_restore(sreg);
  289. return ret_size;
  290. }
  291. uint8_t usb_app_ep2_tx_poll(void *buffer)
  292. {
  293. return USB_APP_UNHANDLED;
  294. }
  295. static bool interface_queue_interrupt(const struct control_interrupt *irq,
  296. uint8_t size, uint8_t count)
  297. {
  298. struct control_interrupt *irqbuf;
  299. struct tx_queue_entry *e;
  300. uint8_t sreg;
  301. BUG_ON(size > sizeof(tx_queue_entry_buffer[0].buffer));
  302. sreg = irq_disable_save();
  303. e = tqentry_alloc();
  304. if (!e) {
  305. irq_queue_overflow = 1;
  306. return 0;
  307. }
  308. e->size = size;
  309. e->count = count;
  310. irqbuf = &e->buffer;
  311. memcpy(irqbuf, irq, size);
  312. irq_restore(sreg);
  313. return 1;
  314. }
  315. static void interface_discard_irqs_by_id(uint8_t irq_id)
  316. {
  317. struct tx_queue_entry *e, *tmp_e;
  318. uint8_t sreg;
  319. sreg = irq_disable_save();
  320. tlist_for_each_delsafe(e, tmp_e, &tx_queued, list) {
  321. if (e->buffer.id == irq_id) {
  322. /* Dequeue and discard it. */
  323. tqentry_free(e);
  324. }
  325. }
  326. irq_restore(sreg);
  327. }
  328. static bool interface_drop_one_droppable_irq(void)
  329. {
  330. struct tx_queue_entry *e;
  331. uint8_t sreg;
  332. bool dropped = 0;
  333. sreg = irq_disable_save();
  334. tlist_for_each(e, &tx_queued, list) { /* not delsafe. Fine. */
  335. if (e->buffer.flags & IRQ_FLG_DROPPABLE) {
  336. /* Dequeue and discard it. */
  337. tqentry_free(e);
  338. dropped = 1;
  339. break;
  340. }
  341. }
  342. irq_restore(sreg);
  343. return dropped;
  344. }
  345. void send_interrupt_count(const struct control_interrupt *irq,
  346. uint8_t size, uint8_t count)
  347. {
  348. bool ok, dropped;
  349. uint8_t i;
  350. while (1) {
  351. for (i = 0; i < 5; i++) {
  352. ok = interface_queue_interrupt(irq, size, count);
  353. if (likely(ok))
  354. return;
  355. if (irqs_disabled())
  356. break; /* Out of luck. */
  357. _delay_ms(5);
  358. }
  359. debug_printf("Control IRQ queue overflow\n");
  360. /* Try to drop IRQs, if this is a higher priority IRQ. */
  361. if (!(irq->flags & IRQ_FLG_PRIO))
  362. break;
  363. dropped = interface_drop_one_droppable_irq();
  364. if (!dropped)
  365. break;
  366. debug_printf("Dropped one droppable IRQ\n");
  367. }
  368. }
  369. void send_interrupt_discard_old(const struct control_interrupt *irq,
  370. uint8_t size)
  371. {
  372. interface_discard_irqs_by_id(irq->id);
  373. send_interrupt(irq, size);
  374. }