Welcome to mirror list, hosted at ThFree Co, Russian Federation.

GCodeQueue.cpp « GCodes « src - github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 0e701acf63e3f87beb938ff4e550310e14fe3c91 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*
 * GCodeQueue.cpp
 *
 *  Created on: 22 Jun 2016
 *      Author: Christian
 */

#include "GCodeQueue.h"

#include "RepRap.h"
#include "GCodes.h"
#include "Movement/Move.h"

// GCodeQueue class

GCodeQueue::GCodeQueue() : freeItems(nullptr), queuedItems(nullptr)
{
	for (size_t i = 0; i < maxQueuedCodes; i++)
	{
		freeItems = new QueuedCode(freeItems);
	}
}

// If moves are scheduled and the command in the passed GCodeBuffer can be queued, try to queue it.
// If successful, return true to indicate it has been queued and the caller should not execute it.
// If it is not a command that should be queued, return false.
// If the queue is full, free up the oldest queued entry by copying its command to our own gcode buffer
// so that we have room to queue the original command.
bool GCodeQueue::QueueCode(GCodeBuffer &gb, uint32_t segmentsLeft)
{
	// Don't queue anything if no moves are being performed
	const uint32_t scheduledMoves = reprap.GetMove().GetScheduledMoves() + segmentsLeft;
	if (scheduledMoves == reprap.GetMove().GetCompletedMoves())
	{
		return false;
	}

#if SUPPORT_ROLAND
	// Don't queue codes if the Roland module is active
	if (reprap.GetRoland()->Active())
	{
		return false;
	}
#endif

	// Check for G-Codes that can be queued
	bool queueCode = false;
	switch (gb.GetCommandLetter())
	{
	case 'G':
		{
			const int code = gb.GetCommandNumber();
			queueCode = (code == 10 && gb.Seen('P'));	// Set active/standby temperatures

		}
		break;

	case 'M':
		{
			switch (gb.GetCommandNumber())
			{
			case 3:		// spindle control
			case 4:		// spindle control
			case 5:		// spindle control
			case 42:	// set IO pin
			case 106:	// fan control
			case 107:	// fan off
			case 104:	// set temperatures and return immediately
			case 140:	// set bed temperature and return immediately
			case 141:	// set chamber temperature and return immediately
			case 144:	// bed standby
			case 117:	// display message
			case 280:	// set servo
			case 300:	// beep
			case 420:	// set RGB colour
				queueCode = true;
				break;

			default:
				break;
			}
		}
		break;

	default:
		break;
	}

	// Does it make sense to queue this code?
	if (queueCode)
	{
		char codeToRun[GCODE_LENGTH];
		size_t codeToRunLength;

		// Can we queue this code somewhere?
		if (freeItems == nullptr)
		{
			// No - we've run out of free items. Run the first outstanding code
			queueCode = false;
			codeToRunLength = strlen(queuedItems->code) + 1;
			SafeStrncpy(codeToRun, queuedItems->code, ARRAY_SIZE(codeToRun));

			// Release the first queued item so that it can be reused later
			QueuedCode * const item = queuedItems;
			queuedItems = item->next;
			item->next = nullptr;
			freeItems = item;
		}

		// Unlink a free element and assign gb's code to it
		QueuedCode * const code = freeItems;
		freeItems = code->next;
		code->AssignFrom(gb);
		code->executeAtMove = scheduledMoves;
		code->next = nullptr;

		// Append it to the list of queued codes
		if (queuedItems == nullptr)
		{
			queuedItems = code;
		}
		else
		{
			QueuedCode *last = queuedItems;
			while (last->Next() != nullptr)
			{
				last = last->Next();
			}
			last->next = code;
		}

		// Overwrite the passed gb's content if we could not store its original code
		if (!queueCode)
		{
			if (reprap.Debug(moduleGcodes))
			{
				reprap.GetPlatform().Message(DebugMessage, "(swap) ");
			}
			if (!gb.Put(codeToRun, codeToRunLength))
			{
				gb.Put('\n');
			}
		}
	}

	return queueCode;
}

bool GCodeQueue::FillBuffer(GCodeBuffer *gb)
{
	// Can this buffer be filled?
	if (queuedItems == nullptr || queuedItems->executeAtMove > reprap.GetMove().GetCompletedMoves())
	{
		// No - stop here
		return false;
	}

	// Yes - load it into the passed GCodeBuffer instance
	QueuedCode *code = queuedItems;
	code->AssignTo(gb);

	// Release this item again
	queuedItems = queuedItems->next;
	code->next = freeItems;
	freeItems = code;
	return true;
}

// Return true if there is nothing to do
bool GCodeQueue::IsIdle() const
{
	return queuedItems == nullptr || queuedItems->executeAtMove > reprap.GetMove().GetCompletedMoves();
}

// Because some moves may end before the print is actually paused, we need a method to
// remove all the entries that will not be executed after the print has finally paused
void GCodeQueue::PurgeEntries()
{
	QueuedCode *item = queuedItems, *lastItem = nullptr;
	while (item != nullptr)
	{
		if (item->executeAtMove > reprap.GetMove().GetScheduledMoves())
		{
			// Release this item
			QueuedCode *nextItem = item->Next();
			item->next = freeItems;
			freeItems = item;

			// Unlink it from the list
			if (lastItem == nullptr)
			{
				queuedItems = nextItem;
			}
			else
			{
				lastItem->next = nextItem;
			}
			item = nextItem;
		}
		else
		{
			lastItem = item;
			item = item->Next();
		}
	}
}

void GCodeQueue::Clear()
{
	while (queuedItems != nullptr)
	{
		QueuedCode * const item = queuedItems;
		queuedItems = item->Next();
		item->next = freeItems;
		freeItems = item;
	}
}

void GCodeQueue::Diagnostics(MessageType mtype)
{
	reprap.GetPlatform().MessageF(mtype, "Code queue is %s\n", (queuedItems == nullptr) ? "empty." : "not empty:");
	if (queuedItems != nullptr)
	{
		const QueuedCode *item = queuedItems;
		size_t queueLength = 0;
		do
		{
			queueLength++;
			reprap.GetPlatform().MessageF(mtype, "Queued '%s' for move %" PRIu32 "\n", item->code, item->executeAtMove);
		} while ((item = item->Next()) != nullptr);
		reprap.GetPlatform().MessageF(mtype, "%d of %d codes have been queued.\n", queueLength, maxQueuedCodes);
	}
}

// QueuedCode class

void QueuedCode::AssignFrom(GCodeBuffer &gb)
{
	toolNumberAdjust = gb.GetToolNumberAdjust();
	SafeStrncpy(code, gb.Buffer(), ARRAY_SIZE(code));
}

void QueuedCode::AssignTo(GCodeBuffer *gb)
{
	gb->SetToolNumberAdjust(toolNumberAdjust);
	if (!gb->Put(code, strlen(code) + 1))
	{
		gb->Put('\n');
	}
}

// End