Merge pull request #294 from wolfmanjm/upstreamedge
[clinton/Smoothieware.git] / src / libs / Kernel.cpp
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 "libs/Kernel.h"
9 #include "libs/Module.h"
10 #include "libs/Config.h"
11 #include "libs/nuts_bolts.h"
12 #include "libs/SlowTicker.h"
13 #include "libs/Adc.h"
14 #include "libs/Pauser.h"
15 #include "libs/StreamOutputPool.h"
16 #include <mri.h>
17
18 #include "modules/communication/SerialConsole.h"
19 #include "modules/communication/GcodeDispatch.h"
20 #include "modules/robot/Planner.h"
21 #include "modules/robot/Robot.h"
22 #include "modules/robot/Stepper.h"
23 #include "modules/robot/Conveyor.h"
24 #include "modules/tools/endstops/Endstops.h"
25 #include <malloc.h>
26
27
28
29 #define baud_rate_setting_checksum CHECKSUM("baud_rate")
30 #define uart0_checksum CHECKSUM("uart0")
31
32 Kernel* Kernel::instance;
33
34 // This is used to configure UARTs depending on the MRI configuration, see Kernel::Kernel()
35 static int isDebugMonitorUsingUart0(){
36 return NVIC_GetPriority(UART0_IRQn) == 0;
37 }
38
39 // The kernel is the central point in Smoothie : it stores modules, and handles event calls
40 Kernel::Kernel(){
41 instance= this; // setup the Singleton instance of the kernel
42
43 // Config first, because we need the baud_rate setting before we start serial
44 this->config = new Config();
45
46 // Serial second, because the other modules might want to say something
47 this->streams = new StreamOutputPool();
48
49 // Configure UART depending on MRI config
50 // If MRI is using UART0, we want to use UART1, otherwise, we want to use UART0. This makes it easy to use only one UART for both debug and actual commands.
51 NVIC_SetPriorityGrouping(0);
52 if( !isDebugMonitorUsingUart0() ){
53 this->serial = new SerialConsole(USBTX, USBRX, this->config->value(uart0_checksum,baud_rate_setting_checksum)->by_default(9600)->as_number());
54 }else{
55 this->serial = new SerialConsole(p13, p14, this->config->value(uart0_checksum,baud_rate_setting_checksum)->by_default(9600)->as_number());
56 }
57
58 this->add_module( this->config );
59 this->add_module( this->serial );
60
61 // HAL stuff
62 add_module( this->slow_ticker = new SlowTicker());
63 this->step_ticker = new StepTicker();
64 this->adc = new Adc();
65
66 // TODO : These should go into platform-specific files
67 // LPC17xx-specific
68 NVIC_SetPriorityGrouping(0);
69 NVIC_SetPriority(TIMER0_IRQn, 2);
70 NVIC_SetPriority(TIMER1_IRQn, 1);
71 NVIC_SetPriority(TIMER2_IRQn, 3);
72
73 // Set other priorities lower than the timers
74 NVIC_SetPriority(ADC_IRQn, 4);
75 NVIC_SetPriority(USB_IRQn, 4);
76
77 // If MRI is enabled
78 if( MRI_ENABLE ){
79 if( NVIC_GetPriority(UART0_IRQn) > 0 ){ NVIC_SetPriority(UART0_IRQn, 4); }
80 if( NVIC_GetPriority(UART1_IRQn) > 0 ){ NVIC_SetPriority(UART1_IRQn, 4); }
81 if( NVIC_GetPriority(UART2_IRQn) > 0 ){ NVIC_SetPriority(UART2_IRQn, 4); }
82 if( NVIC_GetPriority(UART3_IRQn) > 0 ){ NVIC_SetPriority(UART3_IRQn, 4); }
83 }else{
84 NVIC_SetPriority(UART0_IRQn, 4);
85 NVIC_SetPriority(UART1_IRQn, 4);
86 NVIC_SetPriority(UART2_IRQn, 4);
87 NVIC_SetPriority(UART3_IRQn, 4);
88 }
89
90 // Configure the step ticker
91 int base_stepping_frequency = this->config->value(base_stepping_frequency_checksum )->by_default(100000)->as_number();
92 double microseconds_per_step_pulse = this->config->value(microseconds_per_step_pulse_checksum )->by_default(5 )->as_number();
93
94 // Configure the step ticker ( TODO : shouldnt this go into stepticker's code ? )
95 this->step_ticker->set_reset_delay( microseconds_per_step_pulse / 1000000L );
96 this->step_ticker->set_frequency( base_stepping_frequency );
97
98 // Core modules
99 this->add_module( this->gcode_dispatch = new GcodeDispatch() );
100 this->add_module( this->robot = new Robot() );
101 this->add_module( this->stepper = new Stepper() );
102 this->add_module( this->planner = new Planner() );
103 this->add_module( this->conveyor = new Conveyor() );
104 this->add_module( this->pauser = new Pauser() );
105 this->add_module( this->public_data = new PublicData() );
106 this->add_module( this->toolsmanager = new ToolsManager() );
107
108 }
109
110 // Add a module to Kernel. We don't actually hold a list of modules, we just tell it where Kernel is
111 void Kernel::add_module(Module* module){
112 module->kernel = this;
113 module->on_module_loaded();
114 }
115
116 // Adds a hook for a given module and event
117 void Kernel::register_for_event(_EVENT_ENUM id_event, Module* module){
118 this->hooks[id_event].push_back(module);
119 }
120
121 // Call a specific event without arguments
122 void Kernel::call_event(_EVENT_ENUM id_event){
123 for (Module* current : hooks[id_event]) {
124 (current->*kernel_callback_functions[id_event])(this);
125 }
126 }
127
128 // Call a specific event with an argument
129 void Kernel::call_event(_EVENT_ENUM id_event, void * argument){
130 for (Module* current : hooks[id_event]) {
131 (current->*kernel_callback_functions[id_event])(argument);
132 }
133 }