Commit | Line | Data |
---|---|---|
4cff3ded AW |
1 | /* |
2 | This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl). | |
3 | Smoothie 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 3 of the License, or (at your option) any later version. | |
4 | Smoothie 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. | |
5 | You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>. | |
6 | */ | |
7 | ||
3c132bd0 AW |
8 | |
9 | using namespace std; | |
10 | #include <vector> | |
4cff3ded | 11 | #include <string> |
3c132bd0 | 12 | |
4cff3ded AW |
13 | #include "libs/Kernel.h" |
14 | #include "Config.h" | |
4eb9c745 AW |
15 | #include "libs/nuts_bolts.h" |
16 | #include "libs/utils.h" | |
4cff3ded AW |
17 | |
18 | Config::Config(){ | |
19 | config_file_found = false; | |
20 | } | |
21 | ||
cebe90b6 AW |
22 | void Config::on_module_loaded(){ |
23 | this->register_for_event(ON_CONSOLE_LINE_RECEIVED); | |
24 | } | |
25 | ||
26 | // When a new line is received, check if it is a command, and if it is, act upon it | |
27 | void Config::on_console_line_received( void* argument ){ | |
28 | string possible_command = *static_cast<string*>(argument); | |
29 | ||
30 | // We don't compare to a string but to a checksum of that string, this saves some space in flash memory | |
31 | unsigned short check_sum = get_checksum( possible_command.substr(0,possible_command.find_first_of(" \r\n")) ); // todo: put this method somewhere more convenient | |
da24d6ae | 32 | //this->kernel->serial->printf("checksum: %u \r\n", check_sum); |
cebe90b6 AW |
33 | |
34 | // Act depending on command | |
35 | switch( check_sum ){ | |
da24d6ae AW |
36 | case config_get_checksum: this->config_get_command( get_arguments(possible_command)) ; break; |
37 | case config_set_checksum: this->config_set_command( get_arguments(possible_command)) ; break; | |
38 | case config_load_checksum:this->config_load_command(get_arguments(possible_command)) ; break; | |
cebe90b6 AW |
39 | } |
40 | } | |
41 | ||
26806df9 AW |
42 | // Command to retreive the value of a specific configuration setting |
43 | void Config::config_get_command( string parameter ){ | |
b66fb830 | 44 | this->kernel->serial->printf("%s\r\n", this->value( get_checksum( parameter ) )->value.c_str() ); |
26806df9 AW |
45 | } |
46 | ||
47 | // Command to set the value of a specific configuration setting | |
48 | void Config::config_set_command( string parameters ){ | |
49 | string setting = shift_parameter(parameters); | |
50 | string value = shift_parameter(parameters); | |
3c132bd0 | 51 | this->set_string( setting, value ); |
26806df9 AW |
52 | } |
53 | ||
da24d6ae AW |
54 | // Command to reload configuration in all modules ( usefull if you changed one ) |
55 | void Config::config_load_command( string parameters ){ | |
cbc05153 MC |
56 | if(parameters.size() > 12) { |
57 | string param = parameters.substr(12); | |
58 | this->config_file_found = false; | |
59 | //this->try_config_file("/local/" + param); | |
60 | this->try_config_file("/sd/" + param); | |
61 | if( !this->config_file_found ){ | |
62 | printf("ERROR: config file \'%s\' not found, loading default config\r\n", param.c_str()); | |
63 | } | |
64 | } | |
da24d6ae AW |
65 | this->kernel->call_event(ON_CONFIG_RELOAD); |
66 | } | |
67 | ||
26806df9 AW |
68 | // Set a value from the configuration as a string |
69 | // Because we don't like to waste space in Flash with lengthy config parameter names, we take a checksum instead so that the name does not have to be stored | |
70 | // See get_checksum | |
3c132bd0 | 71 | void Config::set_string( string setting, string value ){ |
26806df9 AW |
72 | // Open the config file ( find it if we haven't already found it ) |
73 | FILE *lp = fopen(this->get_config_file().c_str(), "r+"); | |
74 | string buffer; | |
75 | int c; | |
76 | // For each line | |
77 | do { | |
78 | c = fgetc (lp); | |
79 | if (c == '\n'){ | |
80 | // We have a new line | |
81 | if( buffer[0] == '#' ){ buffer.clear(); continue; } // Ignore comments | |
436a2cd1 | 82 | if( buffer.length() < 3 ){ buffer.clear(); continue; } //Ignore empty lines |
26806df9 AW |
83 | size_t begin_key = buffer.find_first_not_of(" "); |
84 | size_t begin_value = buffer.find_first_not_of(" ", buffer.find_first_of(" ", begin_key)); | |
85 | // If this line matches the checksum | |
3c132bd0 AW |
86 | string candidate = buffer.substr(begin_key, buffer.find_first_of(" ", begin_key) - begin_key); |
87 | if( candidate.compare(setting) != 0 ){ buffer.clear(); continue; } | |
da24d6ae AW |
88 | int free_space = int(int(buffer.find_first_of("\r\n#", begin_value+1))-begin_value); |
89 | if( int(value.length()) >= free_space ){ this->kernel->serial->printf("ERROR: Not enough room for value\r\n"); fclose(lp); return; } | |
26806df9 | 90 | // Update value |
da24d6ae | 91 | for( int i = value.length(); i < free_space; i++){ value += " "; } |
26806df9 AW |
92 | fpos_t pos; |
93 | fgetpos( lp, &pos ); | |
94 | int start = pos - buffer.length() + begin_value - 1; | |
95 | fseek(lp, start, SEEK_SET); | |
96 | fputs(value.c_str(), lp); | |
26806df9 AW |
97 | fclose(lp); |
98 | return; | |
99 | }else{ | |
100 | buffer += c; | |
101 | } | |
102 | } while (c != EOF); | |
103 | fclose(lp); | |
104 | this->kernel->serial->printf("ERROR: configuration key not found\r\n"); | |
105 | } | |
cebe90b6 | 106 | |
3c132bd0 AW |
107 | ConfigValue* Config::value(uint16_t check_sum_a, uint16_t check_sum_b, uint16_t check_sum_c ){ |
108 | vector<uint16_t> check_sums; | |
109 | check_sums.push_back(check_sum_a); | |
110 | check_sums.push_back(check_sum_b); | |
111 | check_sums.push_back(check_sum_c); | |
112 | return this->value(check_sums); | |
113 | } | |
114 | ||
115 | ConfigValue* Config::value(uint16_t check_sum_a, uint16_t check_sum_b){ | |
116 | vector<uint16_t> check_sums; | |
117 | check_sums.push_back(check_sum_a); | |
118 | check_sums.push_back(check_sum_b); | |
119 | return this->value(check_sums); | |
120 | } | |
121 | ||
122 | ConfigValue* Config::value(uint16_t check_sum){ | |
123 | vector<uint16_t> check_sums; | |
124 | check_sums.push_back(check_sum); | |
125 | return this->value(check_sums); | |
126 | } | |
127 | ||
4cff3ded AW |
128 | // Get a value from the configuration as a string |
129 | // Because we don't like to waste space in Flash with lengthy config parameter names, we take a checksum instead so that the name does not have to be stored | |
130 | // See get_checksum | |
3c132bd0 | 131 | ConfigValue* Config::value(vector<uint16_t> check_sums){ |
b66fb830 | 132 | ConfigValue* result = new ConfigValue; |
3c132bd0 AW |
133 | //uint16_t check_sum = 0; |
134 | //result->check_sum = check_sum; | |
7dd8133c AW |
135 | if( this->has_config_file() == false ){ |
136 | return result; | |
137 | } | |
4cff3ded AW |
138 | // Open the config file ( find it if we haven't already found it ) |
139 | FILE *lp = fopen(this->get_config_file().c_str(), "r"); | |
140 | string buffer; | |
4eb9c745 | 141 | int c; |
4cff3ded AW |
142 | // For each line |
143 | do { | |
144 | c = fgetc (lp); | |
145 | if (c == '\n'){ | |
146 | // We have a new line | |
147 | if( buffer[0] == '#' ){ buffer.clear(); continue; } // Ignore comments | |
f5598f5b | 148 | if( buffer.length() < 3 ){ buffer.clear(); continue; } //Ignore empty lines |
4cff3ded AW |
149 | size_t begin_key = buffer.find_first_not_of(" "); |
150 | size_t begin_value = buffer.find_first_not_of(" ", buffer.find_first_of(" ", begin_key)); | |
b66fb830 AW |
151 | string key = buffer.substr(begin_key, buffer.find_first_of(" ", begin_key) - begin_key); |
152 | ||
4cff3ded | 153 | // If this line matches the checksum |
3c132bd0 AW |
154 | bool match = true; |
155 | for( unsigned int i = 0; i < check_sums.size(); i++ ){ | |
156 | uint16_t checksum_node = check_sums[i]; | |
157 | size_t end_key = buffer.find_first_of(" .", begin_key); | |
158 | string key_node = buffer.substr(begin_key, end_key - begin_key); | |
159 | ||
160 | //printf("%u(%s) against %u\r\n", get_checksum(key_node), key_node.c_str(), checksum_node); | |
161 | if(get_checksum(key_node) != checksum_node ){ | |
162 | buffer.clear(); | |
163 | match = false; | |
164 | //printf("no match\r\n"); | |
165 | break; | |
166 | } | |
167 | //printf("test:<%s>\r\n",key_node.c_str()); | |
168 | begin_key = end_key + 1; | |
169 | } | |
170 | if( match == false ){ | |
171 | //printf("continue\r\n"); | |
172 | continue; | |
173 | } | |
174 | ||
b66fb830 AW |
175 | result->found = true; |
176 | result->key = key; | |
177 | result->value = buffer.substr(begin_value, buffer.find_first_of("\r\n# ", begin_value+1)-begin_value); | |
b66fb830 | 178 | break; |
f5598f5b AW |
179 | }else{ |
180 | buffer += c; | |
4cff3ded AW |
181 | } |
182 | } while (c != EOF); | |
183 | fclose(lp); | |
b66fb830 | 184 | return result; |
4cff3ded AW |
185 | } |
186 | ||
7dd8133c AW |
187 | bool Config::has_config_file(){ |
188 | if( this->config_file_found ){ return true; } | |
4cff3ded AW |
189 | this->try_config_file("/local/config"); |
190 | this->try_config_file("/sd/config"); | |
191 | if( this->config_file_found ){ | |
7dd8133c AW |
192 | return true; |
193 | }else{ | |
194 | return false; | |
195 | } | |
196 | ||
197 | } | |
198 | ||
199 | // Get the filename for the config file | |
200 | string Config::get_config_file(){ | |
201 | if( this->config_file_found ){ return this->config_file; } | |
202 | if( this->has_config_file() ){ | |
4cff3ded AW |
203 | return this->config_file; |
204 | }else{ | |
205 | printf("ERROR: no config file found\r\n"); | |
206 | } | |
207 | } | |
208 | ||
cebe90b6 AW |
209 | // Tool function for get_config_file |
210 | inline void Config::try_config_file(string candidate){ | |
4cff3ded AW |
211 | FILE *lp = fopen(candidate.c_str(), "r"); |
212 | if(lp){ this->config_file_found = true; this->config_file = candidate; } | |
213 | fclose(lp); | |
214 | } | |
215 | ||
216 | ||
3c132bd0 AW |
217 | void Config::get_module_list(vector<uint16_t>* list, uint16_t family){ |
218 | if( this->has_config_file() == false ){ return; } | |
219 | ||
220 | // Open the config file ( find it if we haven't already found it ) | |
221 | FILE *lp = fopen(this->get_config_file().c_str(), "r"); | |
222 | string buffer; | |
223 | int c; | |
224 | ||
225 | // For each line | |
226 | do { | |
227 | c = fgetc (lp); | |
228 | if (c == '\n'){ | |
229 | ||
230 | // We have a new line | |
231 | if( buffer[0] == '#' ){ buffer.clear(); continue; } // Ignore comments | |
232 | if( buffer.length() < 3 ){ buffer.clear(); continue; } //Ignore empty lines | |
233 | size_t begin_key = buffer.find_first_not_of(" "); | |
234 | size_t begin_value = buffer.find_first_not_of(" ", buffer.find_first_of(" ", begin_key)); | |
235 | string key = buffer.substr(begin_key, buffer.find_first_of(" ", begin_key) - begin_key); | |
236 | ||
237 | // If this line matches the checksum | |
238 | bool match = true; | |
239 | uint16_t match_checksum = 0; | |
240 | for( unsigned int i = 0; i <= 2; i++ ){ | |
241 | size_t end_key = buffer.find_first_of(" .", begin_key); | |
242 | string key_node = buffer.substr(begin_key, end_key - begin_key); | |
243 | if( i == 0 ){ | |
244 | if( family != get_checksum(key_node) ){ | |
245 | buffer.clear(); | |
246 | match = false; | |
247 | continue; | |
248 | } | |
249 | }else if( i == 1 ){ | |
250 | match_checksum = get_checksum(key_node); | |
251 | }else if( i == 2 ){ | |
252 | if( get_checksum(key_node) != 29545 ){ // enable | |
253 | buffer.clear(); | |
254 | match = false; | |
255 | continue; | |
256 | } | |
257 | } | |
258 | begin_key = end_key + 1; | |
259 | } | |
260 | if( match == false ){ continue; } | |
261 | list->push_back(match_checksum); | |
262 | buffer.clear(); | |
263 | }else{ | |
264 | buffer += c; | |
265 | } | |
266 | ||
267 | } while (c != EOF); | |
268 | fclose(lp); | |
269 | } | |
270 | ||
271 | ||
4cff3ded | 272 |