Fork of Smoothie to port to mbed non-LPC targets.

Dependencies:   mbed

Fork of Smoothie by Stéphane Cachat

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SlowTicker.cpp Source File

SlowTicker.cpp

00001 /*
00002       This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
00003       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.
00004       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.
00005       You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
00006 */
00007 
00008 using namespace std;
00009 #include <vector>
00010 #include "libs/nuts_bolts.h"
00011 #include "libs/Module.h"
00012 #include "libs/Kernel.h"
00013 #include "SlowTicker.h"
00014 #include "libs/Hook.h"
00015 #include "modules/robot/Conveyor.h"
00016 
00017 // This module uses a Timer to periodically call hooks
00018 // Modules register with a function ( callback ) and a frequency, and we then call that function at the given frequency.
00019 
00020 SlowTicker* global_slow_ticker;
00021 
00022 SlowTicker::SlowTicker(){
00023     max_frequency = 0;
00024     global_slow_ticker = this;
00025 
00026     // TODO: What is this ??
00027     flag_1s_flag = 0;
00028     flag_1s_count = SystemCoreClock>>2;
00029 
00030     g4_ticks = 0;
00031     g4_pause = false;
00032 }
00033 
00034 void SlowTicker::on_module_loaded(){
00035     register_for_event(ON_IDLE);
00036     register_for_event(ON_GCODE_RECEIVED);
00037     register_for_event(ON_GCODE_EXECUTE);
00038 }
00039 
00040 // Set the base frequency we use for all sub-frequencies
00041 void SlowTicker::set_frequency( int frequency ){
00042     this->interval = (SystemCoreClock >> 2) / frequency;   // SystemCoreClock/4 = Timer increments in a second
00043     flag_1s_count= SystemCoreClock>>2;
00044 }
00045 
00046 // The actual interrupt being called by the timer, this is where work is done
00047 void SlowTicker::tick(){
00048 
00049     // Call all hooks that need to be called ( bresenham )
00050     for (uint32_t i=0; i<this->hooks.size(); i++){
00051         Hook* hook = this->hooks.at(i);
00052         hook->countdown -= this->interval;
00053         if (hook->countdown < 0)
00054         {
00055             hook->countdown += hook->interval;
00056             hook->call();
00057         }
00058     }
00059 
00060     // deduct tick time from secound counter
00061     flag_1s_count -= this->interval;
00062     // if a whole second has elapsed,
00063     if (flag_1s_count < 0)
00064     {
00065         // add a second to our counter
00066         flag_1s_count += SystemCoreClock >> 2;
00067         // and set a flag for idle event to pick up
00068         flag_1s_flag++;
00069     }
00070 
00071     // if we're counting down a pause
00072     if (g4_ticks > 0)
00073     {
00074         // deduct tick time from timeout
00075         if (g4_ticks > interval)
00076             g4_ticks -= interval;
00077         else
00078             g4_ticks = 0;
00079     }
00080 }
00081 
00082 bool SlowTicker::flag_1s(){
00083     // atomic flag check routine
00084     // first disable interrupts
00085     __disable_irq();
00086     // then check for a flag
00087     if (flag_1s_flag)
00088     {
00089         // if we have a flag, decrement the counter
00090         flag_1s_flag--;
00091         // re-enable interrupts
00092         __enable_irq();
00093         // and tell caller that we consumed a flag
00094         return true;
00095     }
00096     // if no flag, re-enable interrupts and return false
00097     __enable_irq();
00098     return false;
00099 }
00100 
00101 #include "gpio.h"
00102 extern GPIO leds[];
00103 void SlowTicker::on_idle(void*)
00104 {
00105     static uint16_t ledcnt= 0;
00106     if(THEKERNEL->use_leds) {
00107         // flash led 3 to show we are alive
00108         leds[2]= (ledcnt++ & 0x1000) ? 1 : 0;
00109     }
00110 
00111     // if interrupt has set the 1 second flag
00112     if (flag_1s())
00113         // fire the on_second_tick event
00114         THEKERNEL->call_event(ON_SECOND_TICK);
00115 
00116     // if G4 has finished, release our pause
00117     if (g4_pause && (g4_ticks == 0))
00118     {
00119         g4_pause = false;
00120         THEKERNEL->pauser->release();
00121     }
00122 }
00123 
00124 // When a G4-type gcode is received, add it to the queue so we can execute it in time
00125 void SlowTicker::on_gcode_received(void* argument){
00126     Gcode* gcode = static_cast<Gcode*>(argument);
00127     // Add the gcode to the queue ourselves if we need it
00128     if( gcode->has_g && gcode->g == 4 ){
00129         THEKERNEL->conveyor->append_gcode(gcode);
00130         // ensure that no subsequent gcodes get executed along with our G4
00131         THEKERNEL->conveyor->queue_head_block();
00132     }
00133 }
00134 
00135 // When a G4-type gcode is executed, start the pause
00136 void SlowTicker::on_gcode_execute(void* argument){
00137     Gcode* gcode = static_cast<Gcode*>(argument);
00138 
00139     if (gcode->has_g){
00140         if (gcode->g == 4){
00141             gcode->mark_as_taken();
00142             bool updated = false;
00143             if (gcode->has_letter('P')) {
00144                 updated = true;
00145                 g4_ticks += gcode->get_int('P') * ((SystemCoreClock >> 2) / 1000UL);
00146             }
00147             if (gcode->has_letter('S')) {
00148                 updated = true;
00149                 g4_ticks += gcode->get_int('S') * (SystemCoreClock >> 2);
00150             }
00151             if (updated){
00152                 // G4 Smm Pnn should pause for mm seconds + nn milliseconds
00153                 // at 120MHz core clock, the longest possible delay is (2^32 / (120MHz / 4)) = 143 seconds
00154                 if (!g4_pause){
00155                     g4_pause = true;
00156                     THEKERNEL->pauser->take();
00157                 }
00158             }
00159         }
00160     }
00161 }
00162 
00163 extern "C" void TIMER2_IRQHandler (void){
00164     global_slow_ticker->tick();
00165 }