/firmware/src/Motherboard/Tool.cc

http://github.com/makerbot/G3Firmware · C++ · 291 lines · 207 code · 41 blank · 43 comment · 32 complexity · 3577764283bbfb974f8f8dc57f1ac854 MD5 · raw file

  1. /*
  2. * Copyright 2010 by Adam Mayer <adam@makerbot.com>
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>
  16. */
  17. #include "Tool.hh"
  18. #include "Timeout.hh"
  19. #include "Errors.hh"
  20. #include "Motherboard.hh"
  21. #include "Commands.hh"
  22. #define RETRIES 5
  23. #define TOOL_PACKET_TIMEOUT_MS 50L
  24. #define TOOL_PACKET_TIMEOUT_MICROS (1000L*TOOL_PACKET_TIMEOUT_MS)
  25. #define DELAY_BETWEEN_TRANSMISSIONS_MICROS (500L)
  26. namespace tool {
  27. // TODO: Don't bother initializing these here.
  28. bool transaction_active = false; ///< True if a transaction is in progress
  29. bool locked = false; ///< True if the tool is in use
  30. uint8_t retries = RETRIES; ///< Rery count for current operation
  31. Timeout timeout; ///< Tool resposnse timeout counter
  32. uint8_t tool_index = 0;
  33. uint32_t sent_packet_count;
  34. uint32_t packet_failure_count;
  35. uint32_t packet_retry_count;
  36. uint32_t noise_byte_count;
  37. InPacket& getInPacket() {
  38. return UART::getSlaveUART().in;
  39. }
  40. OutPacket& getOutPacket() {
  41. return UART::getSlaveUART().out;
  42. }
  43. // Get the total number of packets that were attempted to be sent to a tool
  44. uint32_t getSentPacketCount() {
  45. return sent_packet_count;
  46. }
  47. // Get the total number of packets that failed to get a response from a tool
  48. uint32_t getPacketFailureCount() {
  49. return packet_failure_count;
  50. }
  51. // Get the total packet retries attempted
  52. uint32_t getRetryCount() {
  53. return packet_retry_count;
  54. }
  55. // Get the total number of received bytes that were discarded as noise
  56. uint32_t getNoiseByteCount() {
  57. return noise_byte_count;
  58. }
  59. bool getToolVersion() {
  60. // This code is very lightly modified from handleToolQuery in Host.cc.
  61. // We don't give up if we fail to get a lock; we force it instead.
  62. Timeout acquire_lock_timeout;
  63. acquire_lock_timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2);
  64. while (!tool::getLock()) {
  65. if (acquire_lock_timeout.hasElapsed()) {
  66. locked = true; // grant ourselves the lock
  67. transaction_active = false; // abort transaction!
  68. Motherboard::getBoard().indicateError(ERR_SLAVE_LOCK_TIMEOUT);
  69. break;
  70. }
  71. }
  72. OutPacket& out = getOutPacket();
  73. InPacket& in = getInPacket();
  74. out.reset();
  75. out.append8(0); // Index o
  76. out.append8(SLAVE_CMD_VERSION);
  77. out.append8(0); // Technically, we should report our version here, however
  78. out.append8(0); // it doesn't actually matter.
  79. startTransaction();
  80. // override standard timeout
  81. timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2);
  82. releaseLock();
  83. // WHILE: bounded by tool timeout
  84. while (!isTransactionDone()) {
  85. runToolSlice(); // This will most likely time out if there's multiple toolheads.
  86. }
  87. if (in.getErrorCode() == PacketError::PACKET_TIMEOUT) {
  88. return false;
  89. } else {
  90. // TODO: Should we actually read the tool version?
  91. // in.read8(1-2);
  92. }
  93. // Check that the extruder was able to process the request
  94. if (in.read8(0) != 1) {
  95. return false;
  96. }
  97. return true;
  98. }
  99. void setToolIndicatorLED() {
  100. // This code is very lightly modified from handleToolQuery in Host.cc.
  101. // We don't give up if we fail to get a lock; we force it instead.
  102. Timeout acquire_lock_timeout;
  103. acquire_lock_timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2);
  104. while (!tool::getLock()) {
  105. if (acquire_lock_timeout.hasElapsed()) {
  106. locked = true; // grant ourselves the lock
  107. transaction_active = false; // abort transaction!
  108. Motherboard::getBoard().indicateError(ERR_SLAVE_LOCK_TIMEOUT);
  109. break;
  110. }
  111. }
  112. OutPacket& out = getOutPacket();
  113. InPacket& in = getInPacket();
  114. out.reset();
  115. out.append8(0);
  116. out.append8(SLAVE_CMD_LIGHT_INDICATOR_LED);
  117. startTransaction();
  118. // override standard timeout
  119. timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2);
  120. releaseLock();
  121. // WHILE: bounded by tool timeout
  122. while (!isTransactionDone()) {
  123. runToolSlice(); // This will most likely time out if there's multiple toolheads.
  124. }
  125. }
  126. bool reset() {
  127. // This code is very lightly modified from handleToolQuery in Host.cc.
  128. // We don't give up if we fail to get a lock; we force it instead.
  129. Timeout acquire_lock_timeout;
  130. acquire_lock_timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2);
  131. while (!tool::getLock()) {
  132. if (acquire_lock_timeout.hasElapsed()) {
  133. locked = true; // grant ourselves the lock
  134. transaction_active = false; // abort transaction!
  135. Motherboard::getBoard().indicateError(ERR_SLAVE_LOCK_TIMEOUT);
  136. break;
  137. }
  138. }
  139. OutPacket& out = getOutPacket();
  140. InPacket& in = getInPacket();
  141. out.reset();
  142. out.append8(SLAVE_ID_BROADCAST); // Reset all tools
  143. out.append8(SLAVE_CMD_INIT);
  144. startTransaction();
  145. // override standard timeout
  146. timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2);
  147. releaseLock();
  148. // WHILE: bounded by tool timeout
  149. while (!isTransactionDone()) {
  150. runToolSlice(); // This will most likely time out if there's multiple toolheads.
  151. }
  152. return UART::getSlaveUART().in.isFinished();
  153. }
  154. bool test() {
  155. // Reset packet statistics
  156. sent_packet_count = 0;
  157. packet_failure_count = 0;
  158. packet_retry_count = 0;
  159. noise_byte_count = 0;
  160. // Now, test comms by pinging a extruder controller relentlessly.
  161. // TODO: handle cases where a toolhead is not attached?
  162. uint8_t i = 0;
  163. bool result = true;
  164. while (i < 128 && result) {
  165. result = getToolVersion();
  166. i++;
  167. }
  168. bool rv = (packet_retry_count <= 0);
  169. if (rv) {
  170. setToolIndicatorLED();
  171. }
  172. return rv;
  173. }
  174. /// The tool is considered locked if a transaction is in progress or
  175. /// if the lock was never released.
  176. bool getLock() {
  177. if (transaction_active || locked)
  178. return false;
  179. locked = true;
  180. return true;
  181. }
  182. void releaseLock() {
  183. locked = false;
  184. }
  185. void startTransaction() {
  186. sent_packet_count++;
  187. // Enforce a minimum off-time between transactions
  188. // TODO: Base this on the time from the last transaction.
  189. Timeout t;
  190. t.start(DELAY_BETWEEN_TRANSMISSIONS_MICROS); // wait for xxx us
  191. while (!t.hasElapsed());
  192. transaction_active = true;
  193. timeout.start(TOOL_PACKET_TIMEOUT_MICROS); // 50 ms timeout
  194. retries = RETRIES;
  195. UART::getSlaveUART().in.reset();
  196. UART::getSlaveUART().beginSend();
  197. }
  198. bool isTransactionDone() {
  199. return !transaction_active;
  200. }
  201. void runToolSlice() {
  202. UART& uart = UART::getSlaveUART();
  203. if (transaction_active) {
  204. if (uart.in.isFinished())
  205. {
  206. transaction_active = false;
  207. } else if (uart.in.hasError()) {
  208. if (uart.in.getErrorCode() == PacketError::NOISE_BYTE) {
  209. noise_byte_count++;
  210. uart.in.reset();
  211. } else
  212. if (retries) {
  213. packet_retry_count++;
  214. retries--;
  215. timeout.start(TOOL_PACKET_TIMEOUT_MICROS); // 50 ms timeout
  216. uart.out.prepareForResend();
  217. uart.in.reset();
  218. uart.reset();
  219. uart.beginSend();
  220. } else {
  221. packet_failure_count++;
  222. transaction_active = false;
  223. Motherboard::getBoard().indicateError(ERR_SLAVE_PACKET_MISC);
  224. }
  225. } else if (timeout.hasElapsed()) {
  226. if (retries) {
  227. packet_retry_count++;
  228. retries--;
  229. timeout.start(TOOL_PACKET_TIMEOUT_MICROS); // 50 ms timeout
  230. uart.out.prepareForResend();
  231. uart.in.reset();
  232. uart.reset();
  233. uart.beginSend();
  234. } else {
  235. packet_failure_count++;
  236. uart.in.timeout();
  237. uart.reset();
  238. transaction_active = false;
  239. Motherboard::getBoard().indicateError(ERR_SLAVE_PACKET_TIMEOUT);
  240. }
  241. }
  242. }
  243. }
  244. void setCurrentToolheadIndex(uint8_t tool_index_in) {
  245. tool_index = tool_index_in;
  246. }
  247. uint8_t getCurrentToolheadIndex() {
  248. return tool_index;
  249. }
  250. }