200 lines
5.3 KiB
C++
200 lines
5.3 KiB
C++
|
|
#include "telnet.h"
|
||
|
|
#include "../string_utils.h"
|
||
|
|
#include "grbl.h"
|
||
|
|
#include <sys/socket.h>
|
||
|
|
#include <arpa/inet.h>
|
||
|
|
#include <unistd.h>
|
||
|
|
#include <iostream>
|
||
|
|
#include <fcntl.h>
|
||
|
|
#include <chrono>
|
||
|
|
|
||
|
|
bool iosender::TelnetStream::IsOpen() {
|
||
|
|
return fd > 0 && isConnected;
|
||
|
|
}
|
||
|
|
|
||
|
|
int iosender::TelnetStream::OutCount() {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string iosender::TelnetStream::Reply() {
|
||
|
|
return reply;
|
||
|
|
}
|
||
|
|
|
||
|
|
iosender::Comms::StreamType iosender::TelnetStream::StreamType() {
|
||
|
|
return Comms::StreamType::Telnet;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool iosender::TelnetStream::EventMode() {
|
||
|
|
return eventMode;
|
||
|
|
}
|
||
|
|
|
||
|
|
void iosender::TelnetStream::EventMode(bool mode) {
|
||
|
|
eventMode = mode;
|
||
|
|
}
|
||
|
|
|
||
|
|
void iosender::TelnetStream::Close() {
|
||
|
|
shouldQuit = true;
|
||
|
|
workerThread.join();
|
||
|
|
}
|
||
|
|
|
||
|
|
int iosender::TelnetStream::ReadByte() {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void iosender::TelnetStream::WriteByte(uint8_t data) {
|
||
|
|
auto result = write(fd, &data, 1);
|
||
|
|
if (result == -1) {
|
||
|
|
std::cerr << "Failed while writing." << std::endl;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void iosender::TelnetStream::WriteBytes(uint8_t *bytes, int len) {
|
||
|
|
ssize_t written_bytes = 0;
|
||
|
|
for (; written_bytes < len;) {
|
||
|
|
auto result = write(fd, &bytes, len);
|
||
|
|
if (result == -1) {
|
||
|
|
std::cerr << "Failed while writing." << std::endl;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
written_bytes += result;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void iosender::TelnetStream::WriteString(std::string data) {
|
||
|
|
WriteBytes(reinterpret_cast<uint8_t *>(data.data()), data.size());
|
||
|
|
}
|
||
|
|
|
||
|
|
void iosender::TelnetStream::WriteCommand(std::string command) {
|
||
|
|
CommandState = Comms::State::AwaitAck;
|
||
|
|
|
||
|
|
if (command.size() == 1 && command != GrblConstants::CMD_PROGRAM_DEMARCATION) {
|
||
|
|
WriteByte(*command.data());
|
||
|
|
} else {
|
||
|
|
command += "\r";
|
||
|
|
WriteString(command);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string iosender::TelnetStream::GetReply(std::string command) {
|
||
|
|
reply = "";
|
||
|
|
AwaitResponse(command);
|
||
|
|
return reply;
|
||
|
|
}
|
||
|
|
|
||
|
|
void iosender::TelnetStream::AwaitAck() {
|
||
|
|
while (Comms::GetCom()->CommandState == Comms::State::DataReceived ||
|
||
|
|
Comms::GetCom()->CommandState == Comms::State::AwaitAck) {
|
||
|
|
std::this_thread::sleep_for(std::chrono::microseconds(500));
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void iosender::TelnetStream::AwaitAck(std::string command) {
|
||
|
|
WriteCommand(command);
|
||
|
|
AwaitAck();
|
||
|
|
}
|
||
|
|
|
||
|
|
void iosender::TelnetStream::AwaitResponse() {
|
||
|
|
while (Comms::GetCom()->CommandState == Comms::State::AwaitAck) {
|
||
|
|
std::this_thread::sleep_for(std::chrono::microseconds(500));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void iosender::TelnetStream::AwaitResponse(std::string command) {
|
||
|
|
WriteCommand(command);
|
||
|
|
AwaitResponse();
|
||
|
|
}
|
||
|
|
|
||
|
|
void iosender::TelnetStream::PurgeQueue() {
|
||
|
|
}
|
||
|
|
|
||
|
|
iosender::TelnetStream::TelnetStream(std::string host, iosender::DataReceivedHandler *dataHandler,
|
||
|
|
iosender::ByteReceivedHandler *byteHandler) {
|
||
|
|
Comms::SetCom(this);
|
||
|
|
reply = "";
|
||
|
|
dataReceivedHandler = dataHandler;
|
||
|
|
byteReceivedHandler = byteHandler;
|
||
|
|
|
||
|
|
if (!string_contains(host, ":")) {
|
||
|
|
host += ":23";
|
||
|
|
}
|
||
|
|
|
||
|
|
auto parameter = split_string(host, ":");
|
||
|
|
auto ip = parameter[0];
|
||
|
|
auto port = std::stoi(parameter[1]);
|
||
|
|
|
||
|
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||
|
|
if (fd == -1) {
|
||
|
|
std::cerr << "Error creating socket" << std::endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct sockaddr_in serv_addr{};
|
||
|
|
serv_addr.sin_family = AF_INET;
|
||
|
|
serv_addr.sin_port = htons(port);
|
||
|
|
|
||
|
|
if (inet_pton(AF_INET, ip.c_str(), &serv_addr.sin_addr) <= 0) {
|
||
|
|
std::cerr << "Invalid address/ Address not supported" << std::endl;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
auto status = connect(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
|
||
|
|
if (status < 0) {
|
||
|
|
std::cerr << "Connection failed";
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
isConnected = true;
|
||
|
|
|
||
|
|
// set non-blocking please, after we connected
|
||
|
|
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||
|
|
|
||
|
|
workerThread = std::thread(&iosender::TelnetStream::readWorker, this);
|
||
|
|
}
|
||
|
|
|
||
|
|
iosender::TelnetStream::~TelnetStream() {
|
||
|
|
Close();
|
||
|
|
}
|
||
|
|
|
||
|
|
void iosender::TelnetStream::readWorker() {
|
||
|
|
std::string received;
|
||
|
|
uint8_t buffer[200];
|
||
|
|
|
||
|
|
while (!shouldQuit) {
|
||
|
|
if (isConnected) {
|
||
|
|
|
||
|
|
// anything to read?
|
||
|
|
auto readBytes = read(fd, buffer, 200);
|
||
|
|
if (readBytes == -1 && (errno == EWOULDBLOCK || errno == EAGAIN)) {
|
||
|
|
// do nothing
|
||
|
|
} else if (readBytes == -1) {
|
||
|
|
std::cerr << "Failed while reading." << std::endl;
|
||
|
|
Close();
|
||
|
|
} else {
|
||
|
|
for (int i = 0; i < readBytes; i++) {
|
||
|
|
auto isEol = buffer[i] == '\n';
|
||
|
|
if (isEol) {
|
||
|
|
reply = received;
|
||
|
|
|
||
|
|
CommandState = reply == "ok" ?
|
||
|
|
Comms::State::ACK :
|
||
|
|
(starts_with(reply, "error") ?
|
||
|
|
Comms::State::NAK :
|
||
|
|
Comms::State::DataReceived);
|
||
|
|
|
||
|
|
if (!reply.empty() && dataReceivedHandler != nullptr) {
|
||
|
|
dataReceivedHandler->DataReceived(reply);
|
||
|
|
}
|
||
|
|
|
||
|
|
received.clear();
|
||
|
|
} else {
|
||
|
|
received.push_back(static_cast<char>(buffer[i]));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// give some time to others
|
||
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|