initial implementation of FirmConfigSource #142

Merged
merged 8 commits into from Mar 11, 2013
View
@@ -18,7 +18,7 @@
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
#
-# Updates:
+# Updates:
# Arthur Wolf & Adam Green in 2011 - 2012 - Updated to work with mbed.
###############################################################################
# Check for undefined variables.
@@ -89,6 +89,8 @@ OBJECTS = $(patsubst %.c,$(OUTDIR)/%.o,$(CSRCS)) $(patsubst %.s,$(OUTDIR)/%.o,$(
# Add in the MBED customization stubs which allow hooking in the MRI debug monitor.
OBJECTS += $(OUTDIR)/mbed_custom.o
+OBJECTS += $(OUTDIR)/configdefault.o
+
# List of the header dependency files, one per object file.
DEPFILES = $(patsubst %.o,%.d,$(OBJECTS))
@@ -106,7 +108,7 @@ INCDIRS += $(SRC) $(PROJINCS) $(MRI_DIR) $(MBED_DIR) $(MBED_DIR)/$(DEVICE)
# DEFINEs to be used when building C/C++ code
DEFINES += -DTARGET_$(DEVICE)
-DEFINES += -DMRI_ENABLE=$(MRI_ENABLE) -DMRI_INIT_PARAMETERS='"$(MRI_INIT_PARAMETERS)"'
+DEFINES += -DMRI_ENABLE=$(MRI_ENABLE) -DMRI_INIT_PARAMETERS='"$(MRI_INIT_PARAMETERS)"'
DEFINES += -DMRI_BREAK_ON_INIT=$(MRI_BREAK_ON_INIT) -DMRI_SEMIHOST_STDIO=$(MRI_SEMIHOST_STDIO)
DEFINES += -DWRITE_BUFFER_DISABLE=$(WRITE_BUFFER_DISABLE) -DSTACK_SIZE=$(STACK_SIZE)
@@ -117,7 +119,7 @@ endif
# Libraries to be linked into final binary
MBED_LIBS = $(MBED_DIR)/$(DEVICE)/GCC_ARM/libmbed.a
SYS_LIBS = -lstdc++_s -lsupc++_s -lm -lgcc -lc_s -lgcc -lc_s -lnosys
-LIBS = $(LIBS_PREFIX)
+LIBS = $(LIBS_PREFIX)
ifeq "$(MRI_ENABLE)" "1"
LIBS += $(MRI_DIR)/mri.ar
@@ -130,7 +132,7 @@ LIBS += $(LIBS_SUFFIX)
# Compiler flags used to enable creation of header dependencies.
DEPFLAGS = -MMD -MP
-# Setup wraps for newlib read/writes to redirect to MRI debugger.
+# Setup wraps for newlib read/writes to redirect to MRI debugger.
ifeq "$(MRI_ENABLE)" "1"
MRI_WRAPS=,--wrap=_read,--wrap=_write,--wrap=semihost_connected
else
@@ -158,7 +160,7 @@ AS_FLAGS += -g3 $(DEVICE_FLAGS)
# Linker Options.
-LDFLAGS = $(DEVICE_FLAGS) -specs=$(BUILD_DIR)/startfile.spec
+LDFLAGS = $(DEVICE_FLAGS) -specs=$(BUILD_DIR)/startfile.spec
LDFLAGS += -Wl,-Map=$(OUTDIR)/$(PROJECT).map,--cref,--gc-sections,--wrap=_isatty,--wrap=malloc,--wrap=realloc,--wrap=free$(MRI_WRAPS)
LDFLAGS += -T$(LSCRIPT) -L $(EXTERNAL_DIR)/gcc/LPC1768
ifneq "$(NO_FLOAT_SCANF)" "1"
@@ -219,12 +221,12 @@ $(OUTDIR)/$(PROJECT).hex: $(OUTDIR)/$(PROJECT).elf
@echo Extracting $@
$(Q) $(MKDIR) $(call convert-slash,$(dir $@)) $(QUIET)
$(Q) $(OBJCOPY) -R .stack -O ihex $< $@
-
+
$(OUTDIR)/$(PROJECT).disasm: $(OUTDIR)/$(PROJECT).elf
@echo Extracting disassembly to $@
$(Q) $(MKDIR) $(call convert-slash,$(dir $@)) $(QUIET)
$(Q) $(OBJDUMP) -d -f -M reg-names-std --demangle $< >$@
-
+
$(OUTDIR)/$(PROJECT).elf: $(LSCRIPT) $(OBJECTS)
@echo Linking $@
$(Q) $(MKDIR) $(call convert-slash,$(dir $@)) $(QUIET)
@@ -269,4 +271,7 @@ $(OUTDIR)/%.o : %.s makefile
$(Q) $(MKDIR) $(call convert-slash,$(dir $@)) $(QUIET)
$(Q) $(AS) $(AS_FLAGS) -o $@ $<
-#########################################################################
+$(OUTDIR)/configdefault.o : config.default
+ $(Q) $(OBJCOPY) -I binary -O elf32-littlearm -B arm --readonly-text --rename-section .data=.rodata.configdefault $< $@
+
+#########################################################################
View
@@ -0,0 +1,5 @@
+# This is a place for the user to specify their own 'firm' defaults at compile time
+# One can also use this as the primary config system if an sdcard is unavailable
+# The format of this file is identical to that of a normal config file
+
+
View
@@ -19,10 +19,14 @@ using namespace std;
#include "libs/utils.h"
#include "libs/SerialMessage.h"
#include "libs/ConfigSources/FileConfigSource.h"
+#include "libs/ConfigSources/FirmConfigSource.h"
Config::Config(){
this->config_cache_loaded = false;
+ // Config source for firm config found in src/config.default
+ this->config_sources.push_back( new FirmConfigSource() );
+
// Config source for */config files
FileConfigSource* fcs = NULL;
if( file_exists("/local/config") )
@@ -80,13 +84,13 @@ void Config::config_cache_load(){
// First element is a special empty ConfigValue for values not found
ConfigValue* result = new ConfigValue;
this->config_cache.push_back(result);
-
+
// For each ConfigSource in our stack
for( unsigned int i = 0; i < this->config_sources.size(); i++ ){
ConfigSource* source = this->config_sources[i];
source->transfer_values_to_cache(&this->config_cache);
}
-
+
this->config_cache_loaded = true;
}
@@ -123,15 +127,15 @@ ConfigValue* Config::value(uint16_t check_sum){
check_sums[2] = 0x0000;
return this->value(check_sums);
}
-
+
// Get a value from the configuration as a string
// 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
// See get_checksum
ConfigValue* Config::value(uint16_t check_sums[]){
ConfigValue* result = this->config_cache[0];
bool cache_preloaded = this->config_cache_loaded;
if( !cache_preloaded ){ this->config_cache_load(); }
-
+
for( unsigned int i=1; i<this->config_cache.size(); i++){
// If this line matches the checksum
bool match = true;
@@ -149,7 +153,7 @@ ConfigValue* Config::value(uint16_t check_sums[]){
result = this->config_cache[i];
break;
}
-
+
if( !cache_preloaded ){
this->config_cache_clear();
}
@@ -27,6 +27,66 @@ class ConfigSource {
virtual string read( uint16_t check_sums[3] ) = 0;
uint16_t name_checksum;
+ protected:
+ virtual string process_char_from_ascii_config(int c, ConfigCache* cache) {
+ static string buffer;
+ if (c == '\n' || c == EOF)
+ {
+ // We have a new line
+ if( buffer[0] == '#' ){ buffer.clear(); return ""; } // Ignore comments
+ if( buffer.length() < 3 ){ buffer.clear(); return ""; } //Ignore empty lines
+ size_t begin_key = buffer.find_first_not_of(" ");
+ size_t begin_value = buffer.find_first_not_of(" ", buffer.find_first_of(" ", begin_key));
+
+ uint16_t check_sums[3];
+ get_checksums(check_sums, buffer.substr(begin_key, buffer.find_first_of(" ", begin_key) - begin_key).append(" "));
+
+ ConfigValue* result = new ConfigValue;
+
+ result->found = true;
+ result->check_sums[0] = check_sums[0];
+ result->check_sums[1] = check_sums[1];
+ result->check_sums[2] = check_sums[2];
+
+ result->value = buffer.substr(begin_value, buffer.find_first_of("\r\n# ", begin_value+1)-begin_value);
+ // Append the newly found value to the cache we were passed
+ cache->replace_or_push_back(result);
+
+ buffer.clear();
+
+ return result->value;
+ }
+ else
+ buffer += c;
+
+ return "";
+ };
+ virtual string process_char_from_ascii_config(int c, uint16_t line_checksums[3]) {
+ static string buffer;
+ string value;
+ if (c == '\n' || c == EOF)
+ {
+ // We have a new line
+ if( buffer[0] == '#' ){ buffer.clear(); return ""; } // Ignore comments
+ if( buffer.length() < 3 ){ buffer.clear(); return ""; } //Ignore empty lines
+ size_t begin_key = buffer.find_first_not_of(" ");
+ size_t begin_value = buffer.find_first_not_of(" ", buffer.find_first_of(" ", begin_key));
+
+ uint16_t check_sums[3];
+ get_checksums(check_sums, buffer.substr(begin_key, buffer.find_first_of(" ", begin_key) - begin_key).append(" "));
+
+ if(check_sums[0] == line_checksums[0] && check_sums[1] == line_checksums[1] && check_sums[2] == line_checksums[2] ){
+ value = buffer.substr(begin_value, buffer.find_first_of("\r\n# ", begin_value+1)-begin_value);
+ buffer.clear();
+ return value;
+ }
+
+ buffer.clear();
+ }
+ else
+ buffer += c;
+ return value;
+ };
};
@@ -25,44 +25,13 @@ FileConfigSource::FileConfigSource(string config_file, uint16_t name_checksum){
// Transfer all values found in the file to the passed cache
void FileConfigSource::transfer_values_to_cache( ConfigCache* cache ){
- // Default empty value
- ConfigValue* result = new ConfigValue;
-
if( this->has_config_file() == false ){return;}
// Open the config file ( find it if we haven't already found it )
FILE *lp = fopen(this->get_config_file().c_str(), "r");
- string buffer;
int c;
// For each line
do {
- c = fgetc (lp);
- if (c == '\n' || c == EOF){
-
- // We have a new line
- if( buffer[0] == '#' ){ buffer.clear(); continue; } // Ignore comments
- if( buffer.length() < 3 ){ buffer.clear(); continue; } //Ignore empty lines
- size_t begin_key = buffer.find_first_not_of(" ");
- size_t begin_value = buffer.find_first_not_of(" ", buffer.find_first_of(" ", begin_key));
-
- uint16_t check_sums[3];
- get_checksums(check_sums, buffer.substr(begin_key, buffer.find_first_of(" ", begin_key) - begin_key).append(" "));
-
- result = new ConfigValue;
-
- result->found = true;
- result->check_sums[0] = check_sums[0];
- result->check_sums[1] = check_sums[1];
- result->check_sums[2] = check_sums[2];
-
- result->value = buffer.substr(begin_value, buffer.find_first_of("\r\n# ", begin_value+1)-begin_value);
- // Append the newly found value to the cache we were passed
- cache->replace_or_push_back(result);
-
- buffer.clear();
-
- }else{
- buffer += c;
- }
+ process_char_from_ascii_config(c = fgetc(lp), cache);
} while (c != EOF);
fclose(lp);
}
@@ -121,31 +90,11 @@ string FileConfigSource::read( uint16_t check_sums[3] ){
if( this->has_config_file() == false ){return value;}
// Open the config file ( find it if we haven't already found it )
FILE *lp = fopen(this->get_config_file().c_str(), "r");
- string buffer;
int c;
// For each line
do {
c = fgetc (lp);
- if (c == '\n' || c == EOF){
- // We have a new line
- if( buffer[0] == '#' ){ buffer.clear(); continue; } // Ignore comments
- if( buffer.length() < 3 ){ buffer.clear(); continue; } //Ignore empty lines
- size_t begin_key = buffer.find_first_not_of(" \t");
- size_t begin_value = buffer.find_first_not_of(" \t", buffer.find_first_of(" \t", begin_key));
- string key = buffer.substr(begin_key, buffer.find_first_of(" \t", begin_key) - begin_key).append(" ");
-
- uint16_t line_checksums[3];
- get_checksums(line_checksums, key);
-
- if(check_sums[0] == line_checksums[0] && check_sums[1] == line_checksums[1] && check_sums[2] == line_checksums[2] ){
- value = buffer.substr(begin_value, buffer.find_first_of("\r\n# ", begin_value+1)-begin_value);
- break;
- }
-
- buffer.clear();
- }else{
- buffer += c;
- }
+ process_char_from_ascii_config(c, check_sums);
} while (c != EOF);
fclose(lp);
@@ -0,0 +1,63 @@
+/*
+ This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+ 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.
+ 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.
+ You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "libs/Kernel.h"
+#include "ConfigValue.h"
+#include "FirmConfigSource.h"
+#include "ConfigCache.h"
+#include <malloc.h>
+
+
+using namespace std;
+#include <string>
+
+// we use objdump in the Makefile to import your config.default file into the compiled code
+// Since the two symbols below are derived from the filename, we need to change them if the filename changes
+extern char _binary_config_default_start;
+extern char _binary_config_default_end;
+
+
+FirmConfigSource::FirmConfigSource(uint16_t name_checksum){
+ this->name_checksum = name_checksum;
+}
+
+// Transfer all values found in the file to the passed cache
+void FirmConfigSource::transfer_values_to_cache( ConfigCache* cache ){
+
+ char* p = &_binary_config_default_start;
+ // For each line
+ while( p != &_binary_config_default_end ){
+ process_char_from_ascii_config(*p++, cache);
+ }
+}
+
+// Return true if the check_sums match
+bool FirmConfigSource::is_named( uint16_t check_sum ){
+ return check_sum == this->name_checksum;
+}
+
+// Write a config setting to the file *** FirmConfigSource is read only ***
+void FirmConfigSource::write( string setting, string value ){
+ //this->kernel->streams->printf("ERROR: FirmConfigSource is read only\r\n");
+}
+
+// Return the value for a specific checksum
+string FirmConfigSource::read( uint16_t check_sums[3] ){
+
+ string value = "";
+
+ char* p = &_binary_config_default_start;
+ // For each line
+ while( p != &_binary_config_default_end ){
+ value = process_char_from_ascii_config(*p++, check_sums);
+ if (value.length())
+ return value;
+ }
+
+ return value;
+}
+
@@ -0,0 +1,32 @@
+/*
+ This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+ 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.
+ 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.
+ You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef FIRMCONFIGSOURCE_H
+#define FIRMCONFIGSOURCE_H
+
+#include "ConfigValue.h"
+#include "ConfigSource.h"
+#include "ConfigCache.h"
+
+using namespace std;
+#include <string>
+
+#define FIRM_CONFIGSOURCE_CHECKSUM CHECKSUM("firm")
+
+class FirmConfigSource : public ConfigSource {
+ public:
+ FirmConfigSource(uint16_t name_checksum = FIRM_CONFIGSOURCE_CHECKSUM);
+ void transfer_values_to_cache( ConfigCache* cache );
+ bool is_named( uint16_t check_sum );
+ void write( string setting, string value );
+ string read( uint16_t check_sums[3] );
+
+};
+
+
+
+#endif // FIRMCONFIGSOURCE_H