-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgcodestreamer.cpp
248 lines (193 loc) · 6.79 KB
/
gcodestreamer.cpp
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
#include "gcodestreamer.h"
#include "grbldefinitions.h"
#include <QFile>
#include <QFileInfo>
#define MAX_LINE_LENGTH 256 //Defined by gcode standard
#define DEFAULT_FIFO_DEPTH 1000
const char *GCodeStreamer::s_gcodeCommentsDelimiters[] = {GCODE_COMMENTS_DELIM};
GCodeStreamer::GCodeStreamer(QObject *parent) :
QObject(parent),
m_run(false)
{
clear();
}
GCodeStreamer::states GCodeStreamer::getState(void){
if(!m_usefulLinesVector.isEmpty()){
if(m_run){
return state_running;
}
else{
return state_ready;
}
}
else{
return state_clear;
}
}
void GCodeStreamer::loadFile(const QString &path){
clear();
QFile file(path);
if (file.open(QIODevice::ReadOnly))
{
//file.reset();
//Store file in linevector
while(!file.atEnd()){
//Get line
QByteArray gcodeLine = file.readLine(MAX_LINE_LENGTH);
cleanupLine(&gcodeLine);
m_lineCount++;
//No need to process a useless line
if(gcodeLine.isEmpty()){
continue;
}
//Add it to line vector
GrblInstruction instruction(gcodeLine,m_lineCount);
m_usefulLinesVector.append(instruction);
emit instructionLoaded(instruction);
}
emit fileLoaded(QFileInfo(file).baseName());
}
emit lineCountUpdated(m_lineCount);
emit stateChanged(getState());
//Make the file ready to start from the beginning
//not necessary if file is not open
// rewind();
}
void GCodeStreamer::cleanupLine(QByteArray* code){
int commentDelimiterCount = sizeof(s_gcodeCommentsDelimiters)/sizeof(s_gcodeCommentsDelimiters[0]);
for(int i = 0 ; i < commentDelimiterCount ; i++){
int delimiterPosition = code->indexOf(s_gcodeCommentsDelimiters[i]); //Return start of comment or -1
if(delimiterPosition >= 0){
code->truncate(delimiterPosition); //Resize to start of comment. If -1, do nothing
}
}
//remove any start / and whitespace and special character
(*code) = code->trimmed();
}
void GCodeStreamer::clear(){
rewind();
m_lineCount = 0;
m_usefulLinesVector.clear();
emit lineCountUpdated(0);
emit stateChanged(state_clear);
emit cleared();
}
void GCodeStreamer::goToLine(int line){
if(m_usefulLinesVector.isEmpty()){
return;
}
int firstUsefulLineNumber = m_usefulLinesVector.first().getLineNumber();
int lastUsefulLineNumber = m_usefulLinesVector.last().getLineNumber();
int lastLineIndex = m_usefulLinesVector.size()-1;
//First line
if(line <= firstUsefulLineNumber){
m_lineToSendIndex = 0;
m_lastLineParsedByGrbl = 0;
}
else {
//Last Line
if(line >= lastUsefulLineNumber){
m_lineToSendIndex = lastLineIndex;
}
//Any other line, we need to iterate to find the correct line
else{
//Start from 'line' index, which is always greater than the correct index (due to useless lines not added to linevector)
//then iterate until we find the perfect line number, or a smaller one
m_lineToSendIndex = qMin(line,lastLineIndex-1);
while(m_lineToSendIndex > 0 && getCurrentLineNumber() >= line){
m_lineToSendIndex--;
}
//If we did not find the exact index (due to seeked line being useless, so not part of vector),
// Go to the next line
if(line > getCurrentLineNumber()){
m_lineToSendIndex++;
}
}
//Set previous instruction as parsed
m_lastLineParsedByGrbl = m_usefulLinesVector.at(m_lineToSendIndex-1).getLineNumber();
}
//Next instruction to be processed is the first on in buffer
emit currentLineUpdated(getCurrentLineNumber());
}
void GCodeStreamer::go(void){
if(!m_usefulLinesVector.isEmpty()){
m_run = true;
tryToSendNextInstruction();
emit stateChanged(state_running);
}
}
void GCodeStreamer::step(){
if(!m_usefulLinesVector.isEmpty()){
m_run = false;
tryToSendNextInstruction();
emit stateChanged(state_ready);
}
}
void GCodeStreamer::stop(){
m_run = false;
emit stateChanged(state_ready);
}
void GCodeStreamer::onGrblStatusUpdated(GrblStatus* const status){
int instructionsInPlanningBuffer = status->containsMotionsPlanned() ? status->getMotionsPlanned() : 0;
int executedLine = m_lastLineParsedByGrbl - instructionsInPlanningBuffer;
emit currentLineUpdated(executedLine);
//work should be complete when :
// - currently running
// - line count is not null
// - last line was executed
// - board is not in "run" state anymore
if(m_run && !m_usefulLinesVector.isEmpty() && executedLine == m_usefulLinesVector.last().getLineNumber() && status->getState() != GrblStatus::state_run){
m_run = false;
emit workCompleted();
emit stateChanged(state_ready);
}
}
void GCodeStreamer::onInstructionParsedByGrbl(const GrblInstruction &parsedInstruction){
int parsedLineNumber = parsedInstruction.getLineNumber();
if( parsedLineNumber >= 0){
m_lastLineParsedByGrbl = parsedLineNumber;
}
if(m_run){
tryToSendNextInstruction();
}
}
void GCodeStreamer::onInstructionSentToGrbl(const GrblInstruction &acceptedInstruction){
//If there is actually something to send
if(m_usefulLinesVector.isEmpty()){
return;
}
//If we already sent all useful lines, no need to continue
if(m_lineToSendIndex >= m_usefulLinesVector.size()){
return;
}
//This is not the instruction you're looking for
if(acceptedInstruction != m_usefulLinesVector.at(m_lineToSendIndex)){
return;
}
//Try to avoid an index out of range
int lastUsefulLineIndex = m_usefulLinesVector.size()-1;
if(m_lineToSendIndex > lastUsefulLineIndex){
return;
}
//Then we cant safely increment
m_lineToSendIndex++;
//Schedule sending next instruction
if(m_run){
QTimer::singleShot(0, this, &GCodeStreamer::tryToSendNextInstruction);
}
}
void GCodeStreamer::tryToSendNextInstruction(){
if(m_lineToSendIndex < m_usefulLinesVector.size() ){
m_usefulLinesVector[m_lineToSendIndex].regenerate();
emit instructionToSend(m_usefulLinesVector.at(m_lineToSendIndex));
}
}
int GCodeStreamer::getCurrentLineNumber(){
int currentLineNumber = 0;
if(!m_usefulLinesVector.isEmpty()){
//Since m_currentLinuxIndex can go 1 unit after last line, clamp it
int currentLineIndex = qMin(m_lineToSendIndex, m_usefulLinesVector.size()-1);
currentLineNumber = m_usefulLinesVector.at(currentLineIndex).getLineNumber();
}
return (currentLineNumber);
}