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/>.
11 #include "libs/Kernel.h"
13 #include "libs/nuts_bolts.h"
14 #include "libs/utils.h"
17 config_file_found
= false;
20 void Config::on_module_loaded(){
21 this->register_for_event(ON_CONSOLE_LINE_RECEIVED
);
24 // When a new line is received, check if it is a command, and if it is, act upon it
25 void Config::on_console_line_received( void* argument
){
26 string possible_command
= *static_cast<string
*>(argument
);
28 // We don't compare to a string but to a checksum of that string, this saves some space in flash memory
29 unsigned short check_sum
= get_checksum( possible_command
.substr(0,possible_command
.find_first_of(" \r\n")) ); // todo: put this method somewhere more convenient
30 //this->kernel->serial->printf("checksum: %u \r\n", check_sum);
32 // Act depending on command
34 case config_get_checksum
: this->config_get_command( get_arguments(possible_command
)) ; break;
35 case config_set_checksum
: this->config_set_command( get_arguments(possible_command
)) ; break;
36 case config_load_checksum
:this->config_load_command(get_arguments(possible_command
)) ; break;
40 // Command to retreive the value of a specific configuration setting
41 void Config::config_get_command( string parameter
){
42 this->kernel
->serial
->printf("%s\r\n", this->value( get_checksum( parameter
) )->value
.c_str() );
45 // Command to set the value of a specific configuration setting
46 void Config::config_set_command( string parameters
){
47 string setting
= shift_parameter(parameters
);
48 string value
= shift_parameter(parameters
);
49 this->set_string( get_checksum(setting
), value
);
52 // Command to reload configuration in all modules ( usefull if you changed one )
53 void Config::config_load_command( string parameters
){
54 this->kernel
->call_event(ON_CONFIG_RELOAD
);
57 // Set a value from the configuration as a string
58 // 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
60 void Config::set_string( uint16_t check_sum
, string value
){
61 // Open the config file ( find it if we haven't already found it )
62 FILE *lp
= fopen(this->get_config_file().c_str(), "r+");
70 if( buffer
[0] == '#' ){ buffer
.clear(); continue; } // Ignore comments
71 if( buffer
.length() < 3 ){ buffer
.clear(); continue; } //Ignore empty lines
72 size_t begin_key
= buffer
.find_first_not_of(" ");
73 size_t begin_value
= buffer
.find_first_not_of(" ", buffer
.find_first_of(" ", begin_key
));
74 // If this line matches the checksum
75 if(get_checksum(buffer
.substr(begin_key
, buffer
.find_first_of(" ", begin_key
) - begin_key
)) != check_sum
){ buffer
.clear(); continue; }
76 int free_space
= int(int(buffer
.find_first_of("\r\n#", begin_value
+1))-begin_value
);
77 if( int(value
.length()) >= free_space
){ this->kernel
->serial
->printf("ERROR: Not enough room for value\r\n"); fclose(lp
); return; }
79 for( int i
= value
.length(); i
< free_space
; i
++){ value
+= " "; }
82 int start
= pos
- buffer
.length() + begin_value
- 1;
83 fseek(lp
, start
, SEEK_SET
);
84 fputs(value
.c_str(), lp
);
92 this->kernel
->serial
->printf("ERROR: configuration key not found\r\n");
95 // Get a value from the configuration as a string
96 // 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
98 ConfigValue
* Config::value(uint16_t check_sum
){
99 ConfigValue
* result
= new ConfigValue
;
100 result
->check_sum
= check_sum
;
101 if( this->has_config_file() == false ){
104 // Open the config file ( find it if we haven't already found it )
105 FILE *lp
= fopen(this->get_config_file().c_str(), "r");
112 // We have a new line
113 if( buffer
[0] == '#' ){ buffer
.clear(); continue; } // Ignore comments
114 if( buffer
.length() < 3 ){ buffer
.clear(); continue; } //Ignore empty lines
115 size_t begin_key
= buffer
.find_first_not_of(" ");
116 size_t begin_value
= buffer
.find_first_not_of(" ", buffer
.find_first_of(" ", begin_key
));
117 string key
= buffer
.substr(begin_key
, buffer
.find_first_of(" ", begin_key
) - begin_key
);
119 // If this line matches the checksum
120 if(get_checksum(key
) != check_sum
){ buffer
.clear(); continue; }
121 result
->found
= true;
123 result
->value
= buffer
.substr(begin_value
, buffer
.find_first_of("\r\n# ", begin_value
+1)-begin_value
);
133 bool Config::has_config_file(){
134 if( this->config_file_found
){ return true; }
135 this->try_config_file("/local/config");
136 this->try_config_file("/sd/config");
137 if( this->config_file_found
){
145 // Get the filename for the config file
146 string
Config::get_config_file(){
147 if( this->config_file_found
){ return this->config_file
; }
148 if( this->has_config_file() ){
149 return this->config_file
;
151 printf("ERROR: no config file found\r\n");
155 // Tool function for get_config_file
156 inline void Config::try_config_file(string candidate
){
157 FILE *lp
= fopen(candidate
.c_str(), "r");
158 if(lp
){ this->config_file_found
= true; this->config_file
= candidate
; }