blob: 9d89a8d061696b829dcbbd5c76143089824a25dd [file] [log] [blame]
Luigi Santivetti69972f92019-11-12 22:55:40 +00001/*
2 nuts_bolts.c - Shared functions
3 Part of Grbl
4
5 Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
6 Copyright (c) 2009-2011 Simen Svale Skogsrud
7
8 Grbl is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 Grbl is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Grbl. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "grbl.h"
23
24
25#define MAX_INT_DIGITS 8 // Maximum number of digits in int32 (and float)
26
27
28// Extracts a floating point value from a string. The following code is based loosely on
29// the avr-libc strtod() function by Michael Stumpf and Dmitry Xmelkov and many freely
30// available conversion method examples, but has been highly optimized for Grbl. For known
31// CNC applications, the typical decimal value is expected to be in the range of E0 to E-4.
32// Scientific notation is officially not supported by g-code, and the 'E' character may
33// be a g-code word on some CNC systems. So, 'E' notation will not be recognized.
34// NOTE: Thanks to Radu-Eosif Mihailescu for identifying the issues with using strtod().
35uint8_t read_float(char *line, uint8_t *char_counter, float *float_ptr)
36{
37 char *ptr = line + *char_counter;
38 unsigned char c;
39
40 // Grab first character and increment pointer. No spaces assumed in line.
41 c = *ptr++;
42
43 // Capture initial positive/minus character
44 bool isnegative = false;
45 if (c == '-') {
46 isnegative = true;
47 c = *ptr++;
48 } else if (c == '+') {
49 c = *ptr++;
50 }
51
52 // Extract number into fast integer. Track decimal in terms of exponent value.
53 uint32_t intval = 0;
54 int8_t exp = 0;
55 uint8_t ndigit = 0;
56 bool isdecimal = false;
57 while(1) {
58 c -= '0';
59 if (c <= 9) {
60 ndigit++;
61 if (ndigit <= MAX_INT_DIGITS) {
62 if (isdecimal) { exp--; }
63 intval = (((intval << 2) + intval) << 1) + c; // intval*10 + c
64 } else {
65 if (!(isdecimal)) { exp++; } // Drop overflow digits
66 }
67 } else if (c == (('.'-'0') & 0xff) && !(isdecimal)) {
68 isdecimal = true;
69 } else {
70 break;
71 }
72 c = *ptr++;
73 }
74
75 // Return if no digits have been read.
76 if (!ndigit) { return(false); };
77
78 // Convert integer into floating point.
79 float fval;
80 fval = (float)intval;
81
82 // Apply decimal. Should perform no more than two floating point multiplications for the
83 // expected range of E0 to E-4.
84 if (fval != 0) {
85 while (exp <= -2) {
86 fval *= 0.01;
87 exp += 2;
88 }
89 if (exp < 0) {
90 fval *= 0.1;
91 } else if (exp > 0) {
92 do {
93 fval *= 10.0;
94 } while (--exp > 0);
95 }
96 }
97
98 // Assign floating point value with correct sign.
99 if (isnegative) {
100 *float_ptr = -fval;
101 } else {
102 *float_ptr = fval;
103 }
104
105 *char_counter = ptr - line - 1; // Set char_counter to next statement
106
107 return(true);
108}
109
110
111// Non-blocking delay function used for general operation and suspend features.
112void delay_sec(float seconds, uint8_t mode)
113{
114 uint16_t i = ceil(1000/DWELL_TIME_STEP*seconds);
115 while (i-- > 0) {
116 if (sys.abort) { return; }
117 if (mode == DELAY_MODE_DWELL) {
118 protocol_execute_realtime();
119 } else { // DELAY_MODE_SYS_SUSPEND
120 // Execute rt_system() only to avoid nesting suspend loops.
121 protocol_exec_rt_system();
122 if (sys.suspend & SUSPEND_RESTART_RETRACT) { return; } // Bail, if safety door reopens.
123 }
124 _delay_ms(DWELL_TIME_STEP); // Delay DWELL_TIME_STEP increment
125 }
126}
127
128
129// Delays variable defined milliseconds. Compiler compatibility fix for _delay_ms(),
130// which only accepts constants in future compiler releases.
131void delay_ms(uint16_t ms)
132{
133 while ( ms-- ) { _delay_ms(1); }
134}
135
136
137// Delays variable defined microseconds. Compiler compatibility fix for _delay_us(),
138// which only accepts constants in future compiler releases. Written to perform more
139// efficiently with larger delays, as the counter adds parasitic time in each iteration.
140void delay_us(uint32_t us)
141{
142 while (us) {
143 if (us < 10) {
144 _delay_us(1);
145 us--;
146 } else if (us < 100) {
147 _delay_us(10);
148 us -= 10;
149 } else if (us < 1000) {
150 _delay_us(100);
151 us -= 100;
152 } else {
153 _delay_ms(1);
154 us -= 1000;
155 }
156 }
157}
158
159
160// Simple hypotenuse computation function.
161float hypot_f(float x, float y) { return(sqrt(x*x + y*y)); }
162
163
164float convert_delta_vector_to_unit_vector(float *vector)
165{
166 uint8_t idx;
167 float magnitude = 0.0;
168 for (idx=0; idx<N_AXIS; idx++) {
169 if (vector[idx] != 0.0) {
170 magnitude += vector[idx]*vector[idx];
171 }
172 }
173 magnitude = sqrt(magnitude);
174 float inv_magnitude = 1.0/magnitude;
175 for (idx=0; idx<N_AXIS; idx++) { vector[idx] *= inv_magnitude; }
176 return(magnitude);
177}
178
179
180float limit_value_by_axis_maximum(float *max_value, float *unit_vec)
181{
182 uint8_t idx;
183 float limit_value = SOME_LARGE_VALUE;
184 for (idx=0; idx<N_AXIS; idx++) {
185 if (unit_vec[idx] != 0) { // Avoid divide by zero.
186 limit_value = min(limit_value,fabs(max_value[idx]/unit_vec[idx]));
187 }
188 }
189 return(limit_value);
190}