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 | ||
8 | #include "mbed.h" | |
9 | #include <string> | |
10 | using std::string; | |
11 | #include "libs/Kernel.h" | |
12 | #include "Config.h" | |
4eb9c745 AW |
13 | #include "libs/nuts_bolts.h" |
14 | #include "libs/utils.h" | |
4cff3ded AW |
15 | |
16 | Config::Config(){ | |
17 | config_file_found = false; | |
18 | } | |
19 | ||
cebe90b6 AW |
20 | void Config::on_module_loaded(){ |
21 | this->register_for_event(ON_CONSOLE_LINE_RECEIVED); | |
22 | } | |
23 | ||
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); | |
27 | ||
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 | |
da24d6ae | 30 | //this->kernel->serial->printf("checksum: %u \r\n", check_sum); |
cebe90b6 AW |
31 | |
32 | // Act depending on command | |
33 | switch( check_sum ){ | |
da24d6ae AW |
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; | |
cebe90b6 AW |
37 | } |
38 | } | |
39 | ||
26806df9 AW |
40 | // Command to retreive the value of a specific configuration setting |
41 | void Config::config_get_command( string parameter ){ | |
b66fb830 | 42 | this->kernel->serial->printf("%s\r\n", this->value( get_checksum( parameter ) )->value.c_str() ); |
26806df9 AW |
43 | } |
44 | ||
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 ); | |
50 | } | |
51 | ||
da24d6ae AW |
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); | |
55 | } | |
56 | ||
26806df9 AW |
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 | |
59 | // See get_checksum | |
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+"); | |
63 | string buffer; | |
64 | int c; | |
65 | // For each line | |
66 | do { | |
67 | c = fgetc (lp); | |
68 | if (c == '\n'){ | |
69 | // We have a new line | |
70 | if( buffer[0] == '#' ){ buffer.clear(); continue; } // Ignore comments | |
436a2cd1 | 71 | if( buffer.length() < 3 ){ buffer.clear(); continue; } //Ignore empty lines |
26806df9 AW |
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; } | |
da24d6ae AW |
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; } | |
26806df9 | 78 | // Update value |
da24d6ae | 79 | for( int i = value.length(); i < free_space; i++){ value += " "; } |
26806df9 AW |
80 | fpos_t pos; |
81 | fgetpos( lp, &pos ); | |
82 | int start = pos - buffer.length() + begin_value - 1; | |
83 | fseek(lp, start, SEEK_SET); | |
84 | fputs(value.c_str(), lp); | |
26806df9 AW |
85 | fclose(lp); |
86 | return; | |
87 | }else{ | |
88 | buffer += c; | |
89 | } | |
90 | } while (c != EOF); | |
91 | fclose(lp); | |
92 | this->kernel->serial->printf("ERROR: configuration key not found\r\n"); | |
93 | } | |
cebe90b6 | 94 | |
4cff3ded AW |
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 | |
97 | // See get_checksum | |
b66fb830 AW |
98 | ConfigValue* Config::value(uint16_t check_sum){ |
99 | ConfigValue* result = new ConfigValue; | |
100 | result->check_sum = check_sum; | |
7dd8133c AW |
101 | if( this->has_config_file() == false ){ |
102 | return result; | |
103 | } | |
4cff3ded AW |
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"); | |
106 | string buffer; | |
4eb9c745 | 107 | int c; |
4cff3ded AW |
108 | // For each line |
109 | do { | |
110 | c = fgetc (lp); | |
111 | if (c == '\n'){ | |
112 | // We have a new line | |
113 | if( buffer[0] == '#' ){ buffer.clear(); continue; } // Ignore comments | |
f5598f5b | 114 | if( buffer.length() < 3 ){ buffer.clear(); continue; } //Ignore empty lines |
4cff3ded AW |
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)); | |
b66fb830 AW |
117 | string key = buffer.substr(begin_key, buffer.find_first_of(" ", begin_key) - begin_key); |
118 | ||
4cff3ded | 119 | // If this line matches the checksum |
b66fb830 AW |
120 | if(get_checksum(key) != check_sum){ buffer.clear(); continue; } |
121 | result->found = true; | |
122 | result->key = key; | |
123 | result->value = buffer.substr(begin_value, buffer.find_first_of("\r\n# ", begin_value+1)-begin_value); | |
b66fb830 | 124 | break; |
f5598f5b AW |
125 | }else{ |
126 | buffer += c; | |
4cff3ded AW |
127 | } |
128 | } while (c != EOF); | |
129 | fclose(lp); | |
b66fb830 | 130 | return result; |
4cff3ded AW |
131 | } |
132 | ||
7dd8133c AW |
133 | bool Config::has_config_file(){ |
134 | if( this->config_file_found ){ return true; } | |
4cff3ded AW |
135 | this->try_config_file("/local/config"); |
136 | this->try_config_file("/sd/config"); | |
137 | if( this->config_file_found ){ | |
7dd8133c AW |
138 | return true; |
139 | }else{ | |
140 | return false; | |
141 | } | |
142 | ||
143 | } | |
144 | ||
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() ){ | |
4cff3ded AW |
149 | return this->config_file; |
150 | }else{ | |
151 | printf("ERROR: no config file found\r\n"); | |
152 | } | |
153 | } | |
154 | ||
cebe90b6 AW |
155 | // Tool function for get_config_file |
156 | inline void Config::try_config_file(string candidate){ | |
4cff3ded AW |
157 | FILE *lp = fopen(candidate.c_str(), "r"); |
158 | if(lp){ this->config_file_found = true; this->config_file = candidate; } | |
159 | fclose(lp); | |
160 | } | |
161 | ||
162 | ||
163 |