25 #include "GrblSim.hpp"
32 #include <ccut/Regex.hpp>
34 #include <logger/Logger.hpp>
43 #include "Exception.hpp"
44 #include "local-config.h"
46 using namespace logger;
47 using namespace std::chrono;
51 #define GRBL_GPIOD_EXE_DEV (BUILDDIR "/instroot/bin/grbl-gpiod")
52 #define GRBL_GPIOD_EXENAME "grbl-gpiod"
54 static const std::string s_loggerCat{
"smc:grbldevice:sim"};
55 const milliseconds GrblSim::defaultExpectTimeout(500);
56 static const ccut::Regex s_grblInit(
"^GrblHAL.*$");
58 static const char *getExe()
60 if (::access(GRBL_GPIOD_EXE, X_OK) == 0)
61 return GRBL_GPIOD_EXE;
62 else if (::access(GRBL_GPIOD_EXE_DEV, X_OK) == 0)
63 return GRBL_GPIOD_EXE_DEV;
77 posix_spawn_file_actions_t fileActions;
78 posix_spawn_file_actions_init(&fileActions);
79 posix_spawn_file_actions_addclose(&fileActions, pa2s[1]);
80 posix_spawn_file_actions_adddup2(&fileActions, pa2s[0], STDIN_FILENO);
81 posix_spawn_file_actions_addclose(&fileActions, pa2s[0]);
82 posix_spawn_file_actions_addclose(&fileActions, ps2a[0]);
83 posix_spawn_file_actions_adddup2(&fileActions, ps2a[1], STDOUT_FILENO);
84 posix_spawn_file_actions_addclose(&fileActions, ps2a[1]);
86 char *args[] = {
const_cast<char *
>(getExe()), (
char *) NULL};
87 debug(s_loggerCat) <<
"starting " << args[0];
88 int err = posix_spawnp(&m_simPid, args[0], &fileActions, NULL, args, NULL);
92 crit(s_loggerCat) <<
"failed to spawn " << args[0];
95 posix_spawn_file_actions_destroy(&fileActions);
103 ::fcntl(m_wakeFd[0], F_SETFL, ::fcntl(m_wakeFd[0], F_GETFL, 0) | O_NONBLOCK);
104 ::fcntl(m_wakeFd[1], F_SETFL, ::fcntl(m_wakeFd[1], F_GETFL, 0) | O_NONBLOCK);
105 ::fcntl(m_out, F_SETFL, ::fcntl(m_out, F_GETFL, 0) | O_NONBLOCK);
106 ::fcntl(m_in, F_SETFL, ::fcntl(m_in, F_GETFL, 0) | O_NONBLOCK);
110 [](
const std::string &msg) {
111 notice(s_loggerCat) <<
"<--(init) " << msg;
112 if (s_grblInit.search(msg))
113 throw grbl::ErrorCode{0};
116 std::chrono::milliseconds{3000}) != grbl::ErrorCode{0})
118 error(s_loggerCat) <<
"Grbl welcome banner not found";
120 std::string{
"Failed to get Grbl banner"}};
127 char stopChar = 0x06;
128 ::write(m_out, &stopChar, 1);
131 ::close(m_wakeFd[0]);
132 ::close(m_wakeFd[1]);
135 std::this_thread::sleep_for(std::chrono::milliseconds(100));
136 if (::waitpid(m_simPid, &status, WNOHANG) == -1)
138 ::kill(m_simPid, SIGKILL);
139 ::waitpid(m_simPid, &status, 0);
143 void GrblSim::flush()
150 if (!m_buffer.remaining())
152 error(s_loggerCat) <<
"flushing buffer";
156 ssize_t sz = ::read(m_in, m_buffer.end(), m_buffer.remaining());
164 void GrblSim::write(
const std::string &raw)
166 for (
size_t pos = 0; pos < raw.size();)
168 ssize_t ret = ::write(m_out, raw.c_str() + pos, raw.size() - pos);
172 <<
"failed to send command : " << strerror(errno);
176 if (pos != raw.size())
177 std::this_thread::sleep_for(std::chrono::milliseconds(10));
181 bool GrblSim::wait(
const std::chrono::milliseconds &timeout)
183 struct pollfd pfds[2] = {{m_in, POLLIN | POLLERR, 0},
184 {m_wakeFd[0], POLLIN | POLLERR, 0}};
185 if (::poll(pfds, 2, timeout.count() + 1) >= 0)
187 if (pfds[1].revents & POLLIN)
189 std::vector<char> buffer(10);
190 ::read(m_wakeFd[0], buffer.data(), buffer.size());
192 if (pfds[0].revents & POLLERR || pfds[1].revents & POLLERR)
193 throw smc::make_errno_exception(smc::ErrorCode::IO);
195 return (pfds[0].revents & POLLIN);
198 throw smc::make_errno_exception(smc::ErrorCode::IO);
204 ::write(m_wakeFd[1],
"X", 1);
Exception thrown by MotionController in case of issues with command.