Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
queue-refactor [2017/01/25 14:38]
arthur
queue-refactor [2017/09/01 22:29]
77.100.94.53
Line 9: Line 9:
 == The problem with the queue == The problem with the queue
  
-So essentially,​ Smoothie was originally coded with no consideration whatsoever for RAM usage. Yes. Sue me.+So essentially,​ Smoothie was originally coded with no consideration whatsoever for RAM usage. Yes. Sue me.
  
 It ended up not too bad, but still very very far from optimal. It ended up not too bad, but still very very far from optimal.
Line 15: Line 15:
 I guess we can start by explaining the problem the queue tries to solve before explaining the problem with the way we currently do it. I guess we can start by explaining the problem the queue tries to solve before explaining the problem with the way we currently do it.
  
-A pretty good explanation can be found here : [[[howitworks]]]+A pretty good explanation can be found here:​ [[howitworks]]
  
 === How it now works === How it now works
  
-In short, when we get say, a G-code for a movement, the following happens ( oversimplified ) : +In short, when we get say, a G-code for a movement, the following happens ( oversimplified ) : 
  
 * Robot interprets the G-code and makes a line from it * Robot interprets the G-code and makes a line from it
Line 36: Line 36:
 * Go to first step * Go to first step
  
-Now what this means for a module is there are two different processes/​loops : +Now what this means for a module is there are two different processes/​loops : 
 * The one in which you receive an instruction * The one in which you receive an instruction
 * The one in which you have to execute an instruction * The one in which you have to execute an instruction
Line 44: Line 44:
 Now this is for "​Blocks",​ which describe movements of the Robot ( XYZ movement ). Now this is for "​Blocks",​ which describe movements of the Robot ( XYZ movement ).
  
-But say you have a module that must emit a "​beep"​ in response to the {{G123}} G-code.+But say you have a module that must emit a "​beep"​ in response to the <kbd>G123</​kbd> ​G-code.
  
-It can't emit the "​beep"​ when the G-code is received, as that would violate the order of execution : because G-codes are not executed when they are received, it is very possible ( actually extremely likely ) that the G-code received before ​{{G123}} has not been executed, and is still in the Queue, waiting to be executed. ​+It can't emit the "​beep"​ when the G-code is received, as that would violate the order of execution : because G-codes are not executed when they are received, it is very possible ( actually extremely likely ) that the G-code received before ​<kbd>G123</​kbd> ​has not been executed, and is still in the Queue, waiting to be executed. ​
  
 Emitting the "​beep"​ now would mean emitting it too early and out of order. Emitting the "​beep"​ now would mean emitting it too early and out of order.
Line 66: Line 66:
 For example the G-code : For example the G-code :
  
-{{G1 X23.43 Y12.34 E22.33}} is 23 bytes.+<kbd>G1 X23.43 Y12.34 E22.33</​kbd> ​is 23 bytes.
  
 But because we already store the XYZ target coordinates in the Block, those are redundant. But because we already store the XYZ target coordinates in the Block, those are redundant.
Line 82: Line 82:
 All of these are good reasons to do things differently. All of these are good reasons to do things differently.
  
-For those interrested in more details on how things work now, you can look at the [https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​robot/​Block.h Block], [https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​robot/​Conveyor.cpp Conveyor] and [https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​robot/​Conveyor.h#​L51 Queue].+For those interrested in more details on how things work now, you can look at the [[https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​robot/​Block.h|Block]], [[https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​robot/​Conveyor.cpp|Conveyor]] and [[https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​robot/​Conveyor.h#​L51|Queue]].
  
 == A proposed solution == A proposed solution
Line 94: Line 94:
 Then when the time comes, they get that information back. Then when the time comes, they get that information back.
  
-This has so many advantages : +This has so many advantages :
 * Much lower RAM usage * Much lower RAM usage
 * Can be about as simple to the coder as we do now * Can be about as simple to the coder as we do now
Line 100: Line 100:
 * Fixed-size ( in bytes not Blocks ) Queue for **all** the data ( including non-movement data ), for easier RAM management * Fixed-size ( in bytes not Blocks ) Queue for **all** the data ( including non-movement data ), for easier RAM management
  
-Here is the proposed format for the new Blocks ( now called "​Actions"​ to differentiate them from the movement Blocks ( which become just another kind of Action ) ) : +Here is the proposed format for the new Blocks ( now called "​Actions"​ to differentiate them from the movement Blocks ( which become just another kind of Action ) ) :
  
 * 1 byte : Owner module ID * 1 byte : Owner module ID
-* 1 byte : Length ​in bytes {{n}} +* 1 byte : Length ​in bytes <kbd>n</​kbd>​ 
-{{n}} bytes : Data+<kbd>n</​kbd> ​bytes : Data
  
 The queue is composed of a series of those Actions. When a module tries to add an Action to the Queue, and the Queue does not have enough room, we wait until there is room ( similar to what the current movement queue does ). The queue is composed of a series of those Actions. When a module tries to add an Action to the Queue, and the Queue does not have enough room, we wait until there is room ( similar to what the current movement queue does ).
  
-Example queue ( random non-real-life actions ) : +Example queue ( random non-real-life actions ) : 
  
 ||~ Byte ||~ Length ||~ Value ||~ Explanation || ||~ Byte ||~ Length ||~ Value ||~ Explanation ||
-|| 0 || uint8 || 2 || Action owner ID 2 ​: Laser ​module ||+|| 0 || uint8 || 2 || Action owner ID 2 Laser module ||
 || 1 || uint8 || 1 || 1 byte long Action || || 1 || uint8 || 1 || 1 byte long Action ||
 || 2 || uint8 || 127 || Laser module understands this as : set laser power to 50% || || 2 || uint8 || 127 || Laser module understands this as : set laser power to 50% ||
 || 3 || uint8 || 5 || Action owner ID 5 : Extruder module || || 3 || uint8 || 5 || Action owner ID 5 : Extruder module ||
 || 4 || uint8 || 1 || 1 byte long Action || || 4 || uint8 || 1 || 1 byte long Action ||
-|| 5 || uint8 || 3 || Extruder module understands this as : Extruder ​action ID 3 : do ​unretract ​ ||+|| 5 || uint8 || 3 || Extruder module understands this as : Extruder ​action ID 3 : do unretract ​ ||
 || 6 || uint8 || 5 || Action owner ID 5 : Extruder module || || 6 || uint8 || 5 || Action owner ID 5 : Extruder module ||
 || 7 || uint8 || 3 || 3 bytes long Action || || 7 || uint8 || 3 || 3 bytes long Action ||
Line 123: Line 123:
 || 11 || uint8 || 7 || Action owner ID 7 : Stepper module || || 11 || uint8 || 7 || Action owner ID 7 : Stepper module ||
 || 12 || uint8 || 42 || 42 bytes long Action || || 12 || uint8 || 42 || 42 bytes long Action ||
-|| 13-55 || [https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​robot/​Block.h Block] || 127 || Stepper unpacks this into a Block object and executes it ||+|| 13-55 || [[https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​robot/​Block.h|Block]] || 127 || Stepper unpacks this into a Block object and executes it ||
 || 56 || uint8 || 5 || Action owner ID 5 : Extruder module || || 56 || uint8 || 5 || Action owner ID 5 : Extruder module ||
 || 57 || uint8 || 3 || 3 bytes long Action || || 57 || uint8 || 3 || 3 bytes long Action ||
Line 135: Line 135:
 Here is the general idea of how things would work in the new system. We'll follow the life of our "​beep"​ action from above : Here is the general idea of how things would work in the new system. We'll follow the life of our "​beep"​ action from above :
  
-{{G123 S2}} is received from the Serial line ( meaning "make beep, with tone 2khz" ) +<kbd>G123 S2</​kbd> ​is received from the Serial line ( meaning "make beep, with tone 2khz" ) 
-* Gcodedispatch calls the {{on_gcode_received}} event with this G-code as a parameter +* Gcodedispatch calls the <kbd>on_gcode_received</​kbd> ​event with this G-code as a parameter 
-* Our Beeper module gets it'​s ​{{on_gcode_received}} event called with this G-code as a parameter+* Our Beeper module gets it'​s ​<kbd>on_gcode_received</​kbd> ​event called with this G-code as a parameter
 * It recognizes this as a G-code it wants executed later * It recognizes this as a G-code it wants executed later
-* It makes a new Action, looking like this : {{17}} ( 1 byte, module ID ), {{1}} ( 1 byte, action data size ), {{2}} ( 1 byte, action data, the tone )+* It makes a new Action, looking like this : <kbd>17</​kbd> ​( 1 byte, module ID ), <kbd>1</​kbd> ​( 1 byte, action data size ), <kbd>2</​kbd> ​( 1 byte, action data, the tone )
 * It asks the Conveyor to append this Action to the Queue * It asks the Conveyor to append this Action to the Queue
 * When there is enough room in the Queue, the Action is added * When there is enough room in the Queue, the Action is added
  
-And it sleeps there for a while, until, in another context : +And it sleeps there for a while, until, in another context :
  
 * All Actions in the queue have been executed up to our Action * All Actions in the queue have been executed up to our Action
 * Conveyor pops this Action from the Queue * Conveyor pops this Action from the Queue
-* It finds the Beeper module in it's array of targets as module with ID {{17}} ( from the Action'​s first byte )+* It finds the Beeper module in it's array of targets as module with ID <kbd>17</​kbd> ​( from the Action'​s first byte )
 * It finds that the Action'​s data is 1 byte long * It finds that the Action'​s data is 1 byte long
-* It gathers this 1 byte of data, and calls the Beeper module'​s ​{{action_execute}} method, passing the data ( {{2}} ) as a parameter+* It gathers this 1 byte of data, and calls the Beeper module'​s ​<kbd>action_execute</​kbd> ​method, passing the data ( <kbd>2</​kbd> ​) as a parameter
 * The Beeper module executes the beep at 2khz * The Beeper module executes the beep at 2khz
 * The Conveyor deletes this Action from the Queue * The Conveyor deletes this Action from the Queue
Line 161: Line 161:
 This is a list of the modules that need to change, and in what way they need to change. This is a list of the modules that need to change, and in what way they need to change.
  
-This is what {{ack-grep :​on_gcode_execute *}} gives us : +This is what <kbd>ack-grep :​on_gcode_execute *</​kbd> ​gives us : 
  
-[[code]]+<code>
 src/​modules/​robot/​Stepper.cpp src/​modules/​robot/​Stepper.cpp
 112:void Stepper::​on_gcode_execute(void *argument) 112:void Stepper::​on_gcode_execute(void *argument)
Line 180: Line 180:
 src/​libs/​Module.cpp src/​libs/​Module.cpp
 20:    &​Module::​on_gcode_execute,​ 20:    &​Module::​on_gcode_execute,​
-[[/code]]+</code>
  
-So now, per module, here is what needs to change : +So now, per module, here is what needs to change :
  
 === Planner === Planner
Line 188: Line 188:
 Planner adds Actions ( Blocks ) to the Queue, but does not consume them himself, it's Stepper that consumes them. Planner adds Actions ( Blocks ) to the Queue, but does not consume them himself, it's Stepper that consumes them.
  
-Currently what we do is [https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​robot/​Planner.cpp#​L62 here] we get an old Block from the Queue, and we recycle it to use as a new Block.+Currently what we do is [[https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​robot/​Planner.cpp#​L62|here]] we get an old Block from the Queue, and we recycle it to use as a new Block.
  
 With the Action queue we would make a new Block, and then add it to the Queue as an Action. With the Action queue we would make a new Block, and then add it to the Queue as an Action.
Line 194: Line 194:
 What we have now :  What we have now : 
  
-[[code]]+<code>
 block = queue->​recycle_old_block() block = queue->​recycle_old_block()
 set all of the block'​s properties set all of the block'​s properties
 mark the block as complete mark the block as complete
-[[/code]]+</code>
  
 What we would do in action queue What we would do in action queue
  
-[[code]]+<code>
 block = new Block(); block = new Block();
 set all of the block'​s properties set all of the block'​s properties
 queue->​add_action(the block'​s data) queue->​add_action(the block'​s data)
-[[/code]]+</code>
  
 === Stepper === Stepper
  
-Right now Stepper gets a new Block [https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​robot/​Stepper.cpp#​L145 this way]+Right now Stepper gets a new Block [[https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​robot/​Stepper.cpp#​L145|this way]]
  
 This would simply need to be changed to getting Block-type Actions, that's pretty much it This would simply need to be changed to getting Block-type Actions, that's pretty much it
  
-There is another thing in Stepper : [https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​robot/​Stepper.cpp#​L112 There is a useless on_gcode_execute event] in it.+There is another thing in Stepper : [[https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​robot/​Stepper.cpp#​L112|There is a useless on_gcode_execute event]] in it.
  
-This can be replaced by a {{on_gcode_received}} event, and waiting for the queue to empty before turning the stepper motor drivers on or off.+This can be replaced by a <kbd>on_gcode_received</​kbd> ​event, and waiting for the queue to empty before turning the stepper motor drivers on or off.
  
 === SlowTicker === SlowTicker
  
-As with Stepper, SlowTicker is another example of a place where {{on_gcode_execute}} is used uselessly+As with Stepper, SlowTicker is another example of a place where <kbd>on_gcode_execute</​kbd> ​is used uselessly
  
-[[code]]+<code>
 on_gcode_execute{ on_gcode_execute{
  do_stuff  do_stuff
 } }
-[[/code]]+</code>
  
-can here too be replaced with :  +can here too be replaced with :  
-[[code]]+<code>
 on_gcode_received{ on_gcode_received{
  wait_for_queue_to_empty  wait_for_queue_to_empty
  do_stuff  do_stuff
 } }
-[[/code]]+</code>
  
 === Spindle === Spindle
Line 242: Line 242:
 There are only two possible actions ( Spindle ON, Spindle OFF ), and one bit of data ( Spindle Speed ) There are only two possible actions ( Spindle ON, Spindle OFF ), and one bit of data ( Spindle Speed )
  
-So the action data is, for a Spindle OFF event : +So the action data is, for a Spindle OFF event :
  
-{{0x0}} 1 byte ​)+<kbd>0x0</​kbd> ​1 byte ​)
  
 For a Spindle ON event :  For a Spindle ON event : 
  
-{{0x1}} ( 1 byte )+<kbd>0x1</​kbd> ​( 1 byte )
  
-And for a Spindle set speed : +And for a Spindle set speed : 
  
-{{0x2}} ( 1 byte ) +<kbd>0x2</​kbd> ​( 1 byte ) 
-{{1234.21}} ( 1 float )+<kbd>1234.21</​kbd> ​( 1 float )
  
-Those are simply added to the action queue [https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​tools/​spindle/​Spindle.cpp#​L198 Here]+Those are simply added to the action queue [[https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​tools/​spindle/​Spindle.cpp#​L198|Here]]
  
-Then [https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​tools/​spindle/​Spindle.cpp#​L204 on_gcode_execute] becomes simply : +Then [[https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​tools/​spindle/​Spindle.cpp#​L204|on_gcode_execute]] becomes simply :
  
-[[code]]+<code>
 on_action_execute( data ){ on_action_execute( data ){
  if( data[0] == 0 ){ turn spindle off }  if( data[0] == 0 ){ turn spindle off }
  if( data[0] == 1 ){ turn spindle on }  if( data[0] == 1 ){ turn spindle on }
- if( data[0] == 2 ){ set spindle speed to (float)data[1-4] }+ if( data[[0]|== 2 ){ set spindle speed to (float)data[1-4]] }
 } }
-[[/code]]+</code>
  
 === TemperatureControl === TemperatureControl
  
-Another one where {{on_gcode_execute}} is used uselessly+Another one where <kbd>on_gcode_execute</​kbd> ​is used uselessly
  
-[[code]]+<code>
 on_gcode_execute{ on_gcode_execute{
  do_stuff  do_stuff
 } }
-[[/code]]+</code>
  
 can here too be replaced with :  can here too be replaced with : 
-[[code]]+<code>
 on_gcode_received{ on_gcode_received{
  wait_for_queue_to_empty  wait_for_queue_to_empty
  do_stuff  do_stuff
 } }
-[[/code]]+</code>
  
-The code to replace is [https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​tools/​temperaturecontrol/​TemperatureControl.cpp#​L294 here]+The code to replace is [[https://​github.com/​Smoothieware/​Smoothieware/​blob/​edge/​src/​modules/​tools/​temperaturecontrol/​TemperatureControl.cpp#​L294|here]]
  
 Note : If you don't find a on_gcode_execute there, wolfmanjm was faster than you. Note : If you don't find a on_gcode_execute there, wolfmanjm was faster than you.