def blink_it blink 13, 500 end
end
added pin methods for servos and latching which generate an array of structs to contain setup and status #input_pin 12, :as => :back_off_button, :latch => :off #input_pin 8, :as => :red_button, :latch => :off # adjust is optional with default set to 200
added ::add_to_setup method that takes a string of c code and adds it to setup colons are options and will be added if not present
no translation from ruby for now
example:
::add_to_setup “call_my_new_method();”, “call_another();”
added some checking to c translation that (hopefully) makes it a bit more predictable most notably, we keep track of all external variables and let the translator know they exist
array “char buffer” result: char buffer; array “char buffer” result: char buffer; todo need to feed array external array identifiers to rtc if they are in plugins or libraries, (not so sure about this will do more testing)
# File lib/rad/arduino_sketch.rb, line 204 def array(arg) if arg arg = arg.chomp.rstrip.lstrip name = arg.scan(/\s*(\w*)\[\d*\]?/).first.first # help rad_processor do a better job with array types types = ["int", "long", "char*", "unsigned int", "unsigned long", "byte", "bool", "float" ] types.each_with_index do |type, i| @type = types[i] if /#{type}/ =~ arg end raise ArgumentError, "type not currently supported.. got: #{arg}. Currently supporting #{types.join(", ")}" unless @type arg = "#{arg};" unless arg[-1,1] == ";" $array_types[name] = @type @type = nil $external_var_identifiers << name unless $external_var_identifiers.include?(name) # add array_name declaration $external_array_vars << arg unless $external_array_vars.include?(arg) end end
Write inline assembler code. ‘Name’ is a symbol representing the name of the function to be defined in the assembly code; ‘signature’ is the function signature for the function being defined; and ‘code’ is the assembly code itself (both of these last two arguments are strings). See an example here: rad.rubyforge.org/examples/assembler_test.html
# File lib/rad/arduino_sketch.rb, line 567 def assembler(name, signature, code) @assembler_declarations << signature assembler_code = <<-CODE .file "#{name}.S" .arch #{Makefile.hardware_params['mcu']} .global __do_copy_data .global __do_clear_bss .text .global #{name} .type #{name}, @function #{code} CODE File.open(File.expand_path("#{RAD_ROOT}") + "/#{PROJECT_DIR_NAME}/#{name}.S", "w"){|f| f << assembler_code} end
define “DS1307_SEC 0” result: define DS1307_SEC 0 note we send the constant identifiers and type to our rad_type_checker however, it only knows about long, float, str.… so we don’t send ints …yet.. need more testing
# File lib/rad/arduino_sketch.rb, line 230 def define(arg) if arg arg = arg.chomp.rstrip.lstrip name = arg.split(" ").first value = arg.gsub!("#{name} ","") # negative if value =~ /^-(\d|x)*$/ type = "long" # negative float elsif value =~ /^-(\d|\.|x)*$/ type = "float" elsif value =~ /[a-zA-Z]/ type = "str" value = "\"#{value}\"" elsif value !~ /(\.|x)/ type = "long" elsif value =~ /(\d*\.\d*)/ # and no type = "float" elsif value =~ /0x\d\d/ type = "byte" else raise ArgumentError, "opps, could not determine the define type, got #{value}" end $define_types[name] = type arg = "#define #{name} #{value}" $defines << arg dummy_for_testing = arg, type end end
# File lib/rad/sim/arduino_sketch.rb, line 36 def delay( millis ) end
# File lib/rad/sim/arduino_sketch.rb, line 31 def digitalWrite( pin, value ) to_change = pins.select{|p| p.num == pin.num}.first to_change.value = value end
# File lib/rad/arduino_sketch.rb, line 415 def formatted_print(opts={}) buffer_size = opts[:buffer_size] ? opts[:buffer_size] : 64 if opts[:as] @@sprintf_inc ||= FALSE if @@sprintf_inc == FALSE @@sprintf_inc = TRUE accessor = [] accessor << "\n#undef int\n#include <stdio.h>" accessor << "#define write_line(...) sprintf(#{opts[:as]},__VA_ARGS__);" @accessors << accessor.join( "\n" ) array("char #{opts[:as]}[#{buffer_size}]") end end end
Configure a single pin for input and setup a method to refer to that pin, i.e.:
input_pin 3, :as => :button
would configure pin 3 as an input and let you refer to it from the then on by calling the `button` method in your loop like so:
def loop digital_write led if digital_read button end
# File lib/rad/arduino_sketch.rb, line 350 def input_pin(num, opts={}) raise ArgumentError, "can only define pin from Fixnum, got #{num.class}" unless num.is_a?(Fixnum) @pin_modes[:input] << num if opts[:as] # transitioning to :device => :button syntax if opts[:latch] || opts[:device] == :button if opts[:device] == :button opts[:latch] ||= :off end # add debounce settings to dbce struct array ArduinoPlugin.add_debounce_struct @debounce_pins << num state = opts[:latch] == :on ? 1 : 0 prev = opts[:latch] == :on ? 0 : 1 adjust = opts[:adjust] ? opts[:adjust] : 200 @debounce_settings << "dbce[#{num}].state = #{state}, dbce[#{num}].read = 0, dbce[#{num}].prev = #{prev}, dbce[#{num}].time = 0, dbce[#{num}].adjust = #{adjust}" end if opts[:device] == :sensor ArduinoPlugin.add_sensor_struct count = @hysteresis_pins.length @hysteresis_pins << num @hysteresis_settings << "hyst[#{count}].pin = #{num}, hyst[#{count}].state = 0" end if opts[:device] == :spectra ArduinoPlugin.add_spectra_struct count = @spectra_pins.length @spectra_pins << num @spectra_settings << "spec[#{count}].pin = #{num}, spec[#{count}].state = 10, spec[#{count}].r1 = 0, spec[#{count}].r2 = 0, spec[#{count}].r3 = 0" end @declarations << "int _#{opts[ :as ]} = #{num};" accessor = [] accessor << "int #{opts[ :as ]}() {" accessor << "\treturn _#{opts[ :as ]};" accessor << "}" @accessors << accessor.join( "\n" ) @signatures << "int #{opts[ :as ]}();" end @pullups << num if opts[:as] end
Like #input_pin but configure more than one input pin simultaneously. Takes an array of pin numbers.
# File lib/rad/arduino_sketch.rb, line 393 def input_pins(nums) ar = Array(nums) ar.each {|n| input_pin(n)} end
# File lib/rad/sim/arduino_sketch.rb, line 28 def loop end
Configure a single pin for output and setup a method to refer to that pin, i.e.:
output_pin 7, :as => :led
would configure pin 7 as an output and let you refer to it from the then on by calling the `led` method in your loop like so:
def loop digital_write led, ON end
# File lib/rad/arduino_sketch.rb, line 271 def output_pin(num, opts={}) raise ArgumentError, "can only define pin from Fixnum, got #{num.class}" unless num.is_a?(Fixnum) @pin_modes[:output] << num if opts[:as] if opts[:device] case opts[:device] when :servo servo_setup(num, opts) return # don't use declarations, accessor, signatures below when :pa_lcd || :pa_LCD pa_lcd_setup(num, opts) return when :sf_lcd || :sf_LCD sf_lcd_setup(num, opts) return when :freq_out || :freq_gen || :frequency_generator frequency_timer(num, opts) return when :i2c two_wire(num, opts) unless @@twowire_inc return # when :i2c_eeprom two_wire(num, opts) unless @@twowire_inc i2c_eeprom(num, opts) return # when :i2c_ds1307 two_wire(num, opts) unless @@twowire_inc ds1307(num, opts) return # when :i2c_blinkm two_wire(num, opts) unless @@twowire_inc blinkm return # when :onewire one_wire(num, opts) return # when :ethernet ethernet(num, opts) return # else raise ArgumentError, "today's device choices are: :servo, :pa_lcd, :sf_lcd, :freq_out,:i2c, :i2c_eeprom, :i2c_ds1307, and :i2c_blinkm got #{opts[:device]}" end end # add state variables for outputs with :state => :on or :off -- useful for toggling a light with output_toggle -- need to make this more modular if opts[:state] # add debounce settings to dbce struct array ArduinoPlugin.add_debounce_struct @debounce_pins << num state = opts[:latch] == :on ? 1 : 0 prev = opts[:latch] == :on ? 0 : 1 adjust = opts[:adjust] ? opts[:adjust] : 200 @debounce_settings << "dbce[#{num}].state = #{state}, dbce[#{num}].read = 0, dbce[#{num}].prev = #{prev}, dbce[#{num}].time = 0, dbce[#{num}].adjust = #{adjust}" end @declarations << "int _#{opts[ :as ]} = #{num};" accessor = [] accessor << "int #{opts[ :as ]}() {" accessor << "\treturn _#{opts[ :as ]};" accessor << "}" @accessors << accessor.join( "\n" ) @signatures << "int #{opts[ :as ]}();" end end
Configure Arduino for serial communication. Optionally, set the baud rate:
serial_begin :rate => 2400
default is 9600. See www.arduino.cc/en/Serial/Begin for more details.
# File lib/rad/arduino_sketch.rb, line 408 def serial_begin(opts={}) rate = opts[:rate] ? opts[:rate] : 9600 @other_setup << "Serial.begin(#{rate});" @@hwserial_inc = TRUE end
# File lib/rad/arduino_sketch.rb, line 598 def self.add_to_setup(meth) meth = meth.gsub("setup", "additional_setup") post_process_ruby_to_c_methods(meth) end
# File lib/rad/sim/arduino_sketch.rb, line 9 def initialize @pins = self.class.instance_variable_get("@pins") end
# File lib/rad/sim/arduino_sketch.rb, line 13 def self.output_pin(num, opts) module_eval "@pins ||= []" module_eval do @pins << Pin.new( num, :type => :output ) end if opts[:as] module_eval <<-CODE def #{opts[:as]} pins.select{|p| p.num == #{num}}.first end CODE end end
# File lib/rad/arduino_sketch.rb, line 603 def self.post_process_ruby_to_c_methods(e) clean_c_methods = [] # need to take a look at the \(unsigned in the line below not sure if we are really trying to catch something like that if e !~ /^\s*(#{C_VAR_TYPES})(\W{1,6}|\(unsigned\()(#{$external_var_identifiers.join("|")})/ || $external_var_identifiers.empty? # use the list of identifers the external_vars method of the sketch and remove the parens the ruby2c sometime adds to variables # keep an eye on the gsub!.. are we getting nil errors # and more recently, the \b e.gsub!(/\b((#{$external_var_identifiers.join("|")})\(\))/, '\2') unless $external_var_identifiers.empty? clean_c_methods << e end return clean_c_methods.join( "\n" ) end