继续把 interp_execute.cc、interp_queue.cc、interp_find.cc 等 LinuxCNC 源文件纳入直接编译/链接路径,逐步删除临时 convert_g() wrapper 行为

结论:已将核心 LinuxCNC interpreter 源接入 standalone native 编译链接路径,移除 minimal runtime 中的手写 convert_g 行为,并通过 native probe 验证。
This commit is contained in:
2026-06-06 23:49:01 +08:00
commit 5025b0c1a1
95 changed files with 35453 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,61 @@
//
// IniFile - Ini-file reader and query class
// Copyright (C) 2026 B.Stultiens
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifndef __LINUXCNC_INI_INIFILE_H
#define __LINUXCNC_INI_INIFILE_H
#ifdef __cplusplus
#warning "Including inifile.h in C++ code is inefficient. You should use the C++ API in inifile.hh instead."
#endif
#include <limits.h>
#include <stddef.h>
#include <stdbool.h>
#include <rtapi_stdint.h>
//
// C-API interface functions
//
#ifdef __cplusplus
extern "C" {
#endif
// There is no real limit in the C++ version. This value is for compatibility.
// It has been increased from the original 256 to PATH_MAX to allow for full
// paths to be properly encapsulated.
#define INI_MAX_LINELEN PATH_MAX
int TildeExpansion(const char *file, char *path, size_t size);
int iniFindString(const char *inipath, const char *tag, const char *section, char *buf, size_t bufsize);
int iniFindBool(const char *inipath, const char *tag, const char *section, bool *result);
int iniFindSInt(const char *inipath, const char *tag, const char *section, rtapi_s64 *result);
int iniFindUInt(const char *inipath, const char *tag, const char *section, rtapi_u64 *result);
int iniFindDouble(const char *inipath, const char *tag, const char *section, double *result);
// Compatibility with existing code
// Maps to iniFindSInt() and truncates the result
int iniFindInt(const char *inipath, const char *tag, const char *section, int *result);
#ifdef __cplusplus
}
#endif
#endif
// vim: ts=4 sw=4

View File

@@ -0,0 +1,504 @@
//
// IniFile - Ini-file reader and query class
// Copyright (C) 2026 B.Stultiens
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifndef __LINUXCNC_INI_INIFILE_HH
#define __LINUXCNC_INI_INIFILE_HH
#ifndef __cplusplus
#error "inifile.hh cannot be used in C. Please use the C-API in inifile.h"
#endif
#include <string>
#include <optional>
#include <vector>
#include <map>
#include <utility>
#include <algorithm>
#include <climits>
#include <float.h>
#include <rtapi_stdint.h>
//
// IniFile public methods for extraction of values from the ini-file:
//
// Note that selecting the num'th value is the first argument to prevent
// accidents using wrong arguments for the bool/integer/real versions. This way
// you have to select the num'th as the first argument if you really mean to
// use it and cannot be mistaken as the default or min/max values. You can
// just omit the num if you just want the first value as a convenience method.
//
// All find_X_All() methods, except findStringAll(), will perform conversion to
// the requested type. That also means that mixed value content may result in
// errors and dropped results. Use the find_X_All() methods only when you know
// that the values are all supposed to be of the same type.
//
// Helper methods can be used to query the ini-file to get information about
// sections, variables, paths and line numbers:
// bool hasSection(section)
// bool hasVariable(variable, section)
// bool hasVariable(num, variable, section)
// which all map to:
// bool isSet(variable, section)
// bool isSet(num, variable, section)
//
// Ini-file structural content methods:
// std::vector<std::string> findSections()
// std::vector<std::pair<std::string,std::string>> findVariables(section);
// std::pair<std::string, int> lineOf(variable, section)
// std::pair<std::string, int> lineOf(num, variable, section)
//
// General value extraction methods:
// std::vector<std::string> findStringAll(tag, section)
// std::optional<std::string> findString(tag, section)
// std::optional<std::string> findString(num, tag, section)
// std::string findStringV(tag, section, def)
// std::string findStringV(num, tag, section, def)
//
// std::vector<bool> findBoolAll(tag, section)
// std::optional<bool> findBool(tag, section)
// std::optional<bool> findBool(num, tag, section)
// bool findBoolV(tag, section, def)
// bool findBoolV(num, tag, section, def)
//
// std::vector<rtapi_s64> findSIntAll(tag, section)
// std::optional<rtapi_s64> findSInt(tag, section, mini = INT64_MIN, maxi = INT64_MAX)
// std::optional<rtapi_s64> findSInt(num, tag, section, mini = INT64_MIN, maxi = INT64_MAX)
// rtapi_s64 findSIntV(tag, section, def, mini = INT64_MIN, maxi = INT64_MAX)
// rtapi_s64 findSIntV(num, tag, section, def, mini = INT64_MIN, maxi = INT64_MAX)
//
// std::vector<rtapi_u64> findUIntAll(tag, section)
// std::optional<rtapi_u64> findUInt(tag, section, mini = 0, maxi = UINT64_MAX)
// std::optional<rtapi_u64> findUInt(num, tag, section, mini = 0, maxi = UINT64_MAX)
// rtapi_u64 findUIntV(tag, section, def, mini = 0, maxi = UINT64_MAX)
// rtapi_u64 findUIntV(num, tag, section, def, mini = 0, maxi = UINT64_MAX)
//
// std::vector<double> findRealAll(tag, section)
// std::optional<double> findReal(tag, section, mini = -DBL_MAX, maxi = +DBL_MAX)
// std::optional<double> findReal(num, tag, section, mini = -DBL_MAX, maxi = +DBL_MAX)
// double findRealV(tag, section, def, mini = -DBL_MAX, maxi = +DBL_MAX)
// double findRealV(num, tag, section, def, mini = -DBL_MAX, maxi = +DBL_MAX)
//
// Convenience methods using the (usually 32-bit) integer type are provided and
// map to findSInt:
// std::optional<int> findInt(tag, section, mini = INT_MIN, maxi = INT_MAX)
// std::optional<int> findInt(num, tag, section, mini = INT_MIN, maxi = INT_MAX)
// int findIntV(tag, section, def, mini = INT_MIN, maxi = INT_MAX)
// int findIntV(num, tag, section, def, mini = INT_MIN, maxi = INT_MAX)
//
// Implementing (case [in]sensitive) list type values can be done using the
// IniFile::findMap() template function for case sensitive and case insensitive
// compares. The map defined for type T mapping:
// const std::map<const std::string, const T> = {...}
// const std::map<const std::string, const T, IniFile::caseless> = {...}
// for function:
// T findCustom(const IniFile &ini, const std::string &tag, const std::string &section, T def)
//
// Example:
// double findUnits(const IniFile &ini, const std::string &tag, const std::string &section, double def)
// {
// static const std::map<const std::string, const double> unitsMap = {
// { "mm", 1.0 },
// { "metric", 1.0 },
// { "in", 1/25.4 },
// { "inch", 1/25.4 },
// { "imperial", 1/25.4 },
// };
//
// if(auto c = ini.findMap(unitsMap, tag, section))
// return *c;
// return def;
// }
//
// Forward declaration (must be outside namespace)
// This is found in emc/nml_intf/emc.hh
enum EmcJointType : int;
namespace linuxcnc {
// Forward declaration of internal classes
class IniFileContent;
class IniFileTag;
class IniFileSection;
//
// Public facing IniFile operations
//
class IniFile
{
public:
IniFile(const std::string &filePath);
operator bool() const { return isOpen(); }
bool isOpen() const { return _inifilecontent != nullptr; }
bool hasSection(const std::string &section) const {
return isSet(1, "", section);
}
bool hasVariable(int num, const std::string &tag, const std::string &section) const {
return isSet(num, tag, section);
}
bool hasVariable(const std::string &tag, const std::string &section) const {
return hasVariable(1, tag, section);
}
// Returns true if the specified [section]tag is present
bool isSet(int num, const std::string &tag, const std::string &section) const {
if(tag.empty() && section.empty()) {
// No, we don't have nothing
return false;
}
if(tag.empty()) {
// We can have a section that has no variables in it
return (bool)findSection(section);
}
return (bool)findTag(tag, section, num);
}
bool isSet(const std::string &tag, const std::string &section) const {
return isSet(1, tag, section);
}
// Returns the ini-file path and line number of the specified variable
std::pair<std::string,int> lineOf(int num, const std::string &tag, const std::string &section) const;
std::pair<std::string,int> lineOf(const std::string &tag, const std::string &section) const {
return lineOf(1, tag, section);
}
// Get all variables named 'tag' from (optional) section in a vector.
// Returns an empty vector if none found.
std::vector<std::string> findStringAll(const std::string &tag, const std::string &section) const;
std::vector<bool> findBoolAll(const std::string &tag, const std::string &section) const;
std::vector<rtapi_s64> findSIntAll(const std::string &tag, const std::string &section) const;
std::vector<rtapi_u64> findUIntAll(const std::string &tag, const std::string &section) const;
std::vector<double> findRealAll(const std::string &tag, const std::string &section) const;
// Get the num'th variable named 'tag' from (optional) section.
// Returns std::nullopt if not found
std::optional<std::string> findString(int num, const std::string &tag, const std::string &section) const;
std::optional<bool> findBool(int num, const std::string &tag, const std::string &section) const;
std::optional<std::string> findString(const std::string &tag, const std::string &section) const {
return findString(1, tag, section);
}
std::optional<bool> findBool(const std::string &tag, const std::string &section) const {
return findBool(1, tag, section);
}
// Get numerical values with options bounded ranges.
// Returns std::nullopt if not found or out-of-range.
std::optional<rtapi_s64> findSInt(int num, const std::string &tag, const std::string &section,
rtapi_s64 mini = INT64_MIN, rtapi_s64 maxi = INT64_MAX) const;
std::optional<rtapi_u64> findUInt(int num, const std::string &tag, const std::string &section,
rtapi_u64 mini = 0, rtapi_u64 maxi = UINT64_MAX) const;
std::optional<double> findReal(int num, const std::string &tag, const std::string &section,
double mini = -DBL_MAX, double maxi = +DBL_MAX) const;
std::optional<rtapi_s64> findSInt(const std::string &tag, const std::string &section,
rtapi_s64 mini = INT64_MIN, rtapi_s64 maxi = INT64_MAX) const {
return findSInt(1, tag, section, mini, maxi);
}
std::optional<rtapi_u64> findUInt(const std::string &tag, const std::string &section,
rtapi_u64 mini = 0, rtapi_u64 maxi = UINT64_MAX) const {
return findUInt(1, tag, section, mini, maxi);
}
std::optional<double> findReal(const std::string &tag, const std::string &section,
double mini = -DBL_MAX, double maxi = +DBL_MAX) const {
return findReal(1, tag, section, mini, maxi);
}
// Get the num'th value with defaults if not found.
std::string findStringV(int num, const std::string &tag, const std::string &section, const std::string &def) const {
if(auto v = findString(num, tag, section))
return *v;
return def;
}
bool findBoolV(int num, const std::string &tag, const std::string &section, bool def) const {
if(auto v = findBool(num, tag, section))
return *v;
return def;
}
std::string findStringV(const std::string &tag, const std::string &section, const std::string &def) const {
return findStringV(1, tag, section, def);
}
bool findBoolV(const std::string &tag, const std::string &section, bool def) const {
return findBoolV(1, tag, section, def);
}
// Find the num'th value within min/max range.
// Returns default value if not found or out-of-range.
// These have a suffix 'V' to counter the overloading ambiguity.
rtapi_s64 findSIntV(int num, const std::string &tag, const std::string &section, rtapi_s64 def,
rtapi_s64 mini = INT64_MIN, rtapi_s64 maxi = INT64_MAX) const {
if(auto v = findSInt(num, tag, section, mini, maxi))
return *v;
return def;
}
rtapi_u64 findUIntV(int num, const std::string &tag, const std::string &section, rtapi_u64 def,
rtapi_u64 mini = 0, rtapi_u64 maxi = UINT64_MAX) const {
if(auto v = findUInt(num, tag, section, mini, maxi))
return *v;
return def;
}
double findRealV(int num, const std::string &tag, const std::string &section, double def,
double mini = -DBL_MAX, double maxi = +DBL_MAX) const {
if(auto v = findReal(num, tag, section, mini, maxi))
return *v;
return def;
}
rtapi_s64 findSIntV(const std::string &tag, const std::string &section, rtapi_s64 def,
rtapi_s64 mini = INT64_MIN, rtapi_s64 maxi = INT64_MAX) const {
return findSIntV(1, tag, section, def, mini, maxi);
}
rtapi_u64 findUIntV(const std::string &tag, const std::string &section, rtapi_u64 def,
rtapi_u64 mini = 0, rtapi_u64 maxi = UINT64_MAX) const {
return findUIntV(1, tag, section, def, mini, maxi);
}
double findRealV(const std::string &tag, const std::string &section, double def,
double mini = -DBL_MAX, double maxi = +DBL_MAX) const {
return findRealV(1, tag, section, def, mini, maxi);
}
// Convenience methods
std::optional<int> findInt(int num, const std::string &tag, const std::string &section,
int mini = INT_MIN, int maxi = INT_MAX) const {
if(auto v = findSInt(num, tag, section, mini, maxi))
return (int)*v;
return std::nullopt;
}
std::optional<int> findInt(const std::string &tag, const std::string &section,
int mini = INT_MIN, int maxi = INT_MAX) const {
return findInt(1, tag, section, mini, maxi);
}
int findIntV(int num, const std::string &tag, const std::string &section, int def,
int mini = INT_MIN, int maxi = INT_MAX) const {
return (int)findSIntV(num, tag, section, def, mini, maxi);
}
int findIntV(const std::string &tag, const std::string &section, int def,
int mini = INT_MIN, int maxi = INT_MAX) const {
return findIntV(1, tag, section, def, mini, maxi);
}
// Map-search matching of values returning the mapped value.
// Search is case-sensitive.
template<typename T>
std::optional<T> findMap(int num, const std::map<const std::string, const T> &map,
const std::string &tag, const std::string &section = "") const {
if(auto s = findString(num, tag, section)) {
auto const m = map.find(*s);
if(m != map.end()) {
return m->second;
}
}
return std::nullopt;
}
template<typename T>
std::optional<T> findMap(const std::map<const std::string, const T> &map,
const std::string &tag, const std::string &section = "") const {
return findMap(1, map, tag, section);
}
// Map compare function without case
struct caseless {
struct caseless_cmp {
bool operator() (const char &a, const char &b) const {
return std::tolower(a & 0xff) < std::tolower(b & 0xff);
}
};
bool operator() (const std::string &a, const std::string &b) const {
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), caseless_cmp());
}
};
// Map-search matching of values returning the mapped value.
// Search is case-insensitive.
template<typename T>
std::optional<T> findMap(int num, const std::map<const std::string, const T, caseless> &map,
const std::string &tag, const std::string &section = "") const {
if(auto s = findString(num, tag, section)) {
auto const m = map.find(*s);
if(m != map.end()) {
return m->second;
}
}
return std::nullopt;
}
template<typename T>
std::optional<T> findMap(const std::map<const std::string, const T, caseless> &map,
const std::string &tag, const std::string &section = "") const {
return findMap(1, map, tag, section);
}
template<typename T>
std::optional<T> static mapMap(const std::map<const std::string, const T, caseless> &map,
const std::string &str) {
auto const m = map.find(str);
if(m != map.end()) {
return m->second;
}
return std::nullopt;
}
//
// Mapping functions for enumerated types so they become consistent
// throughout the code base. They take a string argument and match it to
// the mapped values:
// - mapLinearUnits() maps {mm, metric, in, inch, imperial}
// - mapAngularUnits() maps {deg, degree, grad, gon, rad, radian}
// - mapJointType() maps {LINEAR, ANGULAR}
//
static std::optional<double> mapLinearUnits(const std::string &str);
static std::optional<double> mapAngularUnits(const std::string &str);
static std::optional<EmcJointType> mapJointType(const std::string &str);
// The following find*() both lookup the ini variable and attempt to
// convert to the associated numerical value.
std::optional<double> findLinearUnits(int num, const std::string &var, const std::string &sec) const {
if(auto c = findString(num, var, sec))
return mapLinearUnits(*c);
return std::nullopt;
}
std::optional<double> findAngularUnits(int num, const std::string &var, const std::string &sec) const {
if(auto c = findString(num, var, sec))
return mapAngularUnits(*c);
return std::nullopt;
}
std::optional<EmcJointType> findJointType(int num, const std::string &var, const std::string &sec) const {
if(auto c = findString(num, var, sec))
return mapJointType(*c);
return std::nullopt;
}
double findLinearUnits(const std::string &var, const std::string &sec, double def) const {
if(auto m = findLinearUnits(1, var, sec))
return *m;
return def;
}
double findAngularUnits(const std::string &var, const std::string &sec, double def) const {
if(auto m = findAngularUnits(1, var, sec))
return *m;
return def;
}
EmcJointType findJointType(const std::string &var, const std::string &sec, EmcJointType def) const {
if(auto m = findJointType(1, var, sec))
return *m;
return def;
}
// Return a list of section names from the ini-file
std::vector<std::string> findSections() const;
// Return a list of variable name/value pairs from an optional section in the ini-file
std::vector<std::pair<std::string,std::string>> findVariables(const std::string &section) const;
// The fact that this is here is because of compatibility
// Perform tilde expansion using HOME environment variable.
// Returns the filePath "~/path" as "$HOME/path"
// Zero is returned on success or a negative value (-errno) on failure.
static int tildeExpand(const std::string &filePath, std::string &res);
// Compatibility method
static int TildeExpansion(const std::string &filePath, std::string &res) {
return IniFile::tildeExpand(filePath, res);
}
static std::optional<bool> convertBool(const std::string &val);
static std::optional<rtapi_s64> convertSInt(const std::string &val);
static std::optional<rtapi_u64> convertUInt(const std::string &val);
static std::optional<double> convertReal(const std::string &val);
// split() Tokenize 'str' based on 'delim'
static std::vector<std::string> split(const std::string &delim, const std::string &str);
// Trim leading/trailing or both
static void rtrim(std::string &str) {
size_t n = str.find_last_not_of(IniFile::STR_WS);
if(std::string::npos != n)
str.erase(n+1);
}
static void ltrim(std::string &str) {
if(str.empty())
return;
size_t n = str.find_first_not_of(IniFile::STR_WS);
if(std::string::npos == n)
str.clear(); // Only whitespace
else
str.erase(0, n);
}
static void trim(std::string &str) {
rtrim(str);
ltrim(str);
}
// Trim on a copy and return the trimmed copy
static std::string rtrimcpy(const std::string &str) {
std::string cpy = str;
rtrim(cpy);
return cpy;
}
static std::string ltrimcpy(const std::string &str) {
std::string cpy = str;
ltrim(cpy);
return cpy;
}
static std::string trimcpy(const std::string &str) {
std::string cpy = str;
rtrim(cpy);
ltrim(cpy);
return cpy;
}
// White-space characters for argument to find_first_of() and the like.
// Using static constexpr std::string does not seem to work on Debian 11
// with clang-19 and older than that. Gcc on debian 11 and before doesn't
// support enough C++20 to build LinuxCNC at all.
static constexpr char STR_WS[] =" \t\v\f\r\n";
// This isSpace is guaranteed not to depend on locale
static bool isSpace(char c) {
return std::string::npos != (std::string{STR_WS}).find(c);
}
private:
bool Open(const std::string &filePath);
bool Close() { _inifilecontent = nullptr; _filepath.clear(); return true; }
bool hasOpenError(const std::string &tag, const std::string &section) const;
std::string sectionFromTag(const IniFileTag *val) const;
std::optional<const IniFileSection *> findSection(const std::string &section) const;
std::optional<const IniFileTag *> findTag(const std::string &tag, const std::string &section, int num) const;
std::optional<std::vector<const IniFileTag *>> findTags(const std::string &tag, const std::string &section) const;
std::optional<bool> convertBool(const IniFileTag *val) const;
std::optional<rtapi_s64> convertSInt(const IniFileTag *val) const;
std::optional<rtapi_u64> convertUInt(const IniFileTag *val) const;
std::optional<double> convertReal(const IniFileTag *val) const;
const IniFileContent *_inifilecontent;
std::string _filepath;
};
} // namespace linuxcnc
#endif
// vim: ts=4 sw=4

View File

@@ -0,0 +1,27 @@
/********************************************************************
* Description: linuxcnc.h
* Common defines used in many emc2 source files.
*
*
* Author: Petter Reinholdtsen
* License: LGPL Version 2
* System: Any
*
* Copyright (c) 2021 All rights reserved.
********************************************************************/
#ifndef __LINUXCNC_LINUXCNC_H
#define __LINUXCNC_LINUXCNC_H
/* LINELEN is used throughout for buffer sizes, length of file name strings,
etc. Let's just have one instead of a multitude of defines all the same. */
#define LINELEN 255
/* Used in a number of places for sprintf() buffers. */
#define BUFFERLEN 80
/* Imperial/Metric conversion */
#define MM_PER_INCH 25.4
#define INCH_PER_MM (1.0/MM_PER_INCH)
#endif /* LINUXCNC_H */

View File

@@ -0,0 +1,75 @@
/********************************************************************
* Description: emcmotcfg.h
* Default values for compile-time parameters.
*
* Derived from a work by Fred Proctor & Will Shackleford
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
********************************************************************/
#ifndef __LINUXCNC_EMCMOTCFG_H
#define __LINUXCNC_EMCMOTCFG_H
/* default name of EMCMOT INI file */
#define DEFAULT_EMCMOT_INIFILE "emc.ini" /* same as for EMC-- we're in
touch */
/* number of joints supported
Note: this is not a global variable but a compile-time parameter
since it sets array sizes, etc. */
// total number of joints available (kinematics_joints + extra_joints)
#define EMCMOT_MAX_JOINTS 16
// number of extra joints (NOT used in kinematics calculations):
#define EMCMOT_MAX_EXTRAJOINTS EMCMOT_MAX_JOINTS
/* number of axes defined by the interp */ //FIXME: shouldn't be here..
#define EMCMOT_MAX_AXIS 9
#define EMCMOT_MAX_SPINDLES 8
#define EMCMOT_MAX_DIO 64
#define EMCMOT_MAX_AIO 64
#define EMCMOT_MAX_MISC_ERROR 64
#if (EMCMOT_MAX_DIO > 64) || (EMCMOT_MAX_AIO > 64)
#error A 64 bit bitmask is used in the planner. Don't increase these until that's fixed.
#endif
#define EMCMOT_ERROR_NUM 32 /* how many errors we can queue */
#define EMCMOT_ERROR_LEN 1024 /* how long error string can be */
/*
Shared memory keys for simulated motion process. No base address
values need to be computed, since operating system does this for us
*/
#define DEFAULT_SHMEM_KEY 100
/* default comm timeout, in seconds */
#define DEFAULT_EMCMOT_COMM_TIMEOUT 1.0
/* initial velocity, accel used for coordinated moves */
#define DEFAULT_VELOCITY 1.0
#define DEFAULT_ACCELERATION 10.0
/* maximum and minimum limit defaults for all axes */
#define DEFAULT_MAX_LIMIT 1000
#define DEFAULT_MIN_LIMIT -1000
/* default number of motion io pins */
#define DEFAULT_DIO 4
#define DEFAULT_AIO 4
#define DEFAULT_MISC_ERROR 0
/* size of motion queue
* a TC_STRUCT is about 512 bytes so this queue is
* about a megabyte. */
#define DEFAULT_TC_QUEUE_SIZE 2000
/* max following error */
#define DEFAULT_MAX_FERROR 100
#endif

View File

@@ -0,0 +1,140 @@
/********************************************************************
* Description: state_tag.h
*
* A "tag" struct that is used to add interpreter state information to
* a given motion line. This state info isn't actually used by motion
* directly, but indicates the motion state.
*
* Copyright © 2015 Robert W. Ellenberg
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
********************************************************************/
#ifndef STATE_TAG_H
#define STATE_TAG_H
/**
* Enum to define bit names for StateTag's flags register.
* The actual position of the flag isn't important, so the actual index doesn't
* matter. However, the bit field should be <=64 bits to fit within a long int.
*/
typedef enum {
GM_FLAG_UNITS,
GM_FLAG_DISTANCE_MODE,
GM_FLAG_TOOL_OFFSETS_ON,
GM_FLAG_RETRACT_OLDZ,
GM_FLAG_BLEND,
GM_FLAG_EXACT_STOP,
GM_FLAG_FEED_INVERSE_TIME,
GM_FLAG_FEED_UPM,
GM_FLAG_CSS_MODE,
GM_FLAG_IJK_ABS,
GM_FLAG_DIAMETER_MODE,
GM_FLAG_G92_IS_APPLIED,
GM_FLAG_SPINDLE_ON,
GM_FLAG_SPINDLE_CW,
GM_FLAG_MIST,
GM_FLAG_FLOOD,
GM_FLAG_FEED_OVERRIDE,
GM_FLAG_SPEED_OVERRIDE,
GM_FLAG_ADAPTIVE_FEED,
GM_FLAG_FEED_HOLD,
GM_FLAG_RESTORABLE,
GM_FLAG_IN_REMAP,
GM_FLAG_IN_SUB,
GM_FLAG_EXTERNAL_FILE,
GM_FLAG_IS_CIRCLE,
GM_FLAG_MAX_FLAGS
} StateFlag;
/**
* Enum for various fields of state info that are int type.
*
* WARNING:
*
* 1) Since these are used as array indices, they have to start at 0,
* be monotonic, and the GM_FIELD_MAX_FIELDS enum MUST be last in the list.
*
* 2) If your application needs to pass state tags through NML, then
* you MUST update the corresponding cms->update function for state
* tags.
*
* TODO: make that standalone function a method here for maintainability
*/
typedef enum {
GM_FIELD_LINE_NUMBER,
GM_FIELD_G_MODE_0,
GM_FIELD_CUTTER_COMP,
GM_FIELD_MOTION_MODE,
GM_FIELD_PLANE,
GM_FIELD_M_MODES_4,
GM_FIELD_ORIGIN,
GM_FIELD_TOOLCHANGE,
GM_FIELD_MAX_FIELDS
} StateField;
/**
* Enum for indexing state tag `fields_float`, machine state float
* array: feed, speed, etc.
*/
typedef enum {
GM_FIELD_FLOAT_LINE_NUMBER, // eww
GM_FIELD_FLOAT_FEED,
GM_FIELD_FLOAT_SPEED,
GM_FIELD_FLOAT_PATH_TOLERANCE,
GM_FIELD_FLOAT_NAIVE_CAM_TOLERANCE,
GM_FIELD_FLOAT_ARC_RADIUS,
GM_FIELD_FLOAT_ARC_CENTER_X,
GM_FIELD_FLOAT_ARC_CENTER_Y,
GM_FIELD_FLOAT_ARC_CENTER_Z,
GM_FIELD_FLOAT_STRAIGHT_HEADING,
GM_FIELD_FLOAT_NORMAL_HEADING,
GM_FIELD_FLOAT_MAX_FIELDS
} StateFieldFloat;
/**
* Tag structure that is added to a motion segment so that motion has a copy of
* the relevant interp state.
*
* Previously, this information was stored only in the interpreter, and as
* vectors of g codes, m codes, and settings. Considering that the write_XXX
* and gen_XXX functions had to jump through hoops to translate from a settings
* struct, the extra packing here isn't much more complex to deal with, and
* will cost much less space when copying back and forth.
*/
struct state_tag_t {
// Float-type machine settings: feed, speed, etc., indexed by the
// StateFieldFloat enum above
float fields_float[GM_FIELD_FLOAT_MAX_FIELDS];
// Any G / M code states that doesn't pack nicely into a single bit
// These are an array mostly because it's easier to pass an
// arbitrary-length array through NML than individual fields
int fields[GM_FIELD_MAX_FIELDS];
/** G / M mode flags for simple states like inch / mm, feedhold enable, etc.
* This stores packed bits in one field (since we can't use a bitset in a
* pure C struct).
*/
unsigned long int packed_flags;
char filename[256];
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,77 @@
/********************************************************************
* Description: canon_position.hh
*
* CANON position class with operators and common functions
* Derived from a work by Thomas Kramer
*
* Author: Robert W. Ellenberg
* License: GPL Version 2+
* System: Linux
*
* Copyright (c) 2014 All rights reserved.
********************************************************************/
#ifndef CANON_POSITION_HH
#define CANON_POSITION_HH
#include <stdio.h> // FILE
#include <vector>
#include <emcpos.h>
#include "emctool.h"
#include <posemath.h> // For PM_CARTESIAN type
struct CANON_POSITION {
#ifndef JAVA_DIAG_APPLET
CANON_POSITION() :
x(0.0),
y(0.0),
z(0.0),
a(0.0),
b(0.0),
c(0.0),
u(0.0),
v(0.0),
w(0.0) {}
CANON_POSITION(double _x, double _y, double _z,
double _a, double _b, double _c,
double _u, double _v, double _w);
CANON_POSITION(const EmcPose &_pos);
CANON_POSITION(PM_CARTESIAN const &xyz);
CANON_POSITION(PM_CARTESIAN const &xyz, PM_CARTESIAN const &abc);
bool operator==(const CANON_POSITION &o) const;
bool operator!=(const CANON_POSITION &o) const;
CANON_POSITION & operator+=(const CANON_POSITION &o);
CANON_POSITION & operator+=(const EmcPose &o);
const CANON_POSITION operator+(const CANON_POSITION &o) const;
const CANON_POSITION operator+(const EmcPose &o) const;
CANON_POSITION & operator-=(const CANON_POSITION &o);
CANON_POSITION & operator-=(const EmcPose &o);
const CANON_POSITION operator-(const CANON_POSITION &o) const;
const CANON_POSITION operator-(const EmcPose &o) const;
double &operator[](const int ind);
const CANON_POSITION abs() const;
const CANON_POSITION absdiff(const CANON_POSITION &o) const;
double max() const;
const EmcPose toEmcPose() const;
const PM_CARTESIAN xyz() const;
const PM_CARTESIAN abc() const;
const PM_CARTESIAN uvw() const;
void set_xyz(const PM_CARTESIAN & xyz);
void print() const;
#endif
double x, y, z, a, b, c, u, v, w;
};
#endif /* ifndef CANON_POSITION_HH */

View File

@@ -0,0 +1,50 @@
/* This is a component of LinuxCNC
* Copyright 2011, 2012, 2013 Michael Haberler <git@mah.priv.at>,
* Sebastian Kuzminsky <seb@highlab.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
// factored out from emcglb.h so subsystems not requiring the
// emcglb.h defines may include them as well
#define EMC_DEBUG_CONFIG 0x00000002
#define EMC_DEBUG_VERSIONS 0x00000008
#define EMC_DEBUG_TASK_ISSUE 0x00000010
#define EMC_DEBUG_NML 0x00000040
#define EMC_DEBUG_MOTION_TIME 0x00000080
#define EMC_DEBUG_INTERP 0x00000100
#define EMC_DEBUG_RCS 0x00000200
#define EMC_DEBUG_INTERP_LIST 0x00000800
#define EMC_DEBUG_IOCONTROL 0x00001000
#define EMC_DEBUG_OWORD 0x00002000
#define EMC_DEBUG_REMAP 0x00004000
#define EMC_DEBUG_PYTHON 0x00008000
#define EMC_DEBUG_NAMEDPARAM 0x00010000
#define EMC_DEBUG_GDBONSIGNAL 0x00020000
#define EMC_DEBUG_STATE_TAGS 0x00080000
// not interpreted by EMC.
#define EMC_DEBUG_USER1 0x10000000
#define EMC_DEBUG_USER2 0x20000000
#define EMC_DEBUG_UNCONDITIONAL 0x40000000 // always logged
#define EMC_DEBUG_ALL 0x7FFFFFFF /* it's an int for %i to work
*/
// debug prefix flags
#define LOG_TIME 1
#define LOG_PID 2
#define LOG_FILENAME 4 // and line

View File

@@ -0,0 +1,483 @@
/********************************************************************
* Description: emc.hh
* Declarations for EMC NML vocabulary
*
* Derived from a work by Fred Proctor & Will Shackleford
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#ifndef EMC_HH
#define EMC_HH
#include <emcmotcfg.h> // EMC_JOINT_MAX, EMC_AXIS_MAX
#include "libnml/nml/nml_type.hh"
#include "motion_types.h"
#include <stdint.h>
#include "rs274ngc/modal_state.hh"
// Forward class declarations
class EMC_JOINT_STAT;
class EMC_AXIS_STAT;
class EMC_TRAJ_STAT;
class EMC_MOTION_STAT;
class EMC_TASK_STAT;
class EMC_TOOL_STAT;
class EMC_AUX_STAT;
class EMC_SPINDLE_STAT;
class EMC_COOLANT_STAT;
class EMC_IO_STAT;
class EMC_STAT;
class CMS;
class RCS_CMD_CHANNEL;
class RCS_STAT_CHANNEL;
class NML;
struct EmcPose;
struct PM_CARTESIAN;
// ---------------------
// EMC TYPE DECLARATIONS
// ---------------------
// NML for base EMC
#define EMC_OPERATOR_ERROR_TYPE ((NMLTYPE) 11)
#define EMC_OPERATOR_TEXT_TYPE ((NMLTYPE) 12)
#define EMC_OPERATOR_DISPLAY_TYPE ((NMLTYPE) 13)
#define EMC_NULL_TYPE ((NMLTYPE) 21)
#define EMC_SET_DEBUG_TYPE ((NMLTYPE) 22)
#define EMC_SYSTEM_CMD_TYPE ((NMLTYPE) 30)
// NML for EMC_JOINT
#define EMC_JOINT_SET_MIN_POSITION_LIMIT_TYPE ((NMLTYPE) 107)
#define EMC_JOINT_SET_MAX_POSITION_LIMIT_TYPE ((NMLTYPE) 108)
#define EMC_JOINT_SET_FERROR_TYPE ((NMLTYPE) 111)
#define EMC_JOINT_SET_HOMING_PARAMS_TYPE ((NMLTYPE) 112)
#define EMC_JOINT_SET_MIN_FERROR_TYPE ((NMLTYPE) 115)
#define EMC_JOINT_HALT_TYPE ((NMLTYPE) 119)
#define EMC_JOINT_HOME_TYPE ((NMLTYPE) 123)
#define EMC_JOG_CONT_TYPE ((NMLTYPE) 124)
#define EMC_JOG_INCR_TYPE ((NMLTYPE) 125)
#define EMC_JOG_ABS_TYPE ((NMLTYPE) 126)
#define EMC_JOINT_OVERRIDE_LIMITS_TYPE ((NMLTYPE) 129)
#define EMC_JOINT_LOAD_COMP_TYPE ((NMLTYPE) 131)
#define EMC_JOINT_SET_BACKLASH_TYPE ((NMLTYPE) 134)
#define EMC_JOINT_UNHOME_TYPE ((NMLTYPE) 135)
#define EMC_JOG_STOP_TYPE ((NMLTYPE) 136)
#define EMC_JOINT_STAT_TYPE ((NMLTYPE) 198)
#define EMC_AXIS_STAT_TYPE ((NMLTYPE) 199)
// NML for EMC_TRAJ
// defs for termination conditions
#define EMC_TRAJ_TERM_COND_STOP 0
#define EMC_TRAJ_TERM_COND_EXACT 1
#define EMC_TRAJ_TERM_COND_BLEND 2
#define EMC_TRAJ_SET_MODE_TYPE ((NMLTYPE) 204)
#define EMC_TRAJ_SET_VELOCITY_TYPE ((NMLTYPE) 205)
#define EMC_TRAJ_SET_ACCELERATION_TYPE ((NMLTYPE) 206)
#define EMC_TRAJ_SET_MAX_VELOCITY_TYPE ((NMLTYPE) 207)
#define EMC_TRAJ_SET_SCALE_TYPE ((NMLTYPE) 209)
#define EMC_TRAJ_SET_RAPID_SCALE_TYPE ((NMLTYPE) 238)
#define EMC_TRAJ_ABORT_TYPE ((NMLTYPE) 215)
#define EMC_TRAJ_PAUSE_TYPE ((NMLTYPE) 216)
#define EMC_TRAJ_RESUME_TYPE ((NMLTYPE) 218)
#define EMC_TRAJ_DELAY_TYPE ((NMLTYPE) 219)
#define EMC_TRAJ_LINEAR_MOVE_TYPE ((NMLTYPE) 220)
#define EMC_TRAJ_CIRCULAR_MOVE_TYPE ((NMLTYPE) 221)
#define EMC_TRAJ_SET_TERM_COND_TYPE ((NMLTYPE) 222)
#define EMC_TRAJ_SET_OFFSET_TYPE ((NMLTYPE) 223)
#define EMC_TRAJ_SET_G5X_TYPE ((NMLTYPE) 224)
#define EMC_TRAJ_SET_ROTATION_TYPE ((NMLTYPE) 226)
#define EMC_TRAJ_SET_G92_TYPE ((NMLTYPE) 227)
#define EMC_TRAJ_CLEAR_PROBE_TRIPPED_FLAG_TYPE ((NMLTYPE) 228)
#define EMC_TRAJ_PROBE_TYPE ((NMLTYPE) 229)
#define EMC_TRAJ_SET_TELEOP_ENABLE_TYPE ((NMLTYPE) 230)
#define EMC_TRAJ_SET_SPINDLESYNC_TYPE ((NMLTYPE) 232)
#define EMC_TRAJ_SET_SPINDLE_SCALE_TYPE ((NMLTYPE) 233)
#define EMC_TRAJ_SET_FO_ENABLE_TYPE ((NMLTYPE) 234)
#define EMC_TRAJ_SET_SO_ENABLE_TYPE ((NMLTYPE) 235)
#define EMC_TRAJ_SET_FH_ENABLE_TYPE ((NMLTYPE) 236)
#define EMC_TRAJ_RIGID_TAP_TYPE ((NMLTYPE) 237)
#define EMC_TRAJ_STAT_TYPE ((NMLTYPE) 299)
// EMC_MOTION aggregate class type declaration
#define EMC_MOTION_SET_AOUT_TYPE ((NMLTYPE) 304)
#define EMC_MOTION_SET_DOUT_TYPE ((NMLTYPE) 305)
#define EMC_MOTION_ADAPTIVE_TYPE ((NMLTYPE) 306)
#define EMC_MOTION_STAT_TYPE ((NMLTYPE) 399)
// NML for EMC_TASK
#define EMC_TASK_ABORT_TYPE ((NMLTYPE) 503)
#define EMC_TASK_SET_MODE_TYPE ((NMLTYPE) 504)
#define EMC_TASK_SET_STATE_TYPE ((NMLTYPE) 505)
#define EMC_TASK_PLAN_OPEN_TYPE ((NMLTYPE) 506)
#define EMC_TASK_PLAN_RUN_TYPE ((NMLTYPE) 507)
#define EMC_TASK_PLAN_EXECUTE_TYPE ((NMLTYPE) 509)
#define EMC_TASK_PLAN_PAUSE_TYPE ((NMLTYPE) 510)
#define EMC_TASK_PLAN_STEP_TYPE ((NMLTYPE) 511)
#define EMC_TASK_PLAN_RESUME_TYPE ((NMLTYPE) 512)
#define EMC_TASK_PLAN_END_TYPE ((NMLTYPE) 513)
#define EMC_TASK_PLAN_CLOSE_TYPE ((NMLTYPE) 514)
#define EMC_TASK_PLAN_INIT_TYPE ((NMLTYPE) 515)
#define EMC_TASK_PLAN_SYNCH_TYPE ((NMLTYPE) 516)
#define EMC_TASK_PLAN_SET_OPTIONAL_STOP_TYPE ((NMLTYPE) 517)
#define EMC_TASK_PLAN_SET_BLOCK_DELETE_TYPE ((NMLTYPE) 518)
#define EMC_TASK_PLAN_OPTIONAL_STOP_TYPE ((NMLTYPE) 519)
#define EMC_TASK_PLAN_REVERSE_TYPE ((NMLTYPE) 520)
#define EMC_TASK_PLAN_FORWARD_TYPE ((NMLTYPE) 521)
#define EMC_TASK_STAT_TYPE ((NMLTYPE) 599)
// EMC_TOOL type declarations
#define EMC_TOOL_HALT_TYPE ((NMLTYPE) 1102)
#define EMC_TOOL_ABORT_TYPE ((NMLTYPE) 1103)
#define EMC_TOOL_PREPARE_TYPE ((NMLTYPE) 1104)
#define EMC_TOOL_LOAD_TYPE ((NMLTYPE) 1105)
#define EMC_TOOL_UNLOAD_TYPE ((NMLTYPE) 1106)
#define EMC_TOOL_LOAD_TOOL_TABLE_TYPE ((NMLTYPE) 1107)
#define EMC_TOOL_SET_OFFSET_TYPE ((NMLTYPE) 1108)
#define EMC_TOOL_SET_NUMBER_TYPE ((NMLTYPE) 1109)
#define EMC_TOOL_STAT_TYPE ((NMLTYPE) 1199)
// EMC_AUX type declarations
#define EMC_AUX_INPUT_WAIT_TYPE ((NMLTYPE) 1209)
#define EMC_AUX_STAT_TYPE ((NMLTYPE) 1299)
// EMC_SPINDLE type declarations
#define EMC_SPINDLE_ON_TYPE ((NMLTYPE) 1304)
#define EMC_SPINDLE_OFF_TYPE ((NMLTYPE) 1305)
#define EMC_SPINDLE_INCREASE_TYPE ((NMLTYPE) 1309)
#define EMC_SPINDLE_DECREASE_TYPE ((NMLTYPE) 1310)
#define EMC_SPINDLE_CONSTANT_TYPE ((NMLTYPE) 1311)
#define EMC_SPINDLE_BRAKE_RELEASE_TYPE ((NMLTYPE) 1312)
#define EMC_SPINDLE_BRAKE_ENGAGE_TYPE ((NMLTYPE) 1313)
#define EMC_SPINDLE_SPEED_TYPE ((NMLTYPE) 1316)
#define EMC_SPINDLE_ORIENT_TYPE ((NMLTYPE) 1317)
#define EMC_SPINDLE_WAIT_ORIENT_COMPLETE_TYPE ((NMLTYPE) 1318)
#define EMC_SPINDLE_STAT_TYPE ((NMLTYPE) 1399)
// EMC_COOLANT type declarations
#define EMC_COOLANT_MIST_ON_TYPE ((NMLTYPE) 1404)
#define EMC_COOLANT_MIST_OFF_TYPE ((NMLTYPE) 1405)
#define EMC_COOLANT_FLOOD_ON_TYPE ((NMLTYPE) 1406)
#define EMC_COOLANT_FLOOD_OFF_TYPE ((NMLTYPE) 1407)
#define EMC_COOLANT_STAT_TYPE ((NMLTYPE) 1499)
#define EMC_IO_STAT_TYPE ((NMLTYPE) 1699)
#define EMC_STAT_TYPE ((NMLTYPE) 1999)
// types for EMC_TASK mode
enum class EMC_TASK_MODE {
MANUAL = 1,
AUTO = 2,
MDI = 3
};
// types for EMC_TASK state
enum class EMC_TASK_STATE {
ESTOP = 1,
ESTOP_RESET = 2,
OFF = 3,
ON = 4
};
// types for EMC_TASK execState
enum class EMC_TASK_EXEC {
ERROR = 1,
DONE = 2,
WAITING_FOR_MOTION = 3,
WAITING_FOR_MOTION_QUEUE = 4,
WAITING_FOR_IO = 5,
WAITING_FOR_MOTION_AND_IO = 7,
WAITING_FOR_DELAY = 8,
WAITING_FOR_SYSTEM_CMD = 9,
WAITING_FOR_SPINDLE_ORIENTED = 10
};
// types for EMC_TASK interpState
enum class EMC_TASK_INTERP {
IDLE = 1,
READING = 2,
PAUSED = 3,
WAITING = 4
};
// types for motion control
enum class EMC_TRAJ_MODE {
FREE = 1, // independent-axis motion,
COORD = 2, // coordinated-axis motion,
TELEOP = 3 // velocity based world coordinates motion,
};
// types for emcIoAbort() reasons
enum class EMC_ABORT {
TASK_EXEC_ERROR = 1,
AUX_ESTOP = 2,
MOTION_OR_IO_RCS_ERROR = 3,
TASK_STATE_OFF = 4,
TASK_STATE_ESTOP_RESET = 5,
TASK_STATE_ESTOP = 6,
TASK_STATE_NOT_ON = 7,
TASK_ABORT = 8,
INTERPRETER_ERROR = 9, // interpreter failed during readahead
INTERPRETER_ERROR_MDI = 10, // interpreter failed during MDI execution
USER = 100 // user-defined abort codes start here
};
// --------------
// EMC VOCABULARY
// --------------
// NML formatting function
extern int emcFormat(NMLTYPE type, void *buffer, CMS * cms);
// NML Symbol Lookup Function
extern const char *emc_symbol_lookup(uint32_t type);
#define emcSymbolLookup(a) emc_symbol_lookup(a)
// decls for command line args-- mains are responsible for setting these
// so that other modules can get cmd line args for ad hoc processing
extern int Argc;
extern char **Argv;
// ------------------------
// IMPLEMENTATION FUNCTIONS
// ------------------------
// implementation functions for EMC error, message types
// intended to be implemented in main() file, by writing to NML buffer
// print an error
extern int emcOperatorError(const char *fmt, ...) __attribute__((format(printf,1,2)));
// print general text
extern int emcOperatorText(const char *fmt, ...) __attribute__((format(printf,1,2)));
// print note to operator
extern int emcOperatorDisplay(const char *fmt, ...) __attribute__((format(printf,1,2)));
// implementation functions for EMC_AXIS types
extern int emcAxisSetMinPositionLimit(int axis, double limit);
extern int emcAxisSetMaxPositionLimit(int axis, double limit);
extern int emcAxisSetMaxVelocity(int axis, double vel, double ext_offset_vel);
extern int emcAxisSetMaxAcceleration(int axis, double acc, double ext_offset_acc);
extern double emcAxisGetMaxVelocity(int axis);
extern double emcAxisGetMaxAcceleration(int axis);
extern int emcAxisSetLockingJoint(int axis,int joint);
extern int emcAxisUpdate(EMC_AXIS_STAT stat[], int numAxes);
extern int emcAxisSetMaxJerk(int axis,double jerk);
extern int emcAxisHasMaxJerk(int axis);
extern double emcAxisGetMaxJerk(int axis);
// implementation functions for EMC_JOINT types
extern int emcJointSetType(int joint, unsigned char jointType);
extern int emcJointSetUnits(int joint, double units);
extern int emcJointSetBacklash(int joint, double backlash);
extern int emcJointSetMinPositionLimit(int joint, double limit);
extern int emcJointSetMaxPositionLimit(int joint, double limit);
extern int emcJointSetMotorOffset(int joint, double offset);
extern int emcJointSetFerror(int joint, double ferror);
extern int emcJointSetMinFerror(int joint, double ferror);
extern int emcJointSetHomingParams(int joint, double home, double offset, double home_vel,
double search_vel, double latch_vel,
int use_index, int encoder_does_not_reset, int ignore_limits,
int is_shared, int home_sequence, int volatile_home, int locking_indexer,
int absolute_encoder);
extern int emcJointUpdateHomingParams(int joint, double home, double offset, int sequence);
extern int emcJointSetMaxVelocity(int joint, double vel);
extern int emcJointSetMaxAcceleration(int joint, double acc);
extern int emcJointInit(int joint);
extern int emcJointHalt(int joint);
extern int emcJointHome(int joint);
extern int emcJointUnhome(int joint);
extern int emcJointActivate(int joint);
extern int emcJointDeactivate(int joint);
extern int emcJointOverrideLimits(int joint);
extern int emcJointLoadComp(int joint, const char *file, int type);
extern int emcJogStop(int nr, int jjogmode);
extern int emcJogCont(int nr, double vel, int jjogmode);
extern int emcJogIncr(int nr, double incr, double vel, int jjogmode);
extern int emcJogAbs(int nr, double pos, double vel, int jjogmode);
extern int emcJointUpdate(EMC_JOINT_STAT stat[], int numJoints);
extern int emcJointSetMaxJerk(int joint, double jerk);
// implementation functions for EMC_SPINDLE types
extern int emcSpindleSetParams(int spindle, double max_pos, double min_pos, double max_neg,
double min_neg, double search_vel, double home_angle, int sequence, double increment);
// implementation functions for EMC_TRAJ types
extern int emcTrajSetJoints(int joints);
extern int emcTrajUpdateTag(StateTag const &tag);
extern int emcTrajSetAxes(int axismask);
extern int emcTrajSetSpindles(int spindles);
extern int emcTrajSetUnits(double linearUnits, double angularUnits);
extern int emcTrajSetMode(EMC_TRAJ_MODE traj_mode);
extern int emcTrajSetVelocity(double vel, double ini_maxvel);
extern int emcTrajSetAcceleration(double acc);
extern int emcTrajSetMaxVelocity(double vel);
extern int emcTrajSetMaxAcceleration(double acc);
extern int emcTrajSetScale(double scale);
extern int emcTrajSetRapidScale(double scale);
extern int emcTrajSetFOEnable(unsigned char mode); //feed override enable
extern int emcTrajSetFHEnable(unsigned char mode); //feed hold enable
extern int emcTrajSetSpindleScale(int spindle, double scale);
extern int emcTrajSetSOEnable(unsigned char mode); //spindle speed override enable
extern int emcTrajSetAFEnable(unsigned char enable); //adaptive feed enable
extern int emcTrajSetMotionId(int id);
extern double emcTrajGetLinearUnits();
extern double emcTrajGetAngularUnits();
extern int emcTrajInit();
extern int emcTrajHalt();
extern int emcTrajEnable();
extern int emcTrajDisable();
extern int emcTrajAbort();
extern int emcTrajPause();
extern int emcTrajReverse();
extern int emcTrajForward();
extern int emcTrajStep();
extern int emcTrajResume();
extern int emcTrajDelay(double delay);
extern int emcTrajLinearMove(const EmcPose& end, int type, double vel,
double ini_maxvel, double acc, double ini_maxjerk, int indexer_jnum);
extern int emcTrajCircularMove(const EmcPose& end, const PM_CARTESIAN& center, const PM_CARTESIAN&
normal, int turn, int type, double vel, double ini_maxvel, double acc, double ini_maxjerk);
extern int emcTrajSetTermCond(int cond, double tolerance);
extern int emcTrajSetSpindleSync(int spindle, double feed_per_revolution, bool wait_for_index);
extern int emcTrajSetOffset(const EmcPose& tool_offset);
extern int emcTrajSetHome(const EmcPose& home);
extern int emcTrajClearProbeTrippedFlag();
extern int emcTrajProbe(const EmcPose& pos, int type, double vel,
double ini_maxvel, double acc, double ini_maxjerk, unsigned char probe_type);
extern int emcTrajRigidTap(const EmcPose& pos, double vel, double ini_maxvel, double acc, double ini_maxjerk, double scale);
extern int emcTrajUpdate(EMC_TRAJ_STAT * stat);
extern int emcTrajSetJerk(double jerk);
extern int emcTrajSetMaxJerk(double jerk);
extern int emcTrajPlannerType(int type);
// implementation functions for EMC_MOTION aggregate types
extern int emcMotionInit();
extern int emcMotionHalt();
extern int emcMotionAbort();
extern int emcMotionSetDebug(int debug);
extern int emcMotionSetAout(unsigned char index, double start, double end,
unsigned char now);
extern int emcMotionSetDout(unsigned char index, unsigned char start,
unsigned char end, unsigned char now);
extern int emcMotionUpdate(EMC_MOTION_STAT * stat);
extern int emcAbortCleanup(EMC_ABORT reason,const char *message = "");
// implementation functions for EMC_TOOL types
extern int emcToolPrepare(int tool);
extern int emcToolLoad();
extern int emcToolUnload();
extern int emcToolLoadToolTable(const char *file);
extern int emcToolSetOffset(int pocket, int toolno, const EmcPose& offset, double diameter,
double frontangle, double backangle, int orientation);
extern int emcToolSetNumber(int number);
// implementation functions for EMC_AUX types
extern int emcAuxEstopOn();
extern int emcAuxEstopOff();
// implementation functions for EMC_SPINDLE types
extern int emcSpindleAbort(int spindle);
extern int emcSpindleSpeed(int spindle, double speed, double factor, double xoffset);
extern int emcSpindleOn(int spindle, double speed, double factor, double xoffset,int wait_for_atspeed = 1);
extern int emcSpindleOrient(int spindle, double orientation, int direction);
extern int emcSpindleOff(int spindle);
extern int emcSpindleIncrease(int spindle);
extern int emcSpindleDecrease(int spindle);
extern int emcSpindleConstant(int spindle);
extern int emcSpindleBrakeRelease(int spindle);
extern int emcSpindleBrakeEngage(int spindle);
extern int emcSpindleUpdate(EMC_SPINDLE_STAT stat[], int num_spindles);
// implementation functions for EMC_COOLANT types
extern int emcCoolantMistOn();
extern int emcCoolantMistOff();
extern int emcCoolantFloodOn();
extern int emcCoolantFloodOff();
// implementation functions for EMC_IO types
extern int emcIoInit();
extern int emcIoAbort(EMC_ABORT reason);
// implementation functions for EMC aggregate types
int emcSetMaxFeedOverride(double maxFeedScale);
int emcSetupArcBlends(int arcBlendEnable,
int arcBlendFallbackEnable,
int arcBlendOptDepth,
int arcBlendGapCycles,
double arcBlendRampFreq,
double arcBlendTangentKinkRatio);
int emcSetProbeErrorInhibit(int j_inhibit, int h_inhibit);
int emcGetExternalOffsetApplied(void);
EmcPose emcGetExternalOffsets(void);
extern int emcUpdate(EMC_STAT * stat);
// full EMC status
extern EMC_STAT *emcStatus;
// EMC IO status
extern EMC_IO_STAT *emcIoStatus;
// EMC MOTION status
extern EMC_MOTION_STAT *emcMotionStatus;
// values for EMC_JOINT_SET_JOINT, jointType
enum EmcJointType : int {
EMC_LINEAR = 1,
EMC_ANGULAR = 2,
};
/**
* Set the units conversion factor.
* @see EMC_JOINT_SET_INPUT_SCALE
*/
using EmcLinearUnits = double;
using EmcAngularUnits = double;
#endif // #ifndef EMC_HH

View File

@@ -0,0 +1,36 @@
/********************************************************************
* Description: emcpos.h
*
* Derived from a work by Fred Proctor & Will Shackleford
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#ifndef __LINUXCNC_EMCPOS_H
#define __LINUXCNC_EMCPOS_H
#include "posemath.h" /* PmCartesian */
typedef struct EmcPose {
PmCartesian tran;
double a, b, c;
double u, v, w;
} EmcPose;
#define ZERO_EMC_POSE(pos) do { \
(pos).tran.x = 0.0; \
(pos).tran.y = 0.0; \
(pos).tran.z = 0.0; \
(pos).a = 0.0; \
(pos).b = 0.0; \
(pos).c = 0.0; \
(pos).u = 0.0; \
(pos).v = 0.0; \
(pos).w = 0.0; } while(0)
#endif

View File

@@ -0,0 +1,51 @@
/********************************************************************
* Description: emcpose.h
*
* Derived from a work by Fred Proctor & Will Shackleford
*
* Author: Robert W. Ellenberg
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
********************************************************************/
#ifndef __LINUXCNC_EMCPOSE_H
#define __LINUXCNC_EMCPOSE_H
#include "emcpos.h"
typedef enum {
EMCPOSE_ERR_OK = 0,
EMCPOSE_ERR_FAIL = -1,
EMCPOSE_ERR_INPUT_MISSING = -2,
EMCPOSE_ERR_OUTPUT_MISSING = -3,
EMCPOSE_ERR_ALL
} EmcPoseErr;
void emcPoseZero(EmcPose * const pos);
int emcPoseAdd(EmcPose const * const p1, EmcPose const * const p2, EmcPose * const out);
int emcPoseSub(EmcPose const * const p1, EmcPose const * const p2, EmcPose * const out);
int emcPoseToPmCartesian(EmcPose const * const pose,
PmCartesian * const xyz, PmCartesian * const abc, PmCartesian * const uvw);
int pmCartesianToEmcPose(PmCartesian const * const xyz,
PmCartesian const * const abc, PmCartesian const * const uvw, EmcPose * const pose);
int emcPoseSelfAdd(EmcPose * const self, EmcPose const * const p2);
int emcPoseSelfSub(EmcPose * const self, EmcPose const * const p2);
int emcPoseSetXYZ(PmCartesian const * const xyz, EmcPose * const pose);
int emcPoseSetABC(PmCartesian const * const abc, EmcPose * const pose);
int emcPoseSetUVW(PmCartesian const * const uvw, EmcPose * const pose);
int emcPoseGetXYZ(EmcPose const * const pose, PmCartesian * const xyz);
int emcPoseGetABC(EmcPose const * const pose, PmCartesian * const abc);
int emcPoseGetUVW(EmcPose const * const pose, PmCartesian * const uvw);
int emcPoseMagnitude(EmcPose const * const pose, double * const out);
int emcPoseValid(EmcPose const * const pose);
#endif

View File

@@ -0,0 +1,40 @@
// Copyright 2013 Jeff Epler <jepler@unpythonic.net>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#ifndef EMCTOOL_H
#define EMCTOOL_H
#include <emcpos.h>
/* pocketno: 0..(CANON_POCKETS_MAX-1) (0: spindle)
** toolno: no restrictions (0: notool)
*/
#define CANON_POCKETS_MAX 1001 // max size of carousel handled
#define CANON_TOOL_ENTRY_LEN 256 // how long each file line can be
#define CANON_TOOL_COMMENT_SIZE 40 // max comment string (include trailing null)
struct CANON_TOOL_TABLE {
int toolno;
int pocketno;
EmcPose offset;
double diameter;
double frontangle;
double backangle;
int orientation;
char comment[CANON_TOOL_COMMENT_SIZE];
};
#endif

View File

@@ -0,0 +1,40 @@
/********************************************************************
* Description: interp_return.hh
*
* Derived from a work by Thomas Kramer
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2005 All rights reserved.
*
* Last change:
*
* This file declares the public interpreter return values. An
* interpreter may extend this list with return values that are
* used internally within the interpreters own code, but these
* constitute the minimum set.
********************************************************************/
#ifndef INTERP_RETURN_H
#define INTERP_RETURN_H
enum InterpReturn {
INTERP_OK = 0,
INTERP_EXIT = 1,
INTERP_EXECUTE_FINISH = 2,
INTERP_ENDFILE = 3,
INTERP_FILE_NOT_OPEN = 4,
INTERP_ERROR = 5,
};
/*
The return values OK, EXIT, EXECUTE_FINISH, and ENDFILE represent
normal, non-error return conditions. FILE_NOT_OPEN is the first
value that represents an error result. INTERP_MIN_ERROR
is therefore the index of the last non-error return value.
*/
static const InterpReturn INTERP_MIN_ERROR = INTERP_ENDFILE;
#endif /* INTERP_RETURN_H */

View File

@@ -0,0 +1,393 @@
/********************************************************************
* Description: interp_arc.cc
*
* Derived from a work by Thomas Kramer
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <libintl.h>
#include <rtapi_math.h>
#include "rs274ngc.hh"
#include "rs274ngc_return.hh"
#include "rs274ngc_interp.hh"
#include "interp_internal.hh"
#define _(s) gettext(s)
char Interp::arc_axis1(CANON_PLANE plane) {
switch(plane) {
case CANON_PLANE::XY: return 'X';
case CANON_PLANE::XZ: return 'Z';
case CANON_PLANE::YZ: return 'Y';
default: return '!';
}
}
char Interp::arc_axis2(CANON_PLANE plane) {
switch(plane) {
case CANON_PLANE::XY: return 'Y';
case CANON_PLANE::XZ: return 'X';
case CANON_PLANE::YZ: return 'Z';
default: return '!';
}
}
/***********************************************************************/
/*! arc_data_comp_ijk
Returned Value: int
If any of the following errors occur, this returns the error code shown.
Otherwise, it returns INTERP_OK.
1. The two calculable values of the radius differ by more than
tolerance: NCE_RADIUS_TO_END_OF_ARC_DIFFERS_FROM_RADIUS_TO_START
2. move is not G_2 or G_3: NCE_BUG_CODE_NOT_G2_OR_G3
Side effects:
This finds and sets the values of center_x, center_y, and turn.
Called by: convert_arc_comp1
This finds the center coordinates and number of full or partial turns
counterclockwise of a helical or circular arc in ijk-format in the XY
plane. The center is computed easily from the current point and center
offsets, which are given. It is checked that the end point lies one
tool radius from the arc.
*/
int Interp::arc_data_comp_ijk(int move, //!<either G_2 (cw arc) or G_3 (ccw arc)
CANON_PLANE plane, //!<active plane
CUTTER_COMP side, //!<either RIGHT or LEFT
double tool_radius, //!<radius of the tool
double current_x, //!<first coordinate of current point
double current_y, //!<second coordinate of current point
double end_x, //!<first coordinate of arc end point
double end_y, //!<second coordinate of arc end point
int ij_absolute, //!<how to interpret i/j numbers
double i_number, //!<first coordinate of center (abs or incr)
double j_number, //!<second coordinate of center (abs or incr)
int p_number,
double *center_x, //!<pointer to first coordinate of center of arc
double *center_y, //!<pointer to second coordinate of center of arc
int *turn, //!<pointer to number of full or partial circles CCW
double radius_tolerance, //!<minimum radius tolerance
double spiral_abs_tolerance, //!<tolerance of start and end radius difference
double spiral_rel_tolerance)
{
double arc_radius;
double radius2;
char a = arc_axis1(plane), b = arc_axis2(plane);
if ( ij_absolute ) {
*center_x = (i_number);
*center_y = (j_number);
} else {
*center_x = (current_x + i_number);
*center_y = (current_y + j_number);
}
arc_radius = hypot((*center_x - current_x), (*center_y - current_y));
radius2 = hypot((*center_x - end_x), (*center_y - end_y));
CHKS(((arc_radius < radius_tolerance) || (radius2 < radius_tolerance)),
_("Zero-radius arc: "
"start=(%c%.4f,%c%.4f) center=(%c%.4f,%c%.4f) end=(%c%.4f,%c%.4f) r1=%.4f r2=%.4f"),
a, current_x, b, current_y,
a, *center_x, b, *center_y,
a, end_x, b, end_y, arc_radius, radius2);
double abs_err = fabs(arc_radius - radius2);
double rel_err = abs_err / std::max(arc_radius, radius2);
CHKS((abs_err > spiral_abs_tolerance * 100.0) ||
(rel_err > spiral_rel_tolerance && abs_err > spiral_abs_tolerance),
_("Radius to end of arc differs from radius to start: "
"start=(%c%.4f,%c%.4f) center=(%c%.4f,%c%.4f) end=(%c%.4f,%c%.4f) "
"r1=%.4f r2=%.4f abs_err=%.4g rel_err=%.4f%%"),
a, current_x, b, current_y,
a, *center_x, b, *center_y,
a, end_x, b, end_y, arc_radius, radius2,
abs_err, rel_err*100);
CHKS(((arc_radius <= tool_radius) && (((side == CUTTER_COMP::LEFT) && (move == G_3)) ||
((side == CUTTER_COMP::RIGHT) && (move == G_2)))),
NCE_TOOL_RADIUS_NOT_LESS_THAN_ARC_RADIUS_WITH_COMP);
/* This catches an arc too small for the tool, also */
if (move == G_2)
*turn = -1 * p_number;
else if (move == G_3)
*turn = 1 * p_number;
else
ERS(NCE_BUG_CODE_NOT_G2_OR_G3);
return INTERP_OK;
}
/****************************************************************************/
/*! arc_data_comp_r
Returned Value: int
If any of the following errors occur, this returns the error code shown.
Otherwise, it returns INTERP_OK.
1. The arc radius is too small to reach the end point:
NCE_RADIUS_TOO_SMALL_TO_REACH_END_POINT
2. The arc radius is not greater than the tool_radius, but should be:
NCE_TOOL_RADIUS_NOT_LESS_THAN_ARC_RADIUS_WITH_COMP
3. An imaginary value for offset would be found, which should never
happen if the theory is correct: NCE_BUG_IN_TOOL_RADIUS_COMP
Side effects:
This finds and sets the values of center_x, center_y, and turn.
Called by: convert_arc_comp1
This finds the center coordinates and number of full or partial turns
counterclockwise of a helical or circular arc (call it arc1) in
r-format in the XY plane. Arc2 is constructed so that it is tangent
to a circle whose radius is tool_radius and whose center is at the
point (current_x, current_y) and passes through the point (end_x,
end_y). Arc1 has the same center as arc2. The radius of arc1 is one
tool radius larger or smaller than the radius of arc2.
If the value of the big_radius argument is negative, that means [NCMS,
page 21] that an arc larger than a semicircle is to be made.
Otherwise, an arc of a semicircle or less is made.
The algorithm implemented here is to construct a line L from the
current point to the end point, and a perpendicular to it from the
center of the arc which intersects L at point P. Since the distance
from the end point to the center and the distance from the current
point to the center are known, two equations for the length of the
perpendicular can be written. The right sides of the equations can be
set equal to one another and the resulting equation solved for the
length of the line from the current point to P. Then the location of
P, the length of the perpendicular, the angle of the perpendicular,
and the location of the center, can be found in turn.
This needs to be better documented, with figures. There are eight
possible arcs, since there are three binary possibilities: (1) tool
inside or outside arc, (2) clockwise or counterclockwise (3) two
positions for each arc (of the given radius) tangent to the tool
outline and through the end point. All eight are calculated below,
since theta, radius2, and turn may each have two values.
To see two positions for each arc, imagine the arc is a hoop, the
tool is a cylindrical pin, and the arc may rotate around the end point.
The rotation covers all possible positions of the arc. It is easy to
see the hoop is constrained by the pin at two different angles, whether
the pin is inside or outside the hoop.
*/
int Interp::arc_data_comp_r(int move, //!< either G_2 (cw arc) or G_3 (ccw arc)
CANON_PLANE plane,
CUTTER_COMP side, //!< either RIGHT or LEFT
double tool_radius, //!< radius of the tool
double current_x, //!< first coordinate of current point
double current_y, //!< second coordinate of current point
double end_x, //!< first coordinate of arc end point
double end_y, //!< second coordinate of arc end point
double big_radius, //!< radius of arc
int p_number,
double *center_x, //!< pointer to first coordinate of center of arc
double *center_y, //!< pointer to second coordinate of center of arc
int *turn, //!< pointer to number of full or partial circles CCW
double tolerance) //!< tolerance of differing radii
{
double abs_radius; // absolute value of big_radius
abs_radius = fabs(big_radius);
CHKS(((abs_radius <= tool_radius) && (((side == CUTTER_COMP::LEFT) && (move == G_3)) ||
((side == CUTTER_COMP::RIGHT) && (move == G_2)))),
NCE_TOOL_RADIUS_NOT_LESS_THAN_ARC_RADIUS_WITH_COMP);
return arc_data_r(move, plane, current_x, current_y, end_x, end_y, big_radius, p_number,
center_x, center_y, turn, tolerance);
}
/****************************************************************************/
/*! arc_data_ijk
Returned Value: int
If any of the following errors occur, this returns the error code shown.
Otherwise, it returns INTERP_OK.
1. The two calculable values of the radius differ by more than
tolerance: NCE_RADIUS_TO_END_OF_ARC_DIFFERS_FROM_RADIUS_TO_START
2. The move code is not G_2 or G_3: NCE_BUG_CODE_NOT_G2_OR_G3
3. Either of the two calculable values of the radius is zero:
NCE_ZERO_RADIUS_ARC
Side effects:
This finds and sets the values of center_x, center_y, and turn.
Called by:
convert_arc2
convert_arc_comp2
This finds the center coordinates and number of full or partial turns
counterclockwise of a helical or circular arc in ijk-format. This
function is used by convert_arc2 for all three planes, so "x" and
"y" really mean "first_coordinate" and "second_coordinate" wherever
they are used here as suffixes of variable names. The i and j prefixes
are handled similarly.
*/
int Interp::arc_data_ijk(int move, //!< either G_2 (cw arc) or G_3 (ccw arc)
CANON_PLANE plane,
double current_x, //!< first coordinate of current point
double current_y, //!< second coordinate of current point
double end_x, //!< first coordinate of arc end point
double end_y, //!< second coordinate of arc end point
int ij_absolute, //!<how to interpret i/j numbers
double i_number, //!<first coordinate of center (abs or incr)
double j_number, //!<second coordinate of center (abs or incr)
int p_number,
double *center_x, //!< pointer to first coordinate of center of arc
double *center_y, //!< pointer to second coordinate of center of arc
int *turn, //!< pointer to no. of full or partial circles CCW
double radius_tolerance, //!<minimum radius tolerance
double spiral_abs_tolerance, //!<tolerance of start and end radius difference
double spiral_rel_tolerance)
{
double radius; /* radius to current point */
double radius2; /* radius to end point */
char a = arc_axis1(plane), b = arc_axis2(plane);
if ( ij_absolute ) {
*center_x = (i_number);
*center_y = (j_number);
} else {
*center_x = (current_x + i_number);
*center_y = (current_y + j_number);
}
radius = hypot((*center_x - current_x), (*center_y - current_y));
radius2 = hypot((*center_x - end_x), (*center_y - end_y));
CHKS(((radius < radius_tolerance) || (radius2 < radius_tolerance)),_("Zero-radius arc: "
"start=(%c%.4f,%c%.4f) center=(%c%.4f,%c%.4f) end=(%c%.4f,%c%.4f) r1=%.4f r2=%.4f"),
a, current_x, b, current_y,
a, *center_x, b, *center_y,
a, end_x, b, end_y, radius, radius2);
double abs_err = fabs(radius - radius2);
double rel_err = abs_err / std::max(radius, radius2);
CHKS((abs_err > spiral_abs_tolerance * 100.0) ||
(rel_err > spiral_rel_tolerance && abs_err > spiral_abs_tolerance),
_("Radius to end of arc differs from radius to start: "
"start=(%c%.4f,%c%.4f) center=(%c%.4f,%c%.4f) end=(%c%.4f,%c%.4f) "
"r1=%.4f r2=%.4f abs_err=%.4g rel_err=%.4f%%"),
a, current_x, b, current_y,
a, *center_x, b, *center_y,
a, end_x, b, end_y, radius, radius2,
abs_err, rel_err*100);
if (move == G_2)
*turn = -1 * p_number;
else if (move == G_3)
*turn = 1 * p_number;
else
ERS(NCE_BUG_CODE_NOT_G2_OR_G3);
return INTERP_OK;
}
/****************************************************************************/
/*! arc_data_r
Returned Value: int
If any of the following errors occur, this returns the error shown.
Otherwise, it returns INTERP_OK.
1. The radius is too small to reach the end point:
NCE_ARC_RADIUS_TOO_SMALL_TO_REACH_END_POINT
2. The current point is the same as the end point of the arc
(so that it is not possible to locate the center of the circle):
NCE_CURRENT_POINT_SAME_AS_END_POINT_OF_ARC
Side effects:
This finds and sets the values of center_x, center_y, and turn.
Called by:
convert_arc2
convert_arc_comp2
This finds the center coordinates and number of full or partial turns
counterclockwise of a helical or circular arc in the r format. This
function is used by convert_arc2 for all three planes, so "x" and
"y" really mean "first_coordinate" and "second_coordinate" wherever
they are used here as suffixes of variable names.
If the value of the radius argument is negative, that means [NCMS,
page 21] that an arc larger than a semicircle is to be made.
Otherwise, an arc of a semicircle or less is made.
The algorithm used here is based on finding the midpoint M of the line
L between the current point and the end point of the arc. The center
of the arc lies on a line through M perpendicular to L.
*/
int Interp::arc_data_r(int move, //!< either G_2 (cw arc) or G_3 (ccw arc)
CANON_PLANE /*plane*/,
double current_x, //!< first coordinate of current point
double current_y, //!< second coordinate of current point
double end_x, //!< first coordinate of arc end point
double end_y, //!< second coordinate of arc end point
double radius, //!< radius of arc
int p_number,
double *center_x, //!< pointer to first coordinate of center of arc
double *center_y, //!< pointer to second coordinate of center of arc
int *turn, //!< pointer to number of full or partial circles CCW
double tolerance) //!< tolerance of differing radii
{
double abs_radius; /* absolute value of given radius */
double half_length; /* distance from M to end point */
double mid_x; /* first coordinate of M */
double mid_y; /* second coordinate of M */
double offset; /* distance from M to center */
double theta; /* angle of line from M to center */
double turn2; /* absolute value of half of turn */
CHKS(((end_x == current_x) && (end_y == current_y)),
NCE_CURRENT_POINT_SAME_AS_END_POINT_OF_ARC);
abs_radius = fabs(radius);
mid_x = (end_x + current_x) / 2.0;
mid_y = (end_y + current_y) / 2.0;
half_length = hypot((mid_x - end_x), (mid_y - end_y));
CHKS(((half_length - abs_radius) > tolerance),
NCE_ARC_RADIUS_TOO_SMALL_TO_REACH_END_POINT);
if ((half_length / abs_radius) > (1 - TINY))
half_length = abs_radius; /* allow a small error for semicircle */
/* check needed before calling asin */
if (((move == G_2) && (radius > 0)) || ((move == G_3) && (radius < 0)))
theta = atan2((end_y - current_y), (end_x - current_x)) - M_PI_2l;
else
theta = atan2((end_y - current_y), (end_x - current_x)) + M_PI_2l;
turn2 = asin(half_length / abs_radius);
offset = abs_radius * cos(turn2);
*center_x = mid_x + (offset * cos(theta));
*center_y = mid_y + (offset * sin(theta));
*turn = (move == G_2) ? -1 * p_number : 1 * p_number;
return INTERP_OK;
}

View File

@@ -0,0 +1,309 @@
/********************************************************************
* Description: interp_array.cc
*
* This file just allocates space for the static arrays used by the
* interpreter.
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
********************************************************************/
#include "rs274ngc_return.hh"
#include "rs274ngc_interp.hh"
using namespace interp_param_global;
/* Interpreter arrays for g_codes and m_codes. The nth entry
in each array is the modal group number corresponding to the nth
code. Entries which are -1 represent illegal codes. Remember g_codes
in this interpreter are multiplied by 10.
The modal g groups and group numbers defined in [NCMS, pages 71 - 73]
(see also [Fanuc, pages 43 - 45]) are used here, except the canned
cycles (g80 - g89), which comprise modal g group 9 in [Fanuc], are
treated here as being in the same modal group (group 1) with the
straight moves and arcs (g0, g1, g2,g3). [Fanuc, page 45] says only
one g_code from any one group may appear on a line, and we are
following that rule. The straight_probe move, g38.2, is in group 1; it
is not defined in [NCMS].
Some g_codes are non-modal (g4, g10, g28, g30, g53, g92, g92.1, g92.2,
and g92.3 here - many more in [NCMS]). [Fanuc] and [NCMS] put all
these in the same group 0, so we do also. Logically, there are two
subgroups, those which require coordinate values (g10, g28, g30, and
g92) and those which do not (g4, g53, g92.1, g92.2, and g92.3).
The subgroups are identified by itemization when necessary.
Those in group 0 which require coordinate values may not be on the
same line as those in group 1 (except g80) because they would be
competing for the coordinate values. Others in group 0 may be used on
the same line as those in group 1.
A total of 52 G-codes are implemented.
The groups are:
group 0 = {g4,g10,g28,g30,g52,g53,g92,g92.1,g92.2,g92.3} - NON-MODAL
dwell, setup, return to ref1, return to ref2,
local coordinate system, motion in machine coordinates,
set and unset axis offsets
group 1 = {g0,g1,g2,g3,g33,g33.1,g38.2,g38.3,g38.4,g38.5,
g70,g71,g71.1,g71.2,g72,g72.1,g72.2,
g73,g76,g80,
g81,g82,g83,g84,g85,g86,g87,g88,g89} - motion
group 2 = {g17,g17.1,g18,g18.1,g19,g19.1} - plane selection
group 3 = {g90,g91} - distance mode
group 4 = {g90.1,g91.1} - arc IJK distance mode
group 5 = {g93,g94,g95} - feed rate mode
group 6 = {g20,g21} - units
group 7 = {g40,g41,g42} - cutter diameter compensation
group 8 = {g43,g49} - tool length offset
group 10 = {g98,g99} - return mode in canned cycles
group 12 = {g54,g55,g56,g57,g58,g59,g59.1,g59.2,g59.3} - coordinate system
group 13 = {g61,g61.1,g64} - control mode (path following)
group 14 = {g96,g97} - spindle speed mode
group 15 = {G07,G08} - lathe diameter mode
group 16 = {g92.2,g92.3} - whether g92 offset is applied
*/
// This stops indent from reformatting the following code.
// *INDENT-OFF*
const int Interp::gees[] = {
/* 0 */ 1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 20 */ 1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 40 */ //0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 40 */ 0,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1, 1, 0,-1,-1,-1,-1,-1,-1,
/* 60 */ 1, 1, 1, 0,-1,-1,-1,-1,-1,-1,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, // jjf added G6
/* 80 */ 15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 100 */ 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 120 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 140 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 160 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 2, 2,-1,-1,-1,-1,-1,-1,-1,-1,
/* 180 */ 2, 2,-1,-1,-1,-1,-1,-1,-1,-1, 2, 2,-1,-1,-1,-1,-1,-1,-1,-1,
/* 200 */ 6,-1,-1,-1,-1,-1,-1,-1,-1,-1, 6,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 220 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 240 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 260 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 280 */ 0, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 300 */ 0, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 320 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 340 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 360 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 380 */ -1,-1, 1, 1, 1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 400 */ 7,-1,-1,-1,-1,-1,-1,-1,-1,-1, 7, 7,-1,-1,-1,-1,-1,-1,-1,-1,
/* 420 */ 7, 7,-1,-1,-1,-1,-1,-1,-1,-1, 8, 8, 8,-1,-1,-1,-1,-1,-1,-1,
/* 440 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 460 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 480 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 8,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 500 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 520 */ 0,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 540 */ 12,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 560 */ 12,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 580 */ 12,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,12,12,12,-1,-1,-1,-1,-1,-1,
/* 600 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,13,13,-1,-1,-1,-1,-1,-1,-1,-1,
/* 620 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 640 */ 13,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 660 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 680 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 700 */ 1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1, 1,-1,-1,-1,-1,-1,-1,-1,
/* 720 */ 1, 1, 1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 740 */ 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 760 */ 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 780 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 800 */ 1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 820 */ 1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 840 */ 1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 860 */ 1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 880 */ 1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 900 */ 3, 4,-1,-1,-1,-1,-1,-1,-1,-1, 3, 4,-1,-1,-1,-1,-1,-1,-1,-1,
/* 920 */ 0,16,16,16,-1,-1,-1,-1,-1,-1, 5,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 940 */ 5,-1,-1,-1,-1,-1,-1,-1,-1,-1, 5,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 960 */ 14,-1,-1,-1,-1,-1,-1,-1,-1,-1,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,
/* 980 */ 10,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,-1,-1,-1,-1,-1,-1,-1,-1,-1};
/*
Modal groups and modal group numbers for M codes are not described in
[Fanuc]. We have used the groups from [NCMS] and added M60, as an
extension of the language for pallet shuttle and stop. This version has
no codes related to axis clamping.
The groups are:
group 4 = {m0,m1,m2,m30,m60,
m99} - stopping
group 5 = {m62,m63,m64,m65, - turn I/O point on/off
m66} - wait for Input
group 6 = {m6,m61} - tool change
group 7 = {m3,m4,m5,m19} - spindle turning, orient
group 8 = {m7,m8,m9} - coolant
group 9 = {m48,m49, - feed and speed override switch bypass
m50, - feed override switch bypass P1 to turn on, P0 to turn off
m51, - spindle speed override switch bypass P1 to turn on, P0 to turn off
m52, - adaptive feed override switch bypass P1 to turn on, P0 to turn off
m53} - feedstop override switch bypass P1 to turn on, P0 to turn off
group 10 = {m100..m199} - user-defined
*/
const int Interp::ems[] = {
4, 4, 4, 7, 7, 7, 6, 8, 8, 8, // 9
-1, -1, -1, -1, -1, -1, -1, -1, -1, 7, // 19
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 29
4, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 39
-1, -1, -1, -1, -1, -1, -1, -1, 9, 9, // 49
9, 9, 9, 9, -1, -1, -1, -1, -1, -1, // 59
4, 6, 5, 5, 5, 5, 5, 5, 5, -1, // 69
7, 7, 7, 7, -1, -1, -1, -1, -1, -1, // 79
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 89
-1, -1, -1, -1, -1, -1, -1, -1, -1, 4, // 99
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, //109
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, //119
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, //129
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, //139
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, //149
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, //159
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, //169
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, //179
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, //189
10, 10, 10, 10, 10, 10, 10, 10, 10, 10};//199
/*
This is an array of the index numbers of system parameters that must
be included in a file used with the Interp::restore_parameters
function. The array is used by that function and by the
Interp::save_parameters function.
*/
const int Interp::required_parameters[] = {
5161, 5162, 5163, /* G28 home */
5164, 5165, 5166, /* A, B, & C */
5167, 5168, 5169, /* U, V, & W */
5181, 5182, 5183, /* G30 home */
5184, 5185, 5186, /* A, B, & C */
5187, 5188, 5189, /* U, V, & W */
5210, /* G92 is currently applied */
5211, 5212, 5213, /* G92 offsets */
5214, 5215, 5216, /* A, B, & C */
5217, 5218, 5219, /* U, V, & W */
5220, /* selected coordinate */
5221, 5222, 5223, /* coordinate system 1 */
5224, 5225, 5226, /* A, B, & C */
5227, 5228, 5229, /* U, V, & W */
5230,
5241, 5242, 5243, /* coordinate system 2 */
5244, 5245, 5246, /* A, B, & C */
5247, 5248, 5249, /* U, V, & W */
5250,
5261, 5262, 5263, /* coordinate system 3 */
5264, 5265, 5266, /* A, B, & C */
5267, 5268, 5269, /* U, V, & W */
5270,
5281, 5282, 5283, /* coordinate system 4 */
5284, 5285, 5286, /* A, B, & C */
5287, 5288, 5289, /* U, V, & W */
5290,
5301, 5302, 5303, /* coordinate system 5 */
5304, 5305, 5306, /* A, B, & C */
5307, 5308, 5309, /* U, V, & W */
5310,
5321, 5322, 5323, /* coordinate system 6 */
5324, 5325, 5326, /* A, B, & C */
5327, 5328, 5329, /* U, V, & W */
5330,
5341, 5342, 5343, /* coordinate system 7 */
5344, 5345, 5346, /* A, B, & C */
5347, 5348, 5349, /* U, V, & W */
5350,
5361, 5362, 5363, /* coordinate system 8 */
5364, 5365, 5366, /* A, B, & C */
5367, 5368, 5369, /* U, V, & W */
5370,
5381, 5382, 5383, /* coordinate system 9 */
5384, 5385, 5386, /* A, B, & C */
5387, 5388, 5389, /* U, V, & W */
5390,
RS274NGC_MAX_PARAMETERS
};
const int Interp::readonly_parameters[] = {
5400, // tool toolno
5401, // tool x offset
5402, // tool y offset
5403, // tool z offset
5404, // tool a offset
5405, // tool b offset
5406, // tool c offset
5407, // tool u offset
5408, // tool v offset
5409, // tool w offset
5410, // tool diameter
5411, // tool frontangle
5412, // tool backangle
5413, // tool orientation
5420, 5421, 5422, 5423, 5424, 5425, 5426, 5427, 5428, // current X Y ... W
};
const int Interp::n_readonly_parameters = sizeof(readonly_parameters) / sizeof(int);
/* _readers is an array of pointers to functions that read.
It is used by read_one_item.
Each read function is placed in the array according to the ASCII character it
corresponds to. Whilst a switch statement could have been used in read_one_item,
using an array of function pointers allows a new read_foo to be added quickly
in this one table.
At some point, it may be advantageous to add a read_$ or read_n for perhaps
macro or jump labels..
*/
const read_function_pointer Interp::default_readers[256] = {
/* 00 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 10 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 20 */
0, 0, 0,
&Interp::read_parameter_setting, // reads # or ASCII 0x23
&Interp::read_dollar, // reads $ or ASCII 0x24
0, 0, 0,
&Interp::read_comment, // reads ( or ASCII 0x28
0, 0, 0, 0, 0, 0, 0,
/* 30 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
&Interp::read_semicolon,
0, 0, 0, 0,
/* 40 */
&Interp::read_atsign, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 50 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &Interp::read_carat, 0,
/* 60 */
0,
&Interp::read_a, // reads a or ASCII 0x61
&Interp::read_b, // reads b or ASCII 0x62
&Interp::read_c, // reads c or ASCII 0x63
&Interp::read_d, // reads d or ASCII 0x64
&Interp::read_e, // reads d or ASCII 0x65
&Interp::read_f, // reads f or ASCII 0x66
&Interp::read_g, // reads g or ASCII 0x67
&Interp::read_h, // reads h or ASCII 0x68
&Interp::read_i, // reads i or ASCII 0x69
&Interp::read_j, // reads j or ASCII 0x6A
&Interp::read_k, // reads k or ASCII 0x6B
&Interp::read_l, // reads l or ASCII 0x6C
&Interp::read_m, // reads m or ASCII 0x6D
0, 0,
&Interp::read_p, // reads p or ASCII 0x70
&Interp::read_q, // reads q or ASCII 0x71
&Interp::read_r, // reads r or ASCII 0x72
&Interp::read_s, // reads s or ASCII 0x73
&Interp::read_t, // reads t or ASCII 0x74
&Interp::read_u,
&Interp::read_v,
&Interp::read_w,
&Interp::read_x, // reads x or ASCII 0x78
&Interp::read_y, // reads y or ASCII 0x79
&Interp::read_z}; // reads z or ASCII 0x7A
// *INDENT-ON*
// And now indent can continue.
/****************************************************************************/

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2013 Jeff Epler <jepler@unpythonic.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "interp_base.hh"
#include <dlfcn.h>
#include <limits.h>
#include <config.h>
#include <stdio.h>
InterpBase::~InterpBase() {}
InterpBase *interp_from_shlib(const char *shlib) {
void * interp_lib;
char relative_interp[PATH_MAX];
char const * interp_path;
dlopen(NULL, RTLD_GLOBAL);
if (shlib[0] == '/') {
// The passed-in .so name is an absolute path, use it directly.
interp_path = shlib;
} else {
// The passed-in .so name is a relative path or just a bare
// filename, look for it in `${EMC2_HOME}/lib/linuxcnc`.
snprintf(relative_interp, sizeof(relative_interp), "%s/%s", EMC2_HOME "/lib/linuxcnc", shlib);
interp_path = relative_interp;
}
interp_lib = dlopen(interp_path, RTLD_NOW);
if(!interp_lib) {
fprintf(stderr, "emcTaskInit: could not open interpreter '%s': %s\n", interp_path, dlerror());
return 0;
}
fprintf(stderr, "emcTaskInit: using custom interpreter '%s'\n", interp_path);
typedef InterpBase* (*Constructor)();
Constructor constructor = (Constructor)dlsym(interp_lib, "makeInterp");
if(!constructor) {
fprintf(stderr, "emcTaskInit: could not get symbol makeInterp from interpreter '%s': %s\n", shlib, dlerror());
return 0;
}
InterpBase *pinterp = constructor();
if(!pinterp) {
fprintf(stderr, "emcTaskInit: makeInterp() returned NULL from interpreter '%s'\n", shlib);
return 0;
}
return pinterp;
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2013 Jeff Epler <jepler@unpythonic.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef INTERP_BASE_HH
#define INTERP_BASE_HH
#include <stdio.h>
#include <stdlib.h>
#include <boost/noncopyable.hpp>
#include <emcpos.h>
#include "modal_state.hh"
/* Size of certain arrays */
#define ACTIVE_G_CODES 17
#define ACTIVE_M_CODES 10
#define ACTIVE_SETTINGS 5
class InterpBase : boost::noncopyable {
public:
virtual ~InterpBase();
virtual char *error_text(int errcode, char *buf, size_t buflen) = 0;
virtual char *line_text(char *buf, size_t buflen) = 0;
virtual char *file_name(char *buf, size_t buflen) = 0;
virtual char *stack_name(int index, char *buf, size_t buflen) = 0;
virtual size_t line_length() = 0;
virtual int sequence_number() = 0;
virtual int ini_load(const char *inifile) = 0;
virtual int init() = 0;
virtual int execute() = 0;
virtual int execute(const char *line) = 0;
virtual int execute(const char *line, int line_number) = 0;
virtual int synch() = 0;
virtual int exit() = 0;
virtual int open(const char *filename) = 0;
virtual int read() = 0;
virtual int read(const char *line) = 0;
virtual int close() = 0;
virtual int reset() = 0;
virtual int line() = 0;
virtual int call_level() = 0;
virtual char *command(char *buf, size_t buflen) = 0;
virtual char *file(char *buf, size_t buflen) = 0;
virtual int on_abort(int reason, const char *message) = 0;
virtual void active_g_codes(int active_gcodes[ACTIVE_G_CODES]) = 0;
virtual void active_m_codes(int active_mcodes[ACTIVE_M_CODES]) = 0;
virtual void active_settings(double active_settings[ACTIVE_SETTINGS]) = 0;
virtual int active_modes(int g_codes[ACTIVE_G_CODES],
int m_codes[ACTIVE_M_CODES],
double settings[ACTIVE_SETTINGS],
StateTag const &tag) = 0;
virtual int restore_from_tag(StateTag const &tag) = 0;
virtual void print_state_tag(StateTag const &tag) = 0;
virtual void set_loglevel(int level) = 0;
virtual void set_loop_on_main_m99(bool state) = 0;
virtual FILE* get_stdout() { return stdout; };
};
InterpBase *interp_from_shlib(const char *shlib);
extern "C" InterpBase *makeInterp();
#endif

View File

@@ -0,0 +1,389 @@
/********************************************************************
* Description: interp_check.cc
*
* Derived from a work by Thomas Kramer
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "rs274ngc.hh"
#include "rs274ngc_return.hh"
#include "interp_internal.hh"
#include "rs274ngc_interp.hh"
/****************************************************************************/
/*! check_g_codes
Returned Value: int
If any of the following errors occur, this returns the error shown.
Otherwise, it returns INTERP_OK.
1. NCE_DWELL_TIME_MISSING_WITH_G4
2. NCE_MUST_USE_G0_OR_G1_WITH_G53
3. NCE_CANNOT_USE_G53_INCREMENTAL
4. NCE_LINE_WITH_G10_DOES_NOT_HAVE_L2
5. NCE_P_VALUE_NOT_AN_INTEGER_WITH_G10_L2
6. NCE_P_VALUE_OUT_OF_RANGE_WITH_G10_L2
7. NCE_BUG_BAD_G_CODE_MODAL_GROUP_0
Side effects: none
Called by: check_items
This runs checks on g_codes from a block of RS274/NGC instructions.
Currently, all checks are on g_codes in modal group 0.
The read_g function checks for errors which would foul up the reading.
The enhance_block function checks for logical errors in the use of
axis values by G-codes in modal groups 0 and 1.
This function checks for additional logical errors in g_codes.
[Fanuc, page 45, note 4] says there is no maximum for how many g_codes
may be put on the same line, [NCMS] says nothing one way or the other,
so the test for that is not used.
We are suspending any implicit motion g_code when a g_code from our
group 0 is used. The implicit motion g_code takes effect again
automatically after the line on which the group 0 g_code occurs. It
is not clear what the intent of [Fanuc] is in this regard. The
alternative is to require that any implicit motion be explicitly
cancelled.
Not all checks on g_codes are included here. Those checks that are
sensitive to whether other g_codes on the same line have been executed
yet are made by the functions called by convert_g.
Our reference sources differ regarding what codes may be used for
dwell time. [Fanuc, page 58] says use "p" or "x". [NCMS, page 23] says
use "p", "x", or "u". We are allowing "p" only, since it is consistent
with both sources and "x" would be confusing. However, "p" is also used
with G10, where it must be an integer, so reading "p" values is a bit
more trouble than would be nice.
*/
int Interp::check_g_codes(block_pointer block, //!< pointer to a block to be checked
setup_pointer settings) //!< pointer to machine settings
{
int mode0, mode1;
int p_int;
mode0 = block->g_modes[GM_MODAL_0];
mode1 = block->g_modes[GM_MOTION];
if (mode0 == -1) {
} else if (mode0 == G_4) {
CHKS((block->p_number == -1.0), NCE_DWELL_TIME_MISSING_WITH_G4);
CHKS((mode1 == G_2 || mode1 == G_3), _("G4 not allowed with G2 or G3 because they both use P"));
} else if (mode0 == G_10) {
(block->p_number >= 0) ? p_int = (int) (block->p_number +0.5) :p_int = (int) (block->p_number -0.5);
CHKS((block->l_number != 0 && block->l_number != 2 && block->l_number != 1 && block->l_number != 20 && block->l_number != 10 && block->l_number != 11), _("Line with G10 does not have L0, L1, L10, L11, L2, or L20"));
CHKS((((block->p_number + 0.0001) - p_int) > 0.0002), _("P value not an integer with G10"));
CHKS((((block->l_number == 2 || block->l_number == 20) && ((p_int < 0) || (p_int > 9)))), _("P value out of range (0-9) with G10 L%d"), block->l_number);
CHKS((((block->l_number == 1 || block->l_number == 10 || block->l_number == 11) && p_int < 1)), _("P value out of range with G10 L%d"), block->l_number);
} else if (mode0 == G_28) {
} else if (mode0 == G_30) {
} else if (mode0 == G_5_3) {
CHKS(((mode1 != G_5_2) && (mode1 != -1)), _("Between G5.2 and G5.3 codes, only additional G5.2 codes are allowed."));
} else if (mode1 == G_5_2){
} else if (mode1 == G_6_2){
} else if (mode0 == G_28_1 || mode0 == G_30_1) {
} else if (mode0 == G_52) {
} else if (mode0 == G_53) {
CHKS(((block->motion_to_be != G_0) && (block->motion_to_be != G_1)),
NCE_MUST_USE_G0_OR_G1_WITH_G53);
CHKS(((block->g_modes[GM_DISTANCE_MODE] == G_91) ||
((block->g_modes[GM_DISTANCE_MODE] != G_90) &&
(settings->distance_mode == DISTANCE_MODE::INCREMENTAL))),
NCE_CANNOT_USE_G53_INCREMENTAL);
} else if (mode0 == G_92) {
} else
ERS(NCE_BUG_BAD_G_CODE_MODAL_GROUP_0);
return INTERP_OK;
}
/****************************************************************************/
/*! check_items
Returned Value: int
If any one of check_g_codes, check_m_codes, and check_other_codes
returns an error code, this returns that code.
Otherwise, it returns INTERP_OK.
Side effects: none
Called by: parse_line
This runs checks on a block of RS274 code.
The functions named read_XXXX check for errors which would foul up the
reading. This function checks for additional logical errors.
A block has an array of g_codes, which are initialized to -1
(meaning no code). This calls check_g_codes to check the g_codes.
A block has an array of m_codes, which are initialized to -1
(meaning no code). This calls check_m_codes to check the m_codes.
Items in the block which are not m or g codes are checked by
check_other_codes.
*/
int Interp::check_items(block_pointer block, //!< pointer to a block to be checked
setup_pointer settings) //!< pointer to machine settings
{
CHP(check_g_codes(block, settings));
CHP(check_m_codes(block));
CHP(check_other_codes(block));
return INTERP_OK;
}
/****************************************************************************/
/*! check_m_codes
Returned Value: int
If any of the following errors occur, this returns the error code shown.
Otherwise, it returns INTERP_OK.
1. There are too many m codes in the block: NCE_TOO_MANY_M_CODES_ON_LINE
Side effects: none
Called by: check_items
This runs checks on m_codes from a block of RS274/NGC instructions.
The read_m function checks for errors which would foul up the
reading. This function checks for additional errors in m_codes.
*/
int Interp::check_m_codes(block_pointer block) //!< pointer to a block to be checked
{
CHKS((block->m_count > MAX_EMS), NCE_TOO_MANY_M_CODES_ON_LINE);
return INTERP_OK;
}
/****************************************************************************/
/*! check_other_codes
Returned Value: int
If any of the following errors occur, this returns the error code shown.
Otherwise, it returns INTERP_OK.
1. An A-axis value is given with a canned cycle (g80 to g89):
NCE_CANNOT_PUT_AN_A_IN_CANNED_CYCLE
2. A B-axis value is given with a canned cycle (g80 to g89):
NCE_CANNOT_PUT_A_B_IN_CANNED_CYCLE
3. A C-axis value is given with a canned cycle (g80 to g89):
NCE_CANNOT_PUT_A_C_IN_CANNED_CYCLE
4. A d word is in a block with no cutter_radius_compensation_on command:
NCE_D_WORD_WITH_NO_G41_OR_G42
5. An h_number is in a block with no tool length offset setting:
NCE_H_WORD_WITH_NO_G43
6. An i_number is in a block with no G-code that uses it:
NCE_I_WORD_WITH_NO_G2_OR_G3_OR_G87_TO_USE_IT
7. A j_number is in a block with no G-code that uses it:
NCE_J_WORD_WITH_NO_G2_OR_G3_OR_G87_TO_USE_IT
8. A k_number is in a block with no G-code that uses it:
NCE_K_WORD_WITH_NO_G2_OR_G3_OR_G87_TO_USE_IT
9. A l_number is in a block with no G-code that uses it:
NCE_L_WORD_WITH_NO_CANNED_CYCLE_OR_G10
10. A p_number is in a block with no G-code that uses it:
NCE_P_WORD_WITH_NO_G4_G10_G64_G82_G86_G88_G89
11. A q_number is in a block with no G-code that uses it:
NCE_Q_WORD_WITH_NO_G83_OR_M66
12. An r_number is in a block with no G-code that uses it:
NCE_R_WORD_WITH_NO_G_CODE_THAT_USES_IT
13. A k word is missing from a G33 block:
NCE_K_WORD_MISSING_WITH_G33
14. An e word is in a block with no G76 or M66 to use it:
NCE_E_WORD_WITH_NO_G76_OR_M66_TO_USE_IT
Side effects: none
Called by: check_items
This runs checks on codes from a block of RS274/NGC code which are
not m or g codes.
The functions named read_XXXX check for errors which would foul up the
reading. This function checks for additional logical errors in codes.
*/
int Interp::check_other_codes(block_pointer block) //!< pointer to a block of RS274/NGC instructions
{
int motion;
motion = block->motion_to_be;
// bypass ALL checks, argspec takes care of that
if (is_user_defined_g_code(motion)) {
return INTERP_OK;
}
// bypass ALL checks, argspec takes care of that
if (is_any_m_code_remapped(block, &(_setup))) {
return INTERP_OK;
}
if (block->a_flag) {
CHKS(is_a_cycle(motion), NCE_CANNOT_PUT_AN_A_IN_CANNED_CYCLE);
}
if (block->b_flag) {
CHKS(is_a_cycle(motion), NCE_CANNOT_PUT_A_B_IN_CANNED_CYCLE);
}
if (block->c_flag) {
CHKS(is_a_cycle(motion), NCE_CANNOT_PUT_A_C_IN_CANNED_CYCLE);
}
if (block->d_flag) {
CHKS(((block->g_modes[7] != G_41) && (block->g_modes[7] != G_42) &&
(block->g_modes[7] != G_41_1) && (block->g_modes[7] != G_42_1) &&
(motion != G_70) && (motion != G_71) && (motion != G_71_1) &&
(motion != G_71_2) && (motion != G_72) && (motion != G_72_1) &&
(motion != G_72_2) && (motion != G_73) && (motion != G_83) &&
(block->g_modes[14] != G_96)),
_("D word with no G41, G41.1, G42, G42.1, G71, G71.1, G71.2 G73, G83 or G96 to use it"));
}
if (block->dollar_flag) {
CHKS(((motion != G_76) && (motion != G_33) && (motion != G_33_1) &&
(block->g_modes[GM_FEED_MODE] != G_95) &&
(block->g_modes[GM_SPINDLE_MODE] != G_96) &&
(block->g_modes[GM_SPINDLE_MODE] != G_97) &&
(block->m_modes[7] != 3) && (block->m_modes[7] != 4) &&
(block->m_modes[7] != 5) && (block->m_modes[7] != 19) &&
(block->m_modes[9] != 51) && (! block->s_flag)),
_("$ (spindle selection) word with no M3, M4, M5, M19, M51, G33, G33.1, G76, G95, G96 or G97 to use it"));
}
if (block->e_flag) {
CHKS(((motion != G_76) && (motion != G_33) && (motion != G_33_1) &&
(motion != G_70) && (block->m_modes[5] != 66) &&
(block->m_modes[5] != 67) && (block->m_modes[5] != 68)),
_("E word with no G70, G76, M66, M67 or M68 to use it"));
}
if (block->h_flag) {
CHKS((block->g_modes[GM_TOOL_LENGTH_OFFSET] != G_43 && motion != G_76 && block->g_modes[GM_TOOL_LENGTH_OFFSET] != G_43_2),
_("H word with no G43 or G76 to use it"));
}
if (block->i_flag) { /* could still be useless if yz_plane arc */
CHKS(((motion != G_2) && (motion != G_3) && (motion != G_5) && (motion != G_5_1) &&
(motion != G_6) && (motion != G_6_1) &&
(motion != G_71) && (motion != G_71_1) && (motion != G_71_2) &&
(motion != G_72) && (motion != G_72_1) && (motion != G_72_2) &&
(motion != G_76) && (motion != G_87) && (motion != G_33_1) && (block->g_modes[GM_MODAL_0] != G_10)),
_("I word with no G2, G3, G5, G5.1, G6, G6.1, G10, G33.1, G76, or G87 to use it"));
}
if (block->j_flag) { /* could still be useless if xz_plane arc */
CHKS(((motion != G_2) && (motion != G_3) && (motion != G_5) && (motion != G_5_1) &&
(motion != G_6) && (motion != G_6_1) &&
(motion != G_76) && (motion != G_87) && (block->g_modes[GM_MODAL_0] != G_10)),
_("J word with no G2, G3, G5, G5.1, G6, G6.1, G10, G76 or G87 to use it"));
}
if (block->k_flag) { /* could still be useless if xy_plane arc */
CHKS(((motion != G_2) && (motion != G_3) && (motion != G_6_2) && (motion != G_33) && (motion != G_33_1) && (motion != G_76) && (motion != G_87)),
_("K word with no G2, G3, G6.2, G33, G33.1, G76, or G87 to use it"));
}
if (block->l_number != -1) {
CHKS((((motion < G_81) || (motion > G_89)) && (motion != G_76) &&
(motion != G_5_2) && (motion != G_6_2) && (motion != G_73) &&
(block->g_modes[GM_MODAL_0] != G_10) &&
(block->g_modes[GM_CUTTER_COMP] != G_41) && (block->g_modes[GM_CUTTER_COMP] != G_41_1) &&
(block->g_modes[GM_CUTTER_COMP] != G_42) && (block->g_modes[GM_CUTTER_COMP] != G_42_1) &&
(block->m_modes[5] != 66) &&
(block->o_type != M_98) // m98 repeat
),
_("L word with no G10, cutter compensation, canned cycle, "
"digital/analog input, M98 or NURBS code"));
}
if (block->p_flag) {
CHKS(((block->g_modes[GM_MODAL_0] != G_10) && (block->g_modes[GM_MODAL_0] != G_4) && (block->g_modes[GM_CONTROL_MODE] != G_64) &&
(motion != G_76) && (motion != G_82) && (motion != G_86) && (motion != G_88) &&
(motion != G_89) && (motion != G_5) && (motion != G_5_2) &&
(motion != G_70) &&
(motion != G_6) && (motion != G_6_2) &&
(motion != G_2) && (motion != G_3) &&
(motion != G_74) && (motion != G_84) &&
(block->m_modes[9] != 50) && (block->m_modes[9] != 51) && (block->m_modes[9] != 52) &&
(block->m_modes[9] != 53) && (block->m_modes[5] != 62) && (block->m_modes[5] != 63) &&
(block->m_modes[5] != 64) && (block->m_modes[5] != 65) && (block->m_modes[5] != 66) &&
(block->m_modes[7] != 19) && (block->user_m != 1) &&
(block->o_type != M_98)),
_("P word with no G2 G3 G4 G10 G64 G5 G5.2 G6, G6.2, G76 G82 G86 G88 G89"
" or M50 M51 M52 M53 M62 M63 M64 M65 M66 M98 "
"or user M code to use it"));
int p_value = round_to_int(block->p_number);
CHKS(((motion == G_2 || motion == G_3 || (block->m_modes[7] == 19)) &&
fabs(p_value - block->p_number) > 0.001),
_("P value not an integer with M19 G2 or G3"));
CHKS((block->m_modes[7] == 19) && ((p_value > 2) || p_value < 0),
_("P value must be 0,1,or 2 with M19"));
CHKS(((motion == G_2 || motion == G_3) && round_to_int(block->p_number) < 1),
_("P value should be 1 or greater with G2 or G3"));
}
if (block->q_number != -1.0) {
CHKS((motion != G_83) && (motion != G_73) && (motion != G_5) && (motion != G_6) && (motion != G_6_2) && (block->user_m != 1) && (motion != G_76) &&
(block->m_modes[5] != 66) && (block->m_modes[5] != 67) && (block->m_modes[5] != 68) &&
(block->g_modes[GM_MODAL_0] != G_10) && (block->m_modes[6] != 61) && (block->g_modes[GM_CONTROL_MODE] != G_64) &&
(motion != G_70) &&
(motion != G_71) && (motion != G_71_1) && (motion != G_71_2) &&
(motion != G_72) && (motion != G_72_1) && (motion != G_72_2) &&
(block->m_modes[7] != 19),
_("Q word with no G5, G6, G10, G64, G73, G76, G83, M19, M66, M67, M68 or user M code that uses it"));
}
if (block->r_flag) {
CHKS(((motion != G_2) && (motion != G_3) && (motion != G_76) && (motion != G_6_2) &&
(motion != G_71) && (motion != G_71_1) && (motion != G_71_2) &&
(motion != G_72) && (motion != G_72_1) && (motion != G_72_2) &&
((motion < G_81) || (motion > G_89)) && (motion != G_73) &&
(motion != G_74) &&
(block->g_modes[GM_CUTTER_COMP] != G_41_1) && (block->g_modes[GM_CUTTER_COMP] != G_42_1) &&
(block->g_modes[GM_MODAL_0] != G_10) && (block->m_modes[7] != 19) ),
NCE_R_WORD_WITH_NO_G_CODE_THAT_USES_IT);
CHKS((block->m_modes[7] == 19) && ((block->r_number > 360.0) || (block->r_number < 0.0)),
_("R value must be within 0..360 with M19"));
}
if (!block->s_flag) {
CHKS((block->g_modes[GM_SPINDLE_MODE] == G_96), NCE_S_WORD_MISSING_WITH_G96);
}
if (motion == G_33 || motion == G_33_1) {
CHKS((!block->k_flag), NCE_K_WORD_MISSING_WITH_G33);
CHKS((block->f_flag), NCE_F_WORD_USED_WITH_G33);
}
if (motion == G_76) {
// pitch
CHKS((block->p_number == -1), NCE_P_WORD_MISSING_WITH_G76);
CHKS((!block->i_flag || !block->j_flag || !block->k_flag),
NCE_I_J_OR_K_WORDS_MISSING_WITH_G76);
}
return INTERP_OK;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,422 @@
/********************************************************************
* Description: interp_execute.cc
*
* Derived from a work by Thomas Kramer
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <rtapi_math.h>
#include "rs274ngc.hh"
#include "rs274ngc_return.hh"
#include "interp_internal.hh"
#include "rs274ngc_interp.hh"
#define RESULT_OK(x) ((x) == INTERP_OK || (x) == INTERP_EXECUTE_FINISH)
/****************************************************************************/
/*! execute binary
Returned value: int
If execute_binary1 or execute_binary2 returns an error code, this
returns that code.
Otherwise, it returns INTERP_OK.
Side effects: The value of left is set to the result of applying
the operation to left and right.
Called by: read_real_expression
This just calls either execute_binary1 or execute_binary2.
*/
int Interp::execute_binary(double *left, int operation, double *right)
{
if (operation < AND2)
CHP(execute_binary1(left, operation, right));
else
CHP(execute_binary2(left, operation, right));
return INTERP_OK;
}
/****************************************************************************/
/*! execute_binary1
Returned Value: int
If any of the following errors occur, this returns the error shown.
Otherwise, it returns INTERP_OK.
1. operation is unknown: NCE_BUG_UNKNOWN_OPERATION
2. An attempt is made to divide by zero: NCE_ATTEMPT_TO_DIVIDE_BY_ZERO
3. An attempt is made to raise a negative number to a non-integer power:
NCE_ATTEMPT_TO_RAISE_NEGATIVE_TO_NON_INTEGER_POWER
Side effects:
The result from performing the operation is put into what left points at.
Called by: read_real_expression.
This executes the operations: DIVIDED_BY, MODULO, POWER, TIMES.
*/
int Interp::execute_binary1(double *left, //!< pointer to the left operand
int operation, //!< integer code for the operation
double *right) //!< pointer to the right operand
{
switch (operation) {
case DIVIDED_BY:
CHKS((*right == 0.0), NCE_ATTEMPT_TO_DIVIDE_BY_ZERO);
*left = (*left / *right);
break;
case MODULO: /* always calculates a positive answer */
*left = fmod(*left, *right);
if (*left < 0.0) {
*left = (*left + fabs(*right));
}
break;
case POWER:
CHKS(((*left < 0.0) && (floor(*right) != *right)),
NCE_ATTEMPT_TO_RAISE_NEGATIVE_TO_NON_INTEGER_POWER);
*left = pow(*left, *right);
break;
case TIMES:
*left = (*left * *right);
break;
default:
ERS(NCE_BUG_UNKNOWN_OPERATION);
}
return INTERP_OK;
}
/****************************************************************************/
/*! execute_binary2
Returned Value: int
If any of the following errors occur, this returns the error code shown.
Otherwise, it returns INTERP_OK.
1. operation is unknown: NCE_BUG_UNKNOWN_OPERATION
Side effects:
The result from performing the operation is put into what left points at.
Called by: read_real_expression.
This executes the operations: AND2, EXCLUSIVE_OR, MINUS,
NON_EXCLUSIVE_OR, PLUS. The RS274/NGC manual [NCMS] does not say what
the calculated value of the three logical operations should be. This
function calculates either 1.0 (meaning true) or 0.0 (meaning false).
Any non-zero input value is taken as meaning true, and only 0.0 means
false.
*/
int Interp::execute_binary2(double *left, //!< pointer to the left operand
int operation, //!< integer code for the operation
double *right) //!< pointer to the right operand
{
double diff;
switch (operation) {
case AND2:
*left = ((*left == 0.0) || (*right == 0.0)) ? 0.0 : 1.0;
break;
case EXCLUSIVE_OR:
*left = (((*left == 0.0) && (*right != 0.0))
|| ((*left != 0.0) && (*right == 0.0))) ? 1.0 : 0.0;
break;
case MINUS:
*left = (*left - *right);
break;
case NON_EXCLUSIVE_OR:
*left = ((*left != 0.0) || (*right != 0.0)) ? 1.0 : 0.0;
break;
case PLUS:
*left = (*left + *right);
break;
case LT:
*left = (*left < *right) ? 1.0 : 0.0;
break;
case EQ:
diff = fabs(*left - *right);
*left = (diff < TOLERANCE_EQUAL) ? 1.0 : 0.0;
break;
case NE:
diff = fabs(*left - *right);
*left = (diff >= TOLERANCE_EQUAL) ? 1.0 : 0.0;
break;
case LE:
diff = fabs(*left - *right);
*left = ((diff < TOLERANCE_EQUAL) || (*left <= *right)) ? 1.0 : 0.0;
break;
case GE:
diff = fabs(*left - *right);
*left = ((diff < TOLERANCE_EQUAL) || (*left >= *right)) ? 1.0 : 0.0;
break;
case GT:
*left = (*left > *right) ? 1.0 : 0.0;
break;
default:
ERS(NCE_BUG_UNKNOWN_OPERATION);
}
return INTERP_OK;
}
/****************************************************************************/
/*! execute_block
Returned Value: int
If convert_stop returns INTERP_EXIT, this returns INTERP_EXIT.
If any of the following functions is called and returns an error code,
this returns that code.
convert_comment
convert_feed_mode
convert_feed_rate
convert_g
convert_m
convert_speed
convert_stop
convert_tool_select
Otherwise, if the probe_flag in the settings is true,
or the input_flag is set to true this returns
INTERP_EXECUTE_FINISH.
Otherwise, it returns INTERP_OK.
Side effects:
One block of RS274/NGC instructions is executed.
Called by:
Interp::execute
This converts a block to zero to many actions. The order of execution
of items in a block is critical to safe and effective machine operation,
but is not specified clearly in the RS274/NGC documentation.
Actions are executed in the following order:
1. any comment.
2. a feed mode setting (g93, g94, g95)
3. a feed rate (f) setting if in units_per_minute feed mode.
4. a spindle speed (s) setting.
5. a tool selection (t).
6. "m" commands as described in convert_m (includes tool change).
7. any g_codes (except g93, g94) as described in convert_g.
8. stopping commands (m0, m1, m2, m30, or m60).
In inverse time feed mode, the explicit and implicit g code executions
include feed rate setting with g1, g2, and g3. Also in inverse time
feed mode, attempting a canned cycle cycle (g81 to g89) or setting a
feed rate with g0 is illegal and will be detected and result in an
error message.
*/
int Interp::execute_block(block_pointer block, //!< pointer to a block of RS274/NGC instructions
setup_pointer settings) //!< pointer to machine settings
{
int status = INTERP_EXIT;
block->line_number = settings->sequence_number;
if ((block->comment[0] != 0) && ONCE(STEP_COMMENT)) {
status = convert_comment(block->comment);
CHP(status);
}
if ((block->g_modes[GM_SPINDLE_MODE] != -1) && ONCE(STEP_SPINDLE_MODE)) {
settings->active_spindle = 0; //must be single-spindle, default to 0
if (block->dollar_flag){
CHKS((block->dollar_number < 0 || block->dollar_number >= settings->num_spindles),
(_("Invalid spindle ($) number in Spindle Mode command")));
settings->active_spindle = (int)block->dollar_number;
}
status = convert_spindle_mode(settings->active_spindle, block, settings);
CHP(status);
}
if ((block->g_modes[GM_FEED_MODE] != -1) && ONCE(STEP_FEED_MODE)) {
settings->active_spindle = 0; //must be single-spindle, default to 0
if (block->dollar_flag){
CHKS((block->dollar_number < 0 || block->dollar_number >= settings->num_spindles),
(_("Invalid spindle ($) number in Spindle Feed command")));
settings->active_spindle = (int)block->dollar_number;
}
status = convert_feed_mode(block->g_modes[GM_FEED_MODE], settings);
CHP(status);
}
if (block->f_flag){
if ((settings->feed_mode != FEED_MODE::INVERSE_TIME) && ONCE(STEP_SET_FEED_RATE)) {
if (STEP_REMAPPED_IN_BLOCK(block, STEP_SET_FEED_RATE)) {
return (convert_remapped_code(block, settings, STEP_SET_FEED_RATE, 'F'));
} else {
status = convert_feed_rate(block, settings);
CHP(status);
}
}
/* INVERSE_TIME is handled elsewhere */
}
if ((block->s_flag) && ONCE(STEP_SET_SPINDLE_SPEED)){
if (STEP_REMAPPED_IN_BLOCK(block, STEP_SET_SPINDLE_SPEED)) {
return (convert_remapped_code(block,settings,STEP_SET_SPINDLE_SPEED,'S'));
} else {
if (block->dollar_flag){
CHKS((block->dollar_number < -1 || block->dollar_number >= settings->num_spindles),
(_("Invalid spindle ($) number in Spindle speed command")));
if (block->dollar_number == -1 ){
for (int i = 0; i < settings->num_spindles; status = convert_speed(i++, block, settings));
} else {
status = convert_speed(block->dollar_number, block, settings);
}
} else {
status = convert_speed(0, block, settings);
}
CHP(status);
}
}
if ((block->t_flag) && ONCE(STEP_PREPARE)) {
if (STEP_REMAPPED_IN_BLOCK(block, STEP_PREPARE)) {
return (convert_remapped_code(block,settings,STEP_PREPARE,'T'));
} else {
CHP(convert_tool_select(block, settings));
}
}
CHP(convert_m(block, settings));
CHP(convert_g(block, settings));
/* convert m0, m1, m2, m30, m60, or (when main program loops disabled) m99 */
if ((block->m_modes[4] != -1) && ONCE(STEP_MGROUP4)) {
if (STEP_REMAPPED_IN_BLOCK(block, STEP_MGROUP4)) {
status = convert_remapped_code(block,settings,STEP_MGROUP4,'M',block->m_modes[4]);
} else {
status = convert_stop(block, settings);
}
if (status == INTERP_EXIT) {
return(INTERP_EXIT);
}
else if (status != INTERP_OK) {
ERP(status);
}
}
if (settings->probe_flag)
return (INTERP_EXECUTE_FINISH);
if (settings->input_flag)
return (INTERP_EXECUTE_FINISH);
if (settings->toolchange_flag)
return (INTERP_EXECUTE_FINISH);
// All changes to settings are complete
write_canon_state_tag(block, settings);
return INTERP_OK;
}
/****************************************************************************/
/*! execute_unary
Returned Value: int
If any of the following errors occur, this returns the error code shown.
Otherwise, it returns INTERP_OK.
1. the operation is unknown: NCE_BUG_UNKNOWN_OPERATION
2. the argument to acos is not between minus and plus one:
NCE_ARGUMENT_TO_ACOS_OUT_RANGE
3. the argument to asin is not between minus and plus one:
NCE_ARGUMENT_TO_ASIN_OUT_RANGE
4. the argument to the natural logarithm is not positive:
NCE_ZERO_OR_NEGATIVE_ARGUMENT_TO_LN
5. the argument to square root is negative:
NCE_NEGATIVE_ARGUMENT_TO_SQRT
Side effects:
The result from performing the operation on the value in double_ptr
is put into what double_ptr points at.
Called by: read_unary.
This executes the operations: ABS, ACOS, ASIN, COS, EXP, FIX, FUP, LN
ROUND, SIN, SQRT, TAN
All angle measures in the input or output are in degrees.
*/
int Interp::execute_unary(double *double_ptr, //!< pointer to the operand
int operation) //!< integer code for the operation
{
switch (operation) {
case ABS:
if (*double_ptr < 0.0)
*double_ptr = (-1.0 * *double_ptr);
break;
case ACOS:
CHKS(((*double_ptr < -1.0) || (*double_ptr > 1.0)),
NCE_ARGUMENT_TO_ACOS_OUT_OF_RANGE);
*double_ptr = acos(*double_ptr);
*double_ptr = ((*double_ptr * 180.0) / M_PIl);
break;
case ASIN:
CHKS(((*double_ptr < -1.0) || (*double_ptr > 1.0)),
NCE_ARGUMENT_TO_ASIN_OUT_OF_RANGE);
*double_ptr = asin(*double_ptr);
*double_ptr = ((*double_ptr * 180.0) / M_PIl);
break;
case COS:
*double_ptr = cos((*double_ptr * M_PIl) / 180.0);
break;
case EXISTS:
// do nothing here
// result for the EXISTS function is set by Interp:read_unary()
break;
case EXP:
*double_ptr = exp(*double_ptr);
break;
case FIX:
*double_ptr = floor(*double_ptr);
break;
case FUP:
*double_ptr = ceil(*double_ptr);
break;
case LN:
CHKS((*double_ptr <= 0.0), NCE_ZERO_OR_NEGATIVE_ARGUMENT_TO_LN);
*double_ptr = log(*double_ptr);
break;
case ROUND:
*double_ptr = (double)
((int) (*double_ptr + ((*double_ptr < 0.0) ? -0.5 : 0.5)));
break;
case SIN:
*double_ptr = sin((*double_ptr * M_PIl) / 180.0);
break;
case SQRT:
CHKS((*double_ptr < 0.0), NCE_NEGATIVE_ARGUMENT_TO_SQRT);
*double_ptr = sqrt(*double_ptr);
break;
case TAN:
*double_ptr = tan((*double_ptr * M_PIl) / 180.0);
break;
default:
ERS(NCE_BUG_UNKNOWN_OPERATION);
}
return INTERP_OK;
}

View File

@@ -0,0 +1,758 @@
/********************************************************************
* Description: interp_find.cc
*
* Derived from a work by Thomas Kramer
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <rtapi_math.h>
#include "rs274ngc.hh"
#include "nml_intf/interp_return.hh"
#include "interp_internal.hh"
#include "rs274ngc_interp.hh"
#include "units.h"
#include "tooldata/tooldata.hh"
/****************************************************************************/
/*! find_arc_length
Returned Value: double (length of path between start and end points)
Side effects: none
Called by:
inverse_time_rate_arc
inverse_time_rate_arc2
inverse_time_rate_as
This calculates the length of the path that will be made relative to
the XYZ axes for a motion in which the X,Y,Z, motion is a circular or
helical arc with its axis parallel to the Z-axis. If tool length
compensation is on, this is the path of the tool tip; if off, the
length of the path of the spindle tip. Any rotary axis motion is
ignored.
If the arc is helical, it is coincident with the hypotenuse of a right
triangle wrapped around a cylinder. If the triangle is unwrapped, its
base is [the radius of the cylinder times the number of radians in the
helix] and its height is [z2 - z1], and the path length can be found
by the Pythagorean theorem.
This is written as though it is only for arcs whose axis is parallel to
the Z-axis, but it will serve also for arcs whose axis is parallel
to the X-axis or Y-axis, with suitable permutation of the arguments.
This works correctly when turn is zero (find_turn returns 0 in that
case).
*/
double Interp::find_arc_length(double x1, //!< X-coordinate of start point
double y1, //!< Y-coordinate of start point
double z1, //!< Z-coordinate of start point
double center_x, //!< X-coordinate of arc center
double center_y, //!< Y-coordinate of arc center
int turn, //!< no. of full or partial circles CCW
double x2, //!< X-coordinate of end point
double y2, //!< Y-coordinate of end point
double z2) //!< Z-coordinate of end point
{
double radius;
double theta; /* amount of turn of arc in radians */
radius = hypot((center_x - x1), (center_y - y1));
theta = find_turn(x1, y1, center_x, center_y, turn, x2, y2);
if (z2 == z1)
return (radius * fabs(theta));
else
return hypot((radius * theta), (z2 - z1));
}
/* Find the real destination, given the axis's current position, the
commanded destination, and the direction to turn (which comes from
the sign of the commanded value in the gcode). Modulo 360 positions
of the axis are considered equivalent and we just need to find the
nearest one. */
int Interp::unwrap_rotary(double *r, double sign_of, double commanded, double current, char axis) {
double result;
int neg = copysign(1.0, sign_of) < 0.0;
CHKS((sign_of <= -360.0 || sign_of >= 360.0), (_("Invalid absolute position %5.2f for wrapped rotary axis %c")), sign_of, axis);
double d = floor(current/360.0);
result = fabs(commanded) + (d*360.0);
if(!neg && result < current) result += 360.0;
if(neg && result > current) result -= 360.0;
*r = result;
return INTERP_OK;
}
/****************************************************************************/
/*! find_ends
Returned Value: int (INTERP_OK)
Side effects:
The values of px, py, pz, aa_p, bb_p, and cc_p are set
Called by:
convert_arc
convert_home
convert_probe
convert_straight
This finds the coordinates of a point, "end", in the currently
active coordinate system, and sets the values of the pointers to the
coordinates (which are the arguments to the function).
In all cases, if no value for the coordinate is given in the block, the
current value for the coordinate is used. When cutter radius
compensation is on, this function is called before compensation
calculations are performed, so the current value of the programmed
point is used, not the current value of the actual current_point.
There are three cases for when the coordinate is included in the block:
1. G_53 is active. This means to interpret the coordinates as machine
coordinates. That is accomplished by adding the three offsets to the
coordinates given in the block. The x,y block coordinates are also
rotated. The end result is the machine coordinates in the block are
converted to coordinates in the current system.
2. Absolute coordinate mode is in effect. The coordinate in the block
is used.
3. Incremental coordinate mode is in effect. The coordinate in the
block plus either (i) the programmed current position - when cutter
radius compensation is in progress, or (2) the actual current position.
*/
int Interp::find_ends(block_pointer block, //!< pointer to a block of RS274/NGC instructions
setup_pointer s, //!< pointer to machine settings
double *px, //!< pointer to end_x
double *py, //!< pointer to end_y
double *pz, //!< pointer to end_z
double *AA_p, //!< pointer to end_a
double *BB_p, //!< pointer to end_b
double *CC_p, //!< pointer to end_c
double *u_p, double *v_p, double *w_p)
{
bool middle;
CUTTER_COMP comp;
middle = !s->cutter_comp_firstmove;
comp = s->cutter_comp_side;
if (block->g_modes[GM_MODAL_0] == G_53) { /* distance mode is absolute in this case */
#ifdef DEBUG_EMC
COMMENT("interpreter: offsets temporarily suspended");
#endif
CHKS((block->radius_flag || block->theta_flag), _("Cannot use polar coordinates with G53"));
double cx = s->current_x + s->axis_offset_x;
double cy = s->current_y + s->axis_offset_y;
rotate(&cx, &cy, s->rotation_xy);
if(block->x_flag) {
*px = block->x_number - s->origin_offset_x - s->tool_offset.tran.x;
} else {
*px = cx;
}
if(block->y_flag) {
*py = block->y_number - s->origin_offset_y - s->tool_offset.tran.y;
} else {
*py = cy;
}
rotate(px, py, -s->rotation_xy);
*px -= s->axis_offset_x;
*py -= s->axis_offset_y;
if(block->z_flag) {
*pz = block->z_number - s->origin_offset_z - s->axis_offset_z - s->tool_offset.tran.z;
} else {
*pz = s->current_z;
}
if(block->a_flag) {
if(s->a_axis_wrapped) {
CHP(unwrap_rotary(AA_p, block->a_number,
block->a_number - s->AA_origin_offset - s->AA_axis_offset - s->tool_offset.a,
s->AA_current, 'A'));
} else {
*AA_p = block->a_number - s->AA_origin_offset - s->AA_axis_offset;
}
} else {
*AA_p = s->AA_current;
}
if(block->b_flag) {
if(s->b_axis_wrapped) {
CHP(unwrap_rotary(BB_p, block->b_number,
block->b_number - s->BB_origin_offset - s->BB_axis_offset - s->tool_offset.b,
s->BB_current, 'B'));
} else {
*BB_p = block->b_number - s->BB_origin_offset - s->BB_axis_offset;
}
} else {
*BB_p = s->BB_current;
}
if(block->c_flag) {
if(s->c_axis_wrapped) {
CHP(unwrap_rotary(CC_p, block->c_number,
block->c_number - s->CC_origin_offset - s->CC_axis_offset - s->tool_offset.c,
s->CC_current, 'C'));
} else {
*CC_p = block->c_number - s->CC_origin_offset - s->CC_axis_offset;
}
} else {
*CC_p = s->CC_current;
}
if(block->u_flag) {
*u_p = block->u_number - s->u_origin_offset - s->u_axis_offset - s->tool_offset.u;
} else {
*u_p = s->u_current;
}
if(block->v_flag) {
*v_p = block->v_number - s->v_origin_offset - s->v_axis_offset - s->tool_offset.v;
} else {
*v_p = s->v_current;
}
if(block->w_flag) {
*w_p = block->w_number - s->w_origin_offset - s->w_axis_offset - s->tool_offset.w;
} else {
*w_p = s->w_current;
}
} else if (s->distance_mode == DISTANCE_MODE::ABSOLUTE) {
if(block->x_flag) {
*px = block->x_number;
} else {
// both cutter comp planes affect X ...
*px = (comp != CUTTER_COMP::OFF && middle) ? s->program_x : s->current_x;
}
if(block->y_flag) {
*py = block->y_number;
} else {
// but only XY affects Y ...
*py = (comp != CUTTER_COMP::OFF && middle && s->plane == CANON_PLANE::XY) ? s->program_y : s->current_y;
}
if(block->radius_flag && block->theta_flag) {
CHKS((block->x_flag || block->y_flag), _("Cannot specify X or Y words with polar coordinate"));
*px = block->radius * cos(D2R(block->theta));
*py = block->radius * sin(D2R(block->theta));
} else if(block->radius_flag) {
double theta;
CHKS((block->x_flag || block->y_flag), _("Cannot specify X or Y words with polar coordinate"));
CHKS((*py == 0 && *px == 0), _("Must specify angle in polar coordinate if at the origin"));
theta = atan2(*py, *px);
*px = block->radius * cos(theta);
*py = block->radius * sin(theta);
} else if(block->theta_flag) {
double radius;
CHKS((block->x_flag || block->y_flag), _("Cannot specify X or Y words with polar coordinate"));
radius = hypot(*py, *px);
*px = radius * cos(D2R(block->theta));
*py = radius * sin(D2R(block->theta));
}
if(block->z_flag) {
*pz = block->z_number;
} else {
// and only XZ affects Z.
*pz = (comp != CUTTER_COMP::OFF && middle && s->plane == CANON_PLANE::XZ) ? s->program_z : s->current_z;
}
if(block->a_flag) {
if(s->a_axis_wrapped) {
CHP(unwrap_rotary(AA_p, block->a_number, block->a_number, s->AA_current, 'A'));
} else {
*AA_p = block->a_number;
}
} else {
*AA_p = s->AA_current;
}
if(block->b_flag) {
if(s->b_axis_wrapped) {
CHP(unwrap_rotary(BB_p, block->b_number, block->b_number, s->BB_current, 'B'));
} else {
*BB_p = block->b_number;
}
} else {
*BB_p = s->BB_current;
}
if(block->c_flag) {
if(s->c_axis_wrapped) {
CHP(unwrap_rotary(CC_p, block->c_number, block->c_number, s->CC_current, 'C'));
} else {
*CC_p = block->c_number;
}
} else {
*CC_p = s->CC_current;
}
*u_p = (block->u_flag) ? block->u_number : s->u_current;
*v_p = (block->v_flag) ? block->v_number : s->v_current;
*w_p = (block->w_flag) ? block->w_number : s->w_current;
} else { /* mode is DISTANCE_MODE::INCREMENTAL */
// both cutter comp planes affect X ...
*px = (comp != CUTTER_COMP::OFF && middle) ? s->program_x: s->current_x;
if(block->x_flag) *px += block->x_number;
// but only XY affects Y ...
*py = (comp != CUTTER_COMP::OFF && middle && s->plane == CANON_PLANE::XY) ? s->program_y: s->current_y;
if(block->y_flag) *py += block->y_number;
if(block->radius_flag) {
double radius, theta;
CHKS((block->x_flag || block->y_flag), _("Cannot specify X or Y words with polar coordinate"));
CHKS((*py == 0 && *px == 0), _("Incremental motion with polar coordinates is indeterminate when at the origin"));
theta = atan2(*py, *px);
radius = hypot(*py, *px) + block->radius;
*px = radius * cos(theta);
*py = radius * sin(theta);
}
if(block->theta_flag) {
double radius, theta;
CHKS((block->x_flag || block->y_flag), _("Cannot specify X or Y words with polar coordinate"));
CHKS((*py == 0 && *px == 0), _("G91 motion with polar coordinates is indeterminate when at the origin"));
theta = atan2(*py, *px) + D2R(block->theta);
radius = hypot(*py, *px);
*px = radius * cos(theta);
*py = radius * sin(theta);
}
// and only XZ affects Z.
*pz = (comp != CUTTER_COMP::OFF && middle && s->plane == CANON_PLANE::XZ) ? s->program_z: s->current_z;
if(block->z_flag) *pz += block->z_number;
*AA_p = s->AA_current;
if(block->a_flag) *AA_p += block->a_number;
*BB_p = s->BB_current;
if(block->b_flag) *BB_p += block->b_number;
*CC_p = s->CC_current;
if(block->c_flag) *CC_p += block->c_number;
*u_p = s->u_current;
if(block->u_flag) *u_p += block->u_number;
*v_p = s->v_current;
if(block->v_flag) *v_p += block->v_number;
*w_p = s->w_current;
if(block->w_flag) *w_p += block->w_number;
}
return INTERP_OK;
}
/****************************************************************************/
/*! find_relative
Returned Value: int (INTERP_OK)
Side effects:
The values of x2, y2, z2, aa_2, bb_2, and cc_2 are set.
(NOTE: aa_2 etc. are written with lower case letters in this
documentation because upper case would confuse the pre-preprocessor.)
Called by:
convert_home
This finds the coordinates in the current system, under the current
tool length offset, of a point (x1, y1, z1, aa_1, bb_1, cc_1) whose absolute
coordinates are known.
Don't confuse this with the inverse operation.
*/
int Interp::find_relative(double x1, //!< absolute x position
double y1, //!< absolute y position
double z1, //!< absolute z position
double AA_1, //!< absolute a position
double BB_1, //!< absolute b position
double CC_1, //!< absolute c position
double u_1,
double v_1,
double w_1,
double *x2, //!< pointer to relative x
double *y2, //!< pointer to relative y
double *z2, //!< pointer to relative z
double *AA_2, //!< pointer to relative a
double *BB_2, //!< pointer to relative b
double *CC_2, //!< pointer to relative c
double *u_2,
double *v_2,
double *w_2,
setup_pointer settings) //!< pointer to machine settings
{
*x2 = x1 - settings->origin_offset_x - settings->tool_offset.tran.x;
*y2 = y1 - settings->origin_offset_y - settings->tool_offset.tran.y;
rotate(x2, y2, -settings->rotation_xy);
*x2 -= settings->axis_offset_x;
*y2 -= settings->axis_offset_y;
*z2 = z1 - settings->origin_offset_z - settings->axis_offset_z - settings->tool_offset.tran.z;
if(settings->a_axis_wrapped) {
CHP(unwrap_rotary(AA_2, AA_1,
AA_1 - settings->AA_origin_offset - settings->AA_axis_offset - settings->tool_offset.a,
settings->AA_current, 'A'));
} else {
*AA_2 = AA_1 - settings->AA_origin_offset - settings->AA_axis_offset;
}
if(settings->b_axis_wrapped) {
CHP(unwrap_rotary(BB_2, BB_1,
BB_1 - settings->BB_origin_offset - settings->BB_axis_offset - settings->tool_offset.b,
settings->BB_current, 'B'));
} else {
*BB_2 = BB_1 - settings->BB_origin_offset - settings->BB_axis_offset;
}
if(settings->c_axis_wrapped) {
CHP(unwrap_rotary(CC_2, CC_1,
CC_1 - settings->CC_origin_offset - settings->CC_axis_offset - settings->tool_offset.c,
settings->CC_current, 'C'));
} else {
*CC_2 = CC_1 - settings->CC_origin_offset - settings->CC_axis_offset;
}
*u_2 = u_1 - settings->u_origin_offset - settings->u_axis_offset - settings->tool_offset.u;
*v_2 = v_1 - settings->v_origin_offset - settings->v_axis_offset - settings->tool_offset.v;
*w_2 = w_1 - settings->w_origin_offset - settings->w_axis_offset - settings->tool_offset.w;
return INTERP_OK;
}
// find what the current coordinates would be if we were in a different system
int Interp::find_current_in_system(setup_pointer s, int system,
double *x, double *y, double *z,
double *a, double *b, double *c,
double *u, double *v, double *w) {
double *p = s->parameters;
*x = s->current_x;
*y = s->current_y;
*z = s->current_z;
*a = s->AA_current;
*b = s->BB_current;
*c = s->CC_current;
*u = s->u_current;
*v = s->v_current;
*w = s->w_current;
*x += s->axis_offset_x;
*y += s->axis_offset_y;
*z += s->axis_offset_z;
*a += s->AA_axis_offset;
*b += s->BB_axis_offset;
*c += s->CC_axis_offset;
*u += s->u_axis_offset;
*v += s->v_axis_offset;
*w += s->w_axis_offset;
rotate(x, y, s->rotation_xy);
*x += s->origin_offset_x;
*y += s->origin_offset_y;
*z += s->origin_offset_z;
*a += s->AA_origin_offset;
*b += s->BB_origin_offset;
*c += s->CC_origin_offset;
*u += s->u_origin_offset;
*v += s->v_origin_offset;
*w += s->w_origin_offset;
*x -= USER_TO_PROGRAM_LEN(p[5201 + system * 20]);
*y -= USER_TO_PROGRAM_LEN(p[5202 + system * 20]);
*z -= USER_TO_PROGRAM_LEN(p[5203 + system * 20]);
*a -= USER_TO_PROGRAM_ANG(p[5204 + system * 20]);
*b -= USER_TO_PROGRAM_ANG(p[5205 + system * 20]);
*c -= USER_TO_PROGRAM_ANG(p[5206 + system * 20]);
*u -= USER_TO_PROGRAM_LEN(p[5207 + system * 20]);
*v -= USER_TO_PROGRAM_LEN(p[5208 + system * 20]);
*w -= USER_TO_PROGRAM_LEN(p[5209 + system * 20]);
rotate(x, y, -p[5210 + system * 20]);
if (p[5210]) {
*x -= USER_TO_PROGRAM_LEN(p[5211]);
*y -= USER_TO_PROGRAM_LEN(p[5212]);
*z -= USER_TO_PROGRAM_LEN(p[5213]);
*a -= USER_TO_PROGRAM_ANG(p[5214]);
*b -= USER_TO_PROGRAM_ANG(p[5215]);
*c -= USER_TO_PROGRAM_ANG(p[5216]);
*u -= USER_TO_PROGRAM_LEN(p[5217]);
*v -= USER_TO_PROGRAM_LEN(p[5218]);
*w -= USER_TO_PROGRAM_LEN(p[5219]);
}
return INTERP_OK;
}
// find what the current coordinates would be if we were in a different system,
// if TLO were unapplied
int Interp::find_current_in_system_without_tlo(setup_pointer s, int system,
double *x, double *y, double *z,
double *a, double *b, double *c,
double *u, double *v, double *w) {
double *p = s->parameters;
*x = s->current_x;
*y = s->current_y;
*z = s->current_z;
*a = s->AA_current;
*b = s->BB_current;
*c = s->CC_current;
*u = s->u_current;
*v = s->v_current;
*w = s->w_current;
*x += s->axis_offset_x;
*y += s->axis_offset_y;
*z += s->axis_offset_z;
*a += s->AA_axis_offset;
*b += s->BB_axis_offset;
*c += s->CC_axis_offset;
*u += s->u_axis_offset;
*v += s->v_axis_offset;
*w += s->w_axis_offset;
rotate(x, y, s->rotation_xy);
*x += s->origin_offset_x;
*y += s->origin_offset_y;
*z += s->origin_offset_z;
*a += s->AA_origin_offset;
*b += s->BB_origin_offset;
*c += s->CC_origin_offset;
*u += s->u_origin_offset;
*v += s->v_origin_offset;
*w += s->w_origin_offset;
*x += s->tool_offset.tran.x;
*y += s->tool_offset.tran.y;
*z += s->tool_offset.tran.z;
*a += s->tool_offset.a;
*b += s->tool_offset.b;
*c += s->tool_offset.c;
*u += s->tool_offset.u;
*v += s->tool_offset.v;
*w += s->tool_offset.w;
*x -= USER_TO_PROGRAM_LEN(p[5201 + system * 20]);
*y -= USER_TO_PROGRAM_LEN(p[5202 + system * 20]);
*z -= USER_TO_PROGRAM_LEN(p[5203 + system * 20]);
*a -= USER_TO_PROGRAM_ANG(p[5204 + system * 20]);
*b -= USER_TO_PROGRAM_ANG(p[5205 + system * 20]);
*c -= USER_TO_PROGRAM_ANG(p[5206 + system * 20]);
*u -= USER_TO_PROGRAM_LEN(p[5207 + system * 20]);
*v -= USER_TO_PROGRAM_LEN(p[5208 + system * 20]);
*w -= USER_TO_PROGRAM_LEN(p[5209 + system * 20]);
rotate(x, y, -p[5210 + system * 20]);
if (p[5210]) {
*x -= USER_TO_PROGRAM_LEN(p[5211]);
*y -= USER_TO_PROGRAM_LEN(p[5212]);
*z -= USER_TO_PROGRAM_LEN(p[5213]);
*a -= USER_TO_PROGRAM_ANG(p[5214]);
*b -= USER_TO_PROGRAM_ANG(p[5215]);
*c -= USER_TO_PROGRAM_ANG(p[5216]);
*u -= USER_TO_PROGRAM_LEN(p[5217]);
*v -= USER_TO_PROGRAM_LEN(p[5218]);
*w -= USER_TO_PROGRAM_LEN(p[5219]);
}
return INTERP_OK;
}
/****************************************************************************/
/*! find_straight_length
Returned Value: double (length of path between start and end points)
Side effects: none
Called by:
inverse_time_rate_straight
inverse_time_rate_as
This calculates a number to use in feed rate calculations when inverse
time feed mode is used, for a motion in which X,Y,Z,A,B, and C each change
linearly or not at all from their initial value to their end value.
This is used when the feed_reference mode is CANON_XYZ, which is
always in rs274NGC.
If any of the X, Y, or Z axes move or the A-axis, B-axis, and C-axis
do not move, this is the length of the path relative to the XYZ axes
from the first point to the second, and any rotary axis motion is
ignored. The length is the simple Euclidean distance.
The formula for the Euclidean distance "length" of a move involving
only the A, B and C axes is based on a conversation with Jim Frohardt at
Boeing, who says that the Fanuc controller on their 5-axis machine
interprets the feed rate this way. Note that if only one rotary axis
moves, this formula returns the absolute value of that axis move,
which is what is desired.
*/
double Interp::find_straight_length(double x2, //!< X-coordinate of end point
double y2, //!< Y-coordinate of end point
double z2, //!< Z-coordinate of end point
double AA_2, //!< A-coordinate of end point
double BB_2, //!< B-coordinate of end point
double CC_2, //!< C-coordinate of end point
double u_2,
double v_2,
double w_2,
double x1, //!< X-coordinate of start point
double y1, //!< Y-coordinate of start point
double z1, //!< Z-coordinate of start point
double AA_1, //!< A-coordinate of start point
double BB_1, //!< B-coordinate of start point
double CC_1, //!< C-coordinate of start point
double u_1,
double v_1,
double w_1
)
{
#define tiny 1e-7
if ( (fabs(x1-x2) > tiny) || (fabs(y1-y2) > tiny) || (fabs(z1-z2) > tiny) )
return sqrt(pow((x2 - x1), 2) + pow((y2 - y1), 2) + pow((z2 - z1), 2));
else if ( (fabs(u_1-u_2) > tiny) || (fabs(v_1-v_2) > tiny) || (fabs(w_1-w_2) > tiny) )
return sqrt(pow((u_2 - u_1), 2) + pow((v_2 - v_1), 2) + pow((w_2 - w_1), 2));
else
return sqrt(pow((AA_2 - AA_1), 2) + pow((BB_2 - BB_1), 2) + pow((CC_2 - CC_1), 2));
}
/****************************************************************************/
/*! find_turn
Returned Value: double (angle in radians between two radii of a circle)
Side effects: none
Called by: find_arc_length
All angles are in radians.
*/
double Interp::find_turn(double x1, //!< X-coordinate of start point
double y1, //!< Y-coordinate of start point
double center_x, //!< X-coordinate of arc center
double center_y, //!< Y-coordinate of arc center
int turn, //!< no. of full or partial circles CCW
double x2, //!< X-coordinate of end point
double y2) //!< Y-coordinate of end point
{
double alpha; /* angle of first radius */
double beta; /* angle of second radius */
double theta; /* amount of turn of arc CCW - negative if CW */
if (turn == 0)
return 0.0;
alpha = atan2((y1 - center_y), (x1 - center_x));
beta = atan2((y2 - center_y), (x2 - center_x));
if (turn > 0) {
if (beta <= alpha)
beta = (beta + (2 * M_PIl));
theta = ((beta - alpha) + ((turn - 1) * (2 * M_PIl)));
} else { /* turn < 0 */
if (alpha <= beta)
alpha = (alpha + (2 * M_PIl));
theta = ((beta - alpha) + ((turn + 1) * (2 * M_PIl)));
}
return (theta);
}
int Interp::find_tool_index(setup_pointer settings, int toolno, int *index)
{
#ifdef TOOL_NML //{
if(!settings->random_toolchanger && toolno == 0) {
*index = 0;
return INTERP_OK;
}
#else //}{
(void)settings;
// special case is included in tooldata_find_index_for_tool()
#endif //}
*index = tooldata_find_index_for_tool(toolno);
CHKS((*index == -1), (_("Requested tool %d not found in the tool table")), toolno);
return INTERP_OK;
}
int Interp::find_tool_pocket(setup_pointer settings, int toolno, int *pocket)
{
#ifdef TOOL_NML //{
if(!settings->random_toolchanger && toolno == 0) {
*pocket = 0;
return INTERP_OK;
}
#else //}{
(void)settings;
// special case is included in tooldata_find_index_for_tool()
#endif //}
int idx = tooldata_find_index_for_tool(toolno);
*pocket = 0; //not found
CHKS((idx == -1), (_("Requested tool %d not found in the tool table")), toolno);
CANON_TOOL_TABLE tdata = tooldata_entry_init();
if (tooldata_get(&tdata,idx) != IDX_OK) {
fprintf(stderr,"UNEXPECTED idx %s %d\n",__FILE__,__LINE__);
}
*pocket = tdata.pocketno;
return INTERP_OK;
}

View File

@@ -0,0 +1,42 @@
/**
* @file interp_fwd.hh
*
* Forward declarations for interp_internal.hh.
*
* @author Robert W. Ellenberg <rwe24g@gmail.com>
*
* Copyright (c) 2019, Robert W. Ellenberg
*
* This source code is released for free distribution under the terms of the
* GNU General Public License (V2) as published by the Free Software Foundation.
*/
#ifndef INTERP_FWD_HH
#define INTERP_FWD_HH
class Interp;
struct block_struct;
typedef struct block_struct *block_pointer;
typedef struct block_struct block;
struct setup;
typedef struct setup *setup_pointer;
struct remap_struct;
typedef struct remap_struct *remap_pointer;
typedef struct remap_struct remap;
struct context_struct;
typedef struct context_struct *context_pointer;
typedef struct context_struct context;
struct parameter_value_struct;
typedef parameter_value_struct *parameter_pointer;
typedef parameter_value_struct parameter_value;
struct offset_struct;
typedef offset_struct *offset_pointer;
typedef offset_struct offset;
#endif // INTERP_FWD_HH

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,494 @@
/********************************************************************
* Description: interp_internal.cc
*
* Derived from a work by Thomas Kramer
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "rs274ngc.hh"
#include "rs274ngc_return.hh"
#include "interp_internal.hh" // interpreter private definitions
#include "rs274ngc_interp.hh"
#include <string.h>
/****************************************************************************/
/*! close_and_downcase
Returned Value: int
If any of the following errors occur, this returns the error code shown.
Otherwise, it returns INTERP_OK.
1. A left parenthesis is found inside a comment:
NCE_NESTED_COMMENT_FOUND
2. The line ends before an open comment is closed:
NCE_UNCLOSED_COMMENT_FOUND
3. A newline character is found that is not followed by null:
NCE_NULL_MISSING_AFTER_NEWLINE
Side effects: See below
Called by: read_text
To simplify handling upper case letters, spaces, and tabs, this
function removes spaces and tabs and downcases everything on a
line which is not part of a comment.
Comments are left unchanged in place. Comments are anything
enclosed in parentheses. Nested comments, indicated by a left
parenthesis inside a comment, are illegal.
The line must have a null character at the end when it comes in.
The line may have one newline character just before the end. If
there is a newline, it will be removed.
Although this software system detects and rejects all illegal characters
and illegal syntax, this particular function does not detect problems
with anything but comments.
We are treating RS274 code here as case-insensitive and spaces and
tabs as if they have no meaning. [RS274D, page 6] says spaces and tabs
are to be ignored by control.
The KT and NGC manuals say nothing about case or spaces and tabs.
*/
int Interp::close_and_downcase(char *line) //!< string: one line of NC code
{
int m;
int n;
int comment, semicomment;
char item;
comment = semicomment = 0;
for (n = 0, m = 0; (item = line[m]) != '\0'; m++) {
if ((item == ';') && !comment)
semicomment = 1;
if (semicomment) {
line[n++] = item; // pass literally
continue;
}
if (comment) {
line[n++] = item;
if (item == ')') {
comment = 0;
} else if (item == '(')
ERS(NCE_NESTED_COMMENT_FOUND);
} else if ((item == ' ') || (item == '\t') || (item == '\r'));
/* don't copy blank or tab or CR */
else if (item == '\n') { /* don't copy newline *//* but check null follows */
CHKS((line[m + 1] != 0), NCE_NULL_MISSING_AFTER_NEWLINE);
} else if ((64 < item) && (item < 91)) { /* downcase upper case letters */
line[n++] = (32 + item);
} else if ((item == '(') && !semicomment) { /* (comment is starting */
comment = 1;
line[n++] = item;
} else {
line[n++] = item; /* copy anything else */
}
}
CHKS((comment), NCE_UNCLOSED_COMMENT_FOUND);
line[n] = 0;
return INTERP_OK;
}
/****************************************************************************/
/*! enhance_block
Returned Value:
If any of the following errors occur, this returns the error shown.
Otherwise, it returns INTERP_OK.
1. A g80 is in the block, no modal group 0 code that uses axes
is in the block, and one or more axis values is given:
NCE_CANNOT_USE_AXIS_VALUES_WITH_G80
2. A g52 g92 is in the block and no axis value is given:
NCE_ALL_AXES_MISSING_WITH_G52_OR_G92
3. One G-code from group 1 and one from group 0, both of which can use
axis values, are in the block:
NCE_CANNOT_USE_TWO_G_CODES_THAT_BOTH_USE_AXIS_VALUES
4. A G-code (other than 0 or 1, for which we are allowing all axes
missing) from group 1 which can use axis values is in the block,
but no axis value is given: NCE_ALL_AXES_MISSING_WITH_MOTION_CODE
5. Axis values are given, but there is neither a G-code in the block
nor an active previously given modal G-code that uses axis values:
NCE_CANNOT_USE_AXIS_VALUES_WITHOUT_A_G_CODE_THAT_USES_THEM
Side effects:
The value of motion_to_be in the block is set.
Called by: parse_line
If there is a G-code for motion in the block (in g_modes[1]),
set motion_to_be to that. Otherwise, if there is an axis value in the
block and no G-code to use it (any such would be from group 0 in
g_modes[0]), set motion_to_be to be the last motion saved (in
settings->motion mode).
This also make the checks described above.
*/
int Interp::enhance_block(block_pointer block, //!< pointer to a block to be checked
setup_pointer settings) //!< pointer to machine settings
{
int axis_flag;
int ijk_flag;
int polar_flag;
int mode_zero_covets_axes;
int mode0;
int mode1;
if(block->radius_flag || block->theta_flag) {
// someday, tediously add polar support for other planes here:
CHKS((!_readers[(int)'x'] || !_readers[(int)'y']), _("Cannot use polar coordinate on a machine lacking X or Y axes"));
CHKS(((settings->plane != CANON_PLANE::XY)), _("Cannot use polar coordinate except in G17 plane"));
CHKS(((block->x_flag)), _("Cannot specify both polar coordinate and X word"));
CHKS(((block->y_flag)), _("Cannot specify both polar coordinate and Y word"));
}
axis_flag = ((block->x_flag) || (block->y_flag) ||
(block->z_flag) || (block->a_flag) ||
(block->b_flag) || (block->c_flag) ||
(block->u_flag) || (block->v_flag) ||
(block->w_flag));
polar_flag = (block->radius_flag) || (block->theta_flag);
ijk_flag = ((block->i_flag) || (block->j_flag) ||
(block->k_flag));
mode0 = block->g_modes[GM_MODAL_0];
mode1 = block->g_modes[GM_MOTION];
mode_zero_covets_axes =
((mode0 == G_10) || (mode0 == G_28) || (mode0 == G_30)
|| (mode0 == G_52) || (mode0 == G_92));
if (mode1 != -1) {
if (mode1 == G_80) {
CHKS(((polar_flag || axis_flag) && (!mode_zero_covets_axes)),
NCE_CANNOT_USE_AXIS_VALUES_WITH_G80);
CHKS((polar_flag && mode0 == G_92), _("Polar coordinates can only be used for motion"));
CHKS(((!axis_flag) && (mode0 == G_52 || mode0 == G_92)),
NCE_ALL_AXES_MISSING_WITH_G52_OR_G92);
} else {
CHKS(mode_zero_covets_axes, NCE_CANNOT_USE_TWO_G_CODES_THAT_BOTH_USE_AXIS_VALUES);
CHKS(((!axis_flag && !polar_flag) &&
mode1 != G_0 && mode1 != G_1 &&
mode1 != G_2 && mode1 != G_3 &&
mode1 != G_5_2 &&
mode1 != G_6_2 &&
mode1 != G_70 &&
mode1 != G_71 && mode1 != G_71_1 && mode1 != G_71_2 &&
mode1 != G_72 && mode1 != G_72_1 && mode1 != G_72_2 &&
!is_user_defined_g_code(mode1)),
NCE_ALL_AXES_MISSING_WITH_MOTION_CODE);
}
block->motion_to_be = mode1;
} else if (mode_zero_covets_axes) { /* other 3 can get by without axes but not G92 */
CHKS((polar_flag && mode0 == G_92), _("Polar coordinates can only be used for motion"));
CHKS(((!axis_flag) &&
(block->g_modes[GM_MODAL_0] == G_52 || block->g_modes[GM_MODAL_0] == G_92)),
NCE_ALL_AXES_MISSING_WITH_G52_OR_G92);
} else if (axis_flag || polar_flag) {
CHKS(((settings->motion_mode == -1)
|| (settings->motion_mode == G_80)) && (block->g_modes[GM_TOOL_LENGTH_OFFSET] != G_43_1)
&& (block->g_modes[GM_TOOL_LENGTH_OFFSET] != G_43_2),
NCE_CANNOT_USE_AXIS_VALUES_WITHOUT_A_G_CODE_THAT_USES_THEM);
if (block->g_modes[GM_TOOL_LENGTH_OFFSET] != G_43_1) {
block->motion_to_be = settings->motion_mode;
}
} else if (!axis_flag && !polar_flag && ijk_flag && (settings->motion_mode == G_2 || settings->motion_mode == G_3)) {
// this is a block like simply "i1" which should be accepted if we're in arc mode
block->motion_to_be = settings->motion_mode;
}
CHKS((polar_flag && block->motion_to_be == -1), _("Polar coordinates can only be used for motion"));
return INTERP_OK;
}
/****************************************************************************/
/*! init_block
Returned Value: int (INTERP_OK)
Side effects:
Values in the block are reset as described below.
Called by: parse_line
This system reuses the same block over and over, rather than building
a new one for each line of NC code. The block is re-initialized before
each new line of NC code is read.
The block contains many slots for values which may or may not be present
on a line of NC code. For some of these slots, there is a flag which
is turned on (at the time time value of the slot is read) if the item
is present. For slots whose values are to be read which do not have a
flag, there is always some excluded range of values. Setting the
initial value of these slot to some number in the excluded range
serves to show that a value for that slot has not been read.
The rules for the indicators for slots whose values may be read are:
1. If the value may be an arbitrary real number (which is always stored
internally as a double), a flag is needed to indicate if a value has
been read. All such flags are initialized to false.
Note that the value itself is not initialized; there is no point in it.
2. If the value must be a non-negative real number (which is always stored
internally as a double), a value of -1.0 indicates the item is not present.
3. If the value must be an unsigned integer (which is always stored
internally as an int), a value of -1 indicates the item is not present.
(RS274/NGC does not use any negative integers.)
4. If the value is a character string (only the comment slot is one), the
first character is set to 0 (NULL).
*/
int Interp::init_block(block_pointer block) //!< pointer to a block to be initialized or reset
{
int n;
block->breadcrumbs = 0; // clear execution trail
block->executing_remap = NULL;
block->param_cnt = 0;
block->remappings.clear();
block->builtin_used = false;
block->a_flag = false;
block->b_flag = false;
block->c_flag = false;
block->comment[0] = 0;
block->d_flag = false;
block->dollar_flag = false;
block->e_flag = false;
block->f_flag = false;
for (n = 0; n < GM_MAX_MODAL_GROUPS; n++) {
block->g_modes[n] = -1;
}
block->h_flag = false;
block->h_number = -1;
block->i_flag = false;
block->j_flag = false;
block->k_flag = false;
block->l_number = -1;
block->l_flag = false;
block->line_number = -1;
block->n_number = -1;
block->motion_to_be = -1;
block->m_count = 0;
for (n = 0; n < 11; n++) {
block->m_modes[n] = -1;
}
block->user_m = 0;
block->p_number = -1.0;
block->p_flag = false;
block->q_flag = false;
block->q_number = -1.0;
block->r_flag = false;
block->s_flag = false;
block->t_flag = false;
block->u_flag = false;
block->v_flag = false;
block->w_flag = false;
block->x_flag = false;
block->y_flag = false;
block->z_flag = false;
block->theta_flag = false;
block->radius_flag = false;
block->o_type = O_none;
block->o_name = 0;
block->call_type = -1;
return INTERP_OK;
}
/****************************************************************************/
/*! parse_line
Returned Value: int
If any of the following functions returns an error code,
this returns that code.
init_block
read_items
enhance_block
check_items
Otherwise, it returns INTERP_OK.
Side effects:
One RS274 line is read into a block and the block is checked for
errors. System parameters may be reset.
Called by: Interp::read
*/
int Interp::parse_line(char *line, //!< array holding a line of RS274 code
block_pointer block, //!< pointer to a block to be filled
setup_pointer settings) //!< pointer to machine settings
{
CHP(init_block(block));
CHP(read_items(block, line, settings->parameters));
if(settings->skipping_o == 0)
{
CHP(enhance_block(block, settings));
CHP(check_items(block, settings));
int n = find_remappings(block,settings);
if (n) logRemap("parse_line: found %d remappings",n);
}
return INTERP_OK;
}
/****************************************************************************/
/*! precedence
Returned Value: int
This returns an integer representing the precedence level of an_operator
Side Effects: None
Called by: read_real_expression
To add additional levels of operator precedence, edit this function.
*/
int Interp::precedence(int an_operator)
{
switch(an_operator)
{
case RIGHT_BRACKET:
return 1;
case AND2:
case EXCLUSIVE_OR:
case NON_EXCLUSIVE_OR:
return 2;
case LT:
case EQ:
case NE:
case LE:
case GE:
case GT:
return 3;
case MINUS:
case PLUS:
return 4;
case NO_OPERATION:
case DIVIDED_BY:
case MODULO:
case TIMES:
return 5;
case POWER:
return 6;
}
// should never happen
return 0;
}
int Interp::refresh_actual_position(setup_pointer settings)
{
settings->current_x = GET_EXTERNAL_POSITION_X();
settings->current_y = GET_EXTERNAL_POSITION_Y();
settings->current_z = GET_EXTERNAL_POSITION_Z();
settings->AA_current = GET_EXTERNAL_POSITION_A();
settings->BB_current = GET_EXTERNAL_POSITION_B();
settings->CC_current = GET_EXTERNAL_POSITION_C();
settings->u_current = GET_EXTERNAL_POSITION_U();
settings->v_current = GET_EXTERNAL_POSITION_V();
settings->w_current = GET_EXTERNAL_POSITION_W();
return INTERP_OK;
}
/****************************************************************************/
/*! set_probe_data
Returned Value: int (INTERP_OK)
Side effects:
The current position is set.
System parameters for probe position are set.
Called by: Interp::read
*/
int Interp::set_probe_data(setup_pointer settings) //!< pointer to machine settings
{
double a, b, c;
refresh_actual_position(settings);
settings->parameters[5061] = GET_EXTERNAL_PROBE_POSITION_X();
settings->parameters[5062] = GET_EXTERNAL_PROBE_POSITION_Y();
settings->parameters[5063] = GET_EXTERNAL_PROBE_POSITION_Z();
a = GET_EXTERNAL_PROBE_POSITION_A();
if(settings->a_axis_wrapped) {
a = fmod(a, 360.0);
if(a<0) a += 360.0;
}
settings->parameters[5064] = a;
b = GET_EXTERNAL_PROBE_POSITION_B();
if(settings->b_axis_wrapped) {
b = fmod(b, 360.0);
if(b<0) b += 360.0;
}
settings->parameters[5065] = b;
c = GET_EXTERNAL_PROBE_POSITION_C();
if(settings->c_axis_wrapped) {
c = fmod(c, 360.0);
if(c<0) c += 360.0;
}
settings->parameters[5066] = c;
settings->parameters[5067] = GET_EXTERNAL_PROBE_POSITION_U();
settings->parameters[5068] = GET_EXTERNAL_PROBE_POSITION_V();
settings->parameters[5069] = GET_EXTERNAL_PROBE_POSITION_W();
settings->parameters[5070] = (double) GET_EXTERNAL_PROBE_TRIPPED_VALUE();
// was an undocumented feature?: settings->parameters[5067] = GET_EXTERNAL_PROBE_VALUE();
return INTERP_OK;
}
int Interp::call_level(void) { return _setup.call_level; }
std::string toString(GCodes g)
{
char buf[15]={};
int dec_value = g%10;
if (dec_value)
{
// Has a decimal
snprintf(buf, sizeof(buf), "G%d.%d", g/10, dec_value);
} else {
snprintf(buf, sizeof(buf), "G%d", g/10);
}
return buf;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,136 @@
/********************************************************************
* Description: interp_inverse.cc
*
* Derived from a work by Thomas Kramer
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "rs274ngc.hh"
#include "nml_intf/interp_return.hh"
#include "interp_internal.hh"
#include "interp_queue.hh"
#include "rs274ngc_interp.hh"
/****************************************************************************/
/*! inverse_time_rate_arc
Returned Value: int (INTERP_OK)
Side effects: a call is made to SET_FEED_RATE and _setup.feed_rate is set.
Called by:
convert_arc2
convert_arc_comp1
convert_arc_comp2
This finds the feed rate needed by an inverse time move. The move
consists of an a single arc. Most of the work here is in finding the
length of the arc.
*/
int Interp::inverse_time_rate_arc(double x1, //!< x coord of start point of arc
double y1, //!< y coord of start point of arc
double z1, //!< z coord of start point of arc
double cx, //!< x coord of center of arc
double cy, //!< y coord of center of arc
int turn, //!< turn of arc
double x2, //!< x coord of end point of arc
double y2, //!< y coord of end point of arc
double z2, //!< z coord of end point of arc
block_pointer block, //!< pointer to a block of RS274 instructions
setup_pointer settings) //!< pointer to machine settings
{
double length;
double rate;
if (settings->feed_mode != FEED_MODE::INVERSE_TIME) return -1;
length = find_arc_length(x1, y1, z1, cx, cy, turn, x2, y2, z2);
if (length == 0){
rate = 0.1; // See https://github.com/LinuxCNC/linuxcnc/issues/2410
} else {
rate = length * block->f_number;
}
enqueue_SET_FEED_RATE(rate);
settings->feed_rate = rate;
return INTERP_OK;
}
/****************************************************************************/
/*! inverse_time_rate_straight
Returned Value: int (INTERP_OK)
Side effects: a call is made to SET_FEED_RATE and _setup.feed_rate is set.
Called by:
convert_straight
convert_straight_comp1
convert_straight_comp2
This finds the feed rate needed by an inverse time straight move. Most
of the work here is in finding the length of the line.
*/
int Interp::inverse_time_rate_straight(double end_x, //!< x coordinate of end point of straight line
double end_y, //!< y coordinate of end point of straight line
double end_z, //!< z coordinate of end point of straight line
double AA_end, //!< A coordinate of end point of straight line/*AA*/
double BB_end, //!< B coordinate of end point of straight line/*BB*/
double CC_end, //!< C coordinate of end point of straight line/*CC*/
double u_end, double v_end, double w_end,
block_pointer block, //!< pointer to a block of RS274 instructions
setup_pointer settings) //!< pointer to machine settings
{
double length;
double rate;
double cx, cy, cz;
if (settings->feed_mode != FEED_MODE::INVERSE_TIME) return -1;
if (settings->cutter_comp_side != CUTTER_COMP::OFF && settings->cutter_comp_radius > 0.0 &&
!settings->cutter_comp_firstmove) {
cx = settings->program_x;
cy = settings->program_y;
cz = settings->program_z;
} else {
cx = settings->current_x;
cy = settings->current_y;
cz = settings->current_z;
}
length = find_straight_length(end_x, end_y, end_z,
AA_end, BB_end, CC_end,
u_end, v_end, w_end,
cx, cy, cz,
settings->AA_current, settings->BB_current, settings->CC_current,
settings->u_current, settings->v_current, settings->w_current);
if (length == 0){
rate = 0.1; // See https://github.com/LinuxCNC/linuxcnc/issues/2410
} else {
rate = length * block->f_number;
}
enqueue_SET_FEED_RATE(rate);
settings->feed_rate = rate;
return INTERP_OK;
}

View File

@@ -0,0 +1,989 @@
/*misnomer: _setup.current_pocket,selected_pocket
** These are indexes to sequential tooldata entries
** but the names are not changed due to frequent
** legacy usage in py files used for remapping
*/
/********************************************************************
* Description: interp_namedparams.cc
*
* collect all code related to named parameter handling
*
* Author: mostly K. Lerman
* rewrite by Michael Haberler to use STL containers
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change: Juli 2011
********************************************************************/
#include "config.h"
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#define BOOST_PYTHON_MAX_ARITY 4
#include "pythonplugin/python_plugin.hh"
#include <boost/python/dict.hpp>
#include <boost/python/extract.hpp>
#include <boost/python/list.hpp>
#include <boost/python/tuple.hpp>
namespace bp = boost::python;
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sstream>
#include <string>
#include <map>
#include "rs274ngc.hh"
#include "rs274ngc_return.hh"
#include "interp_internal.hh"
#include "rs274ngc_interp.hh"
#include <inifile.hh>
// for HAL pin variables
#include <hal.h>
using namespace linuxcnc;
enum predefined_named_parameters {
NP_LINE,
NP_MOTION_MODE,
NP_PLANE,
NP_CCOMP,
NP_METRIC,
NP_IMPERIAL,
NP_ABSOLUTE,
NP_INCREMENTAL,
NP_INVERSE_TIME,
NP_UNITS_PER_MINUTE,
NP_UNITS_PER_REV,
NP_COORD_SYSTEM,
NP_TOOL_OFFSET,
NP_RETRACT_R_PLANE,
NP_RETRACT_OLD_Z,
NP_SPINDLE_RPM_MODE,
NP_SPINDLE_CSS_MODE,
NP_IJK_ABSOLUTE_MODE,
NP_LATHE_DIAMETER_MODE,
NP_LATHE_RADIUS_MODE,
NP_SPINDLE_ON,
NP_SPINDLE_CW,
NP_MIST,
NP_FLOOD,
NP_SPEED_OVERRIDE,
NP_FEED_OVERRIDE,
NP_ADAPTIVE_FEED,
NP_FEED_HOLD,
NP_FEED,
NP_RPM,
NP_CURRENT_TOOL,
NP_SELECTED_POCKET,
NP_CURRENT_POCKET,
NP_X,
NP_Y,
NP_Z,
NP_A,
NP_B,
NP_C,
NP_U,
NP_V,
NP_W,
NP_ABS_X,
NP_ABS_Y,
NP_ABS_Z,
NP_ABS_A,
NP_ABS_B,
NP_ABS_C,
NP_VALUE,
NP_CALL_LEVEL,
NP_REMAP_LEVEL,
NP_SELECTED_TOOL,
NP_VALUE_RETURNED,
NP_TASK,
};
/****************************************************************************/
/*! read_named_parameter
Returned Value: int
If read_integer_value returns an error code, this returns that code.
If any of the following errors occur, this returns the error code shown.
Otherwise, this returns INTERP_OK.
1. The first character read is not a <:
NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
2. The named parameter string is not terminated by >:
NCE_NAMED_PARAMETER_NOT_TERSINATED
3. The named parameter has not been defined before use:
NCE_NAMED_PARAMETER_NOT_DEFINED
Side effects:
The value of the given parameter is put into what double_ptr points at.
The counter is reset to point to the first character after the
characters which make up the value.
Called by: read_parameter
This attempts to read the value of a parameter out of the line,
starting at the index given by the counter.
According to the RS274/NGC manual [NCMS, p. 62], the characters following
# may be any "parameter expression". Thus, the following are legal
and mean the same thing (the value of the parameter whose number is
stored in parameter 2):
##2
#[#2]
ADDED by K. Lerman
Named parameters are now supported.
#<_abcd> is a parameter with name "abcd" of global scope
#<abce> is a named parameter of local scope.
*/
int Interp::read_named_parameter(
char *line, //!< string: line of RS274/NGC code being processed
int *counter, //!< pointer to a counter for position on the line
double *double_ptr, //!< pointer to double to be read
double * /*parameters*/, //!< array of system parameters
bool check_exists) //!< test for existence, not value
{
static char name[] = "read_named_parameter";
char paramNameBuf[LINELEN+1];
int exists;
double value;
parameter_map_iterator pi;
CHKS((line[*counter] != '<'),
NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
CHP(read_name(line, counter, paramNameBuf));
CHP(find_named_param(paramNameBuf, &exists, &value));
if (check_exists) {
*double_ptr = exists ? 1.0 : 0.0;
return INTERP_OK;
}
if (exists) {
*double_ptr = value;
return INTERP_OK;
} else {
// do not require named parameters to be defined during a
// subroutine definition:
if (_setup.defining_sub)
return INTERP_OK;
logNP("%s: referencing undefined named parameter '%s' level=%d",
name, paramNameBuf, (paramNameBuf[0] == '_') ? 0 : _setup.call_level);
ERS(_("Named parameter #<%s> not defined"), paramNameBuf);
}
return INTERP_OK;
}
// if the variable is of the form '_ini[section]name', then treat it as
// an inifile variable. Lookup section/name and cache the value
// as global and read-only.
// the shortest possible INI variable is '_ini[s]n' or 8 chars long .
int Interp::fetch_ini_param( const char *nameBuf, int *status, double *value)
{
*status = 0;
int n = strlen(nameBuf);
if(n < 8) {
return INTERP_OK;
}
std::string sect = nameBuf + 5; // skip the '_ini[' part
// Make it all upper case
for(auto &c : sect) {
c = toupper(c);
}
size_t i = sect.find(']');
if(std::string::npos == i) {
ERS(_("_ini expansion missing ']'"));
return INTERP_OK;
}
std::string var = sect.substr(i+1);
sect.erase(i); // Remove everything from ']'and after
const char *iniFileName;
if ((iniFileName = getenv("INI_FILE_NAME")) == NULL) {
logNP("warning: referencing INI parameter '%s': no INI file", nameBuf);
return INTERP_OK;
}
IniFile inifile(iniFileName);
if (!inifile) {
ERS(_("can\'t open INI file '%s'"), iniFileName);
return INTERP_OK;
}
if (auto inival = inifile.findReal(var, sect)) {
*value = *inival;
*status = 1;
} else {
ERS(_("Named INI parameter #<%s> not found in INI file '%s'"), nameBuf, iniFileName);
}
return INTERP_OK;
}
// if the variable is of the form '_hal[hal_name]', then treat it as
// a HAL pin, signal or param. Lookup value, convert to float, and export as global and read-only.
// do not cache.
// the shortest possible INI variable is '_hal[x]' or 7 chars long .
int Interp::fetch_hal_param( const char *nameBuf, int *status, double *value)
{
static int comp_id;
int retval;
hal_type_t type = HAL_TYPE_UNINITIALIZED;
hal_data_u* ptr;
bool conn;
char hal_name[HAL_NAME_LEN];
*status = 0;
if (!comp_id) {
char hal_comp[HAL_NAME_LEN];
snprintf(hal_comp, sizeof(hal_comp),"interp%d",getpid());
comp_id = hal_init(hal_comp); // manpage says: NULL ok - which fails miserably
CHKS(comp_id < 0,_("fetch_hal_param: hal_init(%s): %d"), hal_comp,comp_id);
CHKS((retval = hal_ready(comp_id)), _("fetch_hal_param: hal_ready(): %d"),retval);
}
char *s;
int n = strlen(nameBuf);
if ((n > 6) &&
((s = (char *) strchr(&nameBuf[5],']')) != NULL)) {
int closeBracket = s - nameBuf;
strncpy(hal_name, &nameBuf[5], closeBracket);
hal_name[closeBracket - 5] = '\0';
if (nameBuf[closeBracket + 1]) {
logOword("%s: trailing garbage after closing bracket", hal_name);
*status = 0;
ERS("%s: trailing garbage after closing bracket", nameBuf);
}
// the result of these lookups could be cached in the parameter struct, but I'm not sure
// this is a good idea - a removed pin/signal will not be noticed
// I dont think that's needed - no change in pins/sigs/params
// rtapi_mutex_get(&(hal_data->mutex));
// rtapi_mutex_give(&(hal_data->mutex));
if (hal_get_pin_value_by_name(hal_name, &type, &ptr, &conn) == 0) {
if (!conn)
logOword("%s: no signal connected", hal_name);
goto assign;
}
if (hal_get_signal_value_by_name(hal_name, &type, &ptr, &conn) == 0) {
if (!conn)
logOword("%s: signal has no writer", hal_name);
goto assign;
}
if (hal_get_param_value_by_name(hal_name, &type, &ptr) == 0) {
goto assign;
}
*status = 0;
ERS("Named hal parameter #<%s> not found", nameBuf);
}
return INTERP_OK;
assign:
switch (type) {
case HAL_BIT: *value = (double) (ptr->b); break;
case HAL_U32: *value = (double) (ptr->u); break;
case HAL_S32: *value = (double) (ptr->s); break;
case HAL_U64: *value = (double) (ptr->lu); break;
case HAL_S64: *value = (double) (ptr->ls); break;
case HAL_FLOAT: *value = (double) (ptr->f); break;
default: return -1;
}
logOword("%s: value=%f", hal_name, *value);
*status = 1;
return INTERP_OK;
}
int Interp::find_named_param(
const char *nameBuf, //!< pointer to name to be read
int *status, //!< pointer to return status 1 => found
double *value //!< pointer to value of found parameter
)
{
context_pointer frame;
parameter_map_iterator pi;
int level;
level = (nameBuf[0] == '_') ? 0 : _setup.call_level; // determine scope
frame = &_setup.sub_context[level];
*status = 0;
pi = frame->named_params.find(nameBuf);
if (pi == frame->named_params.end()) { // not found
int exists = 0;
double inivalue;
if (FEATURE(INI_VARS) && (strncasecmp(nameBuf,"_ini[",5) == 0)) {
fetch_ini_param(nameBuf, &exists, &inivalue);
if (exists) {
logNP("parameter '%s' retrieved from INI: %f",nameBuf,inivalue);
*value = inivalue;
*status = 1;
parameter_value param; // cache the value
param.value = inivalue;
param.attr = PA_GLOBAL | PA_READONLY | PA_FROM_INI;
_setup.sub_context[0].named_params[strstore(nameBuf)] = param;
return INTERP_OK;
}
}
if (FEATURE(HAL_PIN_VARS) && (strncasecmp(nameBuf,"_hal[",5) == 0)) {
fetch_hal_param(nameBuf, &exists, &inivalue);
if (exists) {
logNP("parameter '%s' retrieved from HAL: %f",nameBuf,inivalue);
*value = inivalue;
*status = 1;
return INTERP_OK;
}
}
*value = 0.0;
*status = 0;
} else {
parameter_pointer pv = &pi->second;
if (pv->attr & PA_UNSET)
logNP("warning: referencing unset variable '%s'",nameBuf);
if (pv->attr & PA_USE_LOOKUP) {
CHP(lookup_named_param(nameBuf, pv->value, value));
*status = 1;
} else if (pv->attr & PA_PYTHON) {
bp::object retval, tupleargs, kwargs;
bp::list plist;
plist.append(*_setup.pythis); // self
tupleargs = bp::tuple(plist);
kwargs = bp::dict();
python_plugin->call(NAMEDPARAMS_MODULE, nameBuf, tupleargs, kwargs, retval);
CHKS(python_plugin->plugin_status() == PLUGIN_EXCEPTION,
"named param - pycall(%s):\n%s", nameBuf,
python_plugin->last_exception().c_str());
CHKS(retval.ptr() == Py_None, "Python namedparams.%s returns no value", nameBuf);
if (PyUnicode_Check(retval.ptr())) {
// returning a string sets the interpreter error message and aborts
*status = 0;
char *msg = bp::extract<char *>(retval);
ERS("%s", msg);
}
if (PyLong_Check(retval.ptr())) { // widen
*value = (double) bp::extract<int>(retval);
*status = 1;
return INTERP_OK;
}
if (PyFloat_Check(retval.ptr())) {
*value = bp::extract<double>(retval);
*status = 1;
return INTERP_OK;
}
// ok, that callable returned something botched.
*status = 0;
PyObject *res_str = PyObject_Str(retval.ptr());
Py_XDECREF(res_str);
ERS("Python call %s.%s returned '%s' - expected double, int or string, got %s",
NAMEDPARAMS_MODULE, nameBuf,
PyUnicode_AsUTF8(res_str),
retval.ptr()->ob_type->tp_name);
} else {
*value = pv->value;
*status = 1;
}
}
return INTERP_OK;
}
int Interp::store_named_param(setup_pointer settings,
const char *nameBuf, //!< pointer to name to be written
double value, //!< value to be written
int override_readonly //!< set to true to init a r/o parameter
)
{
context_pointer frame;
int level;
parameter_map_iterator pi;
level = (nameBuf[0] == '_') ? 0 : _setup.call_level; // determine scope
frame = &settings->sub_context[level];
pi = frame->named_params.find(nameBuf);
if (pi == frame->named_params.end()) {
ERS(_("Internal error: Could not assign #<%s>"), nameBuf);
} else {
parameter_pointer pv = &pi->second;
CHKS(((pv->attr & PA_GLOBAL) && level),
"BUG: variable '%s' marked global, but assigned at level %d", nameBuf, level);
if ((pv->attr & PA_READONLY) && !override_readonly) {
ERS(_("Cannot assign to read-only parameter #<%s>"), nameBuf);
} else {
pv->value = value;
pv->attr &= ~PA_UNSET;
logNP("store_named_parameter: level[%d] %s value=%lf",
level, nameBuf, value);
}
}
return INTERP_OK;
}
int Interp::add_named_param(
const char *nameBuf, //!< pointer to name to be added
int attr) //!< see PA_* defs in interp_internal.hh
{
static char name[] = "add_named_param";
int findStatus;
double value;
int level;
parameter_value param;
// look it up to see if already exists
CHP(find_named_param(nameBuf, &findStatus, &value));
if (findStatus) {
logNP("%s: parameter:|%s| already exists", name, nameBuf);
return INTERP_OK;
}
attr |= PA_UNSET;
if (nameBuf[0] != '_') { // local scope
level = _setup.call_level;
} else {
level = 0; // call level zero is global scope
attr |= PA_GLOBAL;
}
param.value = 0.0;
param.attr = attr;
_setup.sub_context[level].named_params[strstore(nameBuf)] = param;
return INTERP_OK;
}
int Interp::free_named_parameters(context_pointer frame)
{
frame->named_params.clear();
return INTERP_OK;
}
// just a shorthand
int Interp::init_readonly_param(
const char *nameBuf, //!< pointer to name to be added
double value, //!< initial value
int attr) //!< see PA_* defs in interp_internal.hh
{
// static char name[] = "init_readonly_param";
CHKS( add_named_param((char *) nameBuf, PA_READONLY|attr),
"adding r/o '%s'", nameBuf);
CHKS(store_named_param(&_setup, (char *) nameBuf, value, OVERRIDE_READONLY),
"storing r/o '%s' %f", nameBuf, value);
return INTERP_OK;
}
int Interp::lookup_named_param(const char *nameBuf,
double index,
double *value)
{
int cmd = round_to_int(index);
switch (cmd) {
// some active_g_codes fields
case NP_LINE: // _line - sequence number
*value = _setup.sequence_number;
break;
case NP_MOTION_MODE: // _motion_mode
*value = _setup.motion_mode;
break;
case NP_PLANE: // _plane
switch(_setup.plane) {
case CANON_PLANE::XY:
*value = G_17;
break;
case CANON_PLANE::XZ:
*value = G_18;
break;
case CANON_PLANE::YZ:
*value = G_19;
break;
case CANON_PLANE::UV:
*value = G_17_1;
break;
case CANON_PLANE::UW:
*value = G_18_1;
break;
case CANON_PLANE::VW:
*value = G_19_1;
break;
}
break;
case NP_CCOMP: // _ccomp - cutter compensation
*value =
(_setup.cutter_comp_side == CUTTER_COMP::RIGHT) ? G_42 :
(_setup.cutter_comp_side == CUTTER_COMP::LEFT) ? G_41 : G_40;
break;
case NP_METRIC: // _metric
*value = (_setup.length_units == CANON_UNITS_MM);
break;
case NP_IMPERIAL: // _imperial
*value = (_setup.length_units == CANON_UNITS_INCHES);
break;
case NP_ABSOLUTE: // _absolute - distance mode
*value = (_setup.distance_mode == DISTANCE_MODE::ABSOLUTE);
break;
case NP_INCREMENTAL: // _incremental - distance mode
*value = (_setup.distance_mode == DISTANCE_MODE::INCREMENTAL);
break;
case NP_INVERSE_TIME: // _inverse_time - feed mode
*value = (_setup.feed_mode == FEED_MODE::INVERSE_TIME);
break;
case NP_UNITS_PER_MINUTE: // _units_per_minute - feed mode
*value = (_setup.feed_mode == FEED_MODE::UNITS_PER_MINUTE);
break;
case NP_UNITS_PER_REV: // _units_per_rev - feed mode
*value = (_setup.feed_mode == FEED_MODE::UNITS_PER_REVOLUTION);
break;
case NP_COORD_SYSTEM: // _coord_system - 0-9
*value =
(_setup.origin_index < 7) ? (530 + (10 * _setup.origin_index)) :
(584 + _setup.origin_index);
break;
case NP_TOOL_OFFSET: // _tool_offset
*value = (_setup.tool_offset.tran.x || _setup.tool_offset.tran.y || _setup.tool_offset.tran.z ||
_setup.tool_offset.a || _setup.tool_offset.b || _setup.tool_offset.c ||
_setup.tool_offset.u || _setup.tool_offset.v || _setup.tool_offset.w) ;
break;
case NP_RETRACT_R_PLANE: // _retract_r_plane - G98
*value = (_setup.retract_mode == RETRACT_MODE::R_PLANE);
break;
case NP_RETRACT_OLD_Z: // _retract_old_z - G99
*value = (_setup.retract_mode == RETRACT_MODE::OLD_Z);
break;
case NP_SPINDLE_RPM_MODE: // _spindle_rpm_mode G97 currently only reports for spindle 0
*value = (_setup.spindle_mode[0] == SPINDLE_MODE::CONSTANT_RPM);
break;
case NP_SPINDLE_CSS_MODE: // _spindle_css_mode G96
*value = (_setup.spindle_mode[0] == SPINDLE_MODE::CONSTANT_SURFACE);
break;
case NP_IJK_ABSOLUTE_MODE: //_ijk_absolute_mode - G90.1
*value = (_setup.ijk_distance_mode == DISTANCE_MODE::ABSOLUTE);
break;
case NP_LATHE_DIAMETER_MODE: // _lathe_diameter_mode - G7
*value = _setup.lathe_diameter_mode;
break;
case NP_LATHE_RADIUS_MODE: // _lathe_radius_mode - G8
*value = (_setup.lathe_diameter_mode == 0);
break;
// some active_m_codes fields
case NP_SPINDLE_ON: // _spindle_on
*value = (_setup.spindle_turning[0] != CANON_STOPPED);
break;
case NP_SPINDLE_CW: // spindle_cw
*value = (_setup.spindle_turning[0] == CANON_CLOCKWISE);
break;
case NP_MIST: // mist
*value = _setup.mist;
break;
case NP_FLOOD: // flood
*value = _setup.flood;
break;
case NP_SPEED_OVERRIDE: // speed override
*value = _setup.speed_override[0];
break;
case NP_FEED_OVERRIDE: // feed override
*value = _setup.feed_override;
break;
case NP_ADAPTIVE_FEED: // adaptive feed
*value = _setup.adaptive_feed;
break;
case NP_FEED_HOLD: // feed hold
*value = _setup.feed_hold;
break;
// from active_settings:
case NP_FEED: // feed
*value = _setup.feed_rate;
break;
case NP_RPM: // speed (rpm)
*value = abs(_setup.speed[0]);
break;
case NP_CURRENT_TOOL:
*value = _setup.parameters[5400];
break;
case NP_SELECTED_POCKET:
if(_setup.random_toolchanger){//random changers already report the real pocket number
*value = _setup.selected_pocket;
}
else{//non random get it from the tool table
if(_setup.tool_table[_setup.selected_pocket].pocketno == 0){//pocket 0 is special on non-random changers
*value = -1;
}
else{
*value = _setup.tool_table[_setup.selected_pocket].pocketno;
}
}
break;
case NP_CURRENT_POCKET:
if (_setup.current_pocket == -1) {
*value = -1;
break;
}
if(_setup.random_toolchanger){//random changers already report the real pocket number
*value = _setup.current_pocket;
}
else{//non random get it from the tool table
*value = _setup.tool_table[_setup.current_pocket].pocketno;
}
break;
case NP_SELECTED_TOOL:
*value = _setup.selected_tool;
break;
case NP_X: // current position
*value = _setup.current_x;
break;
case NP_Y: // current position
*value = _setup.current_y;
break;
case NP_Z: // current position
*value = _setup.current_z;
break;
case NP_A: // current position
*value = _setup.AA_current;
break;
case NP_B: // current position
*value = _setup.BB_current;
break;
case NP_C: // current position
*value = _setup.CC_current;
break;
case NP_U: // current position
*value = _setup.u_current;
break;
case NP_V: // current position
*value = _setup.v_current;
break;
case NP_W: // current position
*value = _setup.w_current;
break;
case NP_ABS_X: // abs position
{
double x = _setup.current_x + _setup.axis_offset_x;
double y = _setup.current_y + _setup.axis_offset_y;
rotate(&x, &y, _setup.rotation_xy);
*value = x + _setup.origin_offset_x + _setup.tool_offset.tran.x;
}
break;
case NP_ABS_Y: // abs position
{
double x = _setup.current_x + _setup.axis_offset_x;
double y = _setup.current_y + _setup.axis_offset_y;
rotate(&x, &y, _setup.rotation_xy);
*value = y + _setup.origin_offset_y + _setup.tool_offset.tran.y;
}
break;
case NP_ABS_Z: // abs position
*value = _setup.current_z + _setup.axis_offset_z +
_setup.origin_offset_z + _setup.tool_offset.tran.z;
break;
case NP_ABS_A: // abs position
*value = _setup.AA_current + _setup.AA_axis_offset +
_setup.AA_origin_offset + _setup.tool_offset.a;
break;
case NP_ABS_B: // abs position
*value = _setup.BB_current + _setup.BB_axis_offset +
_setup.BB_origin_offset + _setup.tool_offset.b;
break;
case NP_ABS_C: // abs position
*value = _setup.CC_current + _setup.CC_axis_offset +
_setup.CC_origin_offset + _setup.tool_offset.c;
break;
// o-word subs may optionally have an
// expression after endsub and return
// this 'function return value' is accessible as '_value'
case NP_VALUE:
*value = _setup.return_value;
break;
// predicate: the last NGC procedure did/did not return a value
case NP_VALUE_RETURNED:
*value = _setup.value_returned;
break;
case NP_CALL_LEVEL:
*value = _setup.call_level;
break;
case NP_REMAP_LEVEL:
*value = _setup.remap_level;
break;
case NP_TASK:
extern int _task; // zero in gcodemodule, 1 in milltask
*value = _task;
break;
default:
ERS(_("BUG: lookup_named_param(%s): unhandled index=%fn"),
nameBuf,index);
}
return INTERP_OK;
}
int Interp::init_python_predef_parameter(const char *name)
{
int exists = 0;
double value;
parameter_value param;
if (name[0] == '_') { // globals only
find_named_param(name, &exists, &value);
if (exists) {
fprintf(stderr, "warning: redefining named parameter %s\n",name);
_setup.sub_context[0].named_params.erase(name);
}
param.value = 0.0;
param.attr = PA_READONLY|PA_PYTHON|PA_GLOBAL;
_setup.sub_context[0].named_params[strstore(name)] = param;
}
return INTERP_OK;
}
int Interp::init_named_parameters()
{
// version major minor Note
// ------------ -------- ---------- -------------------------------------
// M.N.m M.N 0.m normal format
// M.N.m~xxx M.N 0.m pre-release format
const char *pkgversion = PACKAGE_VERSION; //examples: 2.4.6, 2.5.0~pre
const char *version_major = "_vmajor";// named_parameter name (use lower case)
const char *version_minor = "_vminor";// named_parameter name (use lower case)
const char *metric_machine = "_metric_machine";// named_parameter name (use lower case)
double vmajor=0.0, vminor=0.0, munits = 1.0;
sscanf(pkgversion, "%lf%lf", &vmajor, &vminor);
init_readonly_param(version_major,vmajor,0);
init_readonly_param(version_minor,vminor,0);
munits = inicheck();
init_readonly_param(metric_machine,munits,0);
// params tagged with PA_USE_LOOKUP will call the lookup_named_param()
// method. The value is used as a index for the switch() statement.
// the active_g_codes fields
// I guess this is the line number
init_readonly_param("_line", NP_LINE, PA_USE_LOOKUP);
// any of G1 G2 G3 G5.2 G73 G80 G82 G83 G86 G87 G88 G89
// value is number after 'G' multiplied by 10 (10,20,30,52..)
init_readonly_param("_motion_mode", NP_MOTION_MODE, PA_USE_LOOKUP);
// G17/18/19/17.1/18.1/19.1 -> return 170/180/190/171/181/191
init_readonly_param("_plane", NP_PLANE, PA_USE_LOOKUP);
// return 400,410,420 depending if (G40,G41,G42) is on
init_readonly_param("_ccomp", NP_CCOMP, PA_USE_LOOKUP);
// 1.0 if G21 is on
init_readonly_param("_metric", NP_METRIC, PA_USE_LOOKUP);
// 1.0 if G20 is on
init_readonly_param("_imperial", NP_IMPERIAL, PA_USE_LOOKUP);
//1.0 if G90 is on
init_readonly_param("_absolute", NP_ABSOLUTE, PA_USE_LOOKUP);
//1.0 if G91 is on
init_readonly_param("_incremental", NP_INCREMENTAL, PA_USE_LOOKUP);
// 1.0 if G93 is on
init_readonly_param("_inverse_time", NP_INVERSE_TIME, PA_USE_LOOKUP);
// 1.0 if G94 is on
init_readonly_param("_units_per_minute", NP_UNITS_PER_MINUTE, PA_USE_LOOKUP);
// 1.0 if G95 is on
init_readonly_param("_units_per_rev", NP_UNITS_PER_REV, PA_USE_LOOKUP);
// 0..9 for G54..G59.3
init_readonly_param("_coord_system", NP_COORD_SYSTEM, PA_USE_LOOKUP);
// 1.0 if G43 is on
init_readonly_param("_tool_offset", NP_TOOL_OFFSET, PA_USE_LOOKUP);
// 1 if G98 set
init_readonly_param("_retract_r_plane", NP_RETRACT_R_PLANE, PA_USE_LOOKUP);
// 1 if G99 set
init_readonly_param("_retract_old_z", NP_RETRACT_OLD_Z, PA_USE_LOOKUP);
// really esoteric
// init_readonly_param("_control_mode", 110, PA_USE_LOOKUP);
// 1 if G97 is on
init_readonly_param("_spindle_rpm_mode", NP_SPINDLE_RPM_MODE, PA_USE_LOOKUP);
init_readonly_param("_spindle_css_mode", NP_SPINDLE_CSS_MODE, PA_USE_LOOKUP);
// 1 if G90.1 is on
init_readonly_param("_ijk_absolute_mode", NP_IJK_ABSOLUTE_MODE, PA_USE_LOOKUP);
// 1 if G7 is on
init_readonly_param("_lathe_diameter_mode", NP_LATHE_DIAMETER_MODE, PA_USE_LOOKUP);
// 1 if G8 is on
init_readonly_param("_lathe_radius_mode", NP_LATHE_RADIUS_MODE, PA_USE_LOOKUP);
// the active_m_codes fields
init_readonly_param("_spindle_on", NP_SPINDLE_ON, PA_USE_LOOKUP);
init_readonly_param("_spindle_cw", NP_SPINDLE_CW, PA_USE_LOOKUP);
init_readonly_param("_mist", NP_MIST, PA_USE_LOOKUP);
init_readonly_param("_flood", NP_FLOOD, PA_USE_LOOKUP);
init_readonly_param("_speed_override", NP_SPEED_OVERRIDE, PA_USE_LOOKUP);
init_readonly_param("_feed_override", NP_FEED_OVERRIDE, PA_USE_LOOKUP);
init_readonly_param("_adaptive_feed", NP_ADAPTIVE_FEED, PA_USE_LOOKUP);
init_readonly_param("_feed_hold", NP_FEED_HOLD, PA_USE_LOOKUP);
// active_settings
init_readonly_param("_feed", NP_FEED, PA_USE_LOOKUP);
init_readonly_param("_rpm", NP_RPM, PA_USE_LOOKUP);
// tool related
init_readonly_param("_current_tool", NP_CURRENT_TOOL, PA_USE_LOOKUP);
init_readonly_param("_current_pocket", NP_CURRENT_POCKET, PA_USE_LOOKUP);
init_readonly_param("_selected_pocket", NP_SELECTED_POCKET, PA_USE_LOOKUP);
init_readonly_param("_selected_tool", NP_SELECTED_TOOL, PA_USE_LOOKUP);
// current position - alias to #5420-#5429
init_readonly_param("_x", NP_X, PA_USE_LOOKUP);
init_readonly_param("_y", NP_Y, PA_USE_LOOKUP);
init_readonly_param("_z", NP_Z, PA_USE_LOOKUP);
init_readonly_param("_a", NP_A, PA_USE_LOOKUP);
init_readonly_param("_b", NP_B, PA_USE_LOOKUP);
init_readonly_param("_c", NP_C, PA_USE_LOOKUP);
init_readonly_param("_u", NP_U, PA_USE_LOOKUP);
init_readonly_param("_v", NP_V, PA_USE_LOOKUP);
init_readonly_param("_w", NP_W, PA_USE_LOOKUP);
// current abs position, does not include any offset
init_readonly_param("_abs_x", NP_ABS_X, PA_USE_LOOKUP);
init_readonly_param("_abs_y", NP_ABS_Y, PA_USE_LOOKUP);
init_readonly_param("_abs_z", NP_ABS_Z, PA_USE_LOOKUP);
init_readonly_param("_abs_a", NP_ABS_A, PA_USE_LOOKUP);
init_readonly_param("_abs_b", NP_ABS_B, PA_USE_LOOKUP);
init_readonly_param("_abs_c", NP_ABS_C, PA_USE_LOOKUP);
// last (optional) endsub/return value
init_readonly_param("_value", NP_VALUE, PA_USE_LOOKUP);
// predicate: last NGC procedure did return a value on endsub/return
init_readonly_param("_value_returned", NP_VALUE_RETURNED, PA_USE_LOOKUP);
// predicate: 1 in milltask instance, 0 in UI - control preview behaviour
init_readonly_param("_task", NP_TASK, PA_USE_LOOKUP);
// debugging aids
init_readonly_param("_call_level", NP_CALL_LEVEL, PA_USE_LOOKUP);
init_readonly_param("_remap_level", NP_REMAP_LEVEL, PA_USE_LOOKUP);
return INTERP_OK;
}
double Interp::inicheck()
{
const char *filename;
if ((filename = getenv("INI_FILE_NAME")) == NULL) {
return -1.0;
}
IniFile inifile(filename);
if (!inifile) {
return -1.0;
}
if (auto inistring = inifile.findString("LINEAR_UNITS", "TRAJ")) {
if (*inistring == "inch") {
return 0.0;
} else {
return 1.0;
}
}
return -1.0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,204 @@
/**
* @file interp_parameter_def.hh
* Named global parameters used by the interpreter.
*
* This file exists mostly to avoid magic numbers in interpreter code.
*
* @author Robert W. Ellenberg <rwe24g@gmail.com>
*
* Copyright (c) 2019, Robert W. Ellenberg
*
* This source code is released for free distribution under the terms of the
* GNU General Public License (V2) as published by the Free Software Foundation.
*/
#ifndef INTERP_PARAMETER_DEF_H
#define INTERP_PARAMETER_DEF_H
namespace interp_param_global
{
// 31-5000 - G-code user parameters. These parameters are global in the G-code file, and available for general use. Volatile.
enum InterpParameterIndex {
// 5061-5069 - Coordinates of a G38 probe result (X, Y, Z, A, B, C, U, V & W). Coordinates are in the coordinate system in which the G38 took place. Volatile.
G38_X=5061,
G38_Y,
G38_Z,
G38_A,
G38_B,
G38_C,
G38_U,
G38_V,
G38_W,
// 5070 - G38 probe result: 1 if success, 0 if probe failed to close. Used with G38.3 and G38.5. Volatile.
G38_TRIPPED=5070,
// 5161-5169 - "G28" Home for X, Y, Z, A, B, C, U, V & W. Persistent.
G28_X=5161,
G28_Y,
G28_Z,
G28_A,
G28_B,
G28_C,
G28_U,
G28_V,
G28_W,
// 5181-5189 - "G30" Home for X, Y, Z, A, B, C, U, V & W. Persistent.
G30_X=5181,
G30_Y,
G30_Z,
G30_A,
G30_B,
G30_C,
G30_U,
G30_V,
G30_W,
// 5210 - 1 if "G92" offset is currently applied, 0 otherwise. Persistent.
// 5211-5219 - "G92" offset for X, Y, Z, A, B, C, U, V & W. Persistent.
G92_APPLIED=5210,
G92_X=5211,
G92_Y,
G92_Z,
G92_A,
G92_B,
G92_C,
G92_U,
G92_V,
G92_W,
// 5220 - Coordinate System number 1 - 9 for G54 - G59.3. Persistent.
// 5221-5230 - Coordinate System 1, G54 for X, Y, Z, A, B, C, U, V, W & R. R denotes the XY rotation angle around the Z axis. Persistent.
// 5241-5250 - Coordinate System 2, G55 for X, Y, Z, A, B, C, U, V, W & R. Persistent.
// 5261-5270 - Coordinate System 3, G56 for X, Y, Z, A, B, C, U, V, W & R. Persistent.
// 5281-5290 - Coordinate System 4, G57 for X, Y, Z, A, B, C, U, V, W & R. Persistent.
// 5301-5310 - Coordinate System 5, G58 for X, Y, Z, A, B, C, U, V, W & R. Persistent.
// 5321-5330 - Coordinate System 6, G59 for X, Y, Z, A, B, C, U, V, W & R. Persistent.
// 5341-5350 - Coordinate System 7, G59.1 for X, Y, Z, A, B, C, U, V, W & R. Persistent.
// 5361-5370 - Coordinate System 8, G59.2 for X, Y, Z, A, B, C, U, V, W & R. Persistent.
// 5381-5390 - Coordinate System 9, G59.3 for X, Y, Z, A, B, C, U, V, W & R. Persistent.
ACTIVE_WORK_CSYS=5220,
G54_X=5221,
G54_Y,
G54_Z,
G54_A,
G54_B,
G54_C,
G54_U,
G54_V,
G54_W,
G54_R,
G55_X=5241,
G55_Y,
G55_Z,
G55_A,
G55_B,
G55_C,
G55_U,
G55_V,
G55_W,
G55_R,
G56_X=5261,
G56_Y,
G56_Z,
G56_A,
G56_B,
G56_C,
G56_U,
G56_V,
G56_W,
G56_R,
G57_X=5281,
G57_Y,
G57_Z,
G57_A,
G57_B,
G57_C,
G57_U,
G57_V,
G57_W,
G57_R,
G58_X=5301,
G58_Y,
G58_Z,
G58_A,
G58_B,
G58_C,
G58_U,
G58_V,
G58_W,
G58_R,
G59_X=5321,
G59_Y,
G59_Z,
G59_A,
G59_B,
G59_C,
G59_U,
G59_V,
G59_W,
G59_R,
G59_1_X=5341,
G59_1_Y,
G59_1_Z,
G59_1_A,
G59_1_B,
G59_1_C,
G59_1_U,
G59_1_V,
G59_1_W,
G59_1_R,
G59_2_X=5361,
G59_2_Y,
G59_2_Z,
G59_2_A,
G59_2_B,
G59_2_C,
G59_2_U,
G59_2_V,
G59_2_W,
G59_2_R,
G59_3_X=5381,
G59_3_Y,
G59_3_Z,
G59_3_A,
G59_3_B,
G59_3_C,
G59_3_U,
G59_3_V,
G59_3_W,
G59_3_R,
// 5399 - Result of M66 - Check or wait for input. Volatile.
M66_RESULT=5399,
// 5400 - Tool Number. Volatile.
// 5401-5409 - Tool Offsets for X, Y, Z, A, B, C, U, V & W. Volatile.
TOOL_NUMBER=5400,
TOOL_OFFSET_X=5401,
TOOL_OFFSET_Y,
TOOL_OFFSET_Z,
TOOL_OFFSET_A,
TOOL_OFFSET_B,
TOOL_OFFSET_C,
TOOL_OFFSET_U,
TOOL_OFFSET_V,
TOOL_OFFSET_W,
// 5410 - Tool Diameter. Volatile.
TOOL_DIAMETER=5410,
// 5411 - Tool Front Angle. Volatile.
TOOL_FRONT_ANGLE=5411,
// 5412 - Tool Back Angle. Volatile.
TOOL_BACK_ANGLE=5412,
// 5413 - Tool Orientation. Volatile.
TOOL_ORIENTATION=5413,
// 5420-5428 - Current relative position in the active coordinate system including all offsets and in the current program units for X, Y, Z, A, B, C, U, V & W, volatile.
RELATIVE_POSITION_X=5420,
RELATIVE_POSITION_Y,
RELATIVE_POSITION_Z,
RELATIVE_POSITION_A,
RELATIVE_POSITION_B,
RELATIVE_POSITION_C,
RELATIVE_POSITION_U,
RELATIVE_POSITION_V,
RELATIVE_POSITION_W,
// 5599 - Flag for controlling the output of (DEBUG,) statements. 1=output, 0=no output; default=1. Volatile.
DEBUG_LEVEL_FLAG=5599,
RS274NGC_MAX_PARAMETERS=5602
};
}
#endif // INTERP_PARAMETER_DEF_H

View File

@@ -0,0 +1,692 @@
/********************************************************************
* Description: interp_queue.cc
*
* Author: Chris Radek
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2009 All rights reserved.
*
********************************************************************/
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "rs274ngc.hh"
#include "rs274ngc_return.hh"
#include "interp_queue.hh"
#include "interp_internal.hh"
#include "rs274ngc_interp.hh"
static int debug_qc = 0;
// lathe tools have strange origin points that are not at
// the center of the radius. This means that the point that
// radius compensation controls (center of radius) is not at
// the tool's origin. These functions do the necessary
// translation. Notice tool orientations 0 (mill) and 9, and
// those with radius 0 (a point) do not need any translation.
static double latheorigin_x(setup_pointer settings, double x) {
int o = settings->cutter_comp_orientation;
double r = settings->cutter_comp_radius;
if(settings->plane != CANON_PLANE::XZ) return x;
if(o==2 || o==6 || o==1) x -= r;
if(o==3 || o==8 || o==4) x += r;
return x;
}
static double latheorigin_z(setup_pointer settings, double z) {
int o = settings->cutter_comp_orientation;
double r = settings->cutter_comp_radius;
if(settings->plane != CANON_PLANE::XZ) return z;
if(o==2 || o==7 || o==3) z -= r;
if(o==1 || o==5 || o==4) z += r;
return z;
}
static double endpoint[2];
static int endpoint_valid = 0;
std::vector<queued_canon>& qc(void) {
static std::vector<queued_canon> c;
#if 0
printf("len %d\n", (int)c.size());
#endif
return c;
}
void qc_reset(void) {
if(debug_qc) printf("qc cleared\n");
qc().clear();
endpoint_valid = 0;
}
void enqueue_SET_FEED_RATE(double feed) {
if(qc().empty()) {
if(debug_qc) printf("immediate set feed rate %f\n", feed);
SET_FEED_RATE(feed);
return;
}
queued_canon q;
q.type = QSET_FEED_RATE;
q.data.set_feed_rate.feed = feed;
if(debug_qc) printf("enqueue set feed rate %f\n", feed);
qc().push_back(q);
}
void enqueue_DWELL(double time) {
if(qc().empty()) {
if(debug_qc) printf("immediate dwell %f\n", time);
DWELL(time);
return;
}
queued_canon q;
q.type = QDWELL;
q.data.dwell.time = time;
if(debug_qc) printf("enqueue dwell %f\n", time);
qc().push_back(q);
}
void enqueue_SET_FEED_MODE(int spindle, int mode) {
if(qc().empty()) {
if(debug_qc) printf("immediate set feed mode %d\n", mode);
SET_FEED_MODE(spindle, mode);
return;
}
queued_canon q;
q.type = QSET_FEED_MODE;
q.data.set_feed_mode.spindle = spindle;
q.data.set_feed_mode.mode = mode;
if(debug_qc) printf("enqueue set feed mode %d\n", mode);
qc().push_back(q);
}
void enqueue_MIST_ON(void) {
if(qc().empty()) {
if(debug_qc) printf("immediate mist on\n");
MIST_ON();
return;
}
queued_canon q;
q.type = QMIST_ON;
if(debug_qc) printf("enqueue mist on\n");
qc().push_back(q);
}
void enqueue_MIST_OFF(void) {
if(qc().empty()) {
if(debug_qc) printf("immediate mist off\n");
MIST_OFF();
return;
}
queued_canon q;
q.type = QMIST_OFF;
if(debug_qc) printf("enqueue mist off\n");
qc().push_back(q);
}
void enqueue_FLOOD_ON(void) {
if(qc().empty()) {
if(debug_qc) printf("immediate flood on\n");
FLOOD_ON();
return;
}
queued_canon q;
q.type = QFLOOD_ON;
if(debug_qc) printf("enqueue flood on\n");
qc().push_back(q);
}
void enqueue_FLOOD_OFF(void) {
if(qc().empty()) {
if(debug_qc) printf("immediate flood on\n");
FLOOD_OFF();
return;
}
queued_canon q;
q.type = QFLOOD_OFF;
if(debug_qc) printf("enqueue flood off\n");
qc().push_back(q);
}
void enqueue_START_SPINDLE_CLOCKWISE(int spindle) {
if(qc().empty()) {
if(debug_qc) printf("immediate spindle clockwise\n");
START_SPINDLE_CLOCKWISE(spindle);
return;
}
queued_canon q;
q.type = QSTART_SPINDLE_CLOCKWISE;
q.data.set_spindle_speed.spindle = spindle;
if(debug_qc) printf("enqueue spindle clockwise\n");
qc().push_back(q);
}
void enqueue_START_SPINDLE_COUNTERCLOCKWISE(int spindle) {
if(qc().empty()) {
if(debug_qc) printf("immediate spindle counterclockwise\n");
START_SPINDLE_COUNTERCLOCKWISE(spindle);
return;
}
queued_canon q;
q.type = QSTART_SPINDLE_COUNTERCLOCKWISE;
q.data.set_spindle_speed.spindle = spindle;
if(debug_qc) printf("enqueue spindle counterclockwise\n");
qc().push_back(q);
}
void enqueue_STOP_SPINDLE_TURNING(int spindle) {
if(qc().empty()) {
if(debug_qc) printf("immediate spindle stop\n");
STOP_SPINDLE_TURNING(spindle);
return;
}
queued_canon q;
q.type = QSTOP_SPINDLE_TURNING;
q.data.set_spindle_speed.spindle = spindle;
if(debug_qc) printf("enqueue spindle stop\n");
qc().push_back(q);
}
void enqueue_ORIENT_SPINDLE(int spindle, double orientation, int mode) {
if(qc().empty()) {
if(debug_qc) printf("immediate spindle orient\n");
ORIENT_SPINDLE(spindle, orientation, mode);
return;
}
queued_canon q;
q.type = QORIENT_SPINDLE;
q.data.orient_spindle.spindle = spindle;
q.data.orient_spindle.orientation = orientation;
q.data.orient_spindle.mode = mode;
if(debug_qc) printf("enqueue spindle orient\n");
qc().push_back(q);
}
void enqueue_WAIT_ORIENT_SPINDLE_COMPLETE(int spindle, double timeout) {
if(qc().empty()) {
if(debug_qc) printf("immediate wait spindle orient complete\n");
WAIT_SPINDLE_ORIENT_COMPLETE(spindle, timeout);
return;
}
queued_canon q;
q.type = QWAIT_ORIENT_SPINDLE_COMPLETE;
q.data.wait_orient_spindle_complete.spindle = spindle;
q.data.wait_orient_spindle_complete.timeout = timeout;
if(debug_qc) printf("enqueue wait spindle orient complete\n");
qc().push_back(q);
}
void enqueue_SET_SPINDLE_MODE(int spindle, double mode) {
if(qc().empty()) {
if(debug_qc) printf("immediate spindle mode %f\n", mode);
SET_SPINDLE_MODE(spindle, mode);
return;
}
queued_canon q;
q.type = QSET_SPINDLE_MODE;
q.data.set_spindle_mode.spindle = spindle;
q.data.set_spindle_mode.mode = mode;
if(debug_qc) printf("enqueue spindle mode %f\n", mode);
qc().push_back(q);
}
void enqueue_SET_SPINDLE_SPEED(int spindle, double speed) {
if(qc().empty()) {
if(debug_qc) printf("immediate set spindle speed %f\n", speed);
SET_SPINDLE_SPEED(spindle, speed);
return;
}
queued_canon q;
q.type = QSET_SPINDLE_SPEED;
q.data.set_spindle_speed.spindle = spindle;
q.data.set_spindle_speed.speed = speed;
if(debug_qc) printf("enqueue set spindle speed %f\n", speed);
qc().push_back(q);
}
void enqueue_COMMENT(const char *c) {
if(qc().empty()) {
if(debug_qc) printf("immediate comment \"%s\"\n", c);
COMMENT(c);
return;
}
queued_canon q;
q.type = QCOMMENT;
q.data.comment.comment = strdup(c);
if(debug_qc) printf("enqueue comment \"%s\"\n", c);
qc().push_back(q);
}
int enqueue_STRAIGHT_FEED(setup_pointer settings, int l,
double dx, double dy, double dz,
double x, double y, double z,
double a, double b, double c,
double u, double v, double w) {
queued_canon q;
q.type = QSTRAIGHT_FEED;
q.data.straight_feed.line_number = l;
switch(settings->plane) {
case CANON_PLANE::XY:
q.data.straight_feed.dx = dx;
q.data.straight_feed.dy = dy;
q.data.straight_feed.dz = dz;
q.data.straight_feed.x = x;
q.data.straight_feed.y = y;
q.data.straight_feed.z = z;
break;
case CANON_PLANE::XZ:
q.data.straight_feed.dz = dx;
q.data.straight_feed.dx = dy;
q.data.straight_feed.dy = dz;
q.data.straight_feed.z = x;
q.data.straight_feed.x = y;
q.data.straight_feed.y = z;
break;
default:
;
}
q.data.straight_feed.a = a;
q.data.straight_feed.b = b;
q.data.straight_feed.c = c;
q.data.straight_feed.u = u;
q.data.straight_feed.v = v;
q.data.straight_feed.w = w;
qc().push_back(q);
if(debug_qc) printf("enqueue straight feed lineno %d to %f %f %f direction %f %f %f\n", l, x,y,z, dx, dy, dz);
return 0;
}
int enqueue_STRAIGHT_TRAVERSE(setup_pointer settings, int l,
double dx, double dy, double dz,
double x, double y, double z,
double a, double b, double c,
double u, double v, double w) {
queued_canon q;
q.type = QSTRAIGHT_TRAVERSE;
q.data.straight_traverse.line_number = l;
switch(settings->plane) {
case CANON_PLANE::XY:
q.data.straight_traverse.dx = dx;
q.data.straight_traverse.dy = dy;
q.data.straight_traverse.dz = dz;
q.data.straight_traverse.x = x;
q.data.straight_traverse.y = y;
q.data.straight_traverse.z = z;
break;
case CANON_PLANE::XZ:
q.data.straight_traverse.dz = dx;
q.data.straight_traverse.dx = dy;
q.data.straight_traverse.dy = dz;
q.data.straight_traverse.z = x;
q.data.straight_traverse.x = y;
q.data.straight_traverse.y = z;
break;
default:
;
}
q.data.straight_traverse.a = a;
q.data.straight_traverse.b = b;
q.data.straight_traverse.c = c;
q.data.straight_traverse.u = u;
q.data.straight_traverse.v = v;
q.data.straight_traverse.w = w;
if(debug_qc) printf("enqueue straight traverse lineno %d to %f %f %f direction %f %f %f\n", l, x,y,z, dx, dy, dz);
qc().push_back(q);
return 0;
}
void enqueue_ARC_FEED(setup_pointer /*settings*/, int l,
double original_turns,
double end1, double end2, double center1, double center2,
int turn,
double end3,
double a, double b, double c,
double u, double v, double w) {
queued_canon q;
q.type = QARC_FEED;
q.data.arc_feed.line_number = l;
q.data.arc_feed.original_turns = original_turns;
q.data.arc_feed.end1 = end1;
q.data.arc_feed.end2 = end2;
q.data.arc_feed.center1 = center1;
q.data.arc_feed.center2 = center2;
q.data.arc_feed.turn = turn;
q.data.arc_feed.end3 = end3;
q.data.arc_feed.a = a;
q.data.arc_feed.b = b;
q.data.arc_feed.c = c;
q.data.arc_feed.u = u;
q.data.arc_feed.v = v;
q.data.arc_feed.w = w;
if(debug_qc) printf("enqueue arc lineno %d to %f %f center %f %f turn %d sweeping %f\n", l, end1, end2, center1, center2, turn, original_turns);
qc().push_back(q);
}
void enqueue_M_USER_COMMAND (int index, double p_number, double q_number) {
if(qc().empty()) {
if(debug_qc) printf("immediate M_USER_COMMAND index=%d p=%f q=%f\n",
index,p_number,q_number);
(*(USER_DEFINED_FUNCTION[index - 100])) (index - 100,p_number,q_number);
return;
}
queued_canon q;
q.type = QM_USER_COMMAND;
q.data.mcommand.index = index;
q.data.mcommand.p_number = p_number;
q.data.mcommand.q_number = q_number;
if(debug_qc) printf("enqueue M_USER_COMMAND index=%d p=%f q=%f\n",
index,p_number,q_number);
qc().push_back(q);
}
void qc_scale(double scale) {
if(qc().empty()) {
if(debug_qc) printf("not scaling because qc is empty\n");
return;
}
if(debug_qc) printf("scaling qc by %f\n", scale);
for(unsigned int i = 0; i<qc().size(); i++) {
queued_canon &q = qc()[i];
endpoint[0] *= scale;
endpoint[1] *= scale;
switch(q.type) {
case QARC_FEED:
q.data.arc_feed.end1 *= scale;
q.data.arc_feed.end2 *= scale;
q.data.arc_feed.end3 *= scale;
q.data.arc_feed.center1 *= scale;
q.data.arc_feed.center2 *= scale;
q.data.arc_feed.u *= scale;
q.data.arc_feed.v *= scale;
q.data.arc_feed.w *= scale;
break;
case QSTRAIGHT_FEED:
q.data.straight_feed.x *= scale;
q.data.straight_feed.y *= scale;
q.data.straight_feed.z *= scale;
q.data.straight_feed.u *= scale;
q.data.straight_feed.v *= scale;
q.data.straight_feed.w *= scale;
break;
case QSTRAIGHT_TRAVERSE:
q.data.straight_traverse.x *= scale;
q.data.straight_traverse.y *= scale;
q.data.straight_traverse.z *= scale;
q.data.straight_traverse.u *= scale;
q.data.straight_traverse.v *= scale;
q.data.straight_traverse.w *= scale;
break;
default:
;
}
}
}
void dequeue_canons(setup_pointer settings) {
if(debug_qc) printf("dequeueing: endpoint is now invalid\n");
endpoint_valid = 0;
if(qc().empty()) return;
for(unsigned int i = 0; i<qc().size(); i++) {
queued_canon &q = qc()[i];
switch(q.type) {
case QARC_FEED:
if(debug_qc) printf("issuing arc feed lineno %d\n", q.data.arc_feed.line_number);
ARC_FEED(q.data.arc_feed.line_number,
latheorigin_z(settings, q.data.arc_feed.end1),
latheorigin_x(settings, q.data.arc_feed.end2),
latheorigin_z(settings, q.data.arc_feed.center1),
latheorigin_x(settings, q.data.arc_feed.center2),
q.data.arc_feed.turn,
q.data.arc_feed.end3,
q.data.arc_feed.a, q.data.arc_feed.b, q.data.arc_feed.c,
q.data.arc_feed.u, q.data.arc_feed.v, q.data.arc_feed.w);
break;
case QSTRAIGHT_FEED:
if(debug_qc) printf("issuing straight feed lineno %d\n", q.data.straight_feed.line_number);
STRAIGHT_FEED(q.data.straight_feed.line_number,
latheorigin_x(settings, q.data.straight_feed.x),
q.data.straight_feed.y,
latheorigin_z(settings, q.data.straight_feed.z),
q.data.straight_feed.a, q.data.straight_feed.b, q.data.straight_feed.c,
q.data.straight_feed.u, q.data.straight_feed.v, q.data.straight_feed.w);
break;
case QSTRAIGHT_TRAVERSE:
if(debug_qc) printf("issuing straight traverse lineno %d\n", q.data.straight_traverse.line_number);
STRAIGHT_TRAVERSE(q.data.straight_traverse.line_number,
latheorigin_x(settings, q.data.straight_traverse.x),
q.data.straight_traverse.y,
latheorigin_z(settings, q.data.straight_traverse.z),
q.data.straight_traverse.a, q.data.straight_traverse.b, q.data.straight_traverse.c,
q.data.straight_traverse.u, q.data.straight_traverse.v, q.data.straight_traverse.w);
break;
case QSET_FEED_RATE:
if(debug_qc) printf("issuing set feed rate\n");
SET_FEED_RATE(q.data.set_feed_rate.feed);
break;
case QDWELL:
if(debug_qc) printf("issuing dwell\n");
DWELL(q.data.dwell.time);
break;
case QSET_FEED_MODE:
if(debug_qc) printf("issuing set feed mode\n");
SET_FEED_MODE(q.data.set_feed_mode.spindle,
q.data.set_feed_mode.mode);
break;
case QMIST_ON:
if(debug_qc) printf("issuing mist on\n");
MIST_ON();
break;
case QMIST_OFF:
if(debug_qc) printf("issuing mist off\n");
MIST_OFF();
break;
case QFLOOD_ON:
if(debug_qc) printf("issuing flood on\n");
FLOOD_ON();
break;
case QFLOOD_OFF:
if(debug_qc) printf("issuing flood off\n");
FLOOD_OFF();
break;
case QSTART_SPINDLE_CLOCKWISE:
if(debug_qc) printf("issuing spindle clockwise\n");
START_SPINDLE_CLOCKWISE(q.data.set_spindle_speed.spindle);
break;
case QSTART_SPINDLE_COUNTERCLOCKWISE:
if(debug_qc) printf("issuing spindle counterclockwise\n");
START_SPINDLE_COUNTERCLOCKWISE(q.data.set_spindle_speed.spindle);
break;
case QSTOP_SPINDLE_TURNING:
if(debug_qc) printf("issuing stop spindle\n");
STOP_SPINDLE_TURNING(q.data.set_spindle_speed.spindle);
break;
case QSET_SPINDLE_MODE:
if(debug_qc) printf("issuing set spindle mode\n");
SET_SPINDLE_MODE(q.data.set_spindle_speed.spindle,
q.data.set_spindle_mode.mode);
break;
case QSET_SPINDLE_SPEED:
if(debug_qc) printf("issuing set spindle speed\n");
SET_SPINDLE_SPEED(q.data.set_spindle_speed.spindle,
q.data.set_spindle_speed.speed);
break;
case QCOMMENT:
if(debug_qc) printf("issuing comment\n");
COMMENT(q.data.comment.comment);
free(q.data.comment.comment);
break;
case QM_USER_COMMAND:
if(debug_qc) printf("issuing mcommand\n");
{int index=q.data.mcommand.index;
(*(USER_DEFINED_FUNCTION[index - 100])) (index -100,
q.data.mcommand.p_number,
q.data.mcommand.q_number);
}
break;
case QORIENT_SPINDLE:
if(debug_qc) printf("issuing orient spindle\n");
ORIENT_SPINDLE(q.data.set_spindle_speed.spindle,
q.data.orient_spindle.orientation,
q.data.orient_spindle.mode);
break;
case QWAIT_ORIENT_SPINDLE_COMPLETE:
if(debug_qc) printf("issuing wait orient spindle complete\n");
WAIT_SPINDLE_ORIENT_COMPLETE(q.data.wait_orient_spindle_complete.spindle,
q.data.wait_orient_spindle_complete.timeout);
break;
}
}
qc().clear();
}
int Interp::move_endpoint_and_flush(setup_pointer settings, double x, double y) {
double x1;
double y1;
double x2;
double y2;
double dot;
if(qc().empty()) return 0;
for(unsigned int i = 0; i<qc().size(); i++) {
// there may be several moves in the queue, and we need to
// change all of them. consider moving into a concave corner,
// then up and back down, then continuing on. there will be
// three moves to change.
queued_canon &q = qc()[i];
switch(q.type) {
case QARC_FEED:
double r1, r2, l1, l2;
r1 = hypot(q.data.arc_feed.end1 - q.data.arc_feed.center1,
q.data.arc_feed.end2 - q.data.arc_feed.center2);
l1 = q.data.arc_feed.original_turns;
q.data.arc_feed.end1 = x;
q.data.arc_feed.end2 = y;
r2 = hypot(x - q.data.arc_feed.center1,
y - q.data.arc_feed.center2);
l2 = find_turn(endpoint[0], endpoint[1],
q.data.arc_feed.center1, q.data.arc_feed.center2,
q.data.arc_feed.turn,
x, y);
if(debug_qc) printf("moving endpoint of arc lineno %d old sweep %f new sweep %f\n", q.data.arc_feed.line_number, l1, l2);
if(fabs(r1-r2) > .01)
ERS(_("BUG: cutter compensation has generated an invalid arc with mismatched radii r1 %f r2 %f\n"), r1, r2);
if(l1 != 0.0 && endpoint_valid && fabs(l2) > fabs(l1) + (settings->length_units == CANON_UNITS_MM? .0254 : .001)) {
ERS(_("Arc move in concave corner cannot be reached by the tool without gouging"));
}
q.data.arc_feed.end1 = x;
q.data.arc_feed.end2 = y;
break;
case QSTRAIGHT_TRAVERSE:
switch(settings->plane) {
case CANON_PLANE::XY:
x1 = q.data.straight_traverse.dx; // direction of original motion
y1 = q.data.straight_traverse.dy;
x2 = x - endpoint[0]; // new direction after clipping
y2 = y - endpoint[1];
break;
case CANON_PLANE::XZ:
x1 = q.data.straight_traverse.dz; // direction of original motion
y1 = q.data.straight_traverse.dx;
x2 = x - endpoint[0]; // new direction after clipping
y2 = y - endpoint[1];
break;
default:
ERS(_("BUG: Unsupported plane in cutter compensation"));
}
dot = x1 * x2 + y1 * y2; // not normalized; we only care about the angle
if(debug_qc) printf("moving endpoint of traverse old dir %f new dir %f dot %f endpoint_valid %d\n", atan2(y1,x1), atan2(y2,x2), dot, endpoint_valid);
if(endpoint_valid && dot<0) {
// oops, the move is the wrong way. this means the
// path has crossed because we backed up further
// than the line is long. this will gouge.
ERS(_("Straight traverse in concave corner cannot be reached by the tool without gouging"));
}
switch(settings->plane) {
case CANON_PLANE::XY:
q.data.straight_traverse.x = x;
q.data.straight_traverse.y = y;
break;
case CANON_PLANE::XZ:
q.data.straight_traverse.z = x;
q.data.straight_traverse.x = y;
break;
default:
ERS(_("BUG: Unsupported plane in cutter compensation"));
}
break;
case QSTRAIGHT_FEED:
switch(settings->plane) {
case CANON_PLANE::XY:
x1 = q.data.straight_feed.dx; // direction of original motion
y1 = q.data.straight_feed.dy;
x2 = x - endpoint[0]; // new direction after clipping
y2 = y - endpoint[1];
break;
case CANON_PLANE::XZ:
x1 = q.data.straight_feed.dz; // direction of original motion
y1 = q.data.straight_feed.dx;
x2 = x - endpoint[0]; // new direction after clipping
y2 = y - endpoint[1];
break;
default:
ERS(_("BUG: Unsupported plane [%d] in cutter compensation"),
static_cast<int>(settings->plane));
}
dot = x1 * x2 + y1 * y2;
if(debug_qc) printf("moving endpoint of feed old dir %f new dir %f dot %f endpoint_valid %d\n", atan2(y1,x1), atan2(y2,x2), dot, endpoint_valid);
if(endpoint_valid && dot<0) {
// oops, the move is the wrong way. this means the
// path has crossed because we backed up further
// than the line is long. this will gouge.
ERS(_("Straight feed in concave corner cannot be reached by the tool without gouging"));
}
switch(settings->plane) {
case CANON_PLANE::XY:
q.data.straight_feed.x = x;
q.data.straight_feed.y = y;
break;
case CANON_PLANE::XZ:
q.data.straight_feed.z = x;
q.data.straight_feed.x = y;
break;
default:
ERS(_("BUG: Unsupported plane in cutter compensation"));
}
break;
default:
// other things are not moves - we don't have to mess with them.
;
}
}
dequeue_canons(settings);
set_endpoint(x, y);
return 0;
}
void set_endpoint(double x, double y) {
if(debug_qc) printf("setting endpoint %f %f\n", x, y);
endpoint[0] = x; endpoint[1] = y;
endpoint_valid = 1;
}

View File

@@ -0,0 +1,149 @@
/********************************************************************
* Description: interp_queue.hh
*
* Author: Chris Radek
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2009 All rights reserved.
*
********************************************************************/
#ifndef INTERP_QUEUE_HH
#define INTERP_QUEUE_HH
#include "interp_internal.hh"
#include <vector>
enum queued_canon_type {QSTRAIGHT_TRAVERSE, QSTRAIGHT_FEED, QARC_FEED, QSET_FEED_RATE, QDWELL, QSET_FEED_MODE,
QMIST_ON, QMIST_OFF, QFLOOD_ON, QFLOOD_OFF,
QSTART_SPINDLE_CLOCKWISE, QSTART_SPINDLE_COUNTERCLOCKWISE, QSTOP_SPINDLE_TURNING,
QSET_SPINDLE_MODE, QSET_SPINDLE_SPEED,
QCOMMENT, QM_USER_COMMAND,
QORIENT_SPINDLE, QWAIT_ORIENT_SPINDLE_COMPLETE};
struct straight_traverse {
int line_number;
double dx, dy, dz; // direction of original motion
double x,y,z, a,b,c, u,v,w;
};
struct straight_feed {
int line_number;
double dx, dy, dz; // direction of original motion
double x,y,z, a,b,c, u,v,w; // target
};
struct arc_feed {
int line_number;
double original_turns;
double end1, end2, center1, center2;
int turn;
double end3, a,b,c, u,v,w;
};
struct set_feed_rate {
double feed;
};
struct set_feed_mode {
int spindle;
int mode;
};
struct dwell {
double time;
};
struct set_spindle_mode {
int spindle;
double mode;
};
struct set_spindle_speed {
int spindle;
double speed;
};
struct comment {
char *comment;
};
struct mcommand {
int index;
double p_number;
double q_number;
};
struct orient_spindle {
int spindle;
double orientation;
int mode;
};
struct wait_orient_spindle_complete {
int spindle;
double timeout;
};
struct queued_canon {
queued_canon_type type;
union {
struct straight_traverse straight_traverse;
struct straight_feed straight_feed;
struct arc_feed arc_feed;
struct set_feed_rate set_feed_rate;
struct dwell dwell;
struct set_feed_mode set_feed_mode;
struct set_spindle_mode set_spindle_mode;
struct set_spindle_speed set_spindle_speed;
struct comment comment;
struct mcommand mcommand;
struct orient_spindle orient_spindle;
struct wait_orient_spindle_complete wait_orient_spindle_complete;
} data;
};
std::vector<queued_canon>& qc(void);
void enqueue_SET_FEED_RATE(double feed);
void enqueue_DWELL(double time);
void enqueue_SET_FEED_MODE(int spindle, int mode);
void enqueue_MIST_ON(void);
void enqueue_MIST_OFF(void);
void enqueue_FLOOD_ON(void);
void enqueue_FLOOD_OFF(void);
void enqueue_START_SPINDLE_CLOCKWISE(int spindle);
void enqueue_START_SPINDLE_COUNTERCLOCKWISE(int spinde);
void enqueue_STOP_SPINDLE_TURNING(int spindle);
void enqueue_SET_SPINDLE_MODE(int spindle, double mode);
void enqueue_SET_SPINDLE_SPEED(int spindle, double speed);
void enqueue_COMMENT(const char *c);
int enqueue_STRAIGHT_FEED(setup_pointer settings, int l,
double dx, double dy, double dz,
double x, double y, double z,
double a, double b, double c,
double u, double v, double w);
int enqueue_STRAIGHT_TRAVERSE(setup_pointer settings, int l,
double dx, double dy, double dz,
double x, double y, double z,
double a, double b, double c,
double u, double v, double w);
void enqueue_ARC_FEED(setup_pointer settings, int l,
double original_arclen,
double end1, double end2, double center1, double center2,
int turn,
double end3,
double a, double b, double c,
double u, double v, double w);
void enqueue_M_USER_COMMAND(int index,double p_number,double q_number);
void enqueue_ORIENT_SPINDLE(int spindle, double orientation, int mode);
void enqueue_WAIT_ORIENT_SPINDLE_COMPLETE(int spindle, double timeout);
void dequeue_canons(setup_pointer settings);
void set_endpoint(double x, double y);
void set_endpoint_zx(double z, double x);
int move_endpoint_and_flush(setup_pointer settings, double x, double y);
void qc_reset(void);
void qc_scale(double scale);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,370 @@
/********************************************************************
* Description: interp_write.cc
*
* Derived from a work by Thomas Kramer
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
********************************************************************/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "rs274ngc.hh"
#include "nml_intf/interp_return.hh"
#include "interp_internal.hh"
#include "rs274ngc_interp.hh"
/****************************************************************************/
/*! write_g_codes
Returned Value: int (INTERP_OK)
Side effects:
The active_g_codes in the settings are updated.
Called by:
Interp::execute
Interp::init
The block may be NULL.
This writes active g_codes into the settings->active_g_codes array by
examining the interpreter settings. The array of actives is composed
of ints, so (to handle codes like 59.1) all g_codes are reported as
ints ten times the actual value. For example, 59.1 is reported as 591.
The correspondence between modal groups and array indexes is as follows
(no apparent logic to it).
The group 0 entry is taken from the block (if there is one), since its
codes are not modal.
group 0 - array[2] g4, g10, g28, g30, g53, g92 g92.1, g92.2, g92.3 - misc
group 1 - array[1] g0, g1, g2, g3, g38.2, g80, g81, g82, g83, g84, g85,
g86, g87, g88, g89 - motion
group 2 - array[3] g17, g18, g19 - plane selection
group 3 - array[6] g90, g91 - distance mode
group 4 - array[14] g90.1, g91.1 - IJK distance mode for arcs
group 5 - array[7] g93, g94, g95 - feed rate mode
group 6 - array[5] g20, g21 - units
group 7 - array[4] g40, g41, g42 - cutter radius compensation
group 8 - array[9] g43, g49 - tool length offset
group 9 - no such group
group 10 - array[10] g98, g99 - return mode in canned cycles
group 11 - no such group
group 12 - array[8] g54, g55, g56, g57, g58, g59, g59.1, g59.2, g59.3
- coordinate system
group 13 - array[11] g61, g61.1, g64 - control mode
group 14 - array[12] g50, g51 - adaptive feed mode
group 15 - array[13] g96, g97 - spindle speed mode
group 16 - array[15] g7,g8 - lathe diameter mode
*/
int Interp::write_g_codes(block_pointer block, //!< pointer to a block of RS274/NGC instructions
setup_pointer settings) //!< pointer to machine settings
{
settings->active_g_codes[0] = settings->sequence_number;
settings->active_g_codes[1] = settings->motion_mode;
settings->active_g_codes[2] = ((block == NULL) ? -1 : block->g_modes[GM_MODAL_0]);
switch(settings->plane) {
case CANON_PLANE::XY:
settings->active_g_codes[3] = G_17;
break;
case CANON_PLANE::XZ:
settings->active_g_codes[3] = G_18;
break;
case CANON_PLANE::YZ:
settings->active_g_codes[3] = G_19;
break;
case CANON_PLANE::UV:
settings->active_g_codes[3] = G_17_1;
break;
case CANON_PLANE::UW:
settings->active_g_codes[3] = G_18_1;
break;
case CANON_PLANE::VW:
settings->active_g_codes[3] = G_19_1;
break;
}
settings->active_g_codes[4] =
(settings->cutter_comp_side == CUTTER_COMP::RIGHT) ? G_42 :
(settings->cutter_comp_side == CUTTER_COMP::LEFT) ? G_41 : G_40;
settings->active_g_codes[5] = (settings->length_units == CANON_UNITS_INCHES) ? G_20 : G_21;
settings->active_g_codes[6] = (settings->distance_mode == DISTANCE_MODE::ABSOLUTE) ? G_90 : G_91;
settings->active_g_codes[7] = (settings->feed_mode == FEED_MODE::INVERSE_TIME) ? G_93 :
(settings->feed_mode == FEED_MODE::UNITS_PER_MINUTE) ? G_94 : G_95;
settings->active_g_codes[8] =
(settings->origin_index <
7) ? (530 + (10 * settings->origin_index)) : (584 +
settings->origin_index);
settings->active_g_codes[9] =
(settings->g43_with_zero_offset ||
settings->tool_offset.tran.x || settings->tool_offset.tran.y || settings->tool_offset.tran.z ||
settings->tool_offset.a || settings->tool_offset.b || settings->tool_offset.c ||
settings->tool_offset.u || settings->tool_offset.v || settings->tool_offset.w) ? G_43 : G_49;
settings->active_g_codes[10] = (settings->retract_mode == RETRACT_MODE::OLD_Z) ? G_98 : G_99;
// Three modes: G_64, G_61, G_61_1 or CANON_CONTINUOUS/EXACT_PATH/EXACT_STOP
settings->active_g_codes[11] =
(settings->control_mode == CANON_CONTINUOUS) ? G_64 :
(settings->control_mode == CANON_EXACT_PATH) ? G_61 : G_61_1;
settings->active_g_codes[12] = -1;
settings->active_g_codes[13] = //I don't even know how to display the mode of an arbitrary number of spindles (andypugh 17/6/16)
(settings->spindle_mode[0] == SPINDLE_MODE::CONSTANT_RPM) ? G_97 : G_96;
settings->active_g_codes[14] = (settings->ijk_distance_mode == DISTANCE_MODE::ABSOLUTE) ? G_90_1 : G_91_1;
settings->active_g_codes[15] = (settings->lathe_diameter_mode) ? G_7 : G_8;
// 'G52','G92' are handled in modal group 0 which is cleared on startup, m2/m30 and abort, hence there
// is no indication of active G92 offsets after such events so we need modal group 16 as a workaround
if (block == NULL){ // this handles config startup
if (settings->parameters[5210] == 1){
settings->active_g_codes[16] = G_92_3;
} else {
settings->active_g_codes[16] = -1;
}
} else if (settings->parameters[5210] == 1 && block->g_modes[GM_MODAL_0] == -1){ // this handles aborts, m2/m30
settings->active_g_codes[16] = G_92_3;
} else {
settings->active_g_codes[16] = block->g_modes[GM_G92_IS_APPLIED];
}
return INTERP_OK;
}
/****************************************************************************/
/*! write_m_codes
Returned Value: int (INTERP_OK)
Side effects:
The settings->active_m_codes are updated.
Called by:
Interp::execute
Interp::init
This is testing only the feed override to see if overrides is on.
Might add check of speed override.
*/
int Interp::write_m_codes(block_pointer block, //!< pointer to a block of RS274/NGC instructions
setup_pointer settings) //!< pointer to machine settings
{
settings->active_m_codes[0] = settings->sequence_number; /* 0 seq number */
settings->active_m_codes[1] = (block == NULL) ? -1 : block->m_modes[4]; /* 1 stopping */
settings->active_m_codes[2] = (settings->spindle_turning[0] == CANON_STOPPED) ? 5 : /* 2 spindle */
(settings->spindle_turning[0] == CANON_CLOCKWISE) ? 3 : 4;
settings->active_m_codes[3] = /* 3 tool change */
(block == NULL) ? -1 : block->m_modes[6];
settings->active_m_codes[4] = /* 4 mist */
(settings->mist) ? 7 : (settings->flood) ? -1 : 9;
settings->active_m_codes[5] = /* 5 flood */
(settings->flood) ? 8 : -1;
// This only considers spindle 0. This function //
//doesn't even know how many spindles there are //
if (settings->feed_override) {
if (settings->speed_override[0]) settings->active_m_codes[6] = 48;
else settings->active_m_codes[6] = 50;
} else if (settings->speed_override[0]) {
settings->active_m_codes[6] = 51;
} else settings->active_m_codes[6] = 49;
settings->active_m_codes[7] = /* 7 overrides */
(settings->adaptive_feed) ? 52 : -1;
settings->active_m_codes[8] = /* 8 overrides */
(settings->feed_hold) ? 53 : -1;
return INTERP_OK;
}
/****************************************************************************/
/*! write_settings
Returned Value: int (INTERP_OK)
Side effects:
The settings->active_settings array of doubles is updated with the
sequence number, feed, and speed settings.
Called by:
Interp::execute
Interp::init
*/
int Interp::write_settings(setup_pointer settings) //!< pointer to machine settings
{
settings->active_settings[0] = settings->sequence_number; /* 0 sequence number */
settings->active_settings[1] = settings->feed_rate; /* 1 feed rate */
settings->active_settings[2] = settings->speed[0]; /* 2 spindle speed */
settings->active_settings[3] = settings->tolerance; /* 3 blend tolerance */
settings->active_settings[4] = settings->naivecam_tolerance; /* 4 naive CAM tolerance */
return INTERP_OK;
}
int Interp::write_state_tag(block_pointer block,
setup_pointer settings,
StateTag &state)
{
state.fields[GM_FIELD_LINE_NUMBER] = settings->sequence_number;
//FIXME refactor these into setup methods, and maybe put this
//whole method in setup struct
bool in_remap = (settings->remap_level > 0);
bool in_sub = (settings->call_level > 0 && settings->remap_level == 0);
bool external_sub = strcmp(settings->filename,
settings->sub_context[0].filename);
strncpy(state.filename, settings->filename, sizeof(state.filename));
state.filename[sizeof(state.filename)-1] = 0;
state.flags[GM_FLAG_IN_REMAP] = in_remap;
state.flags[GM_FLAG_IN_SUB] = in_sub;
state.flags[GM_FLAG_EXTERNAL_FILE] = external_sub;
state.flags[GM_FLAG_RESTORABLE] = !in_remap && !in_sub;
state.fields[GM_FIELD_G_MODE_0] =
((block == NULL) ? -1 : block->g_modes[GM_MODAL_0]);
state.fields[GM_FIELD_MOTION_MODE] = settings->motion_mode;
switch(settings->plane) {
case CANON_PLANE::XY:
state.fields[GM_FIELD_PLANE] = G_17;
break;
case CANON_PLANE::XZ:
state.fields[GM_FIELD_PLANE] = G_18;
break;
case CANON_PLANE::YZ:
state.fields[GM_FIELD_PLANE] = G_19;
break;
case CANON_PLANE::UV:
state.fields[GM_FIELD_PLANE] = G_17_1;
break;
case CANON_PLANE::UW:
state.fields[GM_FIELD_PLANE] = G_18_1;
break;
case CANON_PLANE::VW:
state.fields[GM_FIELD_PLANE] = G_19_1;
break;
}
state.fields[GM_FIELD_CUTTER_COMP] =
(settings->cutter_comp_side == CUTTER_COMP::RIGHT) ? G_42 :
(settings->cutter_comp_side == CUTTER_COMP::LEFT) ? G_41 : G_40;
state.flags[GM_FLAG_UNITS] =
(settings->length_units == CANON_UNITS_INCHES);
state.flags[GM_FLAG_DISTANCE_MODE] =
(settings->distance_mode == DISTANCE_MODE::ABSOLUTE);
state.flags[GM_FLAG_FEED_INVERSE_TIME] =
(settings->feed_mode == FEED_MODE::INVERSE_TIME);
state.flags[GM_FLAG_FEED_UPM] =
(settings->feed_mode == FEED_MODE::UNITS_PER_MINUTE);
state.fields[GM_FIELD_ORIGIN] =
((settings->origin_index < 7) ?
(530 + (10 * settings->origin_index)) :
(584 + settings->origin_index));
state.flags[GM_FLAG_G92_IS_APPLIED] = settings->parameters[5210];
state.flags[GM_FLAG_TOOL_OFFSETS_ON] =
(settings->g43_with_zero_offset ||
settings->tool_offset.tran.x ||
settings->tool_offset.tran.y ||
settings->tool_offset.tran.z ||
settings->tool_offset.a ||
settings->tool_offset.b ||
settings->tool_offset.c ||
settings->tool_offset.u ||
settings->tool_offset.v ||
settings->tool_offset.w);
state.flags[GM_FLAG_RETRACT_OLDZ] =
(settings->retract_mode == RETRACT_MODE::OLD_Z);
state.flags[GM_FLAG_BLEND] =
(settings->control_mode == CANON_CONTINUOUS);
state.flags[GM_FLAG_EXACT_STOP] =
(settings->control_mode == CANON_EXACT_STOP);
state.fields_float[GM_FIELD_FLOAT_PATH_TOLERANCE] =
settings->tolerance;
state.fields_float[GM_FIELD_FLOAT_NAIVE_CAM_TOLERANCE] =
settings->naivecam_tolerance;
state.flags[GM_FLAG_CSS_MODE] =
(settings->spindle_mode[0] == SPINDLE_MODE::CONSTANT_RPM);
state.flags[GM_FLAG_IJK_ABS] =
(settings->ijk_distance_mode == DISTANCE_MODE::ABSOLUTE);
state.flags[GM_FLAG_DIAMETER_MODE] =
(settings->lathe_diameter_mode);
state.fields[GM_FIELD_M_MODES_4] =
(block == NULL) ? -1 : block->m_modes[4];
state.flags[GM_FLAG_SPINDLE_ON] =
(settings->spindle_turning[0] != CANON_STOPPED);
state.flags[GM_FLAG_SPINDLE_CW] =
(settings->spindle_turning[0] == CANON_CLOCKWISE);
state.fields[GM_FIELD_TOOLCHANGE] =
(block == NULL) ? -1 : block->m_modes[6];
state.flags[GM_FLAG_MIST] = (settings->mist) ;
state.flags[GM_FLAG_FLOOD] = (settings->flood);
state.flags[GM_FLAG_FEED_OVERRIDE] = settings->feed_override;
state.flags[GM_FLAG_SPEED_OVERRIDE] = settings->speed_override[0];
state.flags[GM_FLAG_ADAPTIVE_FEED] = (settings->adaptive_feed);
state.flags[GM_FLAG_FEED_HOLD] = (settings->feed_hold);
state.fields_float[GM_FIELD_FLOAT_FEED] = settings->feed_rate;
state.fields_float[GM_FIELD_FLOAT_SPEED] = settings->speed[0];
// Pack new geometric data. block is NULL on the M70 save path
// (save_settings() in interp_convert.cc), so guard against null deref.
if(nullptr != block){
state.fields_float[GM_FIELD_FLOAT_STRAIGHT_HEADING] = block->arc_heading;
state.fields_float[GM_FIELD_FLOAT_ARC_RADIUS] = block->arc_radius;
state.fields_float[GM_FIELD_FLOAT_ARC_CENTER_X] = block->arc_center_x;
state.fields_float[GM_FIELD_FLOAT_ARC_CENTER_Y] = block->arc_center_y;
state.fields_float[GM_FIELD_FLOAT_ARC_CENTER_Z] = block->arc_center_z;
state.fields_float[GM_FIELD_FLOAT_NORMAL_HEADING] = block->normal_heading;
state.flags[GM_FLAG_IS_CIRCLE] = block->iscircle;
}
else{
state.fields_float[GM_FIELD_FLOAT_STRAIGHT_HEADING] = 0.0;
state.fields_float[GM_FIELD_FLOAT_ARC_RADIUS] = 0.0;
state.fields_float[GM_FIELD_FLOAT_ARC_CENTER_X] = 0.0;
state.fields_float[GM_FIELD_FLOAT_ARC_CENTER_Y] = 0.0;
state.fields_float[GM_FIELD_FLOAT_ARC_CENTER_Z] = 0.0;
state.fields_float[GM_FIELD_FLOAT_NORMAL_HEADING] = 0.0;
state.flags[GM_FLAG_IS_CIRCLE] = false;
}
return 0;
}
int Interp::write_canon_state_tag(block_pointer block, setup_pointer settings)
{
StateTag tag;
write_state_tag(block, settings, tag);
update_tag(tag);
return 0;
}
/****************************************************************************/

View File

@@ -0,0 +1,70 @@
/********************************************************************
* Description: modal_state.cc
*
* State storage class for interpreter
*
* Copyright © 2014 Robert W. Ellenberg
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
********************************************************************/
#include "interp_base.hh"
#include "modal_state.hh"
#include <string.h>
StateTag::StateTag(): flags(0)
{
memset(fields,-1,sizeof(fields));
packed_flags = 0;
memset(fields_float,-1,sizeof(fields_float));
memset(filename, 0, sizeof(filename));
}
StateTag::StateTag(struct state_tag_t const & basetag):
state_tag_t(basetag), flags(basetag.packed_flags)
{}
/**
* Return true if the tag is a valid state, and false if not
*/
int StateTag::is_valid(void) const
{
if (fields[GM_FIELD_LINE_NUMBER] <= 1) {
return false;
}
//TODO magic numbers
if (fields[GM_FIELD_ORIGIN] < 540) {
return false;
}
if (fields[GM_FIELD_PLANE] < 170 ) {
return false;
}
return true;
}
/**
* Return the C-equivalent state_tag version of the current state.
*/
state_tag_t StateTag::get_state_tag() const
{
state_tag_t out = static_cast<state_tag_t> (*this);
out.packed_flags = flags.to_ulong();
return out;
}

View File

@@ -0,0 +1,53 @@
/********************************************************************
* Description: modal_state.hh
*
* State storage class for interpreter
*
* Copyright © 2014 Robert W. Ellenberg
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
********************************************************************/
#ifndef MODAL_STATE_HH
#define MODAL_STATE_HH
#include <vector>
#include <bitset>
// Bring in C struct for a state tag from motion
extern "C" {
#include "motion/state_tag.h"
}
/**
* C++ version of state_tag_t structure to stuff interp state info in
* a motion message. Previously, this information was stored only in
* the interpreter, and as vectors of g codes, m codes, and
* settings. Considering that the write_XXX and gen_XXX functions had
* to jump through hoops to translate from a settings struct, the
* extra packing here isn't much more complex to deal with, and will
* cost much less space in an NML message.
*
* Using this class means we can work with a bitset instead of raw
* bitmasking operations. Also, because we're inheriting from the C
* struct, copy / assignment is valid.
*/
struct StateTag : public state_tag_t {
StateTag();
StateTag(state_tag_t const &basetag);
std::bitset<64> flags;
int is_valid(void) const;
state_tag_t get_state_tag() const;
};
#endif

View File

@@ -0,0 +1,82 @@
/********************************************************************
* Description: rs274ngc.hh
*
* Derived from a work by Thomas Kramer
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
********************************************************************/
#ifndef RS274NGC_HH
#define RS274NGC_HH
#include "interp_base.hh"
/**********************/
/* INCLUDE DIRECTIVES */
/**********************/
#include <stdio.h>
#include "nml_intf/canon.hh"
#include "nml_intf/emc.hh"
#include "nml_intf/debugflags.h"
#include "interp_fwd.hh"
// Declare class so that we can use it in the typedef.
class Interp;
typedef int (Interp::*read_function_pointer) (char *, int *, block_pointer, double *);
#define DBG(level,fmt,args...) \
do { \
if (level < _setup.loggingLevel) { \
fprintf(stderr,fmt, ## args); \
} \
} while (0)
// print to if RS274NGC/LOG_LEVEL > 1:
#define MSG(fmt,args...) \
do { \
DBG(0, fmt, ##args); \
} while (0)
#undef DEBUG_EMC
#define _logDebug(mask,dlflags,level, fmt, args...) \
do { \
if (((mask & _setup.debugmask) && \
(level < _setup.loggingLevel)) || \
(mask & EMC_DEBUG_UNCONDITIONAL)) { \
doLog(dlflags, \
__FILE__, \
__LINE__ , \
fmt "\n", \
## args); \
} \
} while(0)
//#define logDebug(fmt, args...) _logDebug(EMC_DEBUG_INTERP,LOG_FILENAME,1,fmt, ## args)
#define logDebug(fmt, args...) _logDebug(EMC_DEBUG_INTERP,0,1,fmt, ## args)
#define logConfig(fmt, args...) _logDebug(EMC_DEBUG_CONFIG,0,1,fmt, ## args)
#define logOword(fmt, args...) _logDebug(EMC_DEBUG_OWORD,0,1,fmt, ## args)
#define logRemap(fmt, args...) _logDebug(EMC_DEBUG_REMAP,0,1,fmt, ## args)
#define logPy(fmt, args...) _logDebug(EMC_DEBUG_PYTHON,0,1,fmt, ## args)
#define logNP(fmt, args...) _logDebug(EMC_DEBUG_NAMEDPARAM,0,1,fmt, ## args)
#define logStateTags(fmt, args...) \
_logDebug(EMC_DEBUG_STATE_TAGS,0,1,fmt, ## args)
// log always
#define Log(fmt, args...) _logDebug(EMC_DEBUG_UNCONDITIONAL,LOG_PID|LOG_FILENAME,-1,fmt, ## args)
#define Error(fmt, args...) _logDebug(EMC_DEBUG_UNCONDITIONAL,0,-1,fmt, ## args)
#endif

View File

@@ -0,0 +1,701 @@
// Copyright 2009-2011, various authors
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#ifndef RS274NGC_INTERP_H
#define RS274NGC_INTERP_H
#include "rs274ngc.hh"
#include "interp_internal.hh"
#include "nml_intf/interp_return.hh"
class Interp : public InterpBase {
public:
Interp();
~Interp() override;
/* Interface functions to call to tell the interpreter what to do.
Return values indicate status of execution.
These functions may change the state of the interpreter. */
// close the currently open NC code file
int close() override;
// execute a line of NC code
int execute(const char *command) override;
int execute() override;
int execute(const char *command, int line_no) override; //used for MDI calls to specify the pseudo MDI line number
// stop running
int exit() override;
// get ready to run
int init() override;
void set_loop_on_main_m99(bool state) override;
// load a tool table
int load_tool_table();
// open a file of NC code
int open(const char *filename) override;
// read the mdi or the next line of the open NC code file
int read(const char *mdi) override;
int read() override;
// reset yourself
int reset() override;
// restore interpreter variables from a file
int restore_parameters(const char *filename);
// save interpreter variables to file
int save_parameters(const char *filename,
const double parameters[]);
// synchronize your internal model with the external world
int synch() override;
/* Interface functions to call to get information from the interpreter.
If a function has a return value, the return value contains the information.
If a function returns nothing, information is copied into one of the
arguments to the function. These functions do not change the state of
the interpreter. */
// copy active G-codes into array [0]..[15]
void active_g_codes(int *codes) override;
// copy active M-codes into array [0]..[9]
void active_m_codes(int *codes) override;
// copy active F, S settings into array [0]..[2]
void active_settings(double *settings) override;
// Update the state vectors from a state tag
int active_modes(int *g_codes,
int *mcodes,
double *settings,
StateTag const &tag) override;
// Print contents of state tag for debugging
void print_state_tag(StateTag const &tag) override;
// copy the text of the error message whose number is error_code into the
// error_text array, but stop at max_size if the text is longer.
char *error_text(int error_code, char *error_text,
size_t max_size) override;
void setError(const char *fmt, ...) __attribute__((format(printf,2,3)));
// copy the name of the currently open file into the file_name array,
// but stop at max_size if the name is longer
char *file_name(char *file_name, size_t max_size) override;
// return the length of the most recently read line
size_t line_length() override;
// copy the text of the most recently read line into the line_text array,
// but stop at max_size if the text is longer
char *line_text(char *line_text, size_t max_size) override;
// return the current sequence number (how many lines read)
int sequence_number() override;
// copy the function name from the stack_index'th position of the
// function call stack at the time of the most recent error into
// the function name string, but stop at max_size if the name is longer
char *stack_name(int stack_index, char *function_name,
size_t max_size) override;
// Get the parameter file name from the INI file.
int ini_load(const char *filename) override;
int line() override { return sequence_number(); }
int call_level() override;
char *command(char *buf, size_t len) override { line_text(buf, len); return buf; }
char *file(char *buf, size_t len) override { file_name(buf, len); return buf; }
int init_tool_parameters();
int default_tool_parameters();
int set_tool_parameters();
int on_abort(int reason, const char *message) override;
void set_loglevel(int level) override;
// for now, public - for boost.python access
int find_named_param(const char *nameBuf, int *status, double *value);
int store_named_param(setup_pointer settings,const char *nameBuf, double value, int override_readonly = 0);
int add_named_param(const char *nameBuf, int attr = 0);
int fetch_ini_param( const char *nameBuf, int *status, double *value);
int fetch_hal_param( const char *nameBuf, int *status, double *value);
double inicheck();
// common combination of add_named_param and store_named_param
// int assign_named_param(const char *nameBuf, int attr = 0, double value = 0.0);
remap_pointer remapping(const char *code);
remap_pointer remapping(const char letter, int number = -1);
int find_tool_pocket(setup_pointer settings, int toolno, int *pocket);
int find_tool_index(setup_pointer settings, int toolno, int *index);
/* Function prototypes for all functions */
int arc_data_comp_ijk(int move,
CANON_PLANE plane,
CUTTER_COMP side,
double tool_radius,
double current_x,
double current_y,
double end_x,
double end_y,
int ij_absolute,
double i_number,
double j_number,
int p_number,
double *center_x,
double *center_y,
int *turn,
double radius_tolerance,
double spiral_abs_tolerance,
double spiral_rel_tolerance);
int arc_data_comp_r(int move,
CANON_PLANE plane,
CUTTER_COMP side,
double tool_radius,
double current_x,
double current_y,
double end_x,
double end_y,
double big_radius,
int p_number,
double *center_x,
double *center_y,
int *turn,
double radius_tolerance);
int arc_data_ijk(int move,
CANON_PLANE plane,
double current_x,
double current_y,
double end_x,
double end_y,
int ij_absolute,
double i_number,
double j_number,
int p_number,
double *center_x,
double *center_y,
int *turn,
double radius_tolerance,
double spiral_abs_tolerance,
double spiral_rel_tolerance);
int arc_data_r(int move,
CANON_PLANE plane,
double current_x,
double current_y,
double end_x,
double end_y,
double radius,
int p_number,
double *center_x,
double *center_y,
int *turn,
double radius_tolerance);
int check_g_codes(block_pointer block, setup_pointer settings);
int check_items(block_pointer block, setup_pointer settings);
int check_m_codes(block_pointer block);
int check_other_codes(block_pointer block);
int close_and_downcase(char *line);
void nurbs_reset_global_variables(void);
int convert_nurbs(int move, block_pointer block, setup_pointer settings);
int convert_spline(int move, block_pointer block, setup_pointer settings);
int convert_g7x(int move, block_pointer block, setup_pointer settings);
int comp_get_current(setup_pointer settings, double *x, double *y, double *z);
int comp_set_current(setup_pointer settings, double x, double y, double z);
int comp_get_programmed(setup_pointer settings, double *x, double *y, double *z);
int comp_set_programmed(setup_pointer settings, double x, double y, double z);
int convert_arc(int move, block_pointer block, setup_pointer settings);
int convert_arc2(int move, block_pointer block,
setup_pointer settings,
double *current1, double *current2, double *current3,
double end1, double end2, double end3,
double AA_end, double BB_end, double CC_end,
double u_end, double v_end, double w_end,
double offset1, double offset2);
int convert_arc_comp1(int move, block_pointer block,
setup_pointer settings,
double end_x, double end_y, double end_z,
double offset_x, double offset_y,
double AA_end, double BB_end, double CC_end,
double u_end, double v_end, double w_end);
int convert_arc_comp2(int move, block_pointer block,
setup_pointer settings,
double end_x, double end_y, double end_z,
double offset_x, double offset_y,
double AA_end, double BB_end, double CC_end,
double u_end, double v_end, double w_end);
char arc_axis1(CANON_PLANE plane);
char arc_axis2(CANON_PLANE plane);
int convert_axis_offsets(int g_code, block_pointer block,
setup_pointer settings);
int convert_param_comment(char *comment, char *expanded, int len);
int convert_comment(char *comment, bool enqueue = true);
int convert_control_mode(int g_code, double tolerance, double naivecam_tolerance, setup_pointer settings);
int convert_adaptive_mode(int g_code, setup_pointer settings);
int convert_coordinate_system(int g_code, setup_pointer settings);
int convert_cutter_compensation(int g_code, block_pointer block,
setup_pointer settings);
int convert_cutter_compensation_off(setup_pointer settings);
int convert_cutter_compensation_on(CUTTER_COMP side, block_pointer block,
setup_pointer settings);
int convert_cycle(int motion, block_pointer block,
setup_pointer settings);
int convert_cycle_g81(block_pointer block, CANON_PLANE plane, double x, double y,
double clear_z, double bottom_z);
int convert_cycle_g82(block_pointer block, CANON_PLANE plane, double x, double y,
double clear_z, double bottom_z, double dwell);
int convert_cycle_g73(block_pointer block, CANON_PLANE plane, double x, double y,
double r, double clear_z, double bottom_z,
double delta);
int convert_cycle_g83(block_pointer block, CANON_PLANE plane, double x, double y,
double r, double clear_z, double bottom_z,
double delta);
int convert_cycle_g74_g84(block_pointer block, CANON_PLANE plane, double x, double y,
double clear_z, double bottom_z,
CANON_DIRECTION direction, CANON_SPEED_FEED_MODE mode,
int motion, double dwell, int spindle);
int convert_cycle_g85(block_pointer block, CANON_PLANE plane, double x, double y,
double r, double clear_z, double bottom_z);
int convert_cycle_g86(block_pointer block, CANON_PLANE plane, double x, double y,
double clear_z, double bottom_z, double dwell,
CANON_DIRECTION direction, int spindle);
int convert_cycle_g87(block_pointer block, CANON_PLANE plane, double x, double offset_x,
double y, double offset_y, double r,
double clear_z, double middle_z, double bottom_z,
CANON_DIRECTION direction, int spindle);
int convert_cycle_g88(block_pointer block, CANON_PLANE plane, double x, double y,
double bottom_z, double dwell,
CANON_DIRECTION direction, int spindle);
int convert_cycle_g89(block_pointer block, CANON_PLANE plane, double x, double y,
double clear_z, double bottom_z, double dwell);
int convert_cycle_xy(int motion, block_pointer block,
setup_pointer settings);
int convert_cycle_yz(int motion, block_pointer block,
setup_pointer settings);
int convert_cycle_zx(int motion, block_pointer block,
setup_pointer settings);
int convert_cycle_uv(int motion, block_pointer block,
setup_pointer settings);
int convert_cycle_vw(int motion, block_pointer block,
setup_pointer settings);
int convert_cycle_wu(int motion, block_pointer block,
setup_pointer settings);
int convert_distance_mode(int g_code, setup_pointer settings);
int convert_ijk_distance_mode(int g_code, setup_pointer settings);
int convert_lathe_diameter_mode(int g_code, block_pointer block, setup_pointer settings);
int convert_dwell(setup_pointer settings, double time);
int convert_feed_mode(int g_code, setup_pointer settings);
int convert_feed_rate(block_pointer block, setup_pointer settings);
int convert_g(block_pointer block, setup_pointer settings);
int convert_home(int move, block_pointer block,
setup_pointer settings);
int convert_savehome(int move, block_pointer block,
setup_pointer settings);
int convert_length_units(int g_code, setup_pointer settings);
int convert_m(block_pointer block, setup_pointer settings);
int convert_modal_0(int code, block_pointer block,
setup_pointer settings);
int convert_g92_is_applied(int code, block_pointer block, setup_pointer settings);
int convert_motion(int motion, block_pointer block,
setup_pointer settings);
int convert_probe(block_pointer block, int g_code, setup_pointer settings);
int convert_retract_mode(int g_code, setup_pointer settings);
int convert_setup(block_pointer block, setup_pointer settings);
int convert_setup_tool(block_pointer block, setup_pointer settings);
int convert_set_plane(int g_code, setup_pointer settings);
int convert_speed(int spindle, block_pointer block, setup_pointer settings);
int convert_spindle_mode(int spindle, block_pointer block, setup_pointer settings);
int convert_stop(block_pointer block, setup_pointer settings);
int convert_straight(int move, block_pointer block,
setup_pointer settings);
int convert_straight_comp1(int move, block_pointer block,
setup_pointer settings,
double px, double py, double end_z,
double AA_end, double BB_end, double CC_end,
double u_end, double v_end, double w_end);
int convert_straight_comp2(int move, block_pointer block,
setup_pointer settings,
double px, double py, double end_z,
double AA_end, double BB_end, double CC_end,
double u_end, double v_end, double w_end);
int convert_threading_cycle(block_pointer block, setup_pointer settings,
double end_x, double end_y, double end_z);
int convert_tool_change(setup_pointer settings);
int convert_tool_length_offset(int g_code, block_pointer block,
setup_pointer settings);
int convert_tool_select(block_pointer block, setup_pointer settings);
int update_tag(StateTag &tag);
int cycle_feed(block_pointer block, CANON_PLANE plane, double end1,
double end2, double end3);
int cycle_traverse(block_pointer block, CANON_PLANE plane, double end1, double end2,
double end3);
int enhance_block(block_pointer block, setup_pointer settings);
int _execute(const char *command = 0);
int execute_binary(double *left, int operation, double *right);
int execute_binary1(double *left, int operation, double *right);
int execute_binary2(double *left, int operation, double *right);
int execute_block(block_pointer block, setup_pointer settings);
int execute_unary(double *double_ptr, int operation);
double find_arc_length(double x1, double y1, double z1,
double center_x, double center_y, int turn,
double x2, double y2, double z2);
int find_current_in_system(setup_pointer s, int system, double *x, double *y, double *z,
double *a, double *b, double *c,
double *u, double *v, double *w);
int find_current_in_system_without_tlo(setup_pointer s, int system, double *x, double *y, double *z,
double *a, double *b, double *c,
double *u, double *v, double *w);
int find_ends(block_pointer block, setup_pointer settings,
double *px, double *py, double *pz,
double *AA_p, double *BB_p, double *CC_p,
double *u_p, double *v_p, double *w_p);
int find_relative(double x1, double y1, double z1,
double AA_1, double BB_1, double CC_1,
double u_1, double v_1, double w_1,
double *x2, double *y2, double *z2,
double *AA_2, double *BB_2, double *CC_2,
double *u_2, double *v_2, double *w_2,
setup_pointer settings);
double find_straight_length(double x2, double y2, double z2,
double AA_2, double BB_2, double CC_2,
double u_w, double v_2, double w_2,
double x1, double y1, double z1,
double AA_1, double BB_1, double CC_1,
double u_1, double v_1, double w_1);
double find_turn(double x1, double y1, double center_x,
double center_y, int turn, double x2, double y2);
int init_block(block_pointer block);
int inverse_time_rate_arc(double x1, double y1, double z1,
double cx, double cy, int turn, double x2,
double y2, double z2, block_pointer block,
setup_pointer settings);
int inverse_time_rate_straight(double end_x, double end_y, double end_z,
double AA_end, double BB_end, double CC_end,
double u_end, double v_end, double w_end,
block_pointer block,
setup_pointer settings);
int move_endpoint_and_flush(setup_pointer, double, double);
int parse_line(char *line, block_pointer block,
setup_pointer settings);
int precedence(int an_operator);
int _read(const char *command);
int read_a(char *line, int *counter, block_pointer block,
double *parameters);
int read_atan(char *line, int *counter, double *double_ptr,
double *parameters);
int read_atsign(char *line, int *counter, block_pointer block,
double *parameters);
int read_b(char *line, int *counter, block_pointer block,
double *parameters);
int read_c(char *line, int *counter, block_pointer block,
double *parameters);
int read_carat(char *line, int *counter, block_pointer block,
double *parameters);
int read_comment(char *line, int *counter, block_pointer block,
double *parameters);
int read_semicolon(char *line, int *counter, block_pointer block,
double *parameters);
int read_d(char *line, int *counter, block_pointer block,
double *parameters);
int read_dollar(char *line, int *counter, block_pointer block,
double *parameters);
int read_e(char *line, int *counter, block_pointer block,
double *parameters);
int read_f(char *line, int *counter, block_pointer block,
double *parameters);
int read_g(char *line, int *counter, block_pointer block,
double *parameters);
int read_h(char *line, int *counter, block_pointer block,
double *parameters);
int read_i(char *line, int *counter, block_pointer block,
double *parameters);
int read_integer_unsigned(char *line, int *counter, int *integer_ptr);
int read_integer_value(char *line, int *counter, int *integer_ptr,
double *parameters);
int read_items(block_pointer block, char *line, double *parameters);
int read_j(char *line, int *counter, block_pointer block,
double *parameters);
int read_k(char *line, int *counter, block_pointer block,
double *parameters);
int read_l(char *line, int *counter, block_pointer block,
double *parameters);
int read_n_number(char *line, int *counter, block_pointer block);
int read_m(char *line, int *counter, block_pointer block,
double *parameters);
int read_o(char *line, int *counter, block_pointer block,
double *parameters);
int read_one_item(char *line, int *counter, block_pointer block,
double *parameters);
int read_operation(char *line, int *counter, int *operation);
int read_operation_unary(char *line, int *counter, int *operation);
int read_p(char *line, int *counter, block_pointer block,
double *parameters);
int lookup_named_param(const char *nameBuf, double index, double *value);
int init_readonly_param(const char *nameBuf, double value, int attr);
int free_named_parameters(context_pointer frame);
int save_settings(setup_pointer settings);
int restore_settings(setup_pointer settings, int from_level);
int restore_from_tag(StateTag const &tag) override;
int gen_settings(
int *int_current, int *int_saved,
double *float_current, double *float_saved,
std::string &cmd);
int gen_m_codes(int *current, int *saved, std::string &cmd);
int gen_restore_cmd(int *current_g,
int *current_m,
double *current_settings,
StateTag const &saved,
std::string &cmd);
int read_name(char *line, int *counter, char *nameBuf);
int read_named_parameter(char *line, int *counter, double *double_ptr,
double *parameters, bool check_exists);
int read_parameter(char *line, int *counter, double *double_ptr,
double *parameters, bool check_exists);
int read_parameter_setting(char *line, int *counter,
block_pointer block, double *parameters);
int read_bracketed_parameter(char *line, int *counter, double *double_ptr,
double *parameters, bool check_exists);
int read_named_parameter_setting(char *line, int *counter,
char **param, double *parameters);
int read_q(char *line, int *counter, block_pointer block,
double *parameters);
int read_r(char *line, int *counter, block_pointer block,
double *parameters);
int read_real_expression(char *line, int *counter,
double *hold2, double *parameters);
int read_real_number(char *line, int *counter, double *double_ptr);
int read_real_value(char *line, int *counter, double *double_ptr,
double *parameters);
int read_s(char *line, int *counter, block_pointer block,
double *parameters);
int read_t(char *line, int *counter, block_pointer block,
double *parameters);
int read_text(const char *command, FILE * inport, char *raw_line,
char *line, int *length);
int read_unary(char *line, int *counter, double *double_ptr,
double *parameters);
int read_u(char *line, int *counter, block_pointer block,
double *parameters);
int read_v(char *line, int *counter, block_pointer block,
double *parameters);
int read_w(char *line, int *counter, block_pointer block,
double *parameters);
int read_x(char *line, int *counter, block_pointer block,
double *parameters);
int read_y(char *line, int *counter, block_pointer block,
double *parameters);
int read_z(char *line, int *counter, block_pointer block,
double *parameters);
int refresh_actual_position(setup_pointer settings);
void rotate(double *x, double *y, double t);
int set_probe_data(setup_pointer settings);
int write_g_codes(block_pointer block, setup_pointer settings);
int write_m_codes(block_pointer block, setup_pointer settings);
int write_settings(setup_pointer settings);
int write_state_tag(block_pointer block, setup_pointer settings,
StateTag &state);
int write_canon_state_tag(block_pointer block, setup_pointer settings);
int unwrap_rotary(double *, double, double, double, char);
// O_word stuff
int findFile( // ARGUMENTS
char *direct, // the directory to start looking in
char *target, // the name of the file to find
char *foundFileDirect); // where to store the result
int control_save_offset( /* ARGUMENTS */
// int line, /* (o-word) line number */
block_pointer block, /* pointer to a block of RS274/NGC instructions */
setup_pointer settings); /* pointer to machine settings */
int control_save_offset(
block_pointer block,
const char *o_name, /* o_name key */
setup_pointer settings);
int control_find_oword( /* ARGUMENTS */
const char *o_name, /* o-word name */
setup_pointer settings, /* pointer to machine settings */
offset_pointer *ppo);
int control_find_oword( /* ARGUMENTS */
block_pointer block, /* block pointer to get (o-word) name */
setup_pointer settings, /* pointer to machine settings */
offset_pointer *ppo);
// int *o_index); /* the index of o-word (returned) */
int control_back_to( /* ARGUMENTS */
block_pointer block, // pointer to block
setup_pointer settings); /* pointer to machine settings */
// establish a new subroutine context
int enter_context(setup_pointer settings, block_pointer block);
// leave current subroutine context
int leave_context(setup_pointer settings, bool restore = true);
//int call_fsm(setup_pointer settings, int event);
//int execute_pycall(setup_pointer settings, const char *name, int call_phase);
int execute_call(setup_pointer settings, context_pointer current_frame, int call_type);
int execute_return(setup_pointer settings, context_pointer current_frame, int call_type);
void loop_to_beginning(setup_pointer settings);
//int execute_remap(setup_pointer settings, int call_phase); // remap call state machine
int handler_returned( setup_pointer settings,
context_pointer active_frame, const char *name, bool osub);
int read_inputs(setup_pointer settings);
int convert_control_functions( /* ARGUMENTS */
block_pointer block, /* pointer to a block of RS274/NGC instructions */
setup_pointer settings); /* pointer to machine settings */
// parse a REMAP= descriptor from the INI file
int parse_remap(const char *inistring, int lineno);
// step through parsed block and collect remapped items in
// block.remappings set
int find_remappings(block_pointer block, setup_pointer settings);
// establish a new remapping context
int enter_remap(void);
// leave current remapping context
int leave_remap(void);
// callback when remapping handler done
int remap_finished( int status);
int report_error(setup_pointer settings,int status,const char *text);
// add named params/param dict if argspec given
// present optional words to the subroutine's local variables and Py dict
int add_parameters(setup_pointer settings, block_pointer cblock,
char *posarglist);
int init_named_parameters();
int init_python_predef_parameter(const char *name);
bool remap_in_progress(const char *code);
int convert_remapped_code(block_pointer block,
setup_pointer settings,
int phase,
char letter,
int number = -1);
bool is_pycallable(setup_pointer settings, const char *module, const char *funcname);
#define OWORD_MODULE "oword"
#define REMAP_MODULE "remap"
#define NAMEDPARAMS_MODULE "namedparams"
// describes intended use, and hence parameter and return value
// interpretation
enum py_calltype { PY_OWORDCALL,
PY_FINISH_OWORDCALL,
PY_PROLOG,
PY_FINISH_PROLOG,
PY_BODY,
PY_FINISH_BODY,
PY_EPILOG,
PY_FINISH_EPILOG,
PY_INTERNAL,
PY_EXECUTE,
PY_PLUGIN_CALL
};
int pycall(setup_pointer settings,
context_pointer frame,
const char *module,
const char *funcname,
int calltype);
int py_execute(const char *cmd, bool as_file = false); // for (py, ....) comments
int py_reload();
FILE *find_ngc_file(setup_pointer settings,const char *basename, char *foundhere = NULL);
const char *getSavedError();
// set error message text without going through printf format interpretation
int setSavedError(const char *msg);
int unwind_call(int status, const char *file, int line, const char *function);
int convert_straight_indexer(int anum, int jnum, block* blk, setup* settings);
int issue_straight_index(int anum, int jnum, double end, int lineno, setup* settings);
void doLog(unsigned int flags, const char *file, int line,
const char *fmt, ...) __attribute__((format(printf,5,6)));
/* State Tags Helpers */
int tag_straight(block_pointer block, double x, double y);
int tag_arc(block_pointer block, double x, double y, double z, double center_x, double center_y, double center_z, int move, CANON_PLANE plane);
const char *interp_status(int status);
//technically this violates encapsulation rules but is needed for
// the Python introspection module
FILE *log_file;
read_function_pointer _readers[256];
static const read_function_pointer default_readers[256];
setup _setup;
enum {
AXIS_MASK_X = 1, AXIS_MASK_Y = 2, AXIS_MASK_Z = 4,
AXIS_MASK_A = 8, AXIS_MASK_B = 16, AXIS_MASK_C = 32,
AXIS_MASK_U = 64, AXIS_MASK_V = 128, AXIS_MASK_W = 256,
};
InterpReturn check_g74_g84_spindle(GCodes motion, CANON_DIRECTION dir);
private:
[[nodiscard]] static bool is_parameter_readonly(int index);
[[nodiscard]] static bool is_any_m_code_remapped(block_pointer block, setup_pointer settings);
[[nodiscard]] static bool is_user_defined_m_code(block_pointer block, setup_pointer settings,
int m_group);
[[nodiscard]] static bool is_m_code_remappable(int m_code);
[[nodiscard]] static bool is_g_code_remappable(int g_code);
[[nodiscard]] bool is_user_defined_g_code(int g_code);
static const int gees[];
static const int ems[];
static const int required_parameters[];
static const int readonly_parameters[];
static const int n_readonly_parameters;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,219 @@
// Copyright 2004-2010 various authors.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#ifndef RS274NGC_RETURN_HH
#define RS274NGC_RETURN_HH
#include "nml_intf/interp_return.hh"
#define NCE_A_FILE_IS_ALREADY_OPEN _("A file is already open")
#define NCE_ALL_AXES_MISSING_WITH_G52_OR_G92 \
_("All axes missing with g52 or g92")
#define NCE_ALL_AXES_MISSING_WITH_MOTION_CODE _("All axes missing with motion code")
#define NCE_ARC_RADIUS_TOO_SMALL_TO_REACH_END_POINT _("Arc radius too small to reach end point")
#define NCE_ARGUMENT_TO_ACOS_OUT_OF_RANGE _("Argument to acos out of range")
#define NCE_ARGUMENT_TO_ASIN_OUT_OF_RANGE _("Argument to asin out of range")
#define NCE_ATTEMPT_TO_DIVIDE_BY_ZERO _("Attempt to divide by zero")
#define NCE_ATTEMPT_TO_RAISE_NEGATIVE_TO_NON_INTEGER_POWER _("Attempt to raise negative to non integer power")
#define NCE_BAD_FORMAT_UNSIGNED_INTEGER _("Bad format unsigned integer")
#define NCE_BAD_NUMBER_FORMAT _("Bad number format")
#define NCE_BUG_BAD_G_CODE_MODAL_GROUP_0 _("Bug bad g code modal group 0")
#define NCE_BUG_CODE_NOT_G0_OR_G1 _("Bug code not g0 or g1")
#define NCE_BUG_CODE_NOT_G17_G18_OR_G19 _("Bug code not g17 g18 or g19")
#define NCE_BUG_CODE_NOT_G20_OR_G21 _("Bug code not g20 or g21")
#define NCE_BUG_CODE_NOT_G28_OR_G30 _("Bug code not g28 or g30")
#define NCE_BUG_CODE_NOT_G2_OR_G3 _("Bug code not g2 or g3")
#define NCE_BUG_CODE_NOT_G4_G10_G28_G30_G52_G53_OR_G92_SERIES \
_("Bug code not g4 g10 g28 g30 g52 g53 or g92 series")
#define NCE_BUG_CODE_NOT_G61_G61_1_OR_G64 _("Bug code not g61 g61.1 or g64")
#define NCE_BUG_CODE_NOT_G90_OR_G91 _("Bug code not g90 or g91")
#define NCE_BUG_CODE_NOT_G98_OR_G99 _("Bug code not g98 or g99")
#define NCE_BUG_CODE_NOT_IN_G52_G92_SERIES _("Bug code not in g52 or g92 series")
#define NCE_BUG_CODE_NOT_IN_RANGE_G54_TO_G593 _("Bug code not in range g54 to g593")
#define NCE_BUG_CODE_NOT_M0_M1_M2_M30_M60_M99 _("Bug code not m0 m1 m2 m30 m60 m99")
#define NCE_BUG_DISTANCE_MODE_NOT_G90_OR_G91 _("Bug distance mode not g90 or g91")
#define NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED _("Bug function should not have been called")
#define NCE_BUG_IN_TOOL_RADIUS_COMP _("Bug in tool radius comp")
#define NCE_BUG_PLANE_NOT_XY_YZ_OR_XZ _("Bug plane not xy yz or xz")
#define NCE_BUG_SIDE_NOT_RIGHT_OR_LEFT _("Bug side not right or left")
#define NCE_BUG_UNKNOWN_MOTION_CODE _("Bug unknown motion code")
#define NCE_BUG_UNKNOWN_OPERATION _("Bug unknown operation")
#define NCE_CANNOT_CHANGE_AXIS_OFFSETS_WITH_CUTTER_RADIUS_COMP _("Cannot change axis offsets with cutter radius comp")
#define NCE_CANNOT_CREATE_BACKUP_FILE _("Cannot create backup file")
#define NCE_CANNOT_DO_G1_WITH_ZERO_FEED_RATE _("Cannot do g1 with zero feed rate")
#define NCE_CANNOT_DO_ZERO_REPEATS_OF_CYCLE _("Cannot do zero repeats of cycle")
#define NCE_CANNOT_MAKE_ARC_WITH_ZERO_FEED_RATE _("Cannot make arc with zero feed rate")
#define NCE_CANNOT_OPEN_BACKUP_FILE _("Cannot open backup file")
#define NCE_CANNOT_OPEN_VARIABLE_FILE _("Cannot open variable file")
#define NCE_CANNOT_PROBE_WITH_CUTTER_RADIUS_COMP_ON _("Cannot probe with cutter radius comp on")
#define NCE_CANNOT_PROBE_WITH_ZERO_FEED_RATE _("Cannot probe with zero feed rate")
#define NCE_CANNOT_PUT_A_B_IN_CANNED_CYCLE _("Cannot put a b in canned cycle")
#define NCE_CANNOT_PUT_A_C_IN_CANNED_CYCLE _("Cannot put a c in canned cycle")
#define NCE_CANNOT_PUT_AN_A_IN_CANNED_CYCLE _("Cannot put an a in canned cycle")
#define NCE_CANNOT_TURN_CUTTER_RADIUS_COMP_ON_WHEN_ON _("Cannot turn cutter radius comp on when on")
#define NCE_CANNOT_USE_AXIS_VALUES_WITH_G80 _("Cannot use axis values with g80")
#define NCE_CANNOT_USE_AXIS_VALUES_WITHOUT_A_G_CODE_THAT_USES_THEM _("Cannot use axis values without a g code that uses them")
#define NCE_CANNOT_USE_G28_OR_G30_WITH_CUTTER_RADIUS_COMP _("Cannot use g28 or g30 with cutter radius comp")
#define NCE_CANNOT_USE_G53_INCREMENTAL _("Cannot use g53 incremental")
#define NCE_CANNOT_USE_G53_WITH_CUTTER_RADIUS_COMP _("Cannot use g53 with cutter radius comp")
#define NCE_CANNOT_USE_TWO_G_CODES_THAT_BOTH_USE_AXIS_VALUES _("Cannot use two g codes that both use axis values")
#define NCE_COMMAND_TOO_LONG _("Command too long")
#define NCE_CURRENT_POINT_SAME_AS_END_POINT_OF_ARC _("Current point same as end point of arc")
#define NCE_DWELL_TIME_MISSING_WITH_G4 _("Dwell time missing with g4")
#define NCE_DWELL_TIME_P_WORD_MISSING_WITH_G82 _("Dwell time p word missing with g82")
#define NCE_DWELL_TIME_P_WORD_MISSING_WITH_G86 _("Dwell time p word missing with g86")
#define NCE_DWELL_TIME_P_WORD_MISSING_WITH_G88 _("Dwell time p word missing with g88")
#define NCE_DWELL_TIME_P_WORD_MISSING_WITH_G89 _("Dwell time p word missing with g89")
#define NCE_EQUAL_SIGN_MISSING_IN_PARAMETER_SETTING _("Equal sign missing in parameter setting")
#define NCE_F_WORD_MISSING_WITH_INVERSE_TIME_ARC_MOVE _("F word missing with inverse time arc move")
#define NCE_F_WORD_MISSING_WITH_INVERSE_TIME_G1_MOVE _("F word missing with inverse time g1 move")
#define NCE_FILE_ENDED_WITH_NO_PERCENT_SIGN _("File ended with no percent sign (%%)")
#define NCE_FILE_ENDED_WITH_NO_PERCENT_SIGN_OR_PROGRAM_END _("File ended with no percent sign (%%) or program end (M2)")
#define NCE_FILE_NAME_TOO_LONG _("File name too long")
#define NCE_G_CODE_OUT_OF_RANGE _("G-code out of range")
#define NCE_I_WORD_GIVEN_FOR_ARC_IN_YZ_PLANE _("I word given for arc in yz plane")
#define NCE_I_WORD_MISSING_WITH_G87 _("I word missing with g87")
#define NCE_J_WORD_GIVEN_FOR_ARC_IN_XZ_PLANE _("J word given for arc in xz plane")
#define NCE_J_WORD_MISSING_WITH_G87 _("J word missing with g87")
#define NCE_K_WORD_GIVEN_FOR_ARC_IN_XY_PLANE _("K word given for arc in xy plane")
#define NCE_K_WORD_MISSING_WITH_G87 _("K word missing with g87")
#define NCE_LEFT_BRACKET_MISSING_AFTER_SLASH_WITH_ATAN _("Left bracket missing after slash with atan")
#define NCE_LEFT_BRACKET_MISSING_AFTER_UNARY_OPERATION_NAME _("Left bracket missing after unary operation name")
#define NCE_M_CODE_GREATER_THAN_199 _("M-code greater than 199: M%d")
#define NCE_MIXED_RADIUS_IJK_FORMAT_FOR_ARC _("Mixed radius ijk format for arc")
#define NCE_MULTIPLE_$_WORDS_ON_ONE_LINE _("Multiple spindle choice ($) words on one line")
#define NCE_MULTIPLE_A_WORDS_ON_ONE_LINE _("Multiple a words on one line")
#define NCE_MULTIPLE_B_WORDS_ON_ONE_LINE _("Multiple b words on one line")
#define NCE_MULTIPLE_C_WORDS_ON_ONE_LINE _("Multiple c words on one line")
#define NCE_MULTIPLE_D_WORDS_ON_ONE_LINE _("Multiple d words on one line")
#define NCE_MULTIPLE_F_WORDS_ON_ONE_LINE _("Multiple f words on one line")
#define NCE_MULTIPLE_H_WORDS_ON_ONE_LINE _("Multiple h words on one line")
#define NCE_MULTIPLE_I_WORDS_ON_ONE_LINE _("Multiple i words on one line")
#define NCE_MULTIPLE_J_WORDS_ON_ONE_LINE _("Multiple j words on one line")
#define NCE_MULTIPLE_K_WORDS_ON_ONE_LINE _("Multiple k words on one line")
#define NCE_MULTIPLE_L_WORDS_ON_ONE_LINE _("Multiple l words on one line")
#define NCE_MULTIPLE_P_WORDS_ON_ONE_LINE _("Multiple p words on one line")
#define NCE_MULTIPLE_Q_WORDS_ON_ONE_LINE _("Multiple q words on one line")
#define NCE_MULTIPLE_R_WORDS_ON_ONE_LINE _("Multiple r words on one line")
#define NCE_MULTIPLE_S_WORDS_ON_ONE_LINE _("Multiple s words on one line")
#define NCE_MULTIPLE_T_WORDS_ON_ONE_LINE _("Multiple t words on one line")
#define NCE_MULTIPLE_X_WORDS_ON_ONE_LINE _("Multiple x words on one line")
#define NCE_MULTIPLE_Y_WORDS_ON_ONE_LINE _("Multiple y words on one line")
#define NCE_MULTIPLE_Z_WORDS_ON_ONE_LINE _("Multiple z words on one line")
#define NCE_MUST_USE_G0_OR_G1_WITH_G53 _("Must use g0 or g1 with g53")
#define NCE_NEGATIVE_ARGUMENT_TO_SQRT _("Negative argument to sqrt")
#define NCE_NEGATIVE_D_WORD_TOOL_RADIUS_INDEX_USED _("Negative d word tool radius index used")
#define NCE_NEGATIVE_F_WORD_USED _("Negative f word used")
#define NCE_NEGATIVE_G_CODE_USED _("Negative g code used")
#define NCE_NEGATIVE_H_WORD_USED _("Negative h word used")
#define NCE_NEGATIVE_L_WORD_USED _("Negative l word used")
#define NCE_NEGATIVE_M_CODE_USED _("Negative m code used")
#define NCE_NEGATIVE_OR_ZERO_Q_VALUE_USED _("Negative or zero q value used")
#define NCE_NEGATIVE_P_WORD_USED _("Negative p word used")
#define NCE_NEGATIVE_SPINDLE_SPEED_USED _("Negative spindle speed used")
#define NCE_NEGATIVE_TOOL_ID_USED _("Negative tool id (tool not found)")
#define NCE_NESTED_COMMENT_FOUND _("Nested comment found")
#define NCE_NO_CHARACTERS_FOUND_IN_READING_REAL_VALUE _("No characters found in reading real value")
#define NCE_NON_INTEGER_VALUE_FOR_INTEGER _("Non integer value for integer")
#define NCE_NULL_MISSING_AFTER_NEWLINE _("Null missing after newline")
#define NCE_PARAMETER_FILE_OUT_OF_ORDER _("Parameter file out of order")
#define NCE_PARAMETER_NUMBER_OUT_OF_RANGE _("Parameter number out of range")
#define NCE_PARAMETER_NUMBER_READONLY _("Parameter is readonly")
#define NCE_Q_WORD_MISSING_WITH_G83 _("Q word missing with g83")
#define NCE_QUEUE_IS_NOT_EMPTY_AFTER_PROBING _("Queue is not empty after probing")
#define NCE_R_CLEARANCE_PLANE_UNSPECIFIED_IN_CYCLE _("R clearance plane unspecified in cycle")
#define NCE_R_I_J_K_WORDS_ALL_MISSING_FOR_ARC _("R i j k words all missing for arc")
#define NCE_R_LESS_THAN_X_IN_CYCLE_IN_YZ_PLANE _("R less than x in cycle in yz plane")
#define NCE_R_LESS_THAN_Y_IN_CYCLE_IN_XZ_PLANE _("R less than y in cycle in xz plane")
#define NCE_R_LESS_THAN_Z_IN_CYCLE_IN_XY_PLANE _("R less than z in cycle in xy plane")
#define NCE_R_WORD_WITH_NO_G_CODE_THAT_USES_IT _("R word with no g code that uses it")
#define NCE_SLASH_MISSING_AFTER_FIRST_ATAN_ARGUMENT _("Slash missing after first atan argument")
#define NCE_SPINDLE_NOT_TURNING_CLOCKWISE_IN_G84 _("Spindle not turning clockwise in g84")
#define NCE_SPINDLE_NOT_TURNING_IN_G86 _("Spindle not turning in g86")
#define NCE_SPINDLE_NOT_TURNING_IN_G87 _("Spindle not turning in g87")
#define NCE_SPINDLE_NOT_TURNING_IN_G88 _("Spindle not turning in g88")
#define NCE_SSCANF_FAILED _("Sscanf failed")
#define NCE_START_POINT_TOO_CLOSE_TO_PROBE_POINT _("Start point too close to probe point")
#define NCE_TOO_MANY_M_CODES_ON_LINE _("Too many m codes on line")
#define NCE_POCKET_MAX_TOO_LARGE _("Pocket max too large")
#define NCE_TOOL_RADIUS_NOT_LESS_THAN_ARC_RADIUS_WITH_COMP _("Tool radius not less than arc radius with comp")
#define NCE_TWO_G_CODES_USED_FROM_SAME_MODAL_GROUP _("Two g codes used from same modal group")
#define NCE_TWO_M_CODES_USED_FROM_SAME_MODAL_GROUP _("Two m codes used from same modal group")
#define NCE_UNABLE_TO_OPEN_FILE _("Unable to open file <%s>")
#define NCE_UNCLOSED_COMMENT_FOUND _("Unclosed comment found")
#define NCE_UNCLOSED_EXPRESSION _("Unclosed expression")
#define NCE_UNKNOWN_G_CODE_USED _("Unknown g code used")
#define NCE_UNKNOWN_M_CODE_USED _("Unknown m code used: M%d")
#define NCE_UNKNOWN_OPERATION _("Unknown operation")
#define NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_A _("Unknown operation name starting with a")
#define NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_M _("Unknown operation name starting with m")
#define NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_O _("Unknown operation name starting with o")
#define NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_X _("Unknown operation name starting with x")
#define NCE_UNKNOWN_WORD_STARTING_WITH_A _("Unknown word starting with a")
#define NCE_UNKNOWN_WORD_STARTING_WITH_C _("Unknown word starting with c")
#define NCE_UNKNOWN_WORD_STARTING_WITH_E _("Unknown word starting with e")
#define NCE_UNKNOWN_WORD_STARTING_WITH_F _("Unknown word starting with f")
#define NCE_UNKNOWN_WORD_STARTING_WITH_L _("Unknown word starting with l")
#define NCE_UNKNOWN_WORD_STARTING_WITH_R _("Unknown word starting with r")
#define NCE_UNKNOWN_WORD_STARTING_WITH_S _("Unknown word starting with s")
#define NCE_UNKNOWN_WORD_STARTING_WITH_T _("Unknown word starting with t")
#define NCE_UNKNOWN_WORD_WHERE_UNARY_OPERATION_COULD_BE _("Unknown word where unary operation could be")
#define NCE_X_AND_Y_WORDS_MISSING_FOR_ARC_IN_XY_PLANE _("X and y words missing for arc in xy plane")
#define NCE_X_AND_Z_WORDS_MISSING_FOR_ARC_IN_XZ_PLANE _("X and z words missing for arc in xz plane")
#define NCE_X_VALUE_UNSPECIFIED_IN_YZ_PLANE_CANNED_CYCLE _("X value unspecified in yz plane canned cycle")
#define NCE_Y_AND_Z_WORDS_MISSING_FOR_ARC_IN_YZ_PLANE _("Y and z words missing for arc in yz plane")
#define NCE_Y_VALUE_UNSPECIFIED_IN_XZ_PLANE_CANNED_CYCLE _("Y value unspecified in xz plane canned cycle")
#define NCE_Z_VALUE_UNSPECIFIED_IN_XY_PLANE_CANNED_CYCLE _("Z value unspecified in xy plane canned cycle")
#define NCE_ZERO_OR_NEGATIVE_ARGUMENT_TO_LN _("Zero or negative argument to ln")
#define NCE_ZERO_RADIUS_ARC _("Zero radius arc")
#define NCE_K_WORD_MISSING_WITH_G33 _("K word missing with g33/g33.1")
#define NCE_F_WORD_USED_WITH_G33 _("F word used with a g33/g33.1")
#define NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_E _("Unknown operation name starting with e")
#define NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_N _("Unknown operation name starting with n")
#define NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_G _("Unknown operation name starting with g")
#define NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_L _("Unknown operation name starting with l")
#define NCE_TOO_MANY_SUBROUTINE_PARAMETERS _("Too many subroutine parameters")
#define NCE_TOO_MANY_SUBROUTINE_LEVELS _("Too many subroutine levels")
#define NCE_CALL_STACK_UNDERRUN _("Bug: call stack underrun")
#define NCE_UNKNOWN_COMMAND_IN_O_LINE _("Unknown control command in o word")
#define NCE_TOO_MANY_OWORD_LABELS _("Too many oword labels")
#define NCE_UNKNOWN_OWORD_NUMBER _("Unknown oword number")
#define NCE_NESTED_SUBROUTINE_DEFN _("Nested subroutine definition")
#define NCE_NOT_IN_SUBROUTINE_DEFN _("Not in subroutine definition")
#define NCE_FILE_NOT_OPEN _("File not open")
#define NCE_CANNOT_REOPEN_FILE _("cannot reopen file %s - removed or renamed? (%s)")
#define NCE_TXX_MISSING_FOR_M6 _("Need tool prepared -Txx- for toolchange")
#define NCE_CANNOT_CHANGE_PLANES_WITH_CUTTER_RADIUS_COMP_ON _("Cannot change planes with cutter radius compensation on")
#define NCE_RADIUS_COMP_ONLY_IN_XY_OR_XZ _("Cutter radius compensation allowed only in XY, XZ planes")
#define NCE_P_WORD_MISSING_WITH_G76 _("P word missing with G76")
#define NCE_I_J_OR_K_WORDS_MISSING_WITH_G76 _("I J or K words missing with G76")
#define NCE_CANNOT_MOVE_ROTARY_AXES_WITH_G76 _("Cannot move rotary axes with G76")
#define NCE_MULTIPLE_E_WORDS_ON_ONE_LINE _("Multiple e words on one line")
#define NCE_NAMED_PARAMETER_NOT_TERMINATED _("Named parameter not terminated")
#define NCE_OUT_OF_MEMORY _("Out of memory")
#define NCE_S_WORD_MISSING_WITH_G96 _("S word missing with G96")
#define NCE_QUEUE_IS_NOT_EMPTY_AFTER_INPUT _("Queue is not empty after external input")
#define NCE_ANALOG_INPUT_WITH_WAIT_NOT_IMMEDIATE _("Can't select analog input with wait type != immediate return")
#define NCE_ZERO_TIMEOUT_WITH_WAIT_NOT_IMMEDIATE _("Zero timeout with wait type != immediate return")
#define NCE_BOTH_DIGITAL_AND_ANALOG_INPUT_SELECTED _("Invalid to select both a digital and an analog input with M66")
#define NCE_INVALID_OR_MISSING_P_AND_E_WORDS_FOR_WAIT_INPUT _("Need to have either a valid P or a valid E word with M66")
#define NCE_Q_WORD_MISSING_WITH_G73 _("Q word missing with g73")
#define NCE_DIGITAL_INPUT_INVALID_ON_M66 _("Digital input selected out of bounds")
#define NCE_ANALOG_INPUT_INVALID_ON_M66 _("Analog input selected out of bounds")
#define NCE_W_VALUE_UNSPECIFIED_IN_UV_PLANE_CANNED_CYCLE _("W value unspecified in UV plane canned cycle")
#define NCE_U_VALUE_UNSPECIFIED_IN_VW_PLANE_CANNED_CYCLE _("U value unspecified in VW plane canned cycle")
#define NCE_V_VALUE_UNSPECIFIED_IN_UW_PLANE_CANNED_CYCLE _("V value unspecified in UW plane canned cycle")
#define NCE_R_LESS_THAN_W_IN_CYCLE_IN_UV_PLANE _("R less than W in cycle in UV plane")
#define NCE_R_LESS_THAN_U_IN_CYCLE_IN_VW_PLANE _("R less than U in cycle in VW plane")
#define NCE_R_LESS_THAN_V_IN_CYCLE_IN_UW_PLANE _("R less than V in cycle in UW plane")
#endif

View File

@@ -0,0 +1,37 @@
/********************************************************************
* Description: units.h
* Unit conversion macros and constants
*
* Derived from a work by Fred Proctor & Will Shackleford
*
* License: GPL Version 2
*
* Copyright (c) 2005 All rights reserved.
*
* Last change:
********************************************************************/
/* macros for converting internal (mm/deg) units to external units */
#define TO_EXT_LEN(mm) ((mm) * GET_EXTERNAL_LENGTH_UNITS())
#define TO_EXT_ANG(deg) ((deg) * GET_EXTERNAL_ANGLE_UNITS())
/* macros for converting external units to internal (mm/deg) units */
#define FROM_EXT_LEN(ext) ((ext) / GET_EXTERNAL_LENGTH_UNITS())
#define FROM_EXT_ANG(ext) ((ext) / GET_EXTERNAL_ANGLE_UNITS())
/* macros for converting internal (mm/deg) units to program units */
#define TO_PROG_LEN(mm) ((mm) / (_setup.length_units == CANON_UNITS_INCHES ? 25.4 : _setup.length_units == CANON_UNITS_CM ? 10.0 : 1.0))
#define TO_PROG_ANG(deg) (deg)
/* macros for converting program units to internal (mm/deg) units */
#define FROM_PROG_LEN(prog) ((prog) * (_setup.length_units == CANON_UNITS_INCHES ? 25.4 : _setup.length_units == CANON_UNITS_CM ? 10.0 : 1.0))
#define FROM_PROG_ANG(prog) (prog)
/* macros for converting between user units (INI file) and program units (G-code) */
#define USER_TO_PROGRAM_LEN(u) (TO_PROG_LEN(FROM_EXT_LEN(u)))
#define PROGRAM_TO_USER_LEN(p) (TO_EXT_LEN(FROM_PROG_LEN(p)))
#define USER_TO_PROGRAM_ANG(u) (TO_PROG_ANG(FROM_EXT_ANG(u)))
#define PROGRAM_TO_USER_ANG(p) (TO_EXT_ANG(FROM_PROG_ANG(p)))

View File

@@ -0,0 +1,854 @@
/********************************************************************
* Description: gomath.h
* Library file with various functions for working with matrices
*
* Derived from a work by Fred Proctor,
* changed to work with emc2 and HAL
*
* Adapting Author: Alex Joni
* License: LGPL Version 2
* System: Linux
*
*******************************************************************
Similar to posemath, but using different functions.
TODO:
* find the new functions, add them to posemath, convert the rest
*/
#ifndef __LINUXCNC_GO_MATH_H
#define __LINUXCNC_GO_MATH_H
#include <stddef.h> /* sizeof */
#include "rtapi_math.h" /* M_PI */
#include <float.h> /* FLT,DBL_MIN,MAX,EPSILON */
#include "gotypes.h" /* go_integer,real */
/*! Returns the square of \a x. */
#define go_sq(x) ((x)*(x))
/*! Returns the cube of \a x. */
#define go_cub(x) ((x)*(x)*(x))
/*! Returns \a x to the fourth power. */
#define go_qua(x) ((x)*(x)*(x)*(x))
/*! Returns the sine and cosine of \a x (in radians) in \a s and \a c,
respectively. Implemented as a single call when supported, to speed
up the calculation of the two values. */
extern void go_sincos(go_real x, go_real * s, go_real * c);
/*! Returns the cube root of \a x. */
extern go_real go_cbrt(go_real x);
#ifdef M_PI
/*! The value of Pi. */
#define GO_PI M_PI
#else
/*! The value of Pi. */
#define GO_PI 3.14159265358979323846
#endif
/*! The value of twice Pi. */
#define GO_2_PI (2.0*GO_PI)
#ifdef M_PI_2
/*! The value of half of Pi. */
#define GO_PI_2 M_PI_2
#else
/*! The value of half of Pi. */
#define GO_PI_2 1.57079632679489661923
#endif
#ifdef M_PI_4
/*! The value of one-fourth of Pi. */
#define GO_PI_4 M_PI_4
#else
/*! The value of one-fourth of Pi. */
#define GO_PI_4 0.78539816339744830962
#endif
/*! Returns \a rad in radians as its value in degrees. */
#define GO_TO_DEG(rad) ((rad)*57.295779513082323)
/*! Returns \a deg in degrees as its value in radians. */
#define GO_TO_RAD(deg) ((deg)*0.0174532925199432952)
/*! How close translational quantities must be to be equal. */
#define GO_TRAN_CLOSE(x,y) (fabs((x)-(y)) < GO_REAL_EPSILON)
/*! How small a translational quantity must be to be zero. */
#define GO_TRAN_SMALL(x) (fabs(x) < GO_REAL_EPSILON)
/*! How close rotational quantities must be to be equal. */
#define GO_ROT_CLOSE(x,y) (fabs((x)-(y)) < GO_REAL_EPSILON)
/*! How small a rotational quantity must be to be zero. */
#define GO_ROT_SMALL(x) (fabs(x) < GO_REAL_EPSILON)
/*! How close general quantities must be to be equal. Use this when
you have something other than translational or rotational quantities,
otherwise use one of \a GO_TRAN,ROT_CLOSE. */
#define GO_CLOSE(x,y) (fabs((x)-(y)) < GO_REAL_EPSILON)
/*! How small a general quantity must be to be zero. Use this when
you have something other than a translational or rotational quantity,
otherwise use one of \a GO_TRAN,ROT_SMALL. */
#define GO_SMALL(x) (fabs(x) < GO_REAL_EPSILON)
/*! A point or vector in Cartesian coordinates. */
typedef struct {
go_real x;
go_real y;
go_real z;
} go_cart;
/*! A point or vector in spherical coordinates, with \a phi as
the angle down from the zenith, not up from the XY plane. */
typedef struct {
go_real theta;
go_real phi;
go_real r;
} go_sph;
/*! A point or vector in cylindrical coordinates. */
typedef struct {
go_real theta;
go_real r;
go_real z;
} go_cyl;
/*! A rotation vector, whose direction points along the axis of positive
rotation, and whose magnitude is the amount of rotation around this
axis, in radians. */
typedef struct {
go_real x;
go_real y;
go_real z;
} go_rvec;
/* | m.x.x m.y.x m.z.x | */
/* go_mat m = | m.x.y m.y.y m.z.y | */
/* | m.x.z m.y.z m.z.z | */
/*! A rotation matrix. */
typedef struct {
go_cart x; /*!< X unit vector */
go_cart y; /*!< Y unit vector */
go_cart z; /*!< Z unit vector */
} go_mat;
/*! A quaternion. \a s is the cosine of the half angle of rotation,
and the \a xyz elements comprise the vector that points in the direction
of positive rotation and whose magnitude is the sine of the half
angle of rotation. */
typedef struct {
go_real s;
go_real x;
go_real y;
go_real z;
} go_quat;
/*! ZYZ Euler angles. \a z is the amount of the first rotation around the
Z axis. \a y is the amount of the second rotation around the new \a Y
axis. \a zp is the amount of the third rotation around the new \a Z axis. */
typedef struct {
go_real z;
go_real y;
go_real zp;
} go_zyz;
/*! ZYX Euler angles. \a z is the amount of the first rotation around the
Z axis. \a y is the amount of the second rotation around the new \a Y
axis. \a x is the amount of the third rotation around the new \a X axis. */
typedef struct {
go_real z;
go_real y;
go_real x;
} go_zyx;
/*! Roll-pitch-yaw angles. \a r is the amount of the first rotation
(roll) around the X axis. \a p is the amount of the second rotation
(pitch) around the original Y axis. \a y is the amount of the third
rotation (yaw) around the original Z axis. */
typedef struct {
go_real r;
go_real p;
go_real y;
} go_rpy;
/*!
A \a go_pose represents the Cartesian position vector and quaternion
orientation of a frame.
*/
typedef struct {
go_cart tran;
go_quat rot;
} go_pose;
/*!
A \a go_screw represents the linear- and angular velocity vectors
of a frame. \a v is the Cartesian linear velocity vector.
\a w is the Cartesian angular velocity vector, the instantaneous
vector about which the frame is rotating.
*/
typedef struct {
go_cart v;
go_cart w;
} go_screw;
/*! Convenience function that returns a \a go_pose given individual
elements. */
extern go_pose
go_pose_this(go_real x, go_real y, go_real z,
go_real rs, go_real rx, go_real ry, go_real rz);
/*! Returns the zero vector. */
extern go_cart
go_cart_zero(void);
/*! Returns the identity (zero) quaternion, i.e., no rotation. */
extern go_quat
go_quat_identity(void);
/*! Returns the identity pose, no translation or rotation. */
extern go_pose
go_pose_identity(void);
typedef struct {
go_cart tran;
go_mat rot;
} go_hom;
/* lines, planes and related functions */
/*!
Lines are represented in point-direction form
(point p, direction v) as
(x - px)/vx = (y - py)/vy = (z - pz)vz
*/
typedef struct {
go_cart point;
go_cart direction; /* always a unit vector */
} go_line;
/*!
Given a plane as Ax + By + Cz + D = 0, the normal vector
\a normal is the Cartesian vector (A,B,C), and the number
\a d is the value D.
Planes have a handedness, given by the direction of the normal
vector, so two planes that appear coincident may be different by the
direction of their anti-parallel normal vectors.
*/
typedef struct {
go_cart normal;
go_real d;
} go_plane;
/*! Fills in \a line given \a point and \a direction. Returns GO_RESULT_OK
if \a direction is non-zero, otherwise GO_RESULT_ERROR. */
extern int go_line_from_point_direction(const go_cart * point, const go_cart * direction, go_line * line);
/*! Fills in \a line given two points. Returns GO_RESULT_OK if the points
are different, otherwise GO_RESULT_ERROR. */
extern int go_line_from_points(const go_cart * point1, const go_cart * point2, go_line * line);
/*! Fill in \a line with the intersection of the two planes. Returns GO_RESULT_OK if the planes are not parallel, otherwise GO_RESULT_ERROR. */
extern int go_line_from_planes(const go_plane * plane1, const go_plane * plane2, go_line * line);
/*! Returns non-zero if the lines are the same, otherwise zero. */
extern go_flag go_line_line_compare(const go_line * line1, const go_line * line2);
/*! Fills in \a point with the point located distance \a d along \a line */
extern int go_line_evaluate(const go_line * line, go_real d, go_cart * point);
/*! Fills in \a distance with the distance from \a point to \a line */
extern int go_point_line_distance(const go_cart * point, const go_line * line, go_real * distance);
/*! Fills in \a pout with the nearest point on \a line to \a point */
extern int go_point_line_proj(const go_cart * point, const go_line * line, go_cart * pout);
/*! Fills in \a proj with the projection of \a point onto \a plane */
extern int go_point_plane_proj(const go_cart * point, const go_plane * plane, go_cart * proj);
/*! Fills in \a proj with the projection of \a line onto \a plane */
extern int go_line_plane_proj(const go_line * line, const go_plane * plane, go_line * proj);
/*! Fills in \a plane give a \a point on the plane and the normal \a direction. */
extern int go_plane_from_point_normal(const go_cart * point, const go_cart * normal, go_plane * plane);
/*! Fills in \a plane given the A, B, C and D values in the canonical
form Ax + By + Cz + D = 0. Returns GO_RESULT_OK
if not all of A, B and C are zero, otherwise GO_RESULT_ERROR. */
extern int go_plane_from_abcd(go_real A, go_real B, go_real C, go_real D, go_plane * plane);
/*! Fills in \a plane given three points. Returns GO_RESULT_OK
if the points are distinct, otherwise GO_RESULT_ERROR. */
extern int go_plane_from_points(const go_cart * point1, const go_cart * point2, const go_cart * point3, go_plane * plane);
/*! Fills in \a plane given a \a point on the plane and a \a line
in the plane. Returns GO_RESULT_OK if the point is not on the line,
GO_RESULT_ERROR otherwise. */
extern int go_plane_from_point_line(const go_cart * point, const go_line * line, go_plane * plane);
/*! Returns non-zero if the planes are coincident and have the same
normal direction, otherwise zero. */
extern go_flag go_plane_plane_compare(const go_plane * plane1, const go_plane * plane2);
/*! Fills in the \a distance from the \a point to the \a plane. */
extern int go_point_plane_distance(const go_cart * point, const go_plane * plane, go_real * distance);
/*! Fills in \a point with the point located distances \a u and \a v along
some orthogonal planar coordinate system in \a plane */
extern int go_plane_evaluate(const go_plane * plane, go_real u, go_real v, go_cart * point);
/*! Fills in \a point with the intersection point of
\a line with \a plane, and \a distance with the distance along the
line to the intersection point. Returns GO_RESULT_ERROR if the line
is parallel to the plane and not lying in the plane, otherwise
GO_RESULT_OK. */
extern int go_line_plane_intersect(const go_line * line, const go_plane * plane, go_cart * point, go_real * distance);
/*
struct arguments are passed to functions as const pointers since the
speed is at least as fast for all but structs of one or two elements.
*/
/* translation rep conversion functions */
extern int go_cart_sph_convert(const go_cart *, go_sph *);
extern int go_cart_cyl_convert(const go_cart *, go_cyl *);
extern int go_sph_cart_convert(const go_sph *, go_cart *);
extern int go_sph_cyl_convert(const go_sph *, go_cyl *);
extern int go_cyl_cart_convert(const go_cyl *, go_cart *);
extern int go_cyl_sph_convert(const go_cyl *, go_sph *);
/* rotation rep conversion functions */
extern int go_rvec_quat_convert(const go_rvec *, go_quat *);
extern int go_rvec_mat_convert(const go_rvec *, go_mat *);
extern int go_rvec_zyz_convert(const go_rvec *, go_zyz *);
extern int go_rvec_zyx_convert(const go_rvec *, go_zyx *);
extern int go_rvec_rpy_convert(const go_rvec *, go_rpy *);
extern int go_quat_rvec_convert(const go_quat *, go_rvec *);
extern int go_quat_mat_convert(const go_quat *, go_mat *);
extern int go_quat_zyz_convert(const go_quat *, go_zyz *);
extern int go_quat_zyx_convert(const go_quat *, go_zyx *);
extern int go_quat_rpy_convert(const go_quat *, go_rpy *);
extern int go_mat_rvec_convert(const go_mat *, go_rvec *);
extern int go_mat_quat_convert(const go_mat *, go_quat *);
extern int go_mat_zyz_convert(const go_mat *, go_zyz *);
extern int go_mat_zyx_convert(const go_mat *, go_zyx *);
extern int go_mat_rpy_convert(const go_mat *, go_rpy *);
extern int go_zyz_rvec_convert(const go_zyz *, go_rvec *);
extern int go_zyz_quat_convert(const go_zyz *, go_quat *);
extern int go_zyz_mat_convert(const go_zyz *, go_mat *);
extern int go_zyz_zyx_convert(const go_zyz *, go_zyx *);
extern int go_zyz_rpy_convert(const go_zyz *, go_rpy *);
extern int go_zyx_rvec_convert(const go_zyx *, go_rvec *);
extern int go_zyx_quat_convert(const go_zyx *, go_quat *);
extern int go_zyx_mat_convert(const go_zyx *, go_mat *);
extern int go_zyx_zyz_convert(const go_zyx *, go_zyz *);
extern int go_zyx_rpy_convert(const go_zyx *, go_rpy *);
extern int go_rpy_rvec_convert(const go_rpy *, go_rvec *);
extern int go_rpy_quat_convert(const go_rpy *, go_quat *);
extern int go_rpy_mat_convert(const go_rpy *, go_mat *);
extern int go_rpy_zyz_convert(const go_rpy *, go_zyz *);
extern int go_rpy_zyx_convert(const go_rpy *, go_zyx *);
/* combined rep conversion functions */
extern int go_pose_hom_convert(const go_pose *, go_hom *);
extern int go_hom_pose_convert(const go_hom *, go_pose *);
/* misc conversion functions */
/*!
go_cart_rvec_convert and go_rvec_cart_convert convert between
Cartesian vectors and rotation vectors. The conversion is trivial
but keeps types distinct.
*/
extern int go_cart_rvec_convert(const go_cart * cart, go_rvec * rvec);
extern int go_rvec_cart_convert(const go_rvec * rvec, go_cart * cart);
/* translation functions, that work only with the preferred
go_cart type. Other types must be converted to go_cart
to use these, e.g., there's no go_sph_cyl_compare() */
extern go_flag go_cart_cart_compare(const go_cart *, const go_cart *);
extern int go_cart_cart_dot(const go_cart *, const go_cart *,
go_real *);
extern int go_cart_cart_cross(const go_cart *, const go_cart *,
go_cart *);
extern int go_cart_mag(const go_cart *, go_real *);
extern int go_cart_magsq(const go_cart *, go_real *);
extern go_flag go_cart_cart_par(const go_cart *, const go_cart *);
extern go_flag go_cart_cart_perp(const go_cart *, const go_cart *);
/*! Places the Cartesian displacement between two vectors \a v1 and
\a v2 in \a disp, returning \a GO_RESULT_OK. */
extern int go_cart_cart_disp(const go_cart * v1,
const go_cart * v2,
go_real * disp);
extern int go_cart_cart_add(const go_cart *, const go_cart *,
go_cart *);
extern int go_cart_cart_sub(const go_cart *, const go_cart *,
go_cart *);
extern int go_cart_scale_mult(const go_cart *, go_real, go_cart *);
extern int go_cart_neg(const go_cart *, go_cart *);
extern int go_cart_unit(const go_cart *, go_cart *);
/*!
Given two non-zero vectors \a v1 and \a v2, fill in \a quat with
the minimum rotation that brings \a v1 to \a v2.
*/
extern int go_cart_cart_rot(const go_cart * v1,
const go_cart * v2,
go_quat * quat);
/*!
Project vector \a v1 onto \a v2, with the resulting vector placed
into \a vout. Returns GO_RESULT_OK if it can be done, otherwise
something else.
*/
extern int go_cart_cart_proj(const go_cart * v1, const go_cart * v2,
go_cart * vout);
extern int go_cart_plane_proj(const go_cart *, const go_cart *,
go_cart *);
extern int go_cart_cart_angle(const go_cart *, const go_cart *,
go_real *);
/*!
go_cart_normal finds one of the infinite vectors perpendicular
to \a v, putting the result in \a vout.
*/
extern int go_cart_normal(const go_cart * v, go_cart * vout);
extern int go_cart_centroid(const go_cart * varray,
go_integer num,
go_cart * centroid);
extern int go_cart_centroidize(const go_cart * vinarray,
go_integer num,
go_cart * centroid,
go_cart * voutarray);
extern int go_cart_cart_pose(const go_cart *, const go_cart *,
go_cart *, go_cart *,
go_integer, go_pose *);
/*!
Returns the Cartesian point \a p whose distances from three other points
\a c1, \a c2 and \a c3 are \a l1, \a l2 and \a l3, respectively. In
general there are 0, 1 or two points possible. If no point is possible,
this returns GO_RESULT_ERROR, otherwise the points are returned in \a
p1 and \a p2, which may be the same point.
*/
int go_cart_trilaterate(const go_cart * c1,
const go_cart * c2,
const go_cart * c3,
go_real l1,
go_real l2,
go_real l3,
go_cart * p1,
go_cart * p2);
/* quat functions */
extern go_flag go_quat_quat_compare(const go_quat *, const go_quat *);
extern int go_quat_mag(const go_quat *, go_real *);
/*!
go_quat_unit takes a quaternion rotation \a q and converts it into
a unit rotation about the same axis, \a qout.
*/
extern int go_quat_unit(const go_quat * q, go_quat * qout);
extern int go_quat_norm(const go_quat *, go_quat *);
extern int go_quat_inv(const go_quat *, go_quat *);
extern go_flag go_quat_is_norm(const go_quat *);
extern int go_quat_scale_mult(const go_quat *, go_real, go_quat *);
extern int go_quat_quat_mult(const go_quat *, const go_quat *,
go_quat *);
extern int go_quat_cart_mult(const go_quat *, const go_cart *,
go_cart *);
/* rotation vector functions */
extern go_flag go_rvec_rvec_compare(const go_rvec * r1, const go_rvec * r2);
extern int go_rvec_scale_mult(const go_rvec *, go_real, go_rvec *);
/* rotation matrix functions */
/* | m.x.x m.y.x m.z.x | */
/* M = | m.x.y m.y.y m.z.y | */
/* | m.x.z m.y.z m.z.z | */
/*!
Normalizes rotation matrix \a m so that all columns are mutually
perpendicular unit vectors, placing the result in \a mout.
*/
extern int go_mat_norm(const go_mat * m, go_mat * mout);
extern go_flag go_mat_is_norm(const go_mat *);
extern int go_mat_inv(const go_mat *, go_mat *);
extern int go_mat_cart_mult(const go_mat *, const go_cart *, go_cart *);
extern int go_mat_mat_mult(const go_mat *, const go_mat *, go_mat *);
/* pose functions*/
extern go_flag go_pose_pose_compare(const go_pose *, const go_pose *);
extern int go_pose_inv(const go_pose *, go_pose *);
extern int go_pose_cart_mult(const go_pose *, const go_cart *, go_cart *);
extern int go_pose_pose_mult(const go_pose *, const go_pose *, go_pose *);
extern int go_pose_scale_mult(const go_pose *, go_real, go_pose *);
/*! Given two times \a t1 and \a t2, and associated poses \a p1 and \a
p2, interpolates (or extrapolates) to find pose \a p3 at time \a
t3. The result is stored in \a p3. Returns GO_RESULT_OK if \a t1 and
\a t2 are distinct and \a p1 and \a p2 are valid poses, otherwise it
can't interpolate and returns a relevant error. */
extern int
go_pose_pose_interp(go_real t1,
const go_pose * p1,
go_real t2,
const go_pose * p2,
go_real t3,
go_pose * p3);
/* homogeneous transform functions */
extern int go_hom_inv(const go_hom *, go_hom *);
/* screw functions */
/*! Given \a pose transformation from frame A to B, and a screw \a screw
in frame A, transform the screw into frame B and place in \a out. */
extern int go_pose_screw_mult(const go_pose * pose, const go_screw * screw, go_screw * out);
/* declarations for general MxN matrices */
/*!
Declare a matrix variable \a m with \a rows rows and \a cols columns.
Allocates \a rows X \a columns of space in \a mspace.
*/
typedef go_real go_vector;
typedef struct {
go_integer rows;
go_integer cols;
go_real ** el;
go_real ** elcpy;
go_real * v;
go_integer * index;
} go_matrix;
#define GO_MATRIX_DECLARE(M,Mspace,_rows,_cols) \
go_matrix M = {0, 0, 0, 0, 0, 0}; \
struct { \
go_real * el[_rows]; \
go_real * elcpy[_rows]; \
go_real stg[_rows][_cols]; \
go_real stgcpy[_rows][_cols]; \
go_real v[_rows]; \
go_integer index[_rows]; \
} Mspace
#define go_matrix_init(M,Mspace,_rows,_cols) \
M.el = Mspace.el; \
M.elcpy = Mspace.elcpy; \
for (M.rows = 0; M.rows < (_rows); M.rows++) { \
M.el[M.rows] = Mspace.stg[M.rows]; \
M.elcpy[M.rows] = Mspace.stgcpy[M.rows]; \
} \
M.rows = (_rows); \
M.cols = (_cols); \
M.v = Mspace.v; \
M.index = Mspace.index
extern go_real
go_get_singular_epsilon(void);
extern int
go_set_singular_epsilon(go_real epsilon);
extern int
ludcmp(go_real ** a,
go_real * scratchrow,
go_integer n,
go_integer * indx,
go_real * d);
extern int
lubksb(go_real ** a,
go_integer n,
go_integer * indx,
go_real * b);
/* MxN matrix, Mx1 vector functions */
extern int
go_cart_vector_convert(const go_cart * c,
go_vector * v);
extern int
go_vector_cart_convert(const go_real * v,
go_cart * c);
extern int
go_quat_matrix_convert(const go_quat * quat,
go_matrix * matrix);
extern int
go_mat_matrix_convert(const go_mat * mat,
go_matrix * matrix);
extern int
go_matrix_matrix_add(const go_matrix * a,
const go_matrix * b,
go_matrix * apb);
extern int
go_matrix_matrix_copy(const go_matrix * src,
go_matrix * dst);
extern int
go_matrix_matrix_mult(const go_matrix * a,
const go_matrix * b,
go_matrix * ab);
extern int
go_matrix_vector_mult(const go_matrix * a,
const go_vector * v,
go_vector * av);
/*!
The matrix-vector cross product is a matrix of the same dimension,
whose columns are the column-wise cross products of the matrix
and the vector. The matrices must be 3xN, the vector 3x1.
*/
extern int
go_matrix_vector_cross(const go_matrix * a,
const go_vector * v,
go_matrix * axv);
extern int
go_matrix_transpose(const go_matrix * a,
go_matrix * at);
extern int
go_matrix_inv(const go_matrix * a,
go_matrix * ainv);
/* Square matrix functions, where matN is an NxN matrix, and vecN
is an Nx1 vector */
/* Optimized 3x3 functions */
extern int go_mat3_inv(const go_real a[3][3],
go_real ainv[3][3]);
extern int go_mat3_mat3_mult(const go_real a[3][3],
const go_real b[3][3],
go_real axb[3][3]);
extern int go_mat3_vec3_mult(const go_real a[3][3],
const go_real v[3],
go_real axv[3]);
/* Optimized 4x4 functions */
extern int go_mat4_inv(const go_real a[4][4],
go_real ainv[4][4]);
extern int go_mat4_mat4_mult(const go_real a[4][4],
const go_real b[4][4],
go_real axb[4][4]);
extern int go_mat4_vec4_mult(const go_real a[4][4],
const go_real v[4],
go_real axv[4]);
/*!
Given a 6x6 matrix \a a, computes the inverse and returns it in
\a ainv. Leaves \a a untouched. Returns GO_RESULT_OK if there is an
inverse, else GO_RESULT_SINGULAR if the matrix is singular.
*/
extern int go_mat6_inv(const go_real a[6][6],
go_real ainv[6][6]);
/*!
Given two 6x6 matrices \a a and \a b, multiplies them and returns
the result in \a axb. Leaves \a a and \a b untouched.
Returns GO_RESULT_OK.
*/
extern int go_mat6_mat6_mult(const go_real a[6][6],
const go_real b[6][6],
go_real axb[6][6]);
/*!
Given a 6x6 matrix \a a and a 6x1 vector \a v, multiplies them
and returns the result in \a axv. Leaves \a a and \a v untouched.
Returns GO_RESULT_OK.
*/
extern int go_mat6_vec6_mult(const go_real a[6][6],
const go_real v[6],
go_real axv[6]);
/* Denavit-Hartenberg to pose conversions */
/*
The link frame is assumed to be
| i-1
| T
| i
that is, elements of the link frame expressed wrt the
previous link frame.
*/
/*!
These DH parameters follow the convention in John J. Craig,
_Introduction to Robotics: Mechanics and Control_.
*/
typedef struct {
go_real a; /*< a[i-1] */
go_real alpha; /*< alpha[i-1] */
/* either d or theta are the free variable, depending on quantity */
go_real d; /*< d[i] */
go_real theta; /*< theta[i] */
} go_dh;
/*!
PK parameters are used for parallel kinematic mechanisms, and
represent the Cartesian positions of the ends of the link in the
stationary base frame and the moving platform frame. Currently this
only supports prismatic links.
*/
typedef struct {
go_cart base; /*< position of fixed end in base frame */
go_cart platform; /*< position of moving end in platform frame */
go_real d; /*< the length of the link */
} go_pk;
/*!
PP parameters represent the pose of the link with respect to the
previous link. Revolute joints rotate about the Z axis, prismatic
joints slide along the Z axis.
*/
typedef struct {
go_pose pose; /*< the pose of the link wrt to the previous link */
} go_pp;
/*! Types of link parameter representations */
enum {
GO_LINK_DH = 1, /*< for Denavit-Hartenberg params */
GO_LINK_PK, /*< for parallel kinematics */
GO_LINK_PP /*< for serial kinematics */
};
#define go_link_to_string(L) \
(L) == GO_LINK_DH ? "DH" : \
(L) == GO_LINK_PK ? "PK" : \
(L) == GO_LINK_PP ? "PP" : "None"
/*!
This is the generic link structure for PKM sliding/cable links and
serial revolute/prismatic links.
*/
typedef struct {
union {
go_dh dh; /*< if you have DH params and don't want to convert to PP */
go_pk pk; /*< if you have a parallel machine, e.g., hexapod or robot crane */
go_pp pp; /*< if you have a serial machine, e.g., an industrial robot */
} u;
go_flag type; /*< one of GO_LINK_DH,PK,PP */
go_flag quantity; /*< one of GO_QUANTITY_LENGTH,ANGLE */
} go_link;
/*!
Converts DH parameters in \a dh to their pose equivalent, stored
in \a pose.
*/
extern int go_dh_pose_convert(const go_dh * dh, go_pose * pose);
/*!
Converts \a pose to the equivalent DH parameters, stored in \a dh.
Warning! Conversion from these DH parameters back to a pose via \a
go_dh_pose_convert will NOT in general result in the same
pose. Poses have 6 degrees of freedom, DH parameters have 4, and
conversion to DH parameters loses some information. The source of
this information loss is the convention imposed on DH parameters for
choice of X-Y-Z axis directions. With poses, there is no such
convention, and poses are thus freer than DH parameters.
*/
extern int go_pose_dh_convert(const go_pose * pose, go_dh * dh);
/*!
Fixes the link in \a link to its value when the joint
variable is \a joint, storing the result in \a linkout.
*/
extern int go_link_joint_set(const go_link * link, go_real joint, go_link * linkout);
/*!
Takes the link description of the device in \a links, and the number
of these in \a num, and builds the pose of the device and stores in
\a pose. \a links should have the value of the free link parameter
filled in with the current joint value, e.g., with a prior call to
go_link_joint_set.
*/
extern int go_link_pose_build(const go_link * links, go_integer num, go_pose * pose);
typedef struct {
go_real re;
go_real im;
} go_complex;
extern go_complex go_complex_add(go_complex z1, go_complex z2);
extern go_complex go_complex_sub(go_complex z1, go_complex z2);
extern go_complex go_complex_mult(go_complex z1, go_complex z2);
extern go_complex go_complex_div(go_complex z1, go_complex z2, int * result);
extern go_complex go_complex_scale(go_complex z, go_real scale);
extern go_real go_complex_mag(go_complex z);
extern go_real go_complex_arg(go_complex z);
extern void go_complex_sqrt(go_complex z, go_complex * z1, go_complex * z2);
extern void go_complex_cbrt(go_complex z, go_complex * z1, go_complex * z2, go_complex * z3);
typedef struct {
/* leading coefficient is 1, x^2 + ax + b = 0 */
go_real a;
go_real b;
} go_quadratic;
typedef struct {
/* leading coefficient is 1, x^3 + ax^2 + bx + c = 0 */
go_real a;
go_real b;
go_real c;
} go_cubic;
typedef struct {
/* leading coefficient is 1, x^4 + ax^3 + bx^2 + cx + d = 0 */
go_real a;
go_real b;
go_real c;
go_real d;
} go_quartic;
extern int go_quadratic_solve(const go_quadratic * quad,
go_complex * z1,
go_complex * z2);
extern int go_cubic_solve(const go_cubic * cub,
go_complex * z1,
go_complex * z2,
go_complex * z3);
extern int go_quartic_solve(const go_quartic * quart,
go_complex * z1,
go_complex * z2,
go_complex * z3,
go_complex * z4);
extern int go_tridiag_reduce(go_real ** a,
go_integer n,
go_real * d,
go_real * e);
extern int go_tridiag_ql(go_real * d,
go_real * e,
go_integer n,
go_real ** z);
#endif /* GO_MATH_H */

View File

@@ -0,0 +1,169 @@
/********************************************************************
* Description: gotypes.h
* Library file with various functions for working with matrices
*
* Derived from a work by Fred Proctor,
* changed to work with emc2 and HAL
*
* Adapting Author: Alex Joni
* License: LGPL Version 2
* System: Linux
*
*******************************************************************
Similar to posemath, but using different functions.
TODO:
* find the new functions, add them to posemath, convert the rest
*/
#ifndef __LINUXCNC_GO_TYPES_H
#define __LINUXCNC_GO_TYPES_H
#include <float.h> /* DBL_MAX, FLOAT_MAX */
/*!
GO_RESULT symbols run through a small range of values, on the
order of tens, suitable for a byte. GO_RESULT_OK is zero for easy
detection of error conditions, e.g., if (result) { handle error }
*/
enum {
GO_RESULT_OK = 0,
GO_RESULT_IGNORED, /* action can't be done, ignored */
GO_RESULT_BAD_ARGS, /* arguments bad, e.g., null pointer */
GO_RESULT_RANGE_ERROR, /* supplied range value out of bounds */
GO_RESULT_DOMAIN_ERROR, /* resulting domain out of bounds */
GO_RESULT_ERROR, /* action can't be done, a problem */
GO_RESULT_IMPL_ERROR, /* function not implemented */
GO_RESULT_NORM_ERROR, /* a value is expected to be normalized */
GO_RESULT_DIV_ERROR, /* divide by zero */
GO_RESULT_SINGULAR, /* a matrix is singular */
GO_RESULT_NO_SPACE, /* no space for append operation */
GO_RESULT_EMPTY, /* data structure is empty */
GO_RESULT_BUG /* a bug in Go, e.g., unknown case */
};
#define go_result_to_string(r) \
(r) == GO_RESULT_OK ? "Ok" : \
(r) == GO_RESULT_IGNORED ? "Ignored" : \
(r) == GO_RESULT_BAD_ARGS ? "Bad Args" : \
(r) == GO_RESULT_RANGE_ERROR ? "Range Error" : \
(r) == GO_RESULT_DOMAIN_ERROR ? "Domain Error" : \
(r) == GO_RESULT_ERROR ? "General Error" : \
(r) == GO_RESULT_IMPL_ERROR ? "Implementation Error" : \
(r) == GO_RESULT_NORM_ERROR ? "Norm Error" : \
(r) == GO_RESULT_DIV_ERROR ? "Div Error" : \
(r) == GO_RESULT_SINGULAR ? "Singular" : \
(r) == GO_RESULT_NO_SPACE ? "No Space" : \
(r) == GO_RESULT_EMPTY ? "Empty" : \
(r) == GO_RESULT_BUG ? "Bug" : "?"
/*!
Joints are characterized by the quantities they affect, such as
length for linear joints and angle for rotary joints.
*/
enum {
GO_QUANTITY_NONE = 0,
GO_QUANTITY_LENGTH,
GO_QUANTITY_ANGLE
};
#define go_quantity_to_string(q) \
(q) == GO_QUANTITY_LENGTH ? "Length" : \
(q) == GO_QUANTITY_ANGLE ? "Angle" : "None"
/* go_real: float, long double, default double; GO_INF is defined as
the associated max value from float.h */
/*
In IEEE floating point,
FLT_MIN = 1.175494e-38, FLT_EPSILON 1.192093e-07
DBL_MIN = 2.225074e-308, DBL_EPSILON 2.220446e-16
*/
#if defined(GO_REAL_FLOAT)
typedef float go_real;
#define GO_REAL go_real_float
extern int go_real_float;
#define GO_REAL_MIN FLT_MIN
#define GO_REAL_MAX FLT_MAX
#define GO_REAL_EPSILON (1.0e-4)
#define GO_INF FLT_MAX
#elif defined(GO_REAL_LONG_DOUBLE)
typedef long double go_real;
#define GO_REAL go_real_long_double
extern int go_real_long_double;
#define GO_REAL_MIN DBL_MIN
#define GO_REAL_MAX DBL_MAX
#define GO_REAL_EPSILON (1.0e-10)
#define GO_INF DBL_MAX
#else
#define GO_REAL_DOUBLE
typedef double go_real;
#define GO_REAL go_real_double
extern int go_real_double;
#define GO_REAL_MIN DBL_MIN
#define GO_REAL_MAX DBL_MAX
#define GO_REAL_EPSILON (1.0e-7)
#define GO_INF DBL_MAX
#endif
/* go_integer: short, long, long long, default int */
#if defined(GO_INTEGER_SHORT)
typedef short int go_integer;
#define GO_INTEGER go_integer_short
extern int go_integer_short;
#if defined(SHRT_MAX)
#define GO_INTEGER_MAX SHRT_MAX
#endif
#elif defined(GO_INTEGER_LONG)
typedef long int go_integer;
#define GO_INTEGER go_integer_long
extern int go_integer_long;
#if defined(LONG_MAX)
#define GO_INTEGER_MAX LONG_MAX
#endif
#elif defined(GO_INTEGER_LONG_LONG)
typedef long long int go_integer;
#define GO_INTEGER go_integer_long_long
extern int go_integer_long_long;
#if defined(LONG_MAX)
#define GO_INTEGER_MAX LONG_MAX
#endif
#else
#define GO_INTEGER_INT
typedef int go_integer;
#define GO_INTEGER go_integer_int
extern int go_integer_int;
#if defined(INT_MAX)
#define GO_INTEGER_MAX INT_MAX
#endif
#endif
/* go_flag: unsigned short, unsigned int, default unsigned char */
#if defined(GO_FLAG_USHORT)
typedef unsigned short go_flag;
#define GO_FLAG go_flag_ushort
extern int go_flag_ushort;
#elif defined(GO_FLAG_UINT)
typedef unsigned int go_flag;
#define GO_FLAG go_flag_uint
extern int go_flag_uint;
#else
#define GO_FLAG_UCHAR
typedef unsigned char go_flag;
#define GO_FLAG go_flag_uchar
extern int go_flag_uchar;
#endif
#endif /* GO_TYPES_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,20 @@
/********************************************************************
* Description: sincos.h
* support for native sincos functions
*
* Derived from a work by Fred Proctor & Will Shackleford
*
* Author:
* License: LGPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#ifndef __LINUXCNC_SINCOS_H
#define __LINUXCNC_SINCOS_H
extern void pm_sincos(double x, double *sx, double *cx);
#endif /* #ifndef SINCOS_H */

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2013 Jeff Epler <jepler@unpythonic.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __LINUXCNC_RTAPI_BYTEORDER_H
#define __LINUXCNC_RTAPI_BYTEORDER_H
#ifdef __KERNEL__
#include <asm/byteorder.h>
#ifdef __BIG_ENDIAN
#define RTAPI_BIG_ENDIAN 1
#define RTAPI_LITTLE_ENDIAN 0
#define RTAPI_FLOAT_BIG_ENDIAN 1
#else
#define RTAPI_LITTLE_ENDIAN 1
#define RTAPI_BIG_ENDIAN 0
#define RTAPI_FLOAT_BIG_ENDIAN 0
#endif
#else
#ifdef __FreeBSD__
#include <sys/endian.h>
#define RTAPI_BIG_ENDIAN (_BYTE_ORDER == _BIG_ENDIAN)
#define RTAPI_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN)
#define RTAPI_FLOAT_BIG_ENDIAN (_FLOAT_WORD_ORDER == _BIG_ENDIAN)
#else
#include <endian.h>
#define RTAPI_BIG_ENDIAN (__BYTE_ORDER == __BIG_ENDIAN)
#define RTAPI_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
#define RTAPI_FLOAT_BIG_ENDIAN (__FLOAT_WORD_ORDER == __BIG_ENDIAN)
#endif /* !__FreeBSD__ */
#endif
#endif

View File

@@ -0,0 +1,52 @@
// Copyright 2014 Jeff Epler
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#ifndef __LINUXCNC_RTAPI_GFP_H
#define __LINUXCNC_RTAPI_GFP_H
#ifdef __KERNEL__
#include <linux/gfp.h>
// types
#define rtapi_gpf_e gpf_e
#define rtapi_gpf_t gpf_t
// enumerated values
#define RTAPI_GFP_BUFFER GFP_BUFFER
#define RTAPI_GFP_ATOMIC GFP_ATOMIC
#define RTAPI_GFP_KERNEL GFP_KERNEL
#define RTAPI_GFP_USER GFP_USER
#define RTAPI_GFP_NOBUFFER GFP_NOBUFFER
#define RTAPI_GFP_NFS GFP_NFS
#define RTAPI_GFP_DMA GFP_DMA
#else
enum rtapi_gfp_e {
RTAPI_GFP_BUFFER,
RTAPI_GFP_ATOMIC,
RTAPI_GFP_KERNEL,
RTAPI_GFP_USER,
RTAPI_GFP_NOBUFFER,
RTAPI_GFP_NFS,
RTAPI_GFP_DMA
};
typedef unsigned long rtapi_gfp_t;
#endif
#endif

View File

@@ -0,0 +1,132 @@
// Copyright 2006-2010 Various Authors
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#ifndef __LINUXCNC_RTAPI_MATH_H
#define __LINUXCNC_RTAPI_MATH_H
#include "rtapi.h" /* Because of all the rtapi refs */
#include <float.h> /* DBL_MAX and other FP goodies */
#ifndef M_PIl
#define M_PIl 3.1415926535897932384626433832795029L /* pi */
#endif
#ifndef M_PI_2l
#define M_PI_2l 1.570796326794896619231321691639751442L /* pi/2 */
#endif
#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795029 /* pi */
#endif
#if defined(__KERNEL__)
extern double sin(double);
extern double cos(double);
extern double tan(double);
extern double sqrt(double);
extern double fabs(double);
extern double atan(double);
extern double atan2(double, double);
extern double asin(double);
extern double acos(double);
extern double exp(double);
extern double pow(double, double);
extern double fmin(double, double);
extern double fmax(double, double);
extern double fmod(double, double);
extern double round(double);
extern double ceil(double);
extern double floor(double);
#define frexp(p,q) __builtin_frexp((p),(q))
#define isnan(x) __builtin_isnan((x))
#define signbit(x) __builtin_signbit((x))
#define nan(x) __builtin_nan((x))
#define isinf(x) __builtin_isinf((x))
#define isfinite(x) __builtin_isfinite((x))
#ifdef __i386__
#include "rtapi_math_i386.h"
#endif
#else
#include <math.h>
#endif
#include "rtapi_byteorder.h"
// adapted from ieee754.h
union ieee754_double
{
double d;
/* This is the IEEE 754 double-precision format. */
struct
{
#if RTAPI_BIG_ENDIAN
unsigned int negative:1;
unsigned int exponent:11;
/* Together these comprise the mantissa. */
unsigned int mantissa0:20;
unsigned int mantissa1:32;
#endif /* Big endian. */
#if RTAPI_LITTLE_ENDIAN
# if RTAPI_FLOAT_BIG_ENDIAN
unsigned int mantissa0:20;
unsigned int exponent:11;
unsigned int negative:1;
unsigned int mantissa1:32;
# else
/* Together these comprise the mantissa. */
unsigned int mantissa1:32;
unsigned int mantissa0:20;
unsigned int exponent:11;
unsigned int negative:1;
# endif
#endif /* Little endian. */
} ieee;
/* This format makes it easier to see if a NaN is a signalling NaN. */
struct
{
#if RTAPI_BIG_ENDIAN
unsigned int negative:1;
unsigned int exponent:11;
unsigned int quiet_nan:1;
/* Together these comprise the mantissa. */
unsigned int mantissa0:19;
unsigned int mantissa1:32;
#else
# if RTAPI_FLOAT_BIG_ENDIAN
unsigned int mantissa0:19;
unsigned int quiet_nan:1;
unsigned int exponent:11;
unsigned int negative:1;
unsigned int mantissa1:32;
# else
/* Together these comprise the mantissa. */
unsigned int mantissa1:32;
unsigned int mantissa0:19;
unsigned int quiet_nan:1;
unsigned int exponent:11;
unsigned int negative:1;
# endif
#endif
} ieee_nan;
};
#define IEEE754_DOUBLE_BIAS 0x3ff /* Added to exponent. */
#endif

View File

@@ -0,0 +1,78 @@
// Copyright 2014 Jeff Epler
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#ifndef __LINUXCNC_RTAPI_STDINT_H
#define __LINUXCNC_RTAPI_STDINT_H
#ifdef __KERNEL__
#include <asm/types.h>
typedef s8 rtapi_s8;
typedef s16 rtapi_s16;
typedef s32 rtapi_s32;
typedef s64 rtapi_s64;
typedef long rtapi_intptr_t;
typedef u8 rtapi_u8;
typedef u16 rtapi_u16;
typedef u32 rtapi_u32;
typedef u64 rtapi_u64;
typedef unsigned long rtapi_uintptr_t;
#define RTAPI_INT8_MAX (127)
#define RTAPI_INT8_MIN (-128)
#define RTAPI_UINT8_MAX (255)
#define RTAPI_INT16_MAX (32767)
#define RTAPI_INT16_MIN (-32768)
#define RTAPI_UINT16_MAX (65535)
#define RTAPI_INT32_MAX (2147483647)
#define RTAPI_INT32_MIN (-2147483647-1)
#define RTAPI_UINT32_MAX (4294967295ul)
#define RTAPI_INT64_MAX (9223372036854775807)
#define RTAPI_INT64_MIN (-9223372036854775807-1)
#define RTAPI_UINT64_MAX (18446744073709551615ull)
#else
#include <inttypes.h>
typedef int8_t rtapi_s8;
typedef int16_t rtapi_s16;
typedef int32_t rtapi_s32;
typedef int64_t rtapi_s64;
typedef intptr_t rtapi_intptr_t;
typedef uint8_t rtapi_u8;
typedef uint16_t rtapi_u16;
typedef uint32_t rtapi_u32;
typedef uint64_t rtapi_u64;
typedef uintptr_t rtapi_uintptr_t;
#define RTAPI_INT8_MAX INT8_MAX
#define RTAPI_INT8_MIN INT8_MIN
#define RTAPI_UINT8_MAX UINT8_MAX
#define RTAPI_INT16_MAX INT16_MAX
#define RTAPI_INT16_MIN INT16_MIN
#define RTAPI_UINT16_MAX UINT16_MAX
#define RTAPI_INT32_MAX INT32_MAX
#define RTAPI_INT32_MIN INT32_MIN
#define RTAPI_UINT32_MAX UINT32_MAX
#define RTAPI_INT64_MAX INT64_MAX
#define RTAPI_INT64_MIN INT64_MIN
#define RTAPI_UINT64_MAX UINT64_MAX
#endif
#endif

View File

@@ -0,0 +1,69 @@
// Copyright 2006-2009, Jeff Epler
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#ifndef __LINUXCNC_RTAPI_STRING_H
#define __LINUXCNC_RTAPI_STRING_H
#include "rtapi.h"
#ifdef __cplusplus
#include <assert.h>
#include <type_traits>
#define rtapi_static_assert(a,b) static_assert(a,b)
#define rtapi_is_array(x) (std::is_array<decltype(x)>::value)
#else
#define rtapi_static_assert(a,b) _Static_assert(a,b)
#define rtapi_is_array(x) (!__builtin_types_compatible_p(__typeof__((x)), __typeof__(&(x)[0])))
#endif
#ifdef MODULE
/* Suspect only very early kernels are missing the basic string functions.
To be sure, see what has been implemented by looking in linux/string.h
and {linux_src_dir}/lib/string.c */
#include <linux/string.h>
#include <linux/version.h>
#define rtapi_argv_split argv_split
#define rtapi_argv_free argv_free
#define rtapi_kstrdup(a,b) kstrdup(a,b)
#else
#include <string.h>
#include "rtapi_gfp.h"
RTAPI_BEGIN_DECLS
extern char **rtapi_argv_split(rtapi_gfp_t, const char *argstr, int *argc);
extern void rtapi_argv_free(char **argv);
#define rtapi_kstrdup(a,b) strdup(a)
RTAPI_END_DECLS
#endif
RTAPI_BEGIN_DECLS
static inline size_t rtapi_strlcpy(char *dst, const char *src, size_t size) {
return rtapi_snprintf(dst, size, "%s", src);
}
#define rtapi_strxcpy(dst, src) ({ \
rtapi_static_assert(rtapi_is_array(dst), "dst must be non-const array"); \
rtapi_strlcpy(dst, src, sizeof(dst)); \
})
static inline size_t rtapi_strlcat(char *dst, const char *src, size_t size) {
size_t l = strlen(dst);
return rtapi_snprintf(dst+l, size-l, "%s", src);
}
#define rtapi_strxcat(dst, src) ({ \
rtapi_static_assert(rtapi_is_array(dst), "dst must be non-const array"); \
rtapi_strlcat(dst, src, sizeof(dst)); \
})
RTAPI_END_DECLS
#endif