# of the build directory which contains this gcc4mbed.mk file.
# LIBS_PREFIX: List of library/object files to prepend to mbed.ar capi.ar libs.
# LIBS_SUFFIX: List of library/object files to append to mbed.ar capi.ar libs.
+# GCC4MBED_DELAYED_STDIO_INIT: Set to non-zero value to have intialization of
+# stdin/stdout/stderr delayed which will
+# shrink the size of the resulting binary if
+# APIs like printf(), scanf(), etc. aren't used.
# Example makefile:
# PROJECT=HelloWorld
# SRC=.
# Default project source to be located in current directory.
ifndef SRC
-SRC=./src
+SRC=.
+endif
+
+# Default the init of stdio/stdout/stderr to occur before global constructors.
+ifndef GCC4MBED_DELAYED_STDIO_INIT
+GCC4MBED_DELAYED_STDIO_INIT=0
endif
# List of sources to be compiled/assembled
# Include path which points to external library headers and to subdirectories of this project which contain headers.
SUBDIRS = $(wildcard $(SRC)/* $(SRC)/*/* $(SRC)/*/*/* $(SRC)/*/*/*/* $(SRC)/*/*/*/*/*)
PROJINCS = $(sort $(dir $(SUBDIRS)))
-INCDIRS += $(PROJINCS) $(EXTERNAL_DIR)/mbed $(EXTERNAL_DIR)/mbed/LPC1768 $(EXTERNAL_DIR)/FATFileSystem
+INCDIRS += $(PROJINCS) $(EXTERNAL_DIR)/mbed $(EXTERNAL_DIR)/mbed/LPC1768 $(EXTERNAL_DIR)/FATFileSystem $(GCC4MBED_DIR)/mri
# DEFINEs to be used when building C/C++ code
-DEFINES = -DTARGET_LPC1768
+DEFINES = -DTARGET_LPC1768 -DGCC4MBED_DELAYED_STDIO_INIT=$(GCC4MBED_DELAYED_STDIO_INIT)
# Libraries to be linked into final binary
-LIBS = $(LIBS_PREFIX) $(EXTERNAL_DIR)/mbed/LPC1768/mbed.ar $(EXTERNAL_DIR)/mbed/LPC1768/capi.ar $(EXTERNAL_DIR)/FATFileSystem/LPC1768/FATFileSystem.ar $(LIBS_SUFFIX)
+LIBS = $(LIBS_PREFIX) $(GCC4MBED_DIR)/mri/mri.ar $(EXTERNAL_DIR)/mbed/LPC1768/mbed.ar $(EXTERNAL_DIR)/mbed/LPC1768/capi.ar $(EXTERNAL_DIR)/FATFileSystem/LPC1768/FATFileSystem.ar $(LIBS_SUFFIX)
# Optimization level
OPTIMIZATION = 2
# Compiler Options
-GPFLAGS = -O$(OPTIMIZATION) -gdwarf-2 -mcpu=cortex-m3 -mthumb -mthumb-interwork -fshort-wchar -ffunction-sections -fdata-sections -fpromote-loop-indices -Wall -Wextra -Wimplicit -Wcast-align -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -fno-exceptions
+GPFLAGS = -O$(OPTIMIZATION) -gstabs+3 -mcpu=cortex-m3 -mthumb -mthumb-interwork -fshort-wchar -ffunction-sections -fdata-sections -fpromote-loop-indices -Wall -Wextra -Wimplicit -Wcast-align -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -fno-exceptions
GPFLAGS += $(patsubst %,-I%,$(INCDIRS))
GPFLAGS += $(DEFINES)
SIZE = arm-none-eabi-size
REMOVE = rm
-# Switch to cs-rm on Windows.
+# Switch to cs-rm on Windows and make sure that cmd.exe is used as shell.
ifeq "$(MAKE)" "cs-make"
REMOVE = cs-rm
+SHELL=cmd.exe
endif
#########################################################################
+.PHONY: all clean deploy
all:: $(PROJECT).hex $(PROJECT).bin $(PROJECT).disasm
$(PROJECT).disasm: $(PROJECT).elf
$(OBJDUMP) -d $(PROJECT).elf >$(PROJECT).disasm
-$(PROJECT).elf: $(LSCRIPT) $(OBJECTS)
+$(PROJECT).elf: $(LSCRIPT) $(OBJECTS) $(LIBS)
$(LD) $(LDFLAGS) $(OBJECTS) $(LIBS) -o $(PROJECT).elf
$(SIZE) $(PROJECT).elf
_sidata = LOADADDR (.data);\r
. = ALIGN(4);\r
_sdata = .;\r
+ Image$$RW_IRAM1$$Base = .;\r
\r
*(.ARM.__AT_0x10000000)\r
*(vtable vtable.*)\r
\r
. = ALIGN(4);\r
_ebss = . ;\r
+ Image$$RW_IRAM1$$ZI$$Limit = . ;\r
} >IRAM0\r
\r
/**************************************************/\r
they will be left uninitialized. */\r
.AHBSRAM0 (NOLOAD):\r
{\r
+ Image$$RW_IRAM2$$Base = . ;\r
*(AHBSRAM0)\r
+ Image$$RW_IRAM2$$ZI$$Limit = .;\r
} > IRAM1\r
\r
.AHBSRAM1 (NOLOAD):\r
{\r
+ Image$$RW_IRAM3$$Base = . ;\r
*(AHBSRAM1)\r
+ Image$$RW_IRAM3$$ZI$$Limit = .;\r
} > IRAM2\r
\r
\r
GCC4MBED_DIR=../..\r
LIBS_PREFIX=\r
LIBS_SUFFIX=\r
+GCC4MBED_DELAYED_STDIO_INIT=1\r
\r
include ../../build/gcc4mbed.mk\r
\r
int main() \r
{\r
+ volatile int IterationCount = 0;\r
+ \r
while(1) \r
{\r
myled = 1;\r
wait(0.2);\r
myled = 0;\r
wait(0.2);\r
+ IterationCount++;\r
}\r
}\r
GCC4MBED_DIR=../..\r
LIBS_PREFIX=\r
LIBS_SUFFIX=\r
+GCC4MBED_DELAYED_STDIO_INIT=1\r
\r
include ../../build/gcc4mbed.mk\r
/* LocalFileSystem test modified to use SD cards instead. */\r
#include "mbed.h"\r
#include "SDFileSystem.h"\r
-#include "agutil.h"\r
-\r
-\r
-extern "C" void HardFault_Handler(void)\r
-{\r
- DebugDumpStack();\r
- error("\r\nHardFault\r\n");\r
-}\r
-\r
-extern "C" void MemManage_Handler(void)\r
-{\r
- DebugDumpStack();\r
- error("\r\nMemManage\r\n");\r
-}\r
-\r
-extern "C" void BusFault_Handler(void)\r
-{\r
- DebugDumpStack();\r
- error("\r\nBusFault\r\n");\r
-}\r
-\r
-extern "C" void UsageFault_Handler(void)\r
-{\r
- DebugDumpStack();\r
- error("\r\nUsageFault\r\n");\r
-}\r
-\r
-extern "C" void SVC_Handler(void)\r
-{\r
- DebugDumpStack();\r
- error("\r\nSVC Call\r\n");\r
-}\r
-\r
-extern "C" void DebugMon_Handler(void)\r
-{\r
- DebugDumpStack();\r
- error("\r\nDebugMonitor\r\n");\r
-}\r
-\r
-extern "C" void PendSV_Handler(void)\r
-{\r
- DebugDumpStack();\r
- error("\r\nPendSV\r\n");\r
-}\r
-\r
-extern "C" void SysTick_Handler(void)\r
-{\r
- DebugDumpStack();\r
- error("\r\nSysTick");\r
-}\r
-\r
-\r
-void BreakHandler(void)\r
-{\r
- DebugDumpStack();\r
- error("\r\nManual Break\r\n");\r
-}\r
\r
\r
SDFileSystem sd(p5, p6, p7, p8, "sd"); // the pinout on the mbed Cool Components workshop board\r
-InterruptIn BreakInterrupt(p9);\r
\r
\r
int main() \r
{\r
- // If you pull p9 low, then it should break into a running program and dump the stack.\r
- BreakInterrupt.mode(PullUp);\r
- BreakInterrupt.fall(BreakHandler);\r
-\r
int Result = -1;\r
char Buffer[32];\r
\r
printf("Test 10: closedir\r\n");\r
closedir(d);\r
\r
-\r
-\r
printf("\r\nTest completed\r\n");\r
} \r
# limitations under the License.\r
PROJECT=SDFileSystem\r
GCC4MBED_DIR=../..\r
-INCDIRS=../agutil\r
-LIBS_PREFIX=../agutil/agutil.ar\r
+INCDIRS=\r
+LIBS_PREFIX=\r
LIBS_SUFFIX=\r
\r
include ../../build/gcc4mbed.mk\r
limitations under the License.\r
*/\r
#include <mbed.h>\r
-#include <agutil.h>\r
\r
\r
Ticker flipper;\r
led2 = 1;\r
flipper.attach(&flip, 5.0); // the address of the function to be attached (flip) and the interval (2 seconds)\r
\r
- // Dump the interrupt vector\r
- printf("\r\n");\r
- printf("Vector Table Offset Register\r\n");\r
- DebugDumpMemory((void*)0xE000ED08, 4, 4);\r
- \r
- printf("Vector Table\r\n");\r
- unsigned int VectorAddress = *((unsigned int*)0xE000ED08);\r
- DebugDumpMemory((void*)VectorAddress, 4 * 32, 4);\r
- \r
// spin in a main loop. flipper will interrupt it to call flip\r
while(1) {\r
led1 = !led1;\r
# limitations under the License.\r
PROJECT=Ticker\r
GCC4MBED_DIR=../..\r
-INCDIRS=../agutil\r
-LIBS_PREFIX=../agutil/agutil.ar\r
+INCDIRS=\r
+LIBS_PREFIX=\r
LIBS_SUFFIX=\r
\r
include ../../build/gcc4mbed.mk\r
* Modified by Sagar G V on Mar 11 2011. added __libc_init_array()\r
* Modfied by Adam Green in 2011 to support mbed.\r
******************************************************************************/\r
-#include "mbedsys.h"\r
+#include "mri.h"\r
\r
\r
/* Exported constants --------------------------------------------------------*/\r
extern "C" int main(void);\r
extern "C" void __libc_init_array(void);\r
extern "C" void exit(int ErrorCode);\r
+extern "C" void __GCC4MBEDOpenStandardHandles(void);\r
+extern "C" void __MriTestRegisters(void);\r
\r
\r
/* CRT initialization code called from Reset_Handler after it calls SystemInit() */\r
*(pulDest++) = 0;\r
}\r
\r
+ /* Initialize stdin/stdout/stderr file handles. */\r
+ if (!GCC4MBED_DELAYED_STDIO_INIT)\r
+ {\r
+ __GCC4MBEDOpenStandardHandles();\r
+ }\r
+ \r
/* Initialize static constructors. */\r
__libc_init_array();\r
\r
+ MriInit();\r
+ //__debugbreak();\r
+\r
/* Call the application's entry point. */\r
ExitCode = main();\r
\r
\r
\r
/* Open the stdin/stdout/stderr handles */\r
-static void _OpenStandardHandles(void)\r
+extern "C" void __GCC4MBEDOpenStandardHandles(void)\r
{\r
/* Open stdin/stdout/stderr */\r
_sys_open("/stdin", OPENMODE_R);\r
/* Open stdin/stdout/stderr if needed */\r
if (!g_StandardHandlesOpened && file < 3)\r
{\r
- _OpenStandardHandles();\r
+ __GCC4MBEDOpenStandardHandles();\r
}\r
\r
/* Call the function in mbed.ar and let it handle the read */\r
/* Open stdin/stdout/stderr if needed */\r
if (!g_StandardHandlesOpened && file < 3)\r
{\r
- _OpenStandardHandles();\r
+ __GCC4MBEDOpenStandardHandles();\r
}\r
\r
/* Call the function in mbed.ar and let it handle the writes */\r
Config* config;
Player* player;
+ int debug;
+
private:
vector<Module*> hooks[NUMBER_OF_DEFINED_EVENTS]; // When a module asks to be called for a specific event ( a hook ), this is where that request is remembered
RingBuffer();
int size();
int capacity();
+ int next_block_index(int index);
void push_back(kind object);
void pop_front(kind &object);
void get( int index, kind &object);
return((this->head>this->tail)?length:0)+this->tail-head;
}
+template<class kind, int length> int RingBuffer<kind, length>::next_block_index(int index){
+ index++;
+ if (index == length) { index = 0; }
+ return(index);
+}
+
template<class kind, int length> void RingBuffer<kind, length>::push_back(kind object){
this->buffer[this->tail] = object;
this->tail = (tail+1)&(length-1);
}
template<class kind, int length> void RingBuffer<kind, length>::delete_first(){
- kind dummy;
- this->pop_front(dummy);
+ //kind dummy;
+ //this->pop_front(dummy);
+ this->head = (this->head+1)&(length-1);
}
#include "libs/Kernel.h"
#include "modules/tools/laser/Laser.h"
#include "modules/tools/extruder/Extruder.h"
+#include "modules/robot/Player.h"
#include "modules/utils/simpleshell/SimpleShell.h"
#include "modules/utils/pauser/Pauser.h"
#include "libs/SDFileSystem.h"
}
double get_temperature(){
+ double temp = this->new_thermistor_reading() ;
+ //this->kernel->serial->printf("adc reading: %f \r\n", temp);
return this->adc_value_to_temperature( this->new_thermistor_reading() );
}
double average_adc_reading(){
double total;
+ int j=0;
for( int i = 0; i <= this->queue.size()-1; i++ ){
+ j++;
+ //this->kernel->serial->printf("value:%f\r\n", *(this->queue.get_ref(i)) );
total += *(this->queue.get_ref(i));
}
- return total / this->queue.size();
+ //this->kernel->serial->printf("total:%f, size:%d \r\n", total, this->queue.size() );
+ return total / j;
}
AnalogIn* thermistor_pin;
};
-
int main() {
Kernel* kernel = new Kernel();
kernel->add_module( new Extruder(p26,p27) );
kernel->add_module( new SimpleShell() );
//kernel->add_module( new Pauser(p29,p30) );
- //kernel->add_module( new TemperatureControl() );
+ kernel->add_module( new TemperatureControl() );
while(1){
kernel->call_event(ON_MAIN_LOOP);
+
}
}
+
#include "utils/Gcode.h"
#include "libs/nuts_bolts.h"
#include "GcodeDispatch.h"
+#include "modules/robot/Player.h"
GcodeDispatch::GcodeDispatch(){}
Gcode gcode = Gcode();
gcode.command = possible_command;
this->kernel->call_event(ON_GCODE_RECEIVED, &gcode );
- this->kernel->serial->printf("ok\r\n");
+ //this->kernel->serial->printf("ok %d \r\n", this->kernel->player->queue.size());
//Gcode* test = new Gcode();
- //this->kernel->serial->printf("ok %p\r\n", test);
+ //this->kernel->serial->printf("ok %d %p\r\n", this->kernel->player->queue.size(), test);
//delete test;
+ this->kernel->serial->printf("ok\r\n");
// Ignore comments
}else if( first_char == ';' || first_char == '(' ){
#include "libs/Kernel.h"
#include "libs/nuts_bolts.h"
#include "SerialConsole.h"
+#include "libs/RingBuffer.h"
// Serial reading module
// Treats every received line as a command and passes it ( via event call ) to the command dispatcher.
char received = this->getc();
//On newline, we have received a line, else concatenate in buffer
if( received == '\r' ){ return; }
- if( received == '\n' ){
- this->line_received();
- receive_buffer = "";
- }else{
- this->receive_buffer += received;
- }
- }
+ //if( received == '\n' ){
+ // this->line_received();
+ // receive_buffer = "";
+ //}else{
+ // this->receive_buffer += received;
+ //}
+ this->buffer.push_back(received);
+ }
}
// Call event when newline received, for other modules to read the line
inline void SerialConsole::line_received(){
- string new_string = this->receive_buffer;
- this->received_lines.insert(this->received_lines.begin(),new_string);
+ //string new_string = this->receive_buffer;
+ //this->received_lines.insert(this->received_lines.begin(),new_string);
}
// Actual event calling must happen in the main loop because if it happens in the interrupt we will loose data
void SerialConsole::on_main_loop(void * argument){
- if( this->received_lines.size() < 1 ){ return; }
- this->kernel->call_event(ON_CONSOLE_LINE_RECEIVED, &this->received_lines.back() );
- this->received_lines.pop_back();
+ //if( this->received_lines.size() < 1 ){
+ // return;
+ //}
+ //this->kernel->call_event(ON_CONSOLE_LINE_RECEIVED, &this->received_lines.back() );
+ //this->received_lines.pop_back();
+ if( this->has_char('\n') ){
+ int index = 0;
+ string received;
+ while(1){
+ char c;
+ this->buffer.pop_front(c);
+ if( c == '\n' ){
+ //this->printf("received: <%s> \r\n", received.c_str() );
+ this->kernel->call_event(ON_CONSOLE_LINE_RECEIVED, &received );
+ return;
+ }else{
+ received += c;
+ }
+ }
+ }
}
+bool SerialConsole::has_char(char letter){
+ int index = this->buffer.head;
+ while( index != this->buffer.tail ){
+ if( this->buffer.buffer[index] == letter ){
+ return true;
+ }
+ index = this->buffer.next_block_index(index);
+ }
+ return false;
+}
#include <string>
using std::string;
#include "SerialConsole.h"
+#include "libs/RingBuffer.h"
#define baud_rate_setting_ckeckusm 10922
void on_serial_char_received();
void line_received();
virtual void on_main_loop(void * argument);
+ bool has_char(char letter);
- string receive_buffer; // Received chars are stored here until a newline character is received
- vector<std::string> received_lines; // Received lines are stored here until they are requested
+ //string receive_buffer; // Received chars are stored here until a newline character is received
+ //vector<std::string> received_lines; // Received lines are stored here until they are requested
+ RingBuffer<char,256> buffer; // Receive buffer
+
};
#endif
// Whether or not a Gcode has a letter
bool Gcode::has_letter( char letter ){
- return ( this->command.find( letter ) != string::npos );
+ //return ( this->command->find( letter ) != string::npos );
+ for (size_t i=0; i < this->command.length(); i++){
+ if( this->command.at(i) == letter ){
+ return true;
+ }
+ }
+ return false;
}
// Retrieve the value for a given letter
+//double Gcode::get_value_old( char letter ){
+// size_t start = this->command.find(letter);
+// size_t end = this->command.find_first_not_of("1234567890.-", start+1);
+// if( end == string::npos ){ end = this->command.length()+1; }
+// string extracted = this->command.substr( start+1, end-start-1 );
+// double value = atof(extracted.c_str());
+// return value;
+//}
+
+
+// Retrieve the value for a given letter
+// We don't use the high-level methods of std::string because they call malloc and it's very bad to do that inside of interrupts
double Gcode::get_value( char letter ){
- size_t start = this->command.find(letter);
- size_t end = this->command.find_first_not_of("1234567890.-", start+1);
- if( end == string::npos ){ end = this->command.length()+1; }
- string extracted = this->command.substr( start+1, end-start-1 );
- double value = atof(extracted.c_str());
- return value;
+ __disable_irq();
+ for (size_t i=0; i <= this->command.length()-1; i++){
+ if( letter == this->command.at(i) ){
+ size_t beginning = i+1;
+ char buffer[20];
+ for(size_t j=beginning; j <= this->command.length(); j++){
+ char c;
+ if( j == this->command.length() ){ c = ';'; }else{ c = this->command.at(j); }
+ if( c != '.' && c != '-' && ( c < '0' || c > '9' ) ){
+ buffer[j-beginning] = '\0';
+ __enable_irq();
+ return atof(buffer);
+ }else{
+ buffer[j-beginning] = c;
+ }
+ }
+ }
+ }
+ __enable_irq();
+ return 0;
}
Block::Block(){
clear_vector(this->steps);
this->times_taken = 0; // A block can be "taken" by any number of modules, and the next block is not moved to until all the modules have "released" it. This value serves as a tracker.
+ this->is_ready = false;
+ this->initial_rate = -1;
+ this->final_rate = -1;
}
void Block::debug(Kernel* kernel){
- kernel->serial->printf(" steps:%4d|%4d|%4d(max:%4d) nominal:r%10d/s%6.1f mm:%9.6f rdelta:%8d acc:%5d dec:%5d rates:%10d>%10d \r\n", this->steps[0], this->steps[1], this->steps[2], this->steps_event_count, this->nominal_rate, this->nominal_speed, this->millimeters, this->rate_delta, this->accelerate_until, this->decelerate_after, this->initial_rate, this->final_rate );
+ kernel->serial->printf("%p: steps:%4d|%4d|%4d(max:%4d) nominal:r%10d/s%6.1f mm:%9.6f rdelta:%8d acc:%5d dec:%5d rates:%10d>%10d taken:%d ready:%d \r\n", this, this->steps[0], this->steps[1], this->steps[2], this->steps_event_count, this->nominal_rate, this->nominal_speed, this->millimeters, this->rate_delta, this->accelerate_until, this->decelerate_after, this->initial_rate, this->final_rate, this->times_taken, this->is_ready );
}
this->initial_rate = ceil(this->nominal_rate * entryfactor); // (step/min)
this->final_rate = ceil(this->nominal_rate * exitfactor); // (step/min)
+ //this->player->kernel->serial->printf("%p: r:%d \r\n", this, this->initial_rate);
double acceleration_per_minute = this->rate_delta * this->planner->kernel->stepper->acceleration_ticks_per_second * 60.0;
int accelerate_steps = ceil( this->estimate_acceleration_distance( this->initial_rate, this->nominal_rate, acceleration_per_minute ) );
int decelerate_steps = ceil( this->estimate_acceleration_distance( this->nominal_rate, this->final_rate, -acceleration_per_minute ) );
// Gcodes are attached to their respective blocks so that on_gcode_execute can be called with it
void Block::append_gcode(Gcode* gcode){
- this->commands.push_back(gcode->command);
- this->travel_distances.push_back(gcode->millimeters_of_travel);
+ //this->commands.push_back(gcode->command);
+ //this->travel_distances.push_back(gcode->millimeters_of_travel);
+ __disable_irq();
+ this->gcodes.push_back(*gcode);
+ __enable_irq();
}
// The attached gcodes are then poped and the on_gcode_execute event is called with them as a parameter
void Block::pop_and_execute_gcode(Kernel* &kernel){
- for(unsigned short index=0; index<this->commands.size(); index++){
- string command = this->commands.at(index);
- double distance = this->travel_distances.at(index);
- Gcode gcode = Gcode();
- gcode.command = command;
- gcode.millimeters_of_travel = distance;
- kernel->call_event(ON_GCODE_EXECUTE, &gcode );
+ Block* block = const_cast<Block*>(this);
+ //for(unsigned short index=0; index<block->commands.size(); index++){
+ // Gcode gcode = Gcode();
+ // gcode.command = block->commands.at(index);
+ // gcode.millimeters_of_travel = block->travel_distances.at(index);
+ // kernel->call_event(ON_GCODE_EXECUTE, &gcode );
+ //}
+ for(unsigned short index=0; index<block->gcodes.size(); index++){
+ //this->player->kernel->serial->printf("exec: block:%p gcode:%p command:%p \r\n", block, &(block->gcodes[index]), &(block->gcodes[index].command) );
+ //this->player->kernel->serial->printf(" str:%s \r\n", block->gcodes[index].command.c_str() );
+ //wait(0.1);
+ kernel->call_event(ON_GCODE_EXECUTE, &(block->gcodes[index]));
}
}
// Signal the player that this block is ready to be injected into the system
void Block::ready(){
+ this->is_ready = true;
this->player->new_block_added();
}
this->times_taken--;
if( this->times_taken < 1 ){
this->player->kernel->call_event(ON_BLOCK_END, this);
- //player->kernel->serial->printf("gcodes: %d, dist: %f \r\n", this->commands.size(), this->millimeters );
this->pop_and_execute_gcode(this->player->kernel);
Player* player = this->player;
+
+ //this->player->kernel->serial->printf("a %d\r\n", this->player->queue.size() );
if( player->queue.size() > 0 ){
player->queue.delete_first();
}
- player->current_block = NULL;
- player->pop_and_process_new_block();
+
+ //this->player->kernel->serial->printf("b %d %d\r\n", this->player->queue.size(), player->looking_for_new_block );
+
+ if( player->looking_for_new_block == false ){
+ //player->pop_and_process_new_block(123);
+ if( player->queue.size() > 0 ){
+ Block* candidate = player->queue.get_ref(0);
+ if( candidate->is_ready ){
+ //candidate->debug(player->kernel);
+ //this->player->kernel->serial->printf("c %d %d\r\n", this->player->queue.size(), player->looking_for_new_block );
+ player->current_block = candidate;
+ player->kernel->call_event(ON_BLOCK_BEGIN, player->current_block);
+ if( player->current_block->times_taken < 1 ){
+ player->current_block->release();
+ }
+ }else{
+
+ player->current_block = NULL;
+
+ }
+ }else{
+ //player->current_block->debug(player->kernel);
+ //this->player->kernel->serial->printf("d %d %d\r\n", this->player->queue.size(), player->looking_for_new_block );
+ //wait(0.1);
+ player->current_block = NULL;
+ }
+ }
}
}
vector<std::string> commands;
vector<double> travel_distances;
+ vector<Gcode> gcodes;
unsigned int steps[3]; // Number of steps for each axis for this block
unsigned int steps_event_count; // Steps for the longest axis
double max_entry_speed;
Planner* planner;
Player* player;
+
+ bool is_ready;
short times_taken; // A block can be "taken" by any number of modules, and the next block is not moved to until all the modules have "released" it. This value serves as a tracker.
//if( target[ALPHA_STEPPER] == this->position[ALPHA_STEPPER] && target[BETA_STEPPER] == this->position[BETA_STEPPER] && target[GAMMA_STEPPER] == this->position[GAMMA_STEPPER] ){ this->computing = false; return; }
// Stall here if the queue is ful
- while( this->kernel->player->queue.size() >= this->kernel->player->queue.capacity() ){ wait_us(100); }
+ while( this->kernel->player->queue.size() >= this->kernel->player->queue.capacity()-2 ){ wait_us(100); }
Block* block = this->kernel->player->new_block();
block->planner = this;
// 3. Recalculate trapezoids for all blocks.
//
void Planner::recalculate() {
+ //this->kernel->serial->printf("recalculate last: %p, queue size: %d \r\n", this->kernel->player->queue.get_ref( this->kernel->player->queue.size()-1 ), this->kernel->player->queue.size() );
this->reverse_pass();
this->forward_pass();
this->recalculate_trapezoids();
// planner_recalculate() after updating the blocks. Any recalulate flagged junction will
// compute the two adjacent trapezoids to the junction, since the junction speed corresponds
// to exit speed and entry speed of one another.
+/*
void Planner::recalculate_trapezoids() {
// For each block
- for( int index = 0; index <= this->kernel->player->queue.size()-1; index++ ){ // We skip the first one because we need a previous
-
- if( this->kernel->player->queue.size()-1 == index ){ //last block
+ int size = this->kernel->player->queue.size();
+ for( int index = 0; index <= size-1; index++ ){ // We skip the first one because we need a previous
+ if( size-1 == index ){ //last block
Block* last = this->kernel->player->queue.get_ref(index);
last->calculate_trapezoid( last->entry_speed / last->nominal_speed, MINIMUM_PLANNER_SPEED / last->nominal_speed );
+ this->kernel->serial->printf("%p: %d/%d last r:%d \r\n", last, index, size-1, last->initial_rate);
}else{
Block* current = this->kernel->player->queue.get_ref(index);
Block* next = this->kernel->player->queue.get_ref(index+1);
if( current->recalculate_flag || next->recalculate_flag ){
current->calculate_trapezoid( current->entry_speed/current->nominal_speed, next->entry_speed/current->nominal_speed );
current->recalculate_flag = false; // Reset current only to ensure next trapezoid is computed
+ this->kernel->serial->printf("%p: %d/%d other r:%d \r\n", current, index, size-1, current->initial_rate);
+ }else{
+ this->kernel->serial->printf("%p: %d/%d else r:%d \r\n", current, index, size-1, current->initial_rate);
}
}
}
}
+*/
+void Planner::recalculate_trapezoids() {
+ int block_index = this->kernel->player->queue.head;
+ Block* current;
+ Block* next = NULL;
+ //this->kernel->serial->printf("tail:%d head:%d size:%d\r\n", this->kernel->player->queue.tail, this->kernel->player->queue.head, this->kernel->player->queue.size());
+
+ while(block_index != this->kernel->player->queue.tail){
+ current = next;
+ next = &this->kernel->player->queue.buffer[block_index];
+ //this->kernel->serial->printf("index:%d current:%p next:%p \r\n", block_index, current, next );
+ if( current ){
+ // Recalculate if current block entry or exit junction speed has changed.
+ if( current->recalculate_flag || next->recalculate_flag ){
+ current->calculate_trapezoid( current->entry_speed/current->nominal_speed, next->entry_speed/current->nominal_speed );
+ current->recalculate_flag = false;
+ }
+ }
+ block_index = this->kernel->player->queue.next_block_index( block_index );
+ }
+
+ // Last/newest block in buffer. Exit speed is set with MINIMUM_PLANNER_SPEED. Always recalculated.
+ next->calculate_trapezoid( next->entry_speed/next->nominal_speed, MINIMUM_PLANNER_SPEED/next->nominal_speed); //TODO: Make configuration option
+ next->recalculate_flag = false;
+
+}
// Debug function
void Planner::dump_queue(){
--- /dev/null
+/*
+ This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl) with additions from Sungeun K. Jeon (https://github.com/chamnit/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/>.
+*/
+
+using namespace std;
+#include <vector>
+#include "mbed.h"
+#include "libs/nuts_bolts.h"
+#include "libs/RingBuffer.h"
+#include "../communication/utils/Gcode.h"
+#include "libs/Module.h"
+#include "libs/Kernel.h"
+#include "Block.h"
+#include "Player.h"
+#include "Planner.h"
+
+Player::Player(){
+ this->current_block = NULL;
+ this->looking_for_new_block = false;
+}
+
+// Append a block to the list
+Block* Player::new_block(){
+
+ // Clean up the vector of commands in the block we are about to replace
+ // It is quite strange to do this here, we really should do it inside Block->pop_and_execute_gcode
+ // but that function is called inside an interrupt and thus can break everything if the interrupt was trigerred during a memory access
+ //Block* block = this->queue.get_ref( this->queue.size()-1 );
+ Block* block = this->queue.get_ref( this->queue.size() );
+ if( block->player == this ){
+ for(short index=0; index<block->gcodes.size(); index++){
+ block->gcodes.pop_back();
+ }
+ //for(short index=0; index<block->commands.size(); index++){
+ // block->commands.pop_back();
+ // block->travel_distances.pop_back();
+ //}
+ }
+
+ // Create a new virgin Block in the queue
+ this->queue.push_back(Block());
+ block = this->queue.get_ref( this->queue.size()-1 );
+ block->is_ready = false;
+ block->initial_rate = -2;
+ block->final_rate = -2;
+ block->player = this;
+
+ return block;
+}
+
+// Used by blocks to signal when they are ready to be used by the system
+void Player::new_block_added(){
+ //this->kernel->serial->printf("new block: %p\r\n", this->current_block);
+
+ //if( this->current_block == 0x00 || this->queue.size() == 0 ){
+ //this->kernel->serial->printf("f %p %d\r\n", this->current_block, this->queue.size() );
+ //}
+
+
+ if( this->current_block == NULL ){
+ this->pop_and_process_new_block(33);
+ }
+}
+
+// Process a new block in the queue
+void Player::pop_and_process_new_block(int debug){
+ if( this->looking_for_new_block ){ return; }
+ this->looking_for_new_block = true;
+
+ if( this->current_block != NULL ){ this->looking_for_new_block = false; return; }
+
+ // Return if queue is empty
+ if( this->queue.size() == 0 ){
+ this->current_block = NULL;
+ // TODO : ON_QUEUE_EMPTY event
+ this->looking_for_new_block = false;
+ return;
+ }
+
+ // Get a new block
+ this->current_block = this->queue.get_ref(0);
+
+ // Tell all modules about it
+ this->kernel->call_event(ON_BLOCK_BEGIN, this->current_block);
+
+ // In case the module was not taken
+ if( this->current_block->times_taken < 1 ){
+ //this->kernel->serial->printf("e %p %d %d %d\r\n", this->current_block, this->queue.size(), this->current_block == 0x00, debug );
+ //wait(0.1);
+ this->looking_for_new_block = false;
+ this->current_block->release();
+ }
+
+ this->looking_for_new_block = false;
+
+}
--- /dev/null
+/*
+ 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 PLAYER_H
+#define PLAYER_H
+#include "libs/Module.h"
+#include "libs/Kernel.h"
+using namespace std;
+#include <string>
+#include <vector>
+
+class Player : public Module {
+ public:
+ Player();
+
+ Block* new_block();
+ void new_block_added();
+ void pop_and_process_new_block(int debug);
+
+ RingBuffer<Block,32> queue; // Queue of Blocks
+ Block* current_block;
+ bool looking_for_new_block;
+
+};
+
+
+
+#endif
Gcode* gcode = static_cast<Gcode*>(argument);
gcode->call_on_gcode_execute_event_immediatly = false;
gcode->on_gcode_execute_event_called = false;
-
//If the queue is empty, execute immediatly, otherwise attach to the last added block
if( this->kernel->player->queue.size() == 0 ){
gcode->call_on_gcode_execute_event_immediatly = true;
block->append_gcode(gcode);
}
-
}
}
break;
}
+
+
// As far as the parser is concerned, the position is now == target. In reality the
// motion control system might still be processing the action and the real tool position
// in any intermediate location.
#include "libs/Kernel.h"
#include "Stepper.h"
#include "Planner.h"
+#include "Player.h"
#include "mbed.h"
#include <vector>
using namespace std;
LPC_TIM0->MR0 = 10000;
LPC_TIM0->MCR = 11; // for MR0 and MR1, with no reset at MR1
NVIC_EnableIRQ(TIMER0_IRQn);
- NVIC_SetPriority(TIMER3_IRQn, 1);
+ NVIC_SetPriority(TIMER3_IRQn, 3);
+ NVIC_SetPriority(TIMER0_IRQn, 2);
+ NVIC_SetPriority(TIMER1_IRQn, 2);
LPC_TIM0->TCR = 1;
// Step and Dir pins as outputs
// The stepper does not care about 0-blocks
if( block->millimeters == 0.0 ){ return; }
- this->current_block = block;
+ //this->current_block = block;
// Mark the new block as of interrest to us
block->take();
}else{
this->out_bits = 0;
}
+
}
// We compute this here instead of each time in the interrupt
// Set the Timer interval
LPC_TIM0->MR0 = floor( ( SystemCoreClock/4 ) / ( (steps_per_minute/60L) * speed_factor ) );
-
+ if( LPC_TIM0->MR0 < 150 ){
+ LPC_TIM0->MR0 = 150;
+
+ this->kernel->serial->printf("tim0mr0: %d, steps_per minute: %f \r\n", LPC_TIM0->MR0, steps_per_minute );
+ //Block* block = new Block();
+ //this->kernel->serial->printf(":l queue:%d debug:%d cb:%p cb=null:%d mem:%p tc:%u mr0:%u mr1:%u \r\n", this->kernel->player->queue.size() , this->kernel->debug, this->current_block, this->current_block == NULL, block, LPC_TIM0->TC , LPC_TIM0->MR0, LPC_TIM0->MR1 );
+ //delete block;
+ //this->kernel->serial->printf("mr0:%u, st/m:%f, sf:%f, bsf:%f \r\n", LPC_TIM0->MR0, steps_per_minute, speed_factor, this->base_stepping_frequency );
+ //this->current_block->debug(this->kernel);
+ //wait(0.1);
+ }
+
+
// In case we change the Match Register to a value the Timer Counter has past
if( LPC_TIM0->TC >= LPC_TIM0->MR0 ){ LPC_TIM0->TCR = 3; LPC_TIM0->TCR = 1; }
#include "mbed.h"
#include "libs/Module.h"
#include "libs/Kernel.h"
+#include "modules/robot/Player.h"
#include "modules/robot/Block.h"
#include "modules/tools/extruder/Extruder.h"
void Extruder::on_gcode_execute(void* argument){
Gcode* gcode = static_cast<Gcode*>(argument);
- //this->kernel->serial->printf("gcode_exec: %s \r\n", gcode->command.c_str() );
+ //this->kernel->serial->printf("e: %s\r\n", gcode->command.c_str() );
// Absolute/relative mode
if( gcode->has_letter('M')){
// Extrusion length
if( gcode->has_letter('E' )){
double extrusion_distance = gcode->get_value('E');
+ //this->kernel->serial->printf("a extrusion_distance: %f, target_position: %f, new_extrusion_distance: %f, current_position: %f \r\n", extrusion_distance, this->target_position, extrusion_distance - this->target_position, this->current_position );
if( this->absolute_mode == true ){
extrusion_distance = extrusion_distance - this->target_position;
}
+ //this->kernel->serial->printf("b extrusion_distance: %f, target_position: %f \r\n", extrusion_distance, this->target_position );
if( fabs(gcode->millimeters_of_travel) < 0.0001 ){
this->solo_mode = true;
this->travel_distance = extrusion_distance;
void Extruder::on_block_begin(void* argument){
Block* block = static_cast<Block*>(argument);
- //this->kernel->serial->printf("block_begin ");
- //block->debug(this->kernel);
-
if( fabs(this->travel_distance) > 0.001 ){
block->take(); // In solo mode we take the block so we can move even if the stepper has nothing to do
this->current_block = block;
- //this->kernel->serial->printf("before: start:%f target:%f current:%f\r\n", this->start_position, this->target_position, this->current_position);
this->start_position = this->target_position;
this->target_position = this->start_position + this->travel_distance ;
- //this->kernel->serial->printf("after: start:%f target:%f current:%f\r\n", this->start_position, this->target_position, this->current_position);
+ //this->kernel->serial->printf("bb: target_position: %f, travel_distance:%f \r\n", this->target_position, this->travel_distance );
this->on_speed_change(this);
}
if( fabs(this->travel_ratio) > 0.001 ){
// In non-solo mode, we just follow the stepper module
this->current_block = block;
- //this->kernel->serial->printf("before: start:%f target:%f current:%f\r\n", this->start_position, this->target_position, this->current_position);
- //this->kernel->serial->printf("a:direction: %d start:%f current: %f target: %f add:%f close:%f \r\n", this->direction, this->start_position, this->current_position, this->target_position, (double(double(1)/double(1001)))*double(this->direction), fabs( this->current_position - this->target_position ) );
this->start_position = this->target_position;
this->target_position = this->start_position + ( this->current_block->millimeters * this->travel_ratio );
this->on_speed_change(this);
- //this->kernel->serial->printf("d:direction: %d start:%f current: %f target: %f add:%f close:%f \r\n", this->direction, this->start_position, this->current_position, this->target_position, (double(double(1)/double(1001)))*double(this->direction), fabs( this->current_position - this->target_position ) );
- //this->kernel->serial->printf("after: start:%f target:%f current:%f\r\n", this->start_position, this->target_position, this->current_position);
}
}
void Extruder::on_speed_change(void* argument){
-
- if( this->debug ){ this->kernel->serial->printf("back in event \r\n");wait(0.1); }
-
// Set direction
if( this->target_position > this->current_position ){
this->direction = 1;
}
if( fabs(this->travel_ratio) > 0.001 ){
-
- if( this->debug ){
- this->kernel->serial->printf("back in if \r\n");
- this->kernel->stepper->current_block->debug(this->kernel);
- wait(0.1);
- }
-
- // Do not change rate if stepper rate is null
+
if( this->kernel->stepper->current_block == NULL || fabs(this->kernel->stepper->trapezoid_adjusted_rate) < 0.0001 || this->kernel->stepper->current_block->nominal_rate == 0 ){
- return;
- }
-
-
- if( this->debug ){ this->kernel->serial->printf("back in if2 \r\n");wait(0.1); }
-
- // Get a current/nominal rate ratio
- if( fabs(this->kernel->stepper->current_block->nominal_rate) < 0.01 ){
- wait(1);
+ return;
}
-
- if( this->debug ){ this->kernel->serial->printf("back in if3 \r\n");wait(0.1); }
-
+ // Get a current/nominal rate ratio
double stepper_rate_ratio = this->kernel->stepper->trapezoid_adjusted_rate / double( this->kernel->stepper->current_block->nominal_rate ) ;
// Get a nominal duration for this block
-
-
- if( this->debug ){ this->kernel->serial->printf("back in if4 \r\n");wait(0.1); }
-
double nominal_duration = this->kernel->stepper->current_block->millimeters / ( this->kernel->stepper->current_block->nominal_speed / 60 ) ;
-
- bool testo = false;
- if( this->debug ){
- this->kernel->serial->printf("back in if5 \r\n");wait(0.1);
- this->debug_count--;
- if( this->debug_count == 0 ){
- this->debug = false;
- }
- testo = true;
- }
- if( testo ){ this->kernel->serial->printf("back in if7 \r\n");wait(0.1); }
-
// Get extrusion nominal speed
- if( fabs(nominal_duration) < 0.001 || this->debug ){
- this->kernel->serial->printf("start debugging, nominal_duration: %f \r\n", double(nominal_duration));
- this->kernel->stepper->current_block->debug(this->kernel);
- this->debug = true;
- this->debug_count = 5;
- wait(0.1);
- }
-
- if( testo ){ this->kernel->serial->printf("back in if8 \r\n");wait(0.1); }
double nominal_extrusion_speed = fabs( this->target_position - this->start_position ) / nominal_duration;
-
-
- if( testo ){ this->kernel->serial->printf("back in if9 \r\n");wait(0.1); }
- if( this->debug ){ this->kernel->serial->printf("nom_extr_speed: %f \r\n", double(nominal_extrusion_speed));wait(0.1); }
// Get adjusted speed
double adjusted_speed = nominal_extrusion_speed * stepper_rate_ratio;
-
- if( testo ){ this->kernel->serial->printf("back in if10 \r\n");wait(0.1); }
-
- if( this->debug ){ this->kernel->serial->printf("adj_speed a: %f \r\n", double(adjusted_speed));wait(0.1); }
- //this->kernel->serial->printf("e:direction: %d start:%f current: %f target: %f add:%f close:%f \r\n", this->direction, this->start_position, this->current_position, this->target_position, (double(double(1)/double(1001)))*double(this->direction), fabs( this->current_position - this->target_position ) );
- //this->kernel->serial->printf("speed change rate:%f/%u=%f dur:%f=%f/%f nom_extr_spd:%f/%f=%f adj_speed:%f \r\n", this->kernel->stepper->trapezoid_adjusted_rate, this->kernel->stepper->current_block->nominal_rate, stepper_rate_ratio, nominal_duration, this->kernel->stepper->current_block->millimeters, this->kernel->stepper->current_block->nominal_speed / 60, ( this->target_position - this->start_position ), nominal_duration, nominal_extrusion_speed, adjusted_speed );
-
-
- if( testo ){ this->kernel->serial->printf("back in if11 \r\n");wait(0.1); }
- if( this->debug ){ this->kernel->serial->printf("adj_speed b: %f \r\n", double(adjusted_speed));wait(0.1); }
// Set timer
- LPC_TIM1->MR0 = ((SystemCoreClock/4))/int(floor(adjusted_speed*1000));
+ if((adjusted_speed*1400) < 1 ){
+ return;
+ }
+ LPC_TIM1->MR0 = ((SystemCoreClock/4))/(adjusted_speed*1700);
+ if( LPC_TIM1->MR0 < 300 ){
+ this->kernel->serial->printf("tim1mr0 %d, adjusted_speed: %f\r\n", LPC_TIM1->MR0, adjusted_speed );
+ LPC_TIM1->MR0 = 300;
+ }
- if( testo ){ this->kernel->serial->printf("back in if12 \r\n");wait(0.1); }
- if( this->debug ){ this->kernel->serial->printf("adj_speed c: %f \r\n", double(adjusted_speed));wait(0.1); }
// In case we are trying to set the timer to a limit it has already past by
if( LPC_TIM1->TC >= LPC_TIM1->MR0 ){
LPC_TIM1->TCR = 3;
LPC_TIM1->TCR = 1;
}
-
+
// Update Timer1
LPC_TIM1->MR1 = (( SystemCoreClock/4 ) / 1000000 ) * this->microseconds_per_step_pulse;
- if( testo ){ this->kernel->serial->printf("back in if13 \r\n");wait(0.1); }
- if( this->debug ){ this->kernel->serial->printf("adj_speed d: %f \r\n", double(adjusted_speed));wait(1); }
+
}
if( fabs(this->travel_distance) > 0.001 ){
// Set timer
- LPC_TIM1->MR0 = ((SystemCoreClock/4))/int(floor(1000));
+ LPC_TIM1->MR0 = ((SystemCoreClock/4))/int(floor(1.2*1700));
// In case we are trying to set the timer to a limit it has already past by
if( LPC_TIM1->TC >= LPC_TIM1->MR0 ){
}
-
-
-
inline void Extruder::stepping_tick(){
- if( fabs( this->current_position - this->target_position ) >= 0.001 ){
- //this->kernel->serial->printf("b:direction: %d start:%f current: %f target: %f add:%f close:%f \r\n", this->direction, this->start_position, this->current_position, this->target_position, (double(double(1)/double(1001)))*double(this->direction), fabs( this->current_position - this->target_position ) );
- this->current_position += (double(double(1)/double(1000)))*double(this->direction);
- //this->kernel->serial->printf("c:direction: %d start:%f current: %f target: %f add:%f close:%f \r\n", this->direction, this->start_position, this->current_position, this->target_position, (double(double(1)/double(1001)))*double(this->direction), fabs( this->current_position - this->target_position ) );
+
+ //if( fabs( this->current_position - this->target_position ) >= 0.001 ){
+ if( ( this->current_position < this->target_position && this->direction == 1 ) || ( this->current_position > this->target_position && this->direction == -1 ) ){
+ this->current_position += (double(double(1)/double(1700)))*double(this->direction);
this->dir_pin = ((this->direction > 0) ? 1 : 0);
this->step_pin = 1;
}else{