25 #include "GrblParser.hpp"
33 #include <ccut/Regex.hpp>
34 #include <ccut/utils.hpp>
35 #include <logger/Logger.hpp>
37 #include "Exception.hpp"
41 static const std::string s_loggerCat{
"grbl:parser"};
42 static const Regex s_settingRegex{
"^\\$([0-9]{1,3})=([^\r\n]*)"};
43 static const Regex s_messageRegex{
"^\\[([^:]*):(.*)\\]"};
44 static const Regex s_errorResponse(
"^error:([0-9]*)\\s*$");
47 using namespace logger;
51 LineType GrblParser::getLineType(
const std::string &line)
55 return LineType::Unknown;
59 case '<':
return LineType::State;
60 case '$':
return LineType::Setting;
61 case '[':
return LineType::Message;
63 if (line.compare(0, 2,
"ok") == 0)
65 return LineType::OkReply;
67 else if (line.compare(0, 6,
"error:") == 0)
69 return LineType::ErrorReply;
71 return LineType::Unknown;
75 bool GrblParser::parseMessage(
const std::string &line, Message &message)
77 std::vector<std::string> matches;
79 if (!s_messageRegex.match(line, matches))
81 info(s_loggerCat) <<
"Not a message: " << line;
85 message = std::make_pair(matches[1], matches[2]);
89 bool GrblParser::parseSetting(
const std::string &line, Setting &setting)
91 std::vector<std::string> matches;
93 if (!s_settingRegex.match(line, matches))
95 info(s_loggerCat) <<
"Not a setting: " << line;
99 setting = std::make_pair(std::atoi(matches[1].c_str()), matches[2]);
103 bool GrblParser::parseErrorReply(
const std::string &line,
104 grbl::ErrorCode &errorCode)
106 std::string::size_type idx = line.find(
':');
107 if (idx == std::string::npos)
109 info(s_loggerCat) <<
"Not a valid error: " << line;
113 errorCode = std::atoi(&line[idx + 1]);
117 bool GrblParser::parseState(
const std::string &line,
State &state)
119 std::string::size_type end = line.rfind(
'>');
120 if (line.size() <= 2 || line[0] !=
'<' || end == std::string::npos)
122 info(s_loggerCat) <<
"Not a state: " << line;
126 std::vector<std::string> split;
128 ccut::split(line.cbegin() + 1, line.cbegin() + end,
'|', split);
130 if (split.size() == 0)
132 error(s_loggerCat) <<
"split failed";
138 std::string::size_type sz = split[0].find(
':');
139 if (sz != std::string::npos)
141 const std::string &part = split[0];
142 state.runState = from_string<RunState>(part.substr(0, sz));
144 state.runStateArg = std::strtoul(&part[sz + 1], &strtoulend, 10);
145 if (strtoulend != part.data() + part.length())
147 error(s_loggerCat) <<
"invalid runStateArg: " << part;
152 state.runState = from_string<RunState>(split[0]);
154 if (state.runState == RunState::Unknown)
156 error(s_loggerCat) <<
"invalid RunState: " << split[0];
160 for (
size_t i = 1; i < split.size(); ++i)
162 const std::string &part = split[i];
163 if (ccut::startsWith(part,
"MPos:") ||
164 ccut::startsWith(part,
"WPos:"))
167 std::vector<std::string> positions;
168 positions.reserve(6);
169 ccut::split(part.cbegin() + 5, part.cend(),
',', positions);
170 for (
const std::string &pos : positions)
172 state.motorPositions[axis] = std::stof(pos);
173 axis =
static_cast<Axis
>(
static_cast<int>(axis) + 1);
176 else if (ccut::startsWith(part,
"Bf:"))
178 std::vector<std::string> available;
179 available.reserve(2);
180 ccut::split(part.cbegin() + 3, part.cend(),
',', available);
181 if (available.size() != 2)
183 error(s_loggerCat) <<
"invalid buffer size: " << part;
186 state.motionBufferFree = std::stoul(available[0]);
187 state.charBufferFree = std::stoul(available[1]);
189 else if (ccut::startsWith(part,
"Ln:"))
192 state.line = std::strtoul(&part[3], &strtoulend, 10);
193 if (strtoulend != part.data() + part.length())
195 error(s_loggerCat) <<
"invalid line: " << part;
201 catch (
const std::exception &ex)
203 error(s_loggerCat) <<
"exception parsing state: " << ex.what();
209 bool GrblParser::parseBuildInfo(
const std::string &line,
212 if (getLineType(line) != LineType::Message)
217 grbl::GrblParser::Message msg;
220 if (msg.first ==
"OPT")
222 std::vector<std::string> vec;
224 ccut::split(msg.second,
',', vec);
227 error(s_loggerCat) <<
"invalid OPT in BuildInfo: " << line;
230 buildInfo.options = vec[0];
231 buildInfo.motionBufferSize = std::stoul(vec[1]);
232 buildInfo.charBufferSize = std::stoul(vec[2]);
233 buildInfo.axisCount = std::stoul(vec[3]);
234 buildInfo.toolsCount = std::stoul(vec[4]);
237 else if (msg.first ==
"VER")
238 buildInfo.version = msg.second;
239 else if (msg.first ==
"FIRMWARE")
240 buildInfo.firmware = msg.second;
241 else if (msg.first ==
"DRIVER")
242 buildInfo.driver = msg.second;
243 else if (msg.first ==
"DRIVER VERSION")
244 buildInfo.driverVersion = msg.second;
247 info(s_loggerCat) <<
"Not a build info: " << line;
254 catch (
const std::exception &ex)
256 error(s_loggerCat) <<
"exception parsing buildInfo: " << ex.what();
261 bool GrblParser::parseSettingGroup(
const std::string &line,
SettingGroup &group)
263 if (getLineType(line) != LineType::Message)
268 grbl::GrblParser::Message msg;
270 (msg.first !=
"SETTINGGROUP"))
273 std::vector<std::string> vec;
275 ccut::split(msg.second,
'|', vec);
279 error(s_loggerCat) <<
"invalid SETTINGGROUP: " << line;
282 group.id = std::stoul(vec[0]);
283 group.parentId = std::stoul(vec[1]);
288 catch (
const std::exception &ex)
290 error(s_loggerCat) <<
"exception parsing SettingGroup" << ex.what();
295 bool GrblParser::parseSettingDesc(
const std::string &line,
SettingDesc &desc)
297 if (getLineType(line) != LineType::Message)
302 grbl::GrblParser::Message msg;
304 (msg.first !=
"SETTING"))
307 std::vector<std::string> vec;
309 ccut::split(msg.second,
'|', vec);
313 error(s_loggerCat) <<
"invalid SETTING: " << line;
316 desc.id = std::stoul(vec[0]);
317 desc.groupId = std::stoul(vec[1]);
320 desc.datatype = std::stoul(vec[4]);
321 desc.format = vec[5];
323 desc.min = vec[6].empty() ? NAN : std::stof(vec[6]);
324 desc.max = vec[7].empty() ? NAN : std::stof(vec[7]);
328 catch (
const std::exception &ex)
330 error(s_loggerCat) <<
"exception parsing SettingDesc: " << ex.what();
335 bool GrblParser::parsePinInfo(
const std::string &line,
PinInfo &info)
337 if (getLineType(line) != LineType::Message)
342 grbl::GrblParser::Message msg;
346 std::vector<std::string> vec;
348 ccut::split(msg.second,
',', vec);
352 error(s_loggerCat) <<
"invalid PinInfo (size): " << line;
356 std::string::const_iterator it = std::find_if(vec[0].cbegin(),
357 vec[0].cend(), isdigit);
358 if (it == vec[0].cbegin())
360 info.pin = std::stoul(vec[0]);
361 info.port = std::string();
363 else if (it != vec[0].cend())
365 info.port = std::string(vec[0].cbegin(), it);
366 info.pin = std::stoul(std::string(it, vec[0].cend()));
370 error(s_loggerCat) <<
"invalid PinInfo (pin number): " << line;
373 info.function = vec[1];
374 info.description = (vec.size() > 2) ? vec[2] : std::string();
378 catch (
const std::exception &ex)
380 error(s_loggerCat) <<
"exception parsing PinInfo: " << ex.what();
static bool parseMessage(const std::string &line, Message &message)
parse message
main motion-lib namespace
structure holding Grbl build-info ($I)
structure holding Grbl pin description ($PINS)
structure holding Grbl setting description ($ES)
structure holding Grbl settingroup info ($EG)
Struct holding state of Grbl as returned by "?".