Enabled arcs render after adapting OpenCNCPilot code.

Started porting iosender to C++
This commit is contained in:
2023-05-16 09:18:06 +03:00
parent c05a6a1ad2
commit 42aefe8ed8
23 changed files with 2200 additions and 18 deletions
+11
View File
@@ -0,0 +1,11 @@
#include "comms.h"
static iosender::StreamComms *currentCommunicator = nullptr;
void iosender::Comms::SetCom(iosender::StreamComms *com) {
currentCommunicator = com;
}
iosender::StreamComms *iosender::Comms::GetCom() {
return currentCommunicator;
}
+78
View File
@@ -0,0 +1,78 @@
#pragma once
#include <cstdint>
#include <string>
namespace iosender {
class StreamComms;
class Comms {
public:
enum class State {
AwaitAck,
DataReceived,
ACK,
NAK
};
enum class ResetMode {
None,
DTR,
RTS
};
enum class StreamType {
Serial,
Telnet,
Websocket
};
const int TXBUFFERSIZE = 4096;
const int RXBUFFERSIZE = 1024;
static void SetCom(StreamComms *com);
static StreamComms *GetCom();
};
struct DataReceivedHandler {
virtual void DataReceived(std::string data) = 0;
};
struct ByteReceivedHandler {
virtual void ByteReceived(int b) = 0;
};
class StreamComms {
public:
virtual ~StreamComms() = default;
virtual bool IsOpen() = 0;
virtual int OutCount() = 0;
virtual std::string Reply() = 0;
virtual Comms::StreamType StreamType() = 0;
virtual bool EventMode() = 0;
virtual void EventMode(bool mode) = 0;
virtual void Close() = 0;
virtual int ReadByte() = 0;
virtual void WriteByte(uint8_t data) = 0;
virtual void WriteBytes(uint8_t *bytes, int len) = 0;
virtual void WriteString(std::string data) = 0;
virtual void WriteCommand(std::string command) = 0;
virtual std::string GetReply(std::string command) = 0;
virtual void AwaitAck() = 0;
virtual void AwaitAck(std::string command) = 0;
virtual void AwaitResponse(std::string command) = 0;
virtual void AwaitResponse() = 0;
virtual void PurgeQueue() = 0;
Comms::State CommandState = Comms::State::NAK;
DataReceivedHandler *dataReceivedHandler = nullptr;
ByteReceivedHandler *byteReceivedHandler = nullptr;
};
}
+75
View File
@@ -0,0 +1,75 @@
#include "gcode.h"
#include "../string_utils.h"
std::vector<int> iosender::ToIndices(iosender::AxisFlags flags) {
std::vector<int> result;
int i = 0, j = (int) flags;
while (j != 0) {
if ((j & 0x01) != 0)
result.push_back(i);
i++;
j >>= 1;
}
return result;
}
std::vector<int> iosender::ToIndices(iosender::IJKFlags flags) {
std::vector<int> result;
int i = 0, j = (int) flags;
while (j != 0) {
if ((j & 0x01) != 0)
result.push_back(i);
i++;
j >>= 1;
}
return result;
}
std::vector<int> iosender::ToIndices(iosender::ThreadingFlags flags) {
std::vector<int> result;
int i = 0, j = (int) flags;
while (j != 0) {
if ((j & 0x01) != 0)
result.push_back(i);
i++;
j >>= 1;
}
return result;
}
std::string iosender::GCodeUtils::StripSpaces(std::string line) {
std::string s;
bool skip = true;
s = to_upper(line);
if (string_contains(s, "(MSG,")) {
s = "";
for (auto c: line) {
switch (c) {
case '(':
s += c;
skip = false;
break;
case ')':
skip = true;
s += c;
break;
case ' ':
if (!skip)
s += c;
break;
default:
s += c;
break;
}
}
} else {
s = remove_spaces(line);
}
return s;
}
+369
View File
@@ -0,0 +1,369 @@
#pragma once
#include <vector>
#include <string>
namespace iosender {
enum class Dialect {
Grbl,
GrblHAL,
LinuxCNC
};
enum class AxisFlags : int {
None = 0,
X = 1 << 0,
Y = 1 << 1,
Z = 1 << 2,
A = 1 << 3,
B = 1 << 4,
C = 1 << 5,
U = 1 << 6,
V = 1 << 7,
W = 1 << 8,
XY = 0x03,
XZ = 0x05,
XYZ = 0x07,
All = 0x3F
};
enum class IJKFlags : int {
None = 0,
I = 1 << 0,
J = 1 << 1,
K = 1 << 2,
All = 0x07
};
enum class ThreadingFlags : int {
None = 0,
R = 1 << 0,
Q = 1 << 1,
H = 1 << 2,
E = 1 << 3,
L = 1 << 4,
All = 0x1F
};
enum class Plane {
XY,
XZ,
YZ
};
enum class DistanceMode {
Absolute,
Incremental
};
enum class FeedRateMode {
InverseTime, //G93
UnitsPerMin, //G94 - default
UnitsPerRev //G95
};
enum class MotionMode {
G0 = 0,
G1 = 10,
G2 = 20,
G3 = 30,
G5 = 50,
G5_1 = 51,
G5_2 = 52,
G33 = 330,
G38_2 = 382,
G38_3 = 383,
G38_4 = 384,
G38_5 = 385,
G73 = 730,
G76 = 760,
G80 = 800,
None = G80,
G81 = 810,
G82 = 820,
G83 = 830,
G84 = 840,
G85 = 850,
G86 = 860,
G87 = 870,
G88 = 880,
G89 = 890
};
enum class IJKMode {
Absolute,
Incremental
};
enum class Units {
Imperial = 0,
Metric = 1
};
enum class SpindleState : int {
Off = 1 << 0,
CW = 1 << 1,
CCW = 1 << 2
};
enum class CoolantState : int {
Off = 0,
Flood = 1 << 0,
Mist = 1 << 1,
Shower = 1 << 2
};
enum class ToolLengthOffset {
Cancel = 0, // G49 (Default: Must be zero)
Enable = 1, // G43
EnableDynamic = 2, // G43.1
ApplyAdditional = 3 // G43.2
};
enum class ThreadTaper : int {
None = 0,
Entry = 1 << 0,
Exit = 1 << 1,
Both = Entry | Exit
};
enum class LatheMode : int {
Disabled = 0,
Diameter = 1, // Do not change
Radius = 2 // Do not change
};
enum class Direction {
Positive = 0,
Negative
};
enum class InputWaitMode {
Immediate = 0,
Rise,
Fall,
High,
Low
};
enum class Commands {
G0,
G1,
G2,
G3,
G4,
G5,
G5_1,
G7,
G8,
G10,
G17,
G18,
G19,
G20,
G21,
G28,
G28_1,
G30,
G30_1,
G33,
G38_2,
G38_3,
G38_4,
G38_5,
G40,
G43,
G43_1,
G43_2,
G49,
G50,
G51,
G53,
G54,
G55,
G56,
G57,
G58,
G59,
G59_1,
G59_2,
G59_3,
G61,
G61_1,
G64,
G73,
G76,
G80,
G81,
G82,
G83,
G85,
G86,
G89,
G90,
G90_1,
G91,
G91_1,
G92,
G92_1,
G92_2,
G92_3,
G93,
G94,
G95,
G96,
G97,
G98,
G99,
M0,
M1,
M2,
M3,
M4,
M5,
M6,
M7,
M8,
M9,
M30,
M48,
M49,
M50,
M51,
M52,
M53,
M56,
M61,
M62,
M63,
M64,
M65,
M66,
M67,
M68,
Feedrate,
SpindleRPM,
ToolSelect,
Comment,
UserMCommand,
Undefined
};
std::vector<int> ToIndices(AxisFlags flags);
std::vector<int> ToIndices(IJKFlags flags);
std::vector<int> ToIndices(ThreadingFlags flags);
class GCodeUtils {
public:
static std::string StripSpaces(std::string line);
};
struct Point3D {
union {
struct {
double X, Y, Z;
};
double value[3];
};
double& operator[](int index) {
return value[index];
}
double *Array() { return value; }
};
struct Point6D {
union {
struct {
double X, Y, Z, A, B, C, U, V, W;
};
double value[9];
};
double& operator[](int index) {
return value[index];
}
double *Array() { return value; }
explicit operator Point3D() { return Point3D{X, Y, Z}; }
void Set(double *values, AxisFlags axisFlags, bool relative = false) {
if (relative) {
Add(values, axisFlags);
} else {
for (auto i: ToIndices(axisFlags)) {
switch (i) {
case 0:
X = values[0];
break;
case 1:
Y = values[1];
break;
case 2:
Z = values[2];
break;
case 3:
A = values[3];
break;
case 4:
B = values[4];
break;
case 5:
C = values[5];
break;
case 6:
U = values[6];
break;
case 7:
V = values[7];
break;
case 8:
W = values[8];
break;
}
}
}
}
void Add(const double values[], AxisFlags axisFlags) {
for (auto i: ToIndices(axisFlags)) {
switch (i) {
case 0:
X += values[0];
break;
case 1:
Y += values[1];
break;
case 2:
Z += values[2];
break;
case 3:
A += values[3];
break;
case 4:
B += values[4];
break;
case 5:
C += values[5];
break;
case 6:
U += values[6];
break;
case 7:
V += values[7];
break;
case 8:
W += values[8];
break;
}
}
}
};
}
+1
View File
@@ -0,0 +1 @@
#include "gcode_parser.h"
+10
View File
@@ -0,0 +1,10 @@
#pragma once
namespace iosender {
//class GCodeParser : public Machine {
//public:
//
//};
}
+38
View File
@@ -0,0 +1,38 @@
#include "grbl.h"
#include <thread>
#include "comms.h"
void iosender::Grbl::Reset() {
Comms::GetCom()->WriteByte(GrblConstants::CMD_RESET);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
const std::string iosender::GrblConstants::CMD_STATUS_REPORT_LEGACY = "?";
const std::string iosender::GrblConstants::CMD_CYCLE_START_LEGACY = "~";
const std::string iosender::GrblConstants::CMD_FEED_HOLD_LEGACY = "!";
const std::string iosender::GrblConstants::CMD_UNLOCK = "$X";
const std::string iosender::GrblConstants::CMD_HOMING = "$H";
const std::string iosender::GrblConstants::CMD_CHECK = "$C";
const std::string iosender::GrblConstants::CMD_GETSETTINGS = "$$";
const std::string iosender::GrblConstants::CMD_GETSETTINGS_ALL = "$+";
const std::string iosender::GrblConstants::CMD_GETPARSERSTATE = "$G";
const std::string iosender::GrblConstants::CMD_GETINFO = "$I";
const std::string iosender::GrblConstants::CMD_GETINFO_EXTENDED = "$I+";
const std::string iosender::GrblConstants::CMD_GETNGCPARAMETERS = "$#";
const std::string iosender::GrblConstants::CMD_GETSTARTUPLINES = "$N";
const std::string iosender::GrblConstants::CMD_GETSETTINGSDETAILS = "$ES";
const std::string iosender::GrblConstants::CMD_GETSETTINGSGROUPS = "$EG";
const std::string iosender::GrblConstants::CMD_GETALARMCODES = "$EA";
const std::string iosender::GrblConstants::CMD_GETERRORCODES = "$EE";
const std::string iosender::GrblConstants::CMD_PROGRAM_DEMARCATION = "%";
const std::string iosender::GrblConstants::CMD_SDCARD_MOUNT = "$FM";
const std::string iosender::GrblConstants::CMD_SDCARD_DIR = "$F";
const std::string iosender::GrblConstants::CMD_SDCARD_DIR_ALL = "$F+";
const std::string iosender::GrblConstants::CMD_SDCARD_REWIND = "$FR";
const std::string iosender::GrblConstants::CMD_SDCARD_RUN = "$F=";
const std::string iosender::GrblConstants::CMD_SDCARD_UNLINK = "$FD=";
const std::string iosender::GrblConstants::CMD_SDCARD_DUMP = "$F<=";
const std::string iosender::GrblConstants::FORMAT_METRIC = "###0.000";
const std::string iosender::GrblConstants::FORMAT_IMPERIAL = "##0.0000";
const std::string iosender::GrblConstants::NO_TOOL = "None";
const std::string iosender::GrblConstants::THCSIGNALS = "AERTOVHDU"; // Keep in sync with THCSignals enum below!!
+304
View File
@@ -0,0 +1,304 @@
#pragma once
#include <cstdint>
#include <string>
#include "grbl.h"
namespace iosender {
struct Color {
union {
float r, g, b, a;
};
float values[4];
};
class GrblConstants {
public:
static const uint8_t CMD_EXIT = 0x03; // ctrl-C
static const uint8_t CMD_RESET = 0x18; // ctrl-X
static const uint8_t CMD_STOP = 0x19; // ctrl-Y
static const uint8_t CMD_STATUS_REPORT = 0x80;
static const uint8_t CMD_CYCLE_START = 0x81;
static const uint8_t CMD_FEED_HOLD = 0x82;
static const uint8_t CMD_GCODE_REPORT = 0x83;
static const uint8_t CMD_SAFETY_DOOR = 0x84;
static const uint8_t CMD_JOG_CANCEL = 0x85;
static const uint8_t CMD_STATUS_REPORT_ALL = 0x87;
static const uint8_t CMD_OPTIONAL_STOP_TOGGLE = 0x88;
static const uint8_t CMD_SINGLE_BLOCK_TOGGLE = 0x89;
static const uint8_t CMD_OVERRIDE_FAN0_TOGGLE = 0x8A;
static const uint8_t CMD_FEED_OVR_RESET = 0x90;
static const uint8_t CMD_FEED_OVR_COARSE_PLUS = 0x91;
static const uint8_t CMD_FEED_OVR_COARSE_MINUS = 0x92;
static const uint8_t CMD_FEED_OVR_FINE_PLUS = 0x93;
static const uint8_t CMD_FEED_OVR_FINE_MINUS = 0x94;
static const uint8_t CMD_RAPID_OVR_RESET = 0x95;
static const uint8_t CMD_RAPID_OVR_MEDIUM = 0x96;
static const uint8_t CMD_RAPID_OVR_LOW = 0x97;
static const uint8_t CMD_SPINDLE_OVR_RESET = 0x99;
static const uint8_t CMD_SPINDLE_OVR_COARSE_PLUS = 0x9A;
static const uint8_t CMD_SPINDLE_OVR_COARSE_MINUS = 0x9B;
static const uint8_t CMD_SPINDLE_OVR_FINE_PLUS = 0x9C;
static const uint8_t CMD_SPINDLE_OVR_FINE_MINUS = 0x9D;
static const uint8_t CMD_SPINDLE_OVR_STOP = 0x9E;
static const uint8_t CMD_COOLANT_FLOOD_OVR_TOGGLE = 0xA0;
static const uint8_t CMD_COOLANT_MIST_OVR_TOGGLE = 0xA1;
static const uint8_t CMD_PID_REPORT = 0xA2;
static const uint8_t CMD_TOOL_ACK = 0xA3;
static const uint8_t CMD_PROBE_CONNECTED_TOGGLE = 0xA4;
static const std::string CMD_STATUS_REPORT_LEGACY;
static const std::string CMD_CYCLE_START_LEGACY;
static const std::string CMD_FEED_HOLD_LEGACY;
static const std::string CMD_UNLOCK;
static const std::string CMD_HOMING;
static const std::string CMD_CHECK;
static const std::string CMD_GETSETTINGS;
static const std::string CMD_GETSETTINGS_ALL;
static const std::string CMD_GETPARSERSTATE;
static const std::string CMD_GETINFO;
static const std::string CMD_GETINFO_EXTENDED;
static const std::string CMD_GETNGCPARAMETERS;
static const std::string CMD_GETSTARTUPLINES;
static const std::string CMD_GETSETTINGSDETAILS;
static const std::string CMD_GETSETTINGSGROUPS;
static const std::string CMD_GETALARMCODES;
static const std::string CMD_GETERRORCODES;
static const std::string CMD_PROGRAM_DEMARCATION;
static const std::string CMD_SDCARD_MOUNT;
static const std::string CMD_SDCARD_DIR;
static const std::string CMD_SDCARD_DIR_ALL;
static const std::string CMD_SDCARD_REWIND;
static const std::string CMD_SDCARD_RUN;
static const std::string CMD_SDCARD_UNLINK;
static const std::string CMD_SDCARD_DUMP;
static const std::string FORMAT_METRIC;
static const std::string FORMAT_IMPERIAL;
static const std::string NO_TOOL;
static const std::string THCSIGNALS; // Keep in sync with THCSignals enum below!!
static const int X_AXIS = 0;
static const int Y_AXIS = 1;
static const int Z_AXIS = 2;
static const int A_AXIS = 3;
static const int B_AXIS = 4;
static const int C_AXIS = 5;
};
enum class CameraMoveMode {
XAxisFirst = 1,
YAxisFirst = 2,
BothAxes = 3
};
enum class GrblStates {
Unknown = 0,
Idle,
Run,
Tool,
Hold,
Home,
Check,
Jog,
Alarm,
Door,
Sleep
};
enum class GrblMode {
Normal = 0,
Laser,
Lathe
};
enum class GrblEncoderMode {
Unknown = 0,
FeedRate = 1,
RapidRate = 2,
SpindleRPM = 3
};
enum class GrblSetting {
PulseMicroseconds = 0,
StepperIdleLockTime = 1,
StepInvertMask = 2,
DirInvertMask = 3,
InvertStepperEnable = 4,
LimitPinsInvertMask = 5,
InvertProbePin = 6,
StatusReportMask = 10,
JunctionDeviation = 11,
ArcTolerance = 12,
ReportInches = 13,
SoftLimitsEnable = 20,
HardLimitsEnable = 21,
HomingEnable = 22,
HomingDirMask = 23,
HomingFeedRate = 24,
HomingSeekRate = 25,
HomingDebounceDelay = 26,
HomingPulloff = 27,
G73Retract = 28,
PulseDelayMicroseconds = 29,
RpmMax = 30,
RpmMin = 31,
Mode = 32, // enum GrblMode
PWMFreq = 33,
PWMOffValue = 34,
PWMMinValue = 35,
PWMMaxValue = 36,
TravelResolutionBase = 100,
MaxFeedRateBase = 110,
AccelerationBase = 120,
MaxTravelBase = 130,
MotorCurrentBase = 140,
};
enum class grblHALSetting {
PulseMicroseconds = 0,
StepperIdleLockTime = 1,
StepInvertMask = 2,
DirInvertMask = 3,
InvertStepperEnable = 4,
LimitPinsInvertMask = 5,
InvertProbePin = 6,
StatusReportMask = 10,
JunctionDeviation = 11,
ArcTolerance = 12,
ReportInches = 13,
ControlInvertMask = 14, // Note: Used for detecting GrblHAL firmware
CoolantInvertMask = 15,
SpindleInvertMask = 16,
ControlPullUpDisableMask = 17,
LimitPullUpDisableMask = 18,
ProbePullUpDisable = 19,
SoftLimitsEnable = 20,
HardLimitsEnable = 21,
HomingEnable = 22,
HomingDirMask = 23,
HomingFeedRate = 24,
HomingSeekRate = 25,
HomingDebounceDelay = 26,
HomingPulloff = 27,
G73Retract = 28,
PulseDelayMicroseconds = 29,
RpmMax = 30,
RpmMin = 31,
Mode = 32, // enum GrblMode
PWMFreq = 33,
PWMOffValue = 34,
PWMMinValue = 35,
PWMMaxValue = 36,
StepperDeenergizeMask = 37,
SpindlePPR = 38,
EnableLegacyRTCommands = 39,
SoftLimitJogging = 40,
HomingLocateCycles = 43,
HomingCycle_1 = 44,
HomingCycle_2 = 45,
HomingCycle_3 = 46,
HomingCycle_4 = 47,
HomingCycle_5 = 48,
HomingCycle_6 = 49,
JogStepSpeed = 50,
JogSlowSpeed = 51,
JogFastSpeed = 52,
JogStepDistance = 53,
JogSlowDistance = 54,
JogFastDistance = 55,
// Per axis settings
TravelResolutionBase = 100,
MaxFeedRateBase = 110,
AccelerationBase = 120,
MaxTravelBase = 130,
MotorCurrentBase = 140,
MicroStepsBase = 150,
StallGuardBase = 200,
// End per axis settings
ToolChangeMode = 341
};
enum class StreamingState {
NoFile = 0,
Idle,
Send,
SendMDI,
Home,
Halted,
FeedHold,
ToolChange,
Start,
Stop,
Paused,
JobFinished,
Reset,
AwaitResetAck,
Disabled,
Error
};
enum class HomedState {
Unknown = 0,
NotHomed,
Homed
};
// Keep in sync with GrblInfo.SignalLetters constant below
enum class Signals : int {
Off = 0,
LimitX = 1 << 0,
LimitY = 1 << 1,
LimitZ = 1 << 2,
LimitA = 1 << 3,
LimitB = 1 << 4,
LimitC = 1 << 5,
LimitU = 1 << 6,
LimitV = 1 << 7,
LimitW = 1 << 8,
EStop = 1 << 9,
Probe = 1 << 10,
Reset = 1 << 11,
SafetyDoor = 1 << 12,
Hold = 1 << 13,
CycleStart = 1 << 14,
BlockDelete = 1 << 15,
OptionalStop = 1 << 16,
ProbeDisconnected = 1 << 17,
MotorWarning = 1 << 18,
MotorFault = 1 << 19
};
enum class THCSignals : int {
Off = 0,
ArcOk = 1 << 0,
THCEnabled = 1 << 1,
THCActive = 1 << 2,
TorchOn = 1 << 3,
OhmicProbe = 1 << 4,
VelocityLock = 1 << 5,
VoidLock = 1 << 6,
Down = 1 << 7,
Up = 1 << 8
};
struct GrblState {
GrblStates State;
int Substate;
int LastAlarm;
int Error;
Color color;
bool MPG;
};
class Grbl {
public:
static void Reset();
};
}
+1
View File
@@ -0,0 +1 @@
#include "machine.h"
+48
View File
@@ -0,0 +1,48 @@
#pragma once
#include <vector>
#include "gcode.h"
namespace iosender {
class CoordinateSystem {
};
class Tool {
};
class Machine {
public:
void Reset() {
// // Sync with controller
// if (GrblInfo.IsGrblHAL) {
// GrblParserState.Get();
// GrblWorkParameters.Get();
// } else {
// GrblParserState.Get(true);
// }
// coordinateSystems.Clear();
// for (CoordinateSystem c : GrblWorkParameters.CoordinateSystems) {
// coordinateSystems.Add(c);
// }
}
protected:
double rpm_ = 0;
bool isRelative = false;
int _tool = 0;
double offsets[9];
double origin[9];
double scaleFactors[9];
double toolOffsets[9];
std::vector<CoordinateSystem> coordinateSystems;
std::vector<Tool> toolTable;
Point6D machinePos;
private:
};
}
+1
View File
@@ -0,0 +1 @@
#include "measure_view_model.h"
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <string>
#include "grbl.h"
namespace iosender {
class MeasureViewModel {
public:
bool _isMetric = true;
const double MM_PER_INCH = 25.4;
bool IsMetric() const { return _isMetric; }
void IsMetric(bool value) {
if (value != _isMetric) {
_isMetric = value;
// trigger OnPropertyChanged()
}
}
std::string Unit() const { return _isMetric ? "mm" : "in"; }
std::string FeedrateUnit() const { return _isMetric ? "mm/min" : "in/min"; }
double UnitFactor() const { return _isMetric ? 1.0 : 25.4; }
std::string Format() const { return _isMetric ? GrblConstants::FORMAT_METRIC : GrblConstants::FORMAT_IMPERIAL; }
std::string FormatSigned() const { return "-" + Format(); }
int Precision() const { return _isMetric ? 3 : 4; }
double ConvertMM2Current(double value) const {
if (!_isMetric)
value /= 25.4;
return value;
}
};
}
+199
View File
@@ -0,0 +1,199 @@
#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));
}
}
}
+46
View File
@@ -0,0 +1,46 @@
#pragma once
#include <thread>
#include "comms.h"
namespace iosender {
class TelnetStream : public StreamComms {
public:
TelnetStream(std::string host, DataReceivedHandler* dataHandler = nullptr, ByteReceivedHandler *byteHandler = nullptr);
~TelnetStream() override;
bool IsOpen() override;
int OutCount() override;
std::string Reply() override;
Comms::StreamType StreamType() override;
bool EventMode() override;
void EventMode(bool mode) override;
void Close() override;
int ReadByte() override;
void WriteByte(uint8_t data) override;
void WriteBytes(uint8_t *bytes, int len) override;
void WriteString(std::string data) override;
void WriteCommand(std::string command) override;
std::string GetReply(std::string command) override;
void AwaitAck() override;
void AwaitAck(std::string command) override;
void AwaitResponse(std::string command) override;
void AwaitResponse() override;
void PurgeQueue() override;
private:
volatile bool shouldQuit = false;
void readWorker();
std::string reply;
int fd;
bool isConnected;
bool eventMode = true;
std::thread workerThread;
};
}