PageRenderTime 46ms CodeModel.GetById 13ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 0ms

/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
 18#include "Tool.hh"
 19#include "Timeout.hh"
 20#include "Errors.hh"
 21#include "Motherboard.hh"
 22#include "Commands.hh"
 23
 24#define RETRIES 5
 25
 26#define TOOL_PACKET_TIMEOUT_MS 50L
 27#define TOOL_PACKET_TIMEOUT_MICROS (1000L*TOOL_PACKET_TIMEOUT_MS)
 28
 29#define DELAY_BETWEEN_TRANSMISSIONS_MICROS (500L)
 30
 31namespace tool {
 32
 33// TODO: Don't bother initializing these here.
 34bool transaction_active = false;        ///< True if a transaction is in progress
 35bool locked = false;                    ///< True if the tool is in use
 36uint8_t retries = RETRIES;              ///< Rery count for current operation
 37
 38Timeout timeout;                        ///< Tool resposnse timeout counter
 39
 40uint8_t tool_index = 0;
 41
 42uint32_t sent_packet_count;
 43uint32_t packet_failure_count;
 44uint32_t packet_retry_count;
 45uint32_t noise_byte_count;
 46
 47InPacket& getInPacket() {
 48        return UART::getSlaveUART().in;
 49}
 50
 51OutPacket& getOutPacket() {
 52        return UART::getSlaveUART().out;
 53}
 54
 55
 56// Get the total number of packets that were attempted to be sent to a tool
 57uint32_t getSentPacketCount() {
 58    return sent_packet_count;
 59}
 60
 61// Get the total number of packets that failed to get a response from a tool
 62uint32_t getPacketFailureCount() {
 63    return packet_failure_count;
 64}
 65
 66// Get the total packet retries attempted
 67uint32_t getRetryCount() {
 68    return packet_retry_count;
 69}
 70
 71// Get the total number of received bytes that were discarded as noise
 72uint32_t getNoiseByteCount() {
 73    return noise_byte_count;
 74}
 75
 76
 77bool getToolVersion() {
 78    // This code is very lightly modified from handleToolQuery in Host.cc.
 79    // We don't give up if we fail to get a lock; we force it instead.
 80    Timeout acquire_lock_timeout;
 81    acquire_lock_timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2);
 82    while (!tool::getLock()) {
 83            if (acquire_lock_timeout.hasElapsed()) {
 84                    locked = true; // grant ourselves the lock
 85                    transaction_active = false; // abort transaction!
 86                    Motherboard::getBoard().indicateError(ERR_SLAVE_LOCK_TIMEOUT);
 87                    break;
 88            }
 89    }
 90
 91    OutPacket& out = getOutPacket();
 92    InPacket& in = getInPacket();
 93
 94    out.reset();
 95    out.append8(0); // Index o
 96    out.append8(SLAVE_CMD_VERSION);
 97    out.append8(0);  // Technically, we should report our version here, however
 98    out.append8(0);  // it doesn't actually matter.
 99
100    startTransaction();
101    // override standard timeout
102    timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2);
103    releaseLock();
104    // WHILE: bounded by tool timeout
105    while (!isTransactionDone()) {
106            runToolSlice(); // This will most likely time out if there's multiple toolheads.
107    }
108
109    if (in.getErrorCode() == PacketError::PACKET_TIMEOUT) {
110            return false;
111    } else {
112            // TODO: Should we actually read the tool version?
113//            in.read8(1-2);
114    }
115
116    // Check that the extruder was able to process the request
117    if (in.read8(0) != 1) {
118            return false;
119    }
120
121    return true;
122}
123
124void setToolIndicatorLED() {
125    // This code is very lightly modified from handleToolQuery in Host.cc.
126    // We don't give up if we fail to get a lock; we force it instead.
127    Timeout acquire_lock_timeout;
128    acquire_lock_timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2);
129    while (!tool::getLock()) {
130            if (acquire_lock_timeout.hasElapsed()) {
131                    locked = true; // grant ourselves the lock
132                    transaction_active = false; // abort transaction!
133                    Motherboard::getBoard().indicateError(ERR_SLAVE_LOCK_TIMEOUT);
134                    break;
135            }
136    }
137    OutPacket& out = getOutPacket();
138    InPacket& in = getInPacket();
139    out.reset();
140    out.append8(0);
141    out.append8(SLAVE_CMD_LIGHT_INDICATOR_LED);
142    startTransaction();
143    // override standard timeout
144    timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2);
145    releaseLock();
146    // WHILE: bounded by tool timeout
147    while (!isTransactionDone()) {
148            runToolSlice(); // This will most likely time out if there's multiple toolheads.
149    }
150}
151
152bool reset() {
153	// This code is very lightly modified from handleToolQuery in Host.cc.
154	// We don't give up if we fail to get a lock; we force it instead.
155	Timeout acquire_lock_timeout;
156	acquire_lock_timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2);
157	while (!tool::getLock()) {
158		if (acquire_lock_timeout.hasElapsed()) {
159			locked = true; // grant ourselves the lock
160			transaction_active = false; // abort transaction!
161                        Motherboard::getBoard().indicateError(ERR_SLAVE_LOCK_TIMEOUT);
162			break;
163		}
164	}
165	OutPacket& out = getOutPacket();
166	InPacket& in = getInPacket();
167	out.reset();
168	out.append8(SLAVE_ID_BROADCAST); // Reset all tools
169	out.append8(SLAVE_CMD_INIT);
170	startTransaction();
171	// override standard timeout
172	timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2);
173	releaseLock();
174	// WHILE: bounded by tool timeout
175	while (!isTransactionDone()) {
176		runToolSlice(); // This will most likely time out if there's multiple toolheads.
177	}
178	return UART::getSlaveUART().in.isFinished();
179}
180
181
182bool test() {
183	// Reset packet statistics
184	sent_packet_count = 0;
185	packet_failure_count = 0;
186	packet_retry_count = 0;
187	noise_byte_count = 0;
188
189	// Now, test comms by pinging a extruder controller relentlessly.
190	// TODO: handle cases where a toolhead is not attached?
191	uint8_t i = 0;
192	bool result = true;
193	while (i < 128 && result) {
194
195		result = getToolVersion();
196		i++;
197	}
198	bool rv = (packet_retry_count <= 0);
199	if (rv) {
200		setToolIndicatorLED();
201	}
202	return rv;
203}
204
205/// The tool is considered locked if a transaction is in progress or
206/// if the lock was never released.
207bool getLock() {
208	if (transaction_active || locked)
209		return false;
210	locked = true;
211	return true;
212}
213
214void releaseLock() {
215	locked = false;
216}
217
218void startTransaction() {
219        sent_packet_count++;
220
221        // Enforce a minimum off-time between transactions
222        // TODO: Base this on the time from the last transaction.
223        Timeout t;
224        t.start(DELAY_BETWEEN_TRANSMISSIONS_MICROS); // wait for xxx us
225        while (!t.hasElapsed());
226
227	transaction_active = true;
228	timeout.start(TOOL_PACKET_TIMEOUT_MICROS); // 50 ms timeout
229	retries = RETRIES;
230        UART::getSlaveUART().in.reset();
231        UART::getSlaveUART().beginSend();
232}
233
234bool isTransactionDone() {
235	return !transaction_active;
236}
237
238void runToolSlice() {
239        UART& uart = UART::getSlaveUART();
240	if (transaction_active) {
241		if (uart.in.isFinished())
242		{
243			transaction_active = false;
244		} else if (uart.in.hasError()) {
245		  if (uart.in.getErrorCode() == PacketError::NOISE_BYTE) {
246                    noise_byte_count++;
247		    uart.in.reset();
248		  } else
249			if (retries) {
250                                packet_retry_count++;
251				retries--;
252				timeout.start(TOOL_PACKET_TIMEOUT_MICROS); // 50 ms timeout
253				uart.out.prepareForResend();
254				uart.in.reset();
255				uart.reset();
256				uart.beginSend();
257			} else {
258                                packet_failure_count++;
259				transaction_active = false;
260                                Motherboard::getBoard().indicateError(ERR_SLAVE_PACKET_MISC);
261			}
262		} else if (timeout.hasElapsed()) {
263			if (retries) {
264                                packet_retry_count++;
265				retries--;
266				timeout.start(TOOL_PACKET_TIMEOUT_MICROS); // 50 ms timeout
267				uart.out.prepareForResend();
268				uart.in.reset();
269				uart.reset();
270				uart.beginSend();
271			} else {
272                                packet_failure_count++;
273				uart.in.timeout();
274				uart.reset();
275				transaction_active = false;
276                                Motherboard::getBoard().indicateError(ERR_SLAVE_PACKET_TIMEOUT);
277			}
278		}
279	}
280}
281
282void setCurrentToolheadIndex(uint8_t tool_index_in) {
283    tool_index = tool_index_in;
284}
285
286uint8_t getCurrentToolheadIndex() {
287    return tool_index;
288}
289
290}
291