Merge branch 'edge' into multiconfig
[clinton/Smoothieware.git] / src / libs / Config.cpp
CommitLineData
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
9using 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
18Config::Config(){
19 config_file_found = false;
20}
21
cebe90b6
AW
22void 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
27void 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
43void 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
48void 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 )
55void 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 71void 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
107ConfigValue* 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
115ConfigValue* 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
122ConfigValue* 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 131ConfigValue* 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
187bool 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
200string 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
210inline 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
217void 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