Skip to content
Browse files

initial cleanup

  • Loading branch information...
1 parent c6d7846 commit 51af68268872835f96cb6b694c9259dd5608f0ed @joshbuddy joshbuddy committed with Oct 21, 2009
Showing with 20 additions and 2,067 deletions.
  1. +20 −0 Rakefile
  2. +0 −573 graster.rb
  3. +0 −10 graster.yml
  4. +0 −2 hal/.gitignore
  5. +0 −41 hal/README.jcode
  6. +0 −73 hal/fifotest.hal
  7. +0 −8 hal/hal.py
  8. +0 −612 hal/halgen.rb
  9. +0 −21 hal/haltest.c
  10. +0 −10 hal/haltest.comp
  11. +0 −63 hal/jcode.comp
  12. +0 −65 hal/jcode.hal
  13. +0 −154 hal/mask.hal
  14. +0 −62 hal/stream.comp
  15. +0 −175 hal/stream.hal
  16. +0 −31 hal/stream.hal.rb
  17. +0 −98 hal/stream.rb
  18. +0 −69 tile.rb
View
20 Rakefile
@@ -0,0 +1,20 @@
+begin
+ require 'jeweler'
+ Jeweler::Tasks.new do |s|
+ s.name = "graster"
+ s.description = s.summary = "G Raster!"
+ s.email = "joshbuddy@gmail.com"
+ s.homepage = "http://github.com/joshbuddy/graster"
+ s.authors = ["Jedediah Smith", "Joshua Hull"]
+ s.files = FileList["[A-Z]*", "{lib,bin}/**/*"]
+ s.add_dependency 'RMagick'
+ s.rubyforge_project = 'graster'
+ end
+ Jeweler::GemcutterTasks.new
+ Jeweler::RubyforgeTasks.new do |rubyforge|
+ rubyforge.doc_task = "rdoc"
+ rubyforge.remote_doc_path = ''
+ end
+rescue LoadError
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
+end
View
573 graster.rb
@@ -1,573 +0,0 @@
-#!/usr/bin/env ruby
-
-require 'yaml'
-
-begin
- require 'RMagick'
- IMAGE_BACKEND = :rmagick
-#rescue LoadError
-# require 'png'
-# require 'png/reader'
-# IMAGE_BACKEND = :png
-rescue LoadError
- #raise LoadError.new "One of `png' or `RMagick' gems is required"
- raise LoadError.new "`RMagick' gem is required"
-end
-
-class Graster
- class Image
- PROPS = [:filename,:size,:pixels]
-
- def initialize props
- PROPS.each do |p|
- raise "required image property :#{p} missing" unless props[p]
- instance_variable_set "@#{p}", props[p]
- end
- end
-
- PROPS.each{|p| attr_reader p }
-
- case IMAGE_BACKEND
- when :rmagick
- def self.from_file pathname
- raise "file not found #{pathname}" unless File.exist? pathname
- img = Magick::Image.read(pathname)
- raise "bad image data in #{pathname}" unless img = img[0]
- new :filename => File.basename(pathname),
- :size => [img.columns,img.rows],
- :pixels => img.export_pixels(0,0,img.columns,img.rows,"I")
- end
-
- # get pixel(s) from x,y coords
- # 0,0 is bottom,left
- # image[x,y] => pixel at x,y
- # image[y] => row at y
- def [] y, x=nil
- if x
- @pixels[(@size[1]-y)*@size[0]+x]
- else
- @pixels[(@size[1]-y)*@size[0],@size[0]]
- end
- end
-
- def each_row &block
- @pixels.chars.each_slice(@size[0]).each_with_index &block
- end
-
- when :png
- def self.from_file pathname
- raise "file not found #{pathname}" unless File.exist? pathname
- png = PNG.load_file pathname
- new :filename => File.basename(pathname),
- :size => [png.width,png.height],
- :pixels => png.data
- end
-
- def [] y, x=nil
- # TODO
- end
-
- def each_row
- # TODO
- end
- end
-
- # "encode" a float 0..1 to a pixel
- def self.f_to_pix f
- (f*65535).round
- end
-
- # "decode" an encoded pixel to a float 0..1
- def self.pix_to_f pix
- pix/65535.0
- end
-
-
- # convert bitmap data to spans (or runs) of contiguous pixels
- # also invert the Y axis
- def build_spans on_range
- # TODO: rewrite in terms of each_row
- @spans = Array.new @size[1]
-
- @size[1].times do |y|
- spans = []
- left = (@size[1]-y-1)*@size[0]
- start = nil
-
- @size[0].times do |x|
- d = on_range.include?(@pixels[left+x])
-
- if !start && d
- start = x
- elsif start && !d
- spans << [start, x]
- start = nil
- end
- end
-
- spans << [start, @size[0]] if start
- @spans[y] = spans
- end
- end
-
- attr_reader :spans
-
- def hash
- [@pixels,@width,@height].hash
- end
- end
-
- class GcodeFile < File
- def preamble opts
- @laser = false
- self << "M63 P0\nG61\nF#{opts[:feed] || 60}\n"
- self << "M101\n" if opts[:mask]
- self << "M3 S1\n"
- end
-
- def epilogue
- self << "M63 P0\nM5\nM2\n"
- end
-
- PRIORITY = [:g,:x,:y,:z,:w,:i,:j,:k,:m,:p,:s]
-
- def nc codes
- codes = codes.dup
-
- if codes[:laser] == true && !@laser
- @laser = true
- codes.merge!(:m => 62, :p => 0)
- elsif codes[:laser] == false && @laser
- @laser = false
- codes.merge!(:m => 63, :p => 0)
- end
-
- codes.delete :laser
-
- self << codes.sort {|(k1,v1),(k2,v2)|
- PRIORITY.index(k1) <=> PRIORITY.index(k2)
- }.map {|k,v|
- if v.is_a? Integer
- "#{k.upcase}#{v}"
- elsif v.is_a? Float
- "#{k.upcase}%0.3f" % v
- else
- "#{k.upcase}"
- end
- }.join(' ') + "\n"
- end
-
- def g0 codes
- nc({:g => 0}.merge codes)
- end
- alias_method :jog, :g0
-
- def g1 codes
- nc({:g => 1}.merge codes)
- end
- alias_method :move, :g1
-
- def g2 codes
- nc codes.merge(:g => 2)
- end
- alias_method :turn_cw, :g2
-
- def g3 codes
- nc codes.merge(:g => 3)
- end
- alias_method :turn_ccw, :g3
-
- def comment txt
- txt = txt.gsub(/\(\)/,'')
- self << "(#{txt})\n"
- end
-
- def puts *a
- self.puts *a
- end
- end
-
- class GmaskFile < File
- def preamble
- self << "1 0 0 0\n"
- end
-
- def begin_row forward
- @begin_row = true
- end
-
- def span forward, x1, x2
- if forward
- self << "0 0 0 %0.3f\n" % x1 if @begin_row
- self << "0 0 1 %0.3f\n" % x1
- self << "0 1 1 %0.3f\n" % x2
- else
- self << "0 0 1 %0.3f\n" % x1 if @begin_row
- self << "0 0 0 %0.3f\n" % x1
- self << "0 1 0 %0.3f\n" % x2
- end
- @begin_row = false
- end
- end
-
- ROOT2 = Math.sqrt(2)
-
- OPTIONS = {
- :dpi => [[Float],"X,Y","Dots per inch of your device"],
- :on_range => [[Float],
- "MIN,MAX","Luminosity range for which the",
- "laser should be on"],
- :overshoot => [Float,"INCHES",
- "Distance the X axis should travel",
- "past the outer boundaries of the outer",
- "images. This needs to be wide enough",
- "so that the X axis doesn't start",
- "decelerating until after it has",
- "cleared the image"],
- :offset => [[Float],"X,Y",
- "Location for the bottom left corner",
- "of the bottom left tile. The X",
- "component of this setting must be",
- "equal to or greater than overshoot"],
- :repeat => [[Integer],"X,Y",
- "Number of times to repeat the image",
- "in the X and Y axes, respectively.",
- "Size of the tile(s) inches. Any nil",
- "value is calculated from the size of",
- "the bitmap"],
- :tile_spacing => [[Float],"X,Y",
- "X,Y gap between repeated tiles in",
- "inches"],
- :feed => [Float,"N",
- "Speed to move the X axis while",
- "burning, in inches/minute"],
- :cut_feed => [Float,"N",
- "Speed at which to cut out tiles"],
- :corner_radius => [Float,"N",
- "Radius of rounded corners for",
- "cutout, 0 for pointy corners"]
- }
-
- DEFAULTS = {
- :dpi => [500,500], # X,Y dots per inch of your device
- :on_range => [0.0,0.5], # Luminosity range for which the laser should be on
- :overshoot => 0.5, # Distance the X axis should travel past the outer boundaries of the outer images.
- # This needs to be wide enough so that the X axis doesn't start decelerating
- # until after it has cleared the image.
- :offset => [1.0,1.0], # X,Y location for the bottom left corner of the bottom left tile.
- # The X component of this setting must be equal to or greater than :overshoot.
- :repeat => [1,1], # Number of times to repeat the image in the X and Y axes, respectively.
- :tile_size => [false,false], # Size of the tile(s) inches. Any nil value is calculated from
- # the size of the bitmap.
- :tile_spacing => [0.125,0.125], # X,Y gap between repeated tiles in inches
- :feed => 120, # Speed to move the X axis while burning, in inches/minute
- :cut_feed => 20, # Speed at which to cut out tiles
- :corner_radius => 0 # Radius of rounded corners for cutout, 0 for pointy corners
- }
-
- class InvalidConfig < Exception; end
- def update_config
- @scale = @config[:dpi].map{|n| 1.0/n }
- @offset = @config[:offset]
-
- if @image
- 2.times {|i| @config[:tile_size][i] ||= @image.size[i]*@scale[i] }
- @tile_interval = 2.times.map {|i|
- @config[:tile_size][i] + @config[:tile_spacing][i]
- }
- end
-
- @on_range = Range.new Image.f_to_pix(@config[:on_range].first),
- Image.f_to_pix(@config[:on_range].last)
- end
-
- def validate_config
- raise InvalidConfig.new "X offset (#{@config[:offset][0]}) must be greater or equal to overshoot (#{@config[:overshoot]})"
- end
-
- def config= h
- @config = {}
- DEFAULTS.each {|k,v| @config[k] = h[k] || v }
- update_config
- return h
- end
-
- def merge_config h
- @config ||= DEFAULTS.dup
- h.each {|k,v| @config[k] = v if DEFAULTS[k] }
- update_config
- return h
- end
-
- attr_reader :config
-
- def image= img
- debug "image set to #{img.filename} #{img.size.inspect} #{img.pixels.size} pixels"
- @image = img
- @image.build_spans @on_range
- update_config
- build_tiled_rows
- return img
- end
-
- attr_reader :image
-
- def try_load_config_file pn
- if File.exist?(pn)
- c = {}
- YAML.load_file(pn).each {|k,v| c[k.intern] = v }
- return c
- end
- end
-
- def try_load_default_config_file
- try_load_config_file './graster.yml'
- end
-
- def load_config_file pn
- try_load_config_file pn or raise "config file not found '#{pn}'"
- end
-
- def load_image_file pn
- self.image = Image.from_file(pn)
- end
-
- # convert tile + pixel coordinates to inches
- def axis_inches axis, tile, pixel
- @offset[axis] + tile*@tile_interval[axis] + pixel*@scale[axis]
- end
-
- def x_inches tile, pixel
- axis_inches 0, tile, pixel
- end
-
- def y_inches tile, pixel
- axis_inches 1, tile, pixel
- end
-
- # return a complete tiled row of spans converted to inches
- def tiled_row_spans y, forward=true
- spans = @image.spans[y]
- return spans if spans.empty?
- tiled_spans = []
-
- if forward
- @config[:repeat][0].times do |tile|
- spans.each do |span|
- tiled_spans << [x_inches(tile,span[0]), x_inches(tile,span[1])]
- end
- end
- else
- @config[:repeat][0].times.reverse_each do |tile|
- spans.reverse_each do |span|
- tiled_spans << [x_inches(tile,span[1]), x_inches(tile,span[0])]
- end
- end
- end
-
- return tiled_spans
- end
-
- def build_tiled_rows
- forward = false
- @tiled_rows = @image.size[1].times.map {|y| tiled_row_spans y, (forward = !forward) }
- end
-
- # generate a unique id for this job
- def job_hash
- [@image,@config].hash
- end
-
- # render a complete tiled image to gcode and gmask streams
- def render_tiled_image gcode, gmask
- debug "rendering tiled image"
- job_id = job_hash
- hyst = -@scale[0]/2
- gcode.comment "raster gcode for job #{job_id}"
- gcode.comment "image: #{@image.filename} #{@image.size.inspect}"
- gcode.comment "config: #{@config.inspect}"
-
- gcode.preamble :feed => @config[:feed], :mask => true
- gmask.preamble
-
- @config[:repeat][1].times do |ytile|
- debug "begin tile row #{ytile}"
- @tiled_rows.each_with_index do |spans, ypix|
- debug "pixel row #{ypix} is empty" if spans.empty?
- unless spans.empty?
- yinches = y_inches(ytile, ypix)
- forward = spans[0][0] < spans[-1][1]
- dir = forward ? 1 : -1
-
- debug "pixel row #{ypix} at #{yinches} inches going #{forward ? 'forward' : 'backward'} with #{spans.size} spans"
-
- gcode.g0 :x => spans[0][0] - dir*@config[:overshoot], :y => yinches
- gcode.g1 :x => spans[-1][1] + dir*@config[:overshoot], :y => yinches
- gmask.begin_row forward
- spans.each {|span| gmask.span forward, span[0]+hyst, span[1]+hyst }
- end # unless spans.empty?
- end # @image.each_row
- debug "end tile row #{ytile}"
- end # @config[:repeat][i].times
-
- gcode.epilogue
- end # def render_tiled_image
-
- # cut out the tile with bottom left at x,y
- def render_cut gcode, x, y
- radius = @config[:corner_radius]
- left = x
- bottom = y
- right = x+@config[:tile_size][0]
- top = y+@config[:tile_size][1]
-
- gcode.instance_eval do
- if radius && radius > 0
- jog :x => left, :y => bottom+radius
- move :x => left, :y => top-radius, :laser => true
- turn_cw :x => left+radius, :y => top, :i => radius
- move :x => right-radius, :y => top
- turn_cw :x => right, :y => top-radius, :j => -radius
- move :x => right, :y => bottom+radius
- turn_cw :x => right-radius, :y => bottom, :i => -radius
- move :x => left+radius, :y => bottom
- turn_cw :x => left, :y => bottom+radius, :j => radius
- nc :laser => false
- else
- jog :x => left, :y => bottom
- move :x => left, :y => top, :laser => true
- move :x => right, :y => top
- move :x => right, :y => bottom
- move :x => left, :y => bottom
- nc :laser => false
- end
- end
- end
-
- # render gcode to cut out the tiles
- def render_all_cuts gcode
- gcode.preamble :feed => @config[:cut_feed]
- @config[:repeat][1].times do |ytile|
- @config[:repeat][0].times do |xtile|
- render_cut gcode, x_inches(xtile, 0), y_inches(ytile, 0)
- end
- end
- gcode.epilogue
- end
-
- def render_all gcode, gmask, cuts
- render_tiled_image gcode, gmask
- render_all_cuts cuts
- end
-
- def open_gcode_file &block
- io = GcodeFile.open "#{@image.filename}.raster.ngc", "w", &block
- end
-
- def open_gmask_file &block
- io = GmaskFile.open "#{@image.filename}.raster.gmask", "w", &block
- end
-
- def open_cut_file &block
- io = GcodeFile.open "#{@image.filename}.cut.ngc", "w", &block
- end
-
- def generate_all_files
- open_gcode_file do |gcode|
- open_gmask_file do |gmask|
- render_tiled_image gcode, gmask
- end
- end
-
- open_cut_file do |cut|
- render_all_cuts cut
- end
- end
-
- def config_to_yaml
- @config.map {|k,v| "#{k}: #{v.inspect}\n" }.join
- end
-
- def debug msg
- STDERR.puts msg if @debug
- end
-
- def initialize opts={}
- self.config = DEFAULTS.dup
-
- if opts[:config_file]
- self.merge_config load_config_file opts[:config_file]
- elsif opts[:default_config_file] && c = try_load_default_config_file
- self.merge_config c
- end
-
- self.merge_config opts[:config] if opts[:config]
-
- @debug = opts[:debug]
-
- if opts[:image]
- image = opts[:image]
- elsif opts[:image_file]
- load_image_file opts[:image_file]
- end
- end
-
-end # class Graster
-
-if File.expand_path($PROGRAM_NAME) == File.expand_path(__FILE__)
- require 'optparse'
-
- options = { :default_config_file => true }
- opts = OptionParser.new do |opts|
- opts.banner = "Usage: graster [options] image"
-
- opts.on "-c", "--config FILE", "Use specified configuration file.",
- "The default is ./graster.yml" do |c|
- options[:config_file] = c
- end
-
- opts.on "-g", "--generate", "generate a configuration file with","defaults" do
- options[:generate_config] = true
- end
-
- opts.on "-d", "--debug", "Dump useless debug info" do
- options[:debug] = true
- end
-
- Graster::OPTIONS.each do |key,info|
- type,sym,*desc = info
-
- if type.is_a? Array
- cast = type[0].name.intern
- type = Array
- else
- cast = type.name.intern
- end
-
- opts.on "--#{key.to_s.gsub /_/, '-'} #{sym}", type, *desc do |x|
- options[:config] ||= {}
- if type == Array
- x = x.map {|s| Kernel.send(cast,s) }
- else
- x = Kernel.send(cast,x)
- end
-
- options[:config][key] = x
- end
- end
- end
-
- opts.parse! ARGV
-
- if options[:generate_config]
- print Graster.new(options).config_to_yaml
- else
- unless options[:image_file] = ARGV.shift
- puts opts
- exit 1
- end
-
- Graster.new(options).generate_all_files
- end
-end
-
View
10 graster.yml
@@ -1,10 +0,0 @@
-dpi: [500, 500]
-on_range: [0.0, 0.5]
-overshoot: 0.5
-offset: [1.0, 1.0]
-repeat: [1, 1]
-tile_size: [false, false]
-tile_spacing: [0.125, 0.125]
-feed: 120
-cut_feed: 20
-corner_radius: 0
View
2 hal/.gitignore
@@ -1,2 +0,0 @@
-haltest
-*.ko
View
41 hal/README.jcode
@@ -1,41 +0,0 @@
-= J-code =
-
-J-code is one command per line, in the following format:
-
----
-OPCODE PARAMS*
----
-
-OPCODE is a number specifying the operation and PARAMS is zero or more arguments. Each operation has a different amount of arguments.
-Unless stated otherwise, operations run simultaneously.
-
-
-== Operations ==
-
-Operation Description
---------- -----------
-0 home all axes
-1 AXIS POS VEL start moving AXIS to POS at VEL inches/minute
-2 AXIS wait for AXIS to stop moving
-3 AXIS POS wait for AXIS to be greater than POS
-4 AXIS POS wait for AXIS to be less than POS
-
-
-
-
-
-streamer {
- pin.0 =>
-
-tristate-float.0 {
- enable <= streamer.pin.0 == 1 & streamer.pin.1 == 0
- in <= streamer.pin.2
- out => stepgen.0.position-cmd
-}
-
-tristate-float.1 {
- enable <= streamer.pin
-
-
-
-
View
73 hal/fifotest.hal
@@ -1,73 +0,0 @@
-
-loadrt probe_parport
-loadrt hal_parport cfg=0x378
-setp parport.0.reset-time 100000
-
-loadrt charge_pump
-net charge-pump charge-pump.out parport.0.pin-17-out
-setp parport.0.pin-17-out-reset 1
-setp charge-pump.enable 1
-
-net amp parport.0.pin-14-out
-sets amp 1
-
-loadrt stepgen step_type=0,0
-
-setp stepgen.0.position-scale 500
-setp stepgen.0.steplen 50000
-setp stepgen.0.stepspace 50000
-setp stepgen.0.dirhold 50000
-setp stepgen.0.dirsetup 50000
-setp stepgen.0.maxaccel 30
-setp stepgen.0.enable 1
-net x-dir stepgen.0.dir parport.0.pin-02-out
-net x-step stepgen.0.step parport.0.pin-03-out
-net x-target-pos => stepgen.0.position-cmd
-net x-current-pos <= stepgen.0.position-fb
-
-setp stepgen.1.position-scale 500
-setp stepgen.1.steplen 50000
-setp stepgen.1.stepspace 50000
-setp stepgen.1.dirhold 50000
-setp stepgen.1.dirsetup 50000
-setp stepgen.1.maxaccel 30
-setp stepgen.1.enable 1
-net y-dir stepgen.1.dir parport.0.pin-04-out
-net y-step stepgen.1.step parport.0.pin-05-out
-net y-target-pos => stepgen.1.position-cmd
-net y-current-pos <= stepgen.1.position-fb
-
-loadrt streamer depth=256 cfg="ff"
-net x-target-pos <= streamer.0.pin.0
-net y-target-pos <= streamer.0.pin.1
-net input-latch => streamer.0.enable
-
-# input-latch = (target-pos == actual-pos)
-loadrt comp count=2
-loadrt and2
-setp comp.0.hyst 0.002
-setp comp.1.hyst 0.002
-net x-target-pos => comp.0.in0
-net y-target-pos => comp.1.in0
-net x-current-pos => comp.0.in1
-net y-current-pos => comp.1.in1
-linkpp comp.0.equal and2.0.in0
-linkpp comp.1.equal and2.0.in1
-net input-latch <= and2.0.out
-
-loadrt threads name1="fast-thread" period1=100000, name2="slow-thread" period2=1000000
-
-addf parport.0.read fast-thread
-addf stepgen.make-pulses fast-thread
-addf charge-pump fast-thread
-addf parport.0.write fast-thread
-#addf parport.0.reset fast-thread
-
-addf stepgen.capture-position slow-thread
-addf comp.0 slow-thread
-addf comp.1 slow-thread
-addf and2.0 slow-thread
-addf streamer.0 slow-thread
-addf stepgen.update-freq slow-thread
-
-start
View
8 hal/hal.py
@@ -1,8 +0,0 @@
-#!/usr/bin/env python
-
-import hal
-
-h = hal.component("circle")
-h.newpin("center", hal.HAL_FLOAT, hal.HAL_IN)
-h.newpin("radius", hal.HAL_FLOAT, hal.HAL_IN)
-h.ready()
View
612 hal/halgen.rb
@@ -1,612 +0,0 @@
-require 'set'
-
-class Module
- def define_module_method meth, &block
- define_singleton_method meth, &block
- define_method(meth) {|*args, &block| self.class.send meth, *args, &block }
- end
-end
-
-module HAL
- module Mungers
- def hyphenize id
- id.to_s.gsub(/_|\./,'-')
- end
-
- def dehyphenize id
- id.to_sgsub(/-/,'_').intern
- end
-
- def camelize id
- id.to_s.sub(/^[a-z]/){|m| m.upcase}.gsub(/_([A-Za-z0-9])/){ $1[0].upcase + $1[1..-1] }.intern
- end
-
- def decamelize id
- id.to_s.sub(/^[A-Z]/) {|m| m.downcase}.
- gsub(/[A-Z]/) {|m| "_#{m.downcase}" }
- end
- end
-
- class Builder
- include Mungers
-
- def initialize options={}, &block
- @options = options
- @components = {}
- @threads = {}
- instance_eval &block if block
- end
-
- def trace str
- STDERR.puts ">>> #{str}" if @options[:trace]
- end
-
- def component_type_class_name type
- camelize(type)
- end
-
- def component_type_defined? type
- Component.const_defined? component_type_class_name(type)
- end
-
- def component_type_class type
- cname = component_type_class_name(type)
- raise "unknown component type #{type}" unless Component.const_defined?(cname)
- Component.const_get(cname)
- end
-
- def component_type_count type
- trace "counting components: #{@components.inspect}"
- @components.count {|k,v| v.hal_type == type }
- end
-
- def components_by_type
- @components.reduce({}) do |h,(label,comp)|
- h[comp.class] ||= {}
- h[comp.class][label] = comp
- h
- end
- end
-
- def component_defined? label
- @components.has_key? label
- end
-
- def component label
- @components[label]
- end
-
- def loadrt type, label, options={}, &block
- ordinal = component_type_count(type)
- klass = component_type_class(type)
-
- label ||= if klass.singleton?
- type
- else
- "#{type}_#{ordinal}".intern
- end
-
- trace "loadrt #{type}, #{label}, #{options.inspect}"
- @components[label] = component_type_class(type).new(self, ordinal, label, options)
-
- if block
- trace "evaluating component block for #{label}"
- @components[label].instance_eval &block
- else
- trace "no block for component #{label}"
- @components[label]
- end
- end
-
- def thread id, opts, &block
- raise "period required for thread #{id}" unless opts[:period]
-
- trace "thread #{id}, #{opts.inspect}"
-
- opts[:float] ||= true
- @threads[id] = thread = HAL::Thread.new(self, id, opts)
- thread.instance_eval(block)
- end
-
- def method_missing meth, *args, &block
- trace "method_missing #{meth}, #{args.inspect}, #{block}"
-
- if @components.has_key?(meth)
- trace "resolve component #{meth}"
- if block
- @components[meth].instance_eval &block
- else
- @components[meth]
- end
- elsif component_type_defined?(meth)
- trace "resolve component type #{meth}"
- label,options = if args[0].is_a? Symbol
- [args[0],args[1] || {}]
- else
- [nil,args[0] || {}]
- end
-
- loadrt meth, label, options, &block
- else
- super
- end
- end
-
- def hal_code
- str = ''
-
- cbt = components_by_type
- cbt.each_pair do |klass,instances|
- str << "\n\n### #{klass.hal_type} components ###\n"
- str << klass.hal_loadrt(instances.values)
- str << instances.values.map {|c| c.hal_code }.join("\n")
- end
-
- str << "\n\n### threads ###\n"
- str << HAL::Thread.hal_loadrt(@threads.values)
- str << @threads.values.map {|t| t.hal_code }.join("\n")
-
- str << "\n\n### HAL start ###\nstart\n"
- end
-
- module Grammar
- class Context
-
- class << self
- def rule name, pat, &block
- raise ArgumentError.new "block required" unless block
- @rules ||= []
- @rules << [pat,block]
- end
-
- def rules; @rules || []; end
- end # class << self
-
- def method_missing meth, *args, &block
- rules.each do |pat|
- catch :fail do
- if pat[0].is_a?(Symbol) && meth == pat[0]
- return pat[1].call *args, &block
- elsif pat[0].is_a?(Regexp) && meth =~ pat[0]
- return pat[1].call meth, *args, &block
- end
- end
- end
- super
- end # def method_missing
-
- end # class Context
-
- class Primary < Context
- rule
- end
-
- class Component
- def initialize label
- @label = label
- @type = nil
- @options = {}
- @params = {}
- end
-
- attr_accessor :label, :type, :options, :params
- end
-
- class Pin
- include Mungers
-
- def initialize component, *path
- @component = component
- @path = path
- end
- attr_reader :component
- attr_reader :path
-
- def method_missing meth, *args, &block
- self.class.new @component, [*@path,meth]
- end
-
- def pin_defined?
- false
- end
-
- def validate
- raise "unknown pin reference #{hal_pin}" unless pin_defined?
- end
-
- def hal_pin
- [@component.hal_instance,*path.map{|p| hyphenize(p) }].join('.')
- end
- end
-
- class OutputPin < Pin
- def pin_defined?
- @component.output_defined? @path
- end
- end
-
- class InputPin
- def pin_defined?
- @component.input_defined? @path
- end
-
- def <= value
- @component.assign_input self, value
- end
- end
-
- end # module Grammar
- end # class Builder
-
-
- class Thread
- def initialize context, id, opts
- @context = context
- @id = id
- @period = opts[:period]
- @float = opts[:float] || false
- @calls = []
- end
-
- attr_reader :period
-
- def method_missing meth
- if @context.component_defined? meth
- call = FunctionCall.new(self, @context.component(meth))
- @calls << call
- return call
- else
- super
- end
- end
-
- def hal_id
- hyphenize @id
- end
-
- def self.hal_loadrt instances
- if instances.empty?
- ''
- else
- "loadrt threads " +
- instances.each_with_index.
- map {|th,i| "name#{i+1}=\"#{th.hal_id}\" period#{i+1}=#{th.period}"}.
- join(", ") + "\n"
- end
- end
-
- def hal_calls
- @calls.map {|x| x.hal_code }.join
- end
-
- def hal_comment
- "# thread #{hal_id}\n"
- end
-
- def hal_code
- hal_comment +
- hal_calls
- end
-
- class FunctionCall
- def initialize thread, component, function=nil
- @thread = thread
- @component = component
- @function = function
- end
-
- attr_reader :component
- attr_reader :function
-
- def method_missing meth
- @component.validate_function meth
- @function = meth
- end
-
- def hal_code
- "addf #{@component.hal_function @function} #{@thread.hal_id}\n"
- end
- end # class FunctionCall
-
- end # class Thread
-
- class Component
-
- include Mungers
-
- ASPECTS = [:option,:input,:output,:param,:function]
-
- class << self
- include Mungers
-
- def trace str
- # puts ">>> #{basename}: #{str}"
- end
-
- def inherited klass
- trace "define component #{klass.basename}"
- klass.instance_eval do
- @def = {}
- ASPECTS.each {|asp| @def[asp] = [] }
- end
- end
-
- def singleton x=true
- @singleton = !!x
- end
-
- def hal_loadrt_params instances
- str = ''
- @def[:option].each do |o|
- if instances.any? {|i| i.options.has_key? o }
- raise "option #{o} not specified for all components" unless
- instances.all? {|i| i.options.has_key? o }
- "#{o}=" + instances.map {|i| i.options[o].inspect }.join(',')
- end
- end.join(' ')
- end
-
- def hal_loadrt instances
- trace "generate loadrt instances=#{instances.inspect}"
- if instances.empty?
- ''
- else
- if singleton?
- raise "multiple instances of singleton component #{hal_type}" unless
- instances.size == 1
- "loadrt #{hal_type} #{hal_loadrt_params instances}\n"
- else
- "loadrt #{hal_type} count=#{instances.size} #{hal_loadrt_params instances}\n"
- end
- end
- end
-
- end # class << self
-
- ASPECTS.each do |asp|
- trace "define aspect #{asp}"
- define_module_method "def_#{asp}s" do |*args|
- trace "def_#{asp}s #{args.inspect}"
- @def[asp] = args
- end
-
- define_module_method "#{asp}_defined?" do |id|
- @def[asp].include? id
- end
-
- define_module_method "validate_#{asp}" do |id|
- raise "unknown #{asp} #{hal_type}.#{id}" unless @def[asp].include? id
- end
- end
-
- define_module_method :hal_type do
- decamelize self.basename
- end
-
- define_module_method :singleton? do
- @singleton
- end
-
- def initialize context, index, label, options={}
- options.keys.each {|k| validate_option k }
-
- @context = context
- @index = index
- @label = label
- @options = options
- @inputs = {}
- @outputs = []
- @params = {}
- end
-
- attr_reader :options
- attr_reader :params
-
- def trace str
- @context.trace "#{hal_instance} (#{hal_label}): #{str}"
- end
-
- def assign_input pin, value
- trace "assigning #{value} to input #{pin.hal_pin}"
- raise "invalid input pin value #{value.inspect}" unless
- value.is_a?(Numeric) ||
- (value.is_a?(Array) &&
- value[0].is_a?(Component) &&
- value[1].is_a?(OutputPinReference) &&
- value[1].pin_defined?)
-
- @inputs[pin] = value
- end
-
- def method_missing meth, *args, &block
- trace "resolving within component: #{meth.inspect}, #{args.inspect}, #{block}"
-
- if param_defined? meth
- trace "setting parameter #{meth} to #{args[0].inspect}"
- raise "expected value after parameter #{meth}" unless args[0]
- @params[meth] = args[0]
- elsif input_defined? meth
- trace "referencing input #{meth}"
- return InputPinReference.new self, meth
- elsif output_defined? meth
- trace "referencing output #{meth}"
- return OutputPinReference.new self, meth
- else
- trace "falling through to builder context"
- @context.send meth, *args, &block
- end
- end
-
- def hal_label
- hyphenize(@label)
- end
-
- def hal_instance
- if singleton?
- hyphenize hal_type
- else
- "#{hyphenize hal_type}.#{@index}"
- end
- end
-
- def hal_pin id
- "#{hal_instance}.#{hyphenize(id)}"
- end
-
- # signals are named after the output connected to them
- # with the form label-pin
- def hal_signal pin
- validate_output pin
- "#{hal_label}-#{hyphenize(pin)}"
- end
-
- def hal_constant_signal value
- "signal-#{value.to_s.gsub(/\./,'-')}"
- end
-
- def hal_output_net pin
- validate_output pin
- "net #{hal_signal pin} <= #{hal_pin pin}\n"
- end
-
- def hal_input_net id
- validate_input id
- inp = @inputs[id]
- if inp.is_a? Numeric
- "net #{hal_constant_signal inp} => #{hal_pin id}\n"
- "sets #{hal_constant_signal inp} #{inp}\n"
- else
- src_inst = @inputs[id][0]
- src_pin = @inputs[id][1]
- "net #{src_inst.hal_signal src_pin} => #{hal_pin id}\n"
- end
- end
-
- def hal_param id
- validate_param id
- "setp #{hal_instance}.#{hyphenize(id)} #{@params[id]}\n"
- end
-
- def hal_output_nets
- @outputs.map {|o| hal_output_net o }.join
- end
-
- def hal_input_nets
- @inputs.keys.map {|i| hal_input_net i }.join
- end
-
- def hal_params
- @params.keys.map {|p| hal_param p }.join
- end
-
- def hal_function id=nil
- if id.nil?
- hal_instance
- else
- validate_function id
- "#{hal_instance}.#{hyphenize(id)}"
- end
- end
-
- def hal_comment
- if singleton?
- "\n# #{hal_label}\n"
- else
- "\n# #{hal_instance}: #{hal_label}\n"
- end
- end
-
- def hal_code
- trace "hal_code #{hal_label}"
- if @params.empty? && @inputs.empty? && @outputs.empty?
- ''
- else
- hal_comment +
- hal_params +
- hal_output_nets +
- hal_input_nets
- end
- end
-
- def inspect
- "#<#{self.class.name}:#{object_id.to_s(16)} #{hal_instance}:#{hal_label}>"
- end
-
- class And2 < Component
- def_inputs :in0, :in1
- def_outputs :out
- end # class And
-
- class Or2 < Component
- def_inputs :in0, :in1
- def_outputs :out
- end # class Or
-
- class Comp < Component
- def_params :hyst
- def_inputs :in0, :in1
- def_outputs :out, :equal
- end # class Comp
-
- class Stepgen < Component
- def_options :step_type
- def_params :position_scale,
- :steplen,
- :stepspace,
- :dirhold,
- :dirsetup,
- :maxaccel,
- :enable
- def_inputs :position_cmd
- def_outputs :position_fb, :dir, :step
- end # class Stepgen
-
- class Streamer < Component
- def_options :depth, :cfg
- def_inputs :enable
- def_outputs *(0..63).map{|n| "pin_#{n}".intern }
- end # class Streamer
-
- class Parport < Component
- def_options :address, :direction
- def_params :reset_time, *(0..17).map{|n| "pin_#{n}_out_reset".intern }
- def_inputs *(0..17).map{|n| "pin_#{n}_out".intern }
-
- def self.hal_loadrt instances
- instances.each {|i| raise "parport #{i.hal_label} missing required address option" unless i.options[:address]}
- "loadrt probe_parport\n" +
- "loadrt hal_parport cfg=\"" +
- instances.map {|i| "0x#{i.options[:address].to_s(16)}" +
- (i.options[:direction] ? " #{i.options[:direction]}" : '') }.join(' ') +
- "\""
- end
- end
-
- class ChargePump < Component
- singleton
- def_params :enable
- def_outputs :out
- end
-
- end # class Component
-end # module HAL
-
-=begin
-def make_it
- hal = HAL::Builder.new(:trace => true) do
- or2 :lenny do
- end
-
- and2 :brucy do
- in0 <= lenny.out
- in1 <= 1
- end
- end
-
- print hal.hal_code
-end
-
-
-make_it
-
-=end
View
21 hal/haltest.c
@@ -1,21 +0,0 @@
-#define ULAPI
-
-#include <hal.h>
-
-int M;
-hal_s32_t* Pins;
-
-void RealtimeMain(void* arg, long period) {
- Pins[2] = Pins[0] + Pins[1];
-}
-
-int main(int argc, char* argv[]) {
- M = hal_init("haltest");
- Pins = (hal_s32_t*) hal_malloc(3*sizeof(hal_s32_t));
- hal_pin_s32_new("in0",HAL_IN,&Pins,M);
- hal_pin_s32_new("in1",HAL_IN,&Pins+1,M);
- hal_pin_s32_new("out",HAL_OUT,&Pins+2,M);
- hal_export_funct("haltest",RealtimeMain,NULL,0,1,M);
- hal_ready(M);
- return 0;
-}
View
10 hal/haltest.comp
@@ -1,10 +0,0 @@
-component haltest "woot";
-license "who cares";
-
-pin in bit in0;
-pin in bit in1;
-pin out bit out;
-function _ nofp;
-;;
-
-FUNCTION(_) { out = in0 & in1; }
View
63 hal/jcode.comp
@@ -1,63 +0,0 @@
-component jcode "low level movement command interpreter";
-license "fuck";
-
-param rw float position_scale = 1.0;
-param rw float maxaccel = 1.0;
-
-pin in bit read "set true to read new values from input pins, false to ignore inputs and keep existing values";
-
-pin in float move_to "POS parameter for operation";
-pin in float speed "VEL parameter for operation";
-pin in float boundary "arbitrary test boundary";
-pin in unsigned test "0: always false, 1: always true, 2: moving, 3: not moving, 4: <= boundary, 5: >= boundary";
-
-variable float vmove_to;
-variable float vspeed;
-variable float vboundary;
-variable unsigned vtest;
-
-pin in float position_fb "set to actual axis position, as reported by stepgen";
-
-pin out float velocity_cmd "the value we want for velocity, sent to stepgen";
-pin out bit test_result "result of specified test";
-pin out bit moving "1 if moving";
-pin out bit greater "1 if position is >= boundary";
-pin out bit less "1 if position is <= boundary";
-
-function _ fp;
-;;
-
-#include <rtapi_math.h>
-
-
-FUNCTION(_) {
- float move_delta, step_size, velocity;
-
- if (read) {
- vmove_to = move_to;
- vspeed = speed;
- vboundary = boundary;
- vtest = test;
- }
-
- move_delta = vmove_to - position_fb;
- step_size = 1.0/(position_scale == 0.0 ? 1.0 : position_scale);
-
- /* find velocity given distance and acceleration: v = (2ad)^(1/2) */
- velocity = min((float)sqrt(2.0 * fabs(move_delta) * maxaccel), vspeed);
-
- if (fabs(move_delta) >= step_size) {
- velocity_cmd = move_delta < 0.0 ? -velocity : velocity;
- moving = 1;
- } else {
- velocity_cmd = moving = 0;
- }
-
- greater = position_fb >= vboundary;
- less = position_fb < vboundary;
-
- test_result = (vtest == 1) ||
- (vtest == 2 && moving) ||
- (vtest == 3 && less) ||
- (vtest == 4 && greater) ? 1 : 0;
-}
View
65 hal/jcode.hal
@@ -1,65 +0,0 @@
-
-loadrt jcode count=2
-
-setp jcode.0.position-scale 500
-setp jcode.0.maxaccel 30
-setp jcode.0.speed 5
-
-setp jcode.1.position-scale 500
-setp jcode.1.maxaccel 30
-setp jcode.1.speed 5
-
-
-loadrt stepgen step_type=0,0 ctrl_type=v,v
-
-setp stepgen.0.position-scale 500
-setp stepgen.0.maxaccel 30
-setp stepgen.0.maxvel 5
-setp stepgen.0.steplen 50000
-setp stepgen.0.stepspace 50000
-setp stepgen.0.dirhold 0
-setp stepgen.0.dirsetup 0
-setp stepgen.0.enable 1
-
-net x-position-fb jcode.0.position-fb <= stepgen.0.position-fb
-net x-velocity-cmd jcode.0.velocity-cmd => stepgen.0.velocity-cmd
-
-setp stepgen.1.position-scale 500
-setp stepgen.1.maxaccel 30
-setp stepgen.1.maxvel 5
-setp stepgen.1.steplen 50000
-setp stepgen.1.stepspace 50000
-setp stepgen.1.dirhold 0
-setp stepgen.1.dirsetup 0
-setp stepgen.1.enable 1
-
-net y-position-fb jcode.1.position-fb <= stepgen.1.position-fb
-net y-velocity-cmd jcode.1.velocity-cmd => stepgen.1.velocity-cmd
-
-loadrt streamer depth=256 cfg="fffufffu"
-
-net x-move-to streamer.0.pin.0 => jcode.0.move-to
-net x-speed streamer.0.pin.1 => jcode.0.speed
-net x-boundary streamer.0.pin.2 => jcode.0.boundary
-net x-test streamer.0.pin.3 => jcode.0.test
-
-net y-move-to streamer.0.pin.4 => jcode.1.move-to
-net y-speed streamer.0.pin.5 => jcode.1.speed
-net y-boundary streamer.0.pin.6 => jcode.1.boundary
-net y-test streamer.0.pin.7 => jcode.1.test
-
-loadrt and2 count=1
-net x-test jcode.0.test-result => and2.0.in0
-net y-test jcode.1.test-result => and2.0.in1
-net ready and2.0.out => streamer.0.enable
-
-loadrt threads name1=ted period1=10000
-addf stepgen.capture-position ted
-addf streamer.0 ted
-addf jcode.0 ted
-addf jcode.1 ted
-addf and2.0 ted
-addf stepgen.update-freq ted
-addf stepgen.make-pulses ted
-
-start
View
154 hal/mask.hal
@@ -1,154 +0,0 @@
-
-
-# Raster mask support - stream in laser on/off commands behind AXIS's back
-# Input stream format: reset beam xop xarg
-# reset: 0=mask command 1=reset (begin mask sequence with "1 0 0 0", every other command starts with 0)
-# beam: 0=off 1=on
-# xop: X axis comparison operation 0=less-or-equal 1=greater
-# xarg: X axis comparison operand
-
-loadrt streamer depth=256 cfg="bbbf"
-net mask-reset <= streamer.0.pin.0
-net mask-beam <= streamer.0.pin.1
-net mask-xop <= streamer.0.pin.2
-net mask-xarg <= streamer.0.pin.3
-net mask-empty <= streamer.0.empty
-net mask-latch => streamer.0.enable
-
-# Make sure velocity is zero when we are not executing a command and input FIFO is empty
-loadrt mux2 count=2
-loadrt and2 count=2
-
-net input-empty => and2.0.in0
-net input-latch => and2.0.in1
-net idle <= and2.0.out
-
-net x-velocity-cmd => mux2.0.in0
-net zero => mux2.0.in1
-net idle => mux2.0.sel
-net x-velocity <= mux2.0.out
-
-net y-velocity-cmd => mux2.1.in0
-net zero => mux2.1.in1
-net idle => mux2.1.sel
-net y-velocity <= mux2.1.out
-
-sets zero 0.0
-
-# Connect beam on/off to FIFO field 0
-net beam-enable => parport.0.pin-01-out
-
-# Setup x,y step generators
-# Connect x,y target-pos to FIFO fields 1,4
-loadrt stepgen step_type=0,0 ctrl_type=v,v
-
-setp stepgen.0.position-scale 500
-setp stepgen.0.steplen 15200
-setp stepgen.0.stepspace 15200
-setp stepgen.0.dirhold 15200
-setp stepgen.0.dirsetup 15200
-setp stepgen.0.maxaccel 20
-setp stepgen.0.maxvel 4
-setp stepgen.0.enable 1
-net x-dir stepgen.0.dir parport.0.pin-02-out
-net x-step stepgen.0.step parport.0.pin-03-out
-net x-velocity => stepgen.0.velocity-cmd
-net x-position <= stepgen.0.position-fb
-
-setp stepgen.1.position-scale 500
-setp stepgen.1.steplen 15200
-setp stepgen.1.stepspace 15200
-setp stepgen.1.dirhold 15200
-setp stepgen.1.dirsetup 15200
-setp stepgen.1.maxaccel 20
-setp stepgen.1.maxvel 5
-setp stepgen.1.enable 1
-net y-dir stepgen.1.dir parport.0.pin-04-out
-net y-step stepgen.1.step parport.0.pin-05-out
-net y-velocity => stepgen.1.velocity-cmd
-net y-position <= stepgen.1.position-fb
-
-# Wire up logic to perform compare operation and start/stop FIFO
-loadrt comp count=2
-loadrt or2 count=4
-loadrt xor2 count=2
-
-# x-cmp-result = x-cmp-op ? x-current-pos >= x-cmp-val : x-current-pos <= x-cmp-val
-setp comp.0.hyst 0.002
-net x-position => comp.0.in0
-net x-cmp-val => comp.0.in1
-net x-cmp-eq <= comp.0.equal
-net x-cmp-lt <= comp.0.out
-
-net x-cmp-eq => or2.0.in0
-net x-cmp-lt => or2.0.in1
-net x-cmp-lte <= or2.0.out # x-cmp-lte = x-current-pos == x-target-pos || x-current-pos < x-target-pos
-
-net x-cmp-lte => xor2.0.in0
-net x-cmp-op => xor2.0.in1
-net x-cmp-op-result <= xor2.0.out # x-cmp-result = (x-cmp-lte && !x-cmp-op) || (!x-cmp-lte && x-cmp-op)
-
-net x-cmp-op-result => or2.1.in0
-net x-cmp-bypass => or2.1.in1
-net x-cmp-result <= or2.1.out
-
-# y-cmp-result = y-cmp-op ? y-current-pos >= y-cmp-val : y-current-pos <= y-cmp-val
-setp comp.1.hyst 0.002
-net y-position => comp.1.in0
-net y-cmp-val => comp.1.in1
-net y-cmp-eq <= comp.1.equal
-net y-cmp-lt <= comp.1.out
-
-net y-cmp-eq => or2.2.in0
-net y-cmp-lt => or2.2.in1
-net y-cmp-lte <= or2.2.out # x-cmp-lte = x-current-pos == x-target-pos || x-current-pos < x-target-pos
-
-net y-cmp-lte => xor2.1.in0
-net y-cmp-op => xor2.1.in1
-net y-cmp-op-result <= xor2.1.out # x-cmp-result = (x-cmp-lte && !x-cmp-op) || (!x-cmp-lte && x-cmp-op)
-
-net y-cmp-op-result => or2.3.in0
-net y-cmp-bypass => or2.3.in1
-net y-cmp-result <= or2.3.out
-
-net x-cmp-result => and2.1.in0
-net y-cmp-result => and2.1.in1
-net input-latch <= and2.1.out # input-latch = x-cmp-result || y-cmp-result
-
-# beam-enable x-current-pos x-target-pos x-cmp-op x-cmp-val input-latch
-loadrt sampler depth=256 cfg="bffbfffbfb"
-net beam-enable => sampler.0.pin.0
-net x-velocity => sampler.0.pin.1
-net y-velocity => sampler.0.pin.2
-net x-position => sampler.0.pin.3
-net y-position => sampler.0.pin.4
-net x-home => sampler.0.pin.5
-net y-home => sampler.0.pin.6
-net estop-ext => sampler.0.pin.7
-
-loadrt threads name1="fast-thread" period1=100000, name2="slow-thread" period2=1000000
-
-addf parport.0.read fast-thread
-addf stepgen.make-pulses fast-thread
-addf charge-pump fast-thread
-addf parport.0.write fast-thread
-#addf parport.0.reset fast-thread
-
-addf streamer.0 slow-thread
-addf stepgen.capture-position slow-thread
-addf comp.0 slow-thread
-addf comp.1 slow-thread
-addf or2.0 slow-thread
-addf or2.1 slow-thread
-addf or2.2 slow-thread
-addf or2.3 slow-thread
-addf xor2.0 slow-thread
-addf xor2.1 slow-thread
-addf mux2.0 slow-thread
-addf mux2.1 slow-thread
-addf and2.0 slow-thread
-addf and2.1 slow-thread
-addf stepgen.update-freq slow-thread
-addf sampler.0 slow-thread
-
-start
View
62 hal/stream.comp
@@ -1,62 +0,0 @@
-component stream "stream timed pulses to the steppers asynchronously";
-license "fuck";
-
-param rw float position_scale = 1.0;
-param rw float maxaccel = 1.0;
-
-pin in bit read "set true to read new values from input pins, false to ignore inputs and keep existing values";
-
-pin in float move_to "POS parameter for operation";
-pin in float speed "VEL parameter for operation";
-pin in float boundary "arbitrary test boundary";
-pin in unsigned test "0: always false, 1: always true, 2: moving, 3: not moving, 4: <= boundary, 5: >= boundary";
-
-variable float vmove_to;
-variable float vspeed;
-variable float vboundary;
-variable unsigned vtest;
-
-pin in float position_fb "set to actual axis position, as reported by stepgen";
-
-pin out float velocity_cmd "the value we want for velocity, sent to stepgen";
-pin out bit test_result "result of specified test";
-pin out bit moving "1 if moving";
-pin out bit greater "1 if position is >= boundary";
-pin out bit less "1 if position is <= boundary";
-
-function _ fp;
-;;
-
-#include <rtapi_math.h>
-
-FUNCTION(_) {
- float move_delta, step_size, velocity;
-
- if (read) {
- vmove_to = move_to;
- vspeed = speed;
- vboundary = boundary;
- vtest = test;
- }
-
- move_delta = vmove_to - position_fb;
- step_size = 1.0/(position_scale == 0.0 ? 1.0 : position_scale);
-
- /* find velocity given distance and acceleration: v = (2ad)^(1/2) */
- velocity = min((float)sqrt(2.0 * fabs(move_delta) * maxaccel), vspeed);
-
- if (fabs(move_delta) >= step_size) {
- velocity_cmd = move_delta < 0.0 ? -velocity : velocity;
- moving = 1;
- } else {
- velocity_cmd = moving = 0;
- }
-
- greater = position_fb >= vboundary;
- less = position_fb < vboundary;
-
- test_result = (vtest == 1) ||
- (vtest == 2 && moving) ||
- (vtest == 3 && less) ||
- (vtest == 4 && greater) ? 1 : 0;
-}
View
175 hal/stream.hal
@@ -1,175 +0,0 @@
-
-loadrt probe_parport
-loadrt hal_parport cfg=0x378
-setp parport.0.reset-time 100000
-
-loadrt charge_pump
-net charge-pump charge-pump.out parport.0.pin-17-out
-setp parport.0.pin-17-out-reset 1
-setp charge-pump.enable 1
-
-net amp parport.0.pin-14-out
-sets amp 1
-
-net x-home <= parport.0.pin-10-in
-net y-home <= parport.0.pin-12-in
-net estop-ext <= parport.0.pin-15-in
-
-# FIFO input component
-# beam xpos xop xarg ypos yop yarg
-#
-# beam: 0=off 1=on
-# ?pos: target position
-# ?op: compare operation 0=less-or-equal 1=greater-or-equal
-# ?arg: compare operand
-
-loadrt streamer depth=256 cfg="bfbffbf"
-net beam-enable <= streamer.0.pin.0
-net x-velocity-cmd <= streamer.0.pin.1
-net x-cmp-op <= streamer.0.pin.2
-net x-cmp-val <= streamer.0.pin.3
-net x-cmp-bypass <= streamer.0.pin.4
-net y-velocity-cmd <= streamer.0.pin.5
-net y-cmp-op <= streamer.0.pin.6
-net y-cmp-val <= streamer.0.pin.7
-net y-cmp-bypass <= streamer.0.pin.8
-net input-empty <= streamer.0.empty
-net input-latch => streamer.0.enable
-
-# Make sure velocity is zero when we are not executing a command and input FIFO is empty
-loadrt mux2 count=2
-loadrt and2 count=2
-
-net input-empty => and2.0.in0
-net input-latch => and2.0.in1
-net idle <= and2.0.out
-
-net x-velocity-cmd => mux2.0.in0
-net zero => mux2.0.in1
-net idle => mux2.0.sel
-net x-velocity <= mux2.0.out
-
-net y-velocity-cmd => mux2.1.in0
-net zero => mux2.1.in1
-net idle => mux2.1.sel
-net y-velocity <= mux2.1.out
-
-sets zero 0.0
-
-# Connect beam on/off to FIFO field 0
-net beam-enable => parport.0.pin-01-out
-
-# Setup x,y step generators
-# Connect x,y target-pos to FIFO fields 1,4
-loadrt stepgen step_type=0,0 ctrl_type=v,v
-
-setp stepgen.0.position-scale 500
-setp stepgen.0.steplen 15200
-setp stepgen.0.stepspace 15200
-setp stepgen.0.dirhold 15200
-setp stepgen.0.dirsetup 15200
-setp stepgen.0.maxaccel 20
-setp stepgen.0.maxvel 4
-setp stepgen.0.enable 1
-net x-dir stepgen.0.dir parport.0.pin-02-out
-net x-step stepgen.0.step parport.0.pin-03-out
-net x-velocity => stepgen.0.velocity-cmd
-net x-position <= stepgen.0.position-fb
-
-setp stepgen.1.position-scale 500
-setp stepgen.1.steplen 15200
-setp stepgen.1.stepspace 15200
-setp stepgen.1.dirhold 15200
-setp stepgen.1.dirsetup 15200
-setp stepgen.1.maxaccel 20
-setp stepgen.1.maxvel 5
-setp stepgen.1.enable 1
-net y-dir stepgen.1.dir parport.0.pin-04-out
-net y-step stepgen.1.step parport.0.pin-05-out
-net y-velocity => stepgen.1.velocity-cmd
-net y-position <= stepgen.1.position-fb
-
-# Wire up logic to perform compare operation and start/stop FIFO
-loadrt comp count=2
-loadrt or2 count=4
-loadrt xor2 count=2
-
-# x-cmp-result = x-cmp-op ? x-current-pos >= x-cmp-val : x-current-pos <= x-cmp-val
-setp comp.0.hyst 0.002
-net x-position => comp.0.in0
-net x-cmp-val => comp.0.in1
-net x-cmp-eq <= comp.0.equal
-net x-cmp-lt <= comp.0.out
-
-net x-cmp-eq => or2.0.in0
-net x-cmp-lt => or2.0.in1
-net x-cmp-lte <= or2.0.out # x-cmp-lte = x-current-pos == x-target-pos || x-current-pos < x-target-pos
-
-net x-cmp-lte => xor2.0.in0
-net x-cmp-op => xor2.0.in1
-net x-cmp-op-result <= xor2.0.out # x-cmp-result = (x-cmp-lte && !x-cmp-op) || (!x-cmp-lte && x-cmp-op)
-
-net x-cmp-op-result => or2.1.in0
-net x-cmp-bypass => or2.1.in1
-net x-cmp-result <= or2.1.out
-
-# y-cmp-result = y-cmp-op ? y-current-pos >= y-cmp-val : y-current-pos <= y-cmp-val
-setp comp.1.hyst 0.002
-net y-position => comp.1.in0
-net y-cmp-val => comp.1.in1
-net y-cmp-eq <= comp.1.equal
-net y-cmp-lt <= comp.1.out
-
-net y-cmp-eq => or2.2.in0
-net y-cmp-lt => or2.2.in1
-net y-cmp-lte <= or2.2.out # x-cmp-lte = x-current-pos == x-target-pos || x-current-pos < x-target-pos
-
-net y-cmp-lte => xor2.1.in0
-net y-cmp-op => xor2.1.in1
-net y-cmp-op-result <= xor2.1.out # x-cmp-result = (x-cmp-lte && !x-cmp-op) || (!x-cmp-lte && x-cmp-op)
-
-net y-cmp-op-result => or2.3.in0
-net y-cmp-bypass => or2.3.in1
-net y-cmp-result <= or2.3.out
-
-net x-cmp-result => and2.1.in0
-net y-cmp-result => and2.1.in1
-net input-latch <= and2.1.out # input-latch = x-cmp-result || y-cmp-result
-
-# beam-enable x-current-pos x-target-pos x-cmp-op x-cmp-val input-latch
-loadrt sampler depth=256 cfg="bffbfffbfb"
-net beam-enable => sampler.0.pin.0
-net x-velocity => sampler.0.pin.1
-net y-velocity => sampler.0.pin.2
-net x-position => sampler.0.pin.3
-net y-position => sampler.0.pin.4
-net x-home => sampler.0.pin.5
-net y-home => sampler.0.pin.6
-net estop-ext => sampler.0.pin.7
-
-loadrt threads name1="fast-thread" period1=100000, name2="slow-thread" period2=1000000
-
-addf parport.0.read fast-thread
-addf stepgen.make-pulses fast-thread
-addf charge-pump fast-thread
-addf parport.0.write fast-thread
-#addf parport.0.reset fast-thread
-
-addf streamer.0 slow-thread
-addf stepgen.capture-position slow-thread
-addf comp.0 slow-thread
-addf comp.1 slow-thread
-addf or2.0 slow-thread
-addf or2.1 slow-thread
-addf or2.2 slow-thread
-addf or2.3 slow-thread
-addf xor2.0 slow-thread
-addf xor2.1 slow-thread
-addf mux2.0 slow-thread
-addf mux2.1 slow-thread
-addf and2.0 slow-thread
-addf and2.1 slow-thread
-addf stepgen.update-freq slow-thread
-addf sampler.0 slow-thread
-
-start
View
31 hal/stream.hal.rb
@@ -1,31 +0,0 @@
-load "./halgen.rb"
-
-print HAL::Builder.new(:trace => false) {
-
- charge_pump do
- enable 1
- end
-
- parport :address => 0x378 do
- reset_time 100000
- pin_17_out_reset 1
- pin_17_out <= charge_pump.out
- pin_14_out <= 1
- end
-
- streamer :instream, :depth => 256, :cfg => "bfbffbf" do
-
- end
-
- stepgen :step_x, :step_type => 0 do
- position_scale 500
- steplen 50000
- stepspace 50000
- dirhold 50000
- dirsetup 50000
- maxaccel 30
- enable 1
- position_cmd <= instream.pin.1
- end
-
-}.hal_code
View
98 hal/stream.rb
@@ -1,98 +0,0 @@
-class Spawner
- def initialize *cmd
- @stdin_ext, @stdin = IO.pipe
- @stdout,@stdout_ext = IO.pipe
- @stderr,@stderr_ext = IO.pipe
- @pid = spawn *cmd,
- STDIN => @stdin_ext,
- STDOUT => @stdout_ext,
- STDERR => @stderr_ext
- @stdin_ext.close
- @stdout_ext.close
- @stderr_ext.close
- end
-
- attr_reader :pid, :stdin, :stdout, :stderr
-end
-
-module Graster
- class Motion < Thread
- def initialize
- @streamer = Spawner.new "halstreamer"
- @sampler = Spawner.new "halsampler"
- super {
- @sampler.each_line {|l|
- @beam_enable,
- @x_velocity,
- @y_velocity,
- @x_position_raw,
- @y_position_raw,
- @x_home_switch,
- @y_home_switch,
- @estop_ext = l.split(/\s+/)
-
- if !@y_home_position
- cmd :yop =>
- elsif !@x_home_position
-
- else
- end
- }
- }
- end # def initialize
-
- attr_reader :x_velocity, :y_velocity,
- :beam_enable, :estop_ext
-
- def x_position
- @x_home_position && @x_position_raw - @x_home_position
- end
-
- def y_position
- @y_home_position && @y_position_raw - @y_home_position
- end
-
- attr_accessor :x_target, :y_target
-
- def cmd o
- o = o.dup
-
- o[:beam] ||= 0
-
- if o[:xop]
- o[:xop] = case o[:xop] when :lte then 0 when :gt then 1 end
- o[:xbypass] = 0
- o[:xval] ||= 0
- else
- o[:xbypass] = 1
- o[:xval] = 0
- end
-
- if o[:yop]
- o[:yop] = case o[:yop] when :lte then 0 when :gt then 1 end
- o[:ybypass] = 0
- o[:yval] ||= 0
- else
- o[:ybypass] = 1
- o[:yval] = 0
- end
-
- @streamer.puts [o[:beam],
- o[:xvel],o[:xop],o[:xbypass],
- o[:yvel],o[:yop],o[:ybypass]].join(' ')
- end
-
- end # class Motion
-
- class HalSession
- def initialize
- @hal = Spawner.new "halrun -s -f"
- @motion = Motion.new
- end
-
- def cmd str
- @hal.stdin.puts str
- @hal.stdout.lines.take_while {|l| l.chomp != '%' }
- end
- end
-end
View
69 tile.rb
@@ -1,71 +1,2 @@
#!/usr/bin/ruby
-unless ARGV.size == 5
- puts "usage: ruby tile.rb <input-gcode-file> <tile-width> <tile-height> <horiz-count> <vert-count>"
- exit(1)
-end
-
-def parse_line line
- nc = {}
- line.gsub(/\([^)]*\)/,'').upcase.scan(/([A-Z])\s*([0-9\.]+)?/).each {|code| nc[code[0].intern] = (code[1] && code[1].to_f) }
- nc
-end
-
-def gcode ncs
- ncs = [ncs] unless ncs.is_a? Array
- ncs.reduce('') {|a,nc| a << (nc.map {|k,v| "#{k}#{v}" }.join(' ') + "\n") }
-end
-
-tile_width = ARGV[1].to_f
-tile_height = ARGV[2].to_f
-horiz_count = ARGV[3].to_i
-vert_count = ARGV[4].to_i
-
-header = []
-body = []
-footer = []
-state = :header
-
-
-File.open ARGV[0] do |io|
- io.each_line do |line|
- if (nc = parse_line(line)) != {}
- case state
- when :header
- if nc[:G] == 0 || nc[:G] == 1
- state = :body
- body << nc
- else
- header << nc
- end
-
- when :body
- if nc[:G] == 0 || nc[:G] == 1
- body << nc
- else
- state = :footer
- footer << nc
- end
-
- when :footer
- footer << nc
- end
- end # case
-
- end # io.each_line
-end # File.open
-
-print gcode(header)
-
-vert_count.times.map do |yc|
- horiz_count.times.map do |xc|
- body.each do |nc|
- nc = nc.dup
- nc[:X] += xc*tile_width if nc[:X]
- nc[:Y] += yc*tile_height if nc[:Y]
- print gcode(nc)
- end
- end
-end
-
-print gcode(footer)

0 comments on commit 51af682

Please sign in to comment.
Something went wrong with that request. Please try again.