Repository: atduskgreg/rad Branch: master Commit: 353a9f4040fb Files: 114 Total size: 384.7 KB Directory structure: gitextract_7rauuwcn/ ├── .gitignore ├── History.txt ├── License.txt ├── Manifest.txt ├── README.markdown ├── Rakefile ├── bin/ │ └── rad ├── lib/ │ ├── examples/ │ │ ├── add_hysteresis.rb │ │ ├── basic_blink.rb │ │ ├── blink_m_address_assignment.rb │ │ ├── blink_m_hello.rb │ │ ├── blink_m_multi.rb │ │ ├── blink_with_serial.rb │ │ ├── configure_pa_lcd_boot.rb │ │ ├── debounce_methods.rb │ │ ├── external_variable_fu.rb │ │ ├── external_variables.rb │ │ ├── first_sound.rb │ │ ├── frequency_generator.rb │ │ ├── hello_array.rb │ │ ├── hello_array2.rb │ │ ├── hello_array_eeprom.rb │ │ ├── hello_clock.rb │ │ ├── hello_eeprom.rb │ │ ├── hello_eeprom_lcdpa.rb │ │ ├── hello_format_print.rb │ │ ├── hello_lcd_charset.rb │ │ ├── hello_pa_lcd.rb │ │ ├── hello_servos.rb │ │ ├── hello_spectra_sound.rb │ │ ├── hello_world.rb │ │ ├── hello_xbee.rb │ │ ├── hysteresis_duel.rb │ │ ├── i2c_with_clock_chip.rb │ │ ├── midi_beat_box.rb │ │ ├── midi_scales.rb │ │ ├── motor_knob.rb │ │ ├── servo_buttons.rb │ │ ├── servo_calibrate_continuous.rb │ │ ├── servo_throttle.rb │ │ ├── software_serial.rb │ │ ├── sparkfun_lcd.rb │ │ ├── spectra_soft_pot.rb │ │ ├── times_method.rb │ │ ├── toggle.rb │ │ ├── twitter.rb │ │ └── two_wire.rb │ ├── libraries/ │ │ └── Wire/ │ │ └── utility/ │ │ ├── twi.c │ │ └── twi.h │ ├── plugins/ │ │ ├── bitwise_ops.rb │ │ ├── blink.rb │ │ ├── blink_m.rb │ │ ├── debounce.rb │ │ ├── debug_output_to_lcd.rb │ │ ├── hysteresis.rb │ │ ├── input_output_state.rb │ │ ├── lcd_padding.rb │ │ ├── mem_test.rb │ │ ├── midi.rb │ │ ├── parallax_ping.rb │ │ ├── servo_pulse.rb │ │ ├── servo_setup.rb │ │ ├── smoother.rb │ │ ├── spark_fun_serial_lcd.rb │ │ ├── spectra_symbol.rb │ │ └── twitter_connect.rb │ ├── rad/ │ │ ├── README.rdoc │ │ ├── antiquated_todo.txt │ │ ├── arduino_plugin.rb │ │ ├── arduino_sketch.rb │ │ ├── darwin_installer.rb │ │ ├── generators/ │ │ │ └── makefile/ │ │ │ ├── makefile.erb │ │ │ └── makefile.rb │ │ ├── hardware_library.rb │ │ ├── init.rb │ │ ├── linux_installer.rb │ │ ├── progressbar.rb │ │ ├── rad_processor.rb │ │ ├── rad_rewriter.rb │ │ ├── rad_type_checker.rb │ │ ├── sim/ │ │ │ └── arduino_sketch.rb │ │ ├── sketch_compiler.rb │ │ ├── tasks/ │ │ │ ├── build_and_make.rake │ │ │ └── rad.rb │ │ ├── todo.txt │ │ ├── variable_processing.rb │ │ └── version.rb │ └── rad.rb ├── rad.gemspec ├── scripts/ │ └── txt2html ├── setup.rb ├── spec/ │ ├── examples/ │ │ ├── hello_world.rb │ │ └── serial_motor.rb │ ├── models/ │ │ ├── arduino_sketch_spec.rb │ │ ├── sketch_compiler_spec.rb │ │ └── spec_helper.rb │ ├── sim/ │ │ └── hello_world_spec.rb │ └── spec.opts ├── test/ │ ├── hello_world_test/ │ │ ├── Makefile │ │ └── hello_world.cpp │ ├── test_array_processing.rb │ ├── test_plugin_loading.rb │ ├── test_translation_post_processing.rb │ └── test_variable_processing.rb └── website/ ├── examples/ │ ├── assembler_test.rb.html │ ├── gps_reader.rb.html │ ├── hello_world.rb.html │ └── serial_motor.rb.html ├── index.html ├── index.txt ├── javascripts/ │ └── rounded_corners_lite.inc.js ├── stylesheets/ │ ├── code.css │ └── screen.css └── template.rhtml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .DS_Store bin/.DS_Store lib/.DS_Store lib/libraries/.DS_Store lib/rad/.DS_Store lib/libraries/*/*.* ================================================ FILE: History.txt ================================================ == 0.3.0 2008-09-22 * Pushing to rubyforge.. - added rad install arduino - added rad test arduino == 0.2.5 2008-07-21 * 1ish large post Bastille Day update: - added i2c capability - added actual Wire library until workaround for os_x file caching is found - added DS1307 and OneWire libraries - added cool instance variable style global variables - added array and define methods - added def setup method, which added to setup  - added numerous examples == 0.2.4 2008-07-12 * 1ish large update: - added incredibly primitive tests - added 11 sketch examples which are compiled or compiled/uploaded - use rake test:compile or rake test:upload - can also use the following to run an example (make:compile also works) - make:upload sketch=examples/hello_servos == 0.2.3 2008-07-10 * Manyish updates: - updated servo library to support position parameter - plus: - addition of plugins - latest and greatest lcd libraries for pa and sf - multiple methods - addition of rad_process and rad_rewrite methods methods - options for :device => servo, button, lcd, - and many more == 0.2.2 2008-04-27 * 2ish updates: - updated makefile template and cli to expect arduino-0011 - applied David Michael's patch for longs == 0.2.1 2008-04-02 * 6ish updates: - applied Brian Riley's SWSerLCDpa patch - experimental libraries system in vendor/libraries - fixed require 'yaml' bug in makefile.rb - enhancements to the rad command: can set project config. - added first significant documentation - added examples directory to the website == 0.2.0 2008-03-15 * 8ish updates, some major: * fixed regular serial support * class method for writing functions in assembler * applied Scott Windsor's patch for software serial support * added support for HIGH/LOW/ON/OFF constants * add an option for skipping the reset prompt on rake make:upload * changed default arduino location to be more realistic * put screencasts #1 and #2 on rad.rubyforge.org * put google analytics on rad.rubyforge.org == 0.1.1 2007-10-29 * 2 major fixes: * explicitly specify path to arduino avr tools (this was broken on systems that didn't have the avr toolchain installed, oops) * add explicit path to avrdude.conf in the upload make target == 0.1.0 2007-10-28 * 4ish major updates: * Arduino interop has been updated, and consequently now requires Arduino 0010: * new Makefile imported, with new configuration items (see below) * main() function added to C++ output * make:upload rake task has been updated * C++ generation has been changed to produce a more readable output * configuration file changes: * hardware * fixed typo in serial_port key * added mcu key to specify atmega8/atmega168. Defaults to atmega168 * changed serial_port to /dev/tty.usbserial*, which will pick the first device that matches that blob * software * updated arduino_root for 0010 * 2 major enhancement: * gem should now correctly install RubyToC * can now enable internal pull-up resistors on input pins by passing the :pullup => true parameter to input_pin * 2 minor enhancements: * cleanups in makefile.rb * serial_print_str method added; can now send strings over the serial port == 0.0.4 2007-07-24 * 1 major enhancement: * serial_begin class method == 0.0.3 2007-07-23 * 1 major enhancement: * bug fix in blink helper method == 0.0.2 2007-07-23 * 1 major enhancement: * blink helper method == 0.0.1 2007-07-22 * 1 major enhancement: * Initial release * most features of the Arduino software library functional * experimental implementation of the serial interface * complete rake-based build, compile, and upload cycle ================================================ FILE: License.txt ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. ================================================ FILE: Manifest.txt ================================================ History.txt License.txt Manifest.txt README.rdoc Rakefile bin/rad lib/examples/add_hysteresis.rb lib/examples/basic_blink.rb lib/examples/blink_m_address_assignment.rb lib/examples/blink_m_hello.rb lib/examples/blink_m_multi.rb lib/examples/blink_with_serial.rb lib/examples/configure_pa_lcd_boot.rb lib/examples/debounce_methods.rb lib/examples/external_variable_fu.rb lib/examples/external_variables.rb lib/examples/first_sound.rb lib/examples/frequency_generator.rb lib/examples/hello_array.rb lib/examples/hello_array2.rb lib/examples/hello_array_eeprom.rb lib/examples/hello_clock.rb lib/examples/hello_eeprom.rb lib/examples/hello_eeprom_lcdpa.rb lib/examples/hello_format_print.rb lib/examples/hello_lcd_charset.rb lib/examples/hello_pa_lcd.rb lib/examples/hello_servos.rb lib/examples/hello_spectra_sound.rb lib/examples/hello_world.rb lib/examples/hello_xbee.rb lib/examples/hysteresis_duel.rb lib/examples/i2c_with_clock_chip.rb lib/examples/midi_beat_box.rb lib/examples/midi_scales.rb lib/examples/motor_knob.rb lib/examples/servo_buttons.rb lib/examples/servo_calibrate_continuous.rb lib/examples/servo_throttle.rb lib/examples/software_serial.rb lib/examples/sparkfun_lcd.rb lib/examples/spectra_soft_pot.rb lib/examples/times_method.rb lib/examples/toggle.rb lib/examples/twitter.rb lib/examples/two_wire.rb lib/libraries/AFSoftSerial/AFSoftSerial.cpp lib/libraries/AFSoftSerial/AFSoftSerial.h lib/libraries/AFSoftSerial/keywords.txt lib/libraries/AF_XPort/AF_XPort.cpp lib/libraries/AF_XPort/AF_XPort.h lib/libraries/DS1307/DS1307.cpp lib/libraries/DS1307/DS1307.h lib/libraries/DS1307/keywords.txt lib/libraries/FrequencyTimer2/FrequencyTimer2.cpp lib/libraries/FrequencyTimer2/FrequencyTimer2.h lib/libraries/FrequencyTimer2/keywords.txt lib/libraries/I2CEEPROM/I2CEEPROM.cpp lib/libraries/I2CEEPROM/I2CEEPROM.h lib/libraries/I2CEEPROM/keywords.txt lib/libraries/LoopTimer/LoopTimer.cpp lib/libraries/LoopTimer/LoopTimer.h lib/libraries/LoopTimer/keywords.txt lib/libraries/OneWire/OneWire.cpp lib/libraries/OneWire/OneWire.h lib/libraries/OneWire/keywords.txt lib/libraries/OneWire/readme.txt lib/libraries/SWSerLCDpa/SWSerLCDpa.cpp lib/libraries/SWSerLCDpa/SWSerLCDpa.h lib/libraries/SWSerLCDsf/SWSerLCDsf.cpp lib/libraries/SWSerLCDsf/SWSerLCDsf.h lib/libraries/Servo/Servo.cpp lib/libraries/Servo/Servo.h lib/libraries/Stepper/Stepper.cpp lib/libraries/Stepper/Stepper.h lib/libraries/Stepper/keywords.txt lib/libraries/Wire/Wire.cpp lib/libraries/Wire/Wire.h lib/libraries/Wire/keywords.txt lib/libraries/Wire/twi.h lib/libraries/Wire/utility/twi.c lib/libraries/Wire/utility/twi.h lib/plugins/bitwise_ops.rb lib/plugins/blink.rb lib/plugins/blink_m.rb lib/plugins/debounce.rb lib/plugins/debug_output_to_lcd.rb lib/plugins/hysteresis.rb lib/plugins/input_output_state.rb lib/plugins/lcd_padding.rb lib/plugins/mem_test.rb lib/plugins/midi.rb lib/plugins/parallax_ping.rb lib/plugins/servo_pulse.rb lib/plugins/servo_setup.rb lib/plugins/smoother.rb lib/plugins/spark_fun_serial_lcd.rb lib/plugins/spectra_symbol.rb lib/plugins/twitter_connect.rb lib/rad.rb lib/rad/README.rdoc lib/rad/arduino_plugin.rb lib/rad/arduino_sketch.rb lib/rad/darwin_installer.rb lib/rad/generators/makefile/makefile.erb lib/rad/generators/makefile/makefile.rb lib/rad/hardware_library.rb lib/rad/init.rb lib/rad/linux_installer.rb lib/rad/progressbar.rb lib/rad/rad_processor.rb lib/rad/rad_rewriter.rb lib/rad/rad_type_checker.rb lib/rad/sim/arduino_sketch.rb lib/rad/sketch_compiler.rb lib/rad/tasks/build_and_make.rake lib/rad/tasks/rad.rb lib/rad/todo.txt lib/rad/variable_processing.rb lib/rad/version.rb scripts/txt2html setup.rb spec/examples/hello_world.rb spec/examples/serial_motor.rb spec/models/arduino_sketch_spec.rb spec/models/sketch_compiler_spec.rb spec/models/spec_helper.rb spec/sim/hello_world_spec.rb spec/spec.opts test/hello_world_test/Makefile test/hello_world_test/hello_world.cpp test/test_array_processing.rb test/test_plugin_loading.rb test/test_translation_post_processing.rb test/test_variable_processing.rb website/index.html website/index.txt website/javascripts/rounded_corners_lite.inc.js website/stylesheets/screen.css website/template.rhtml website/examples/assembler_test.rb.html website/examples/gps_reader.rb.html website/examples/hello_world.rb.html website/examples/serial_motor.rb.html ================================================ FILE: README.markdown ================================================ # Welcome to RAD (Ruby Arduino Development) RAD is a framework for programming the Arduino physcial computing platform using Ruby. RAD converts Ruby scripts written using a set of Rails-like conventions and helpers into C source code which can be compiled and run on the Arduino microcontroller. It also provides a set of Rake tasks for automating the compilation and upload process. For a full introduction see http://rad.rubyforge.org ## Documentation The main documentation is here: ArduinoSketch. See also the Arduino Software reference: http://www.arduino.cc/en/Reference/HomePage ## Examples See the examples directory for lots of examples of RAD in action: http://github.com/atduskgreg/rad/tree/master/lib/examples The atduskgreg/rad wiki also contains a growing library of examples and hardware tutorials: http://github.com/atduskgreg/rad/wikis ## Getting Started To install the gem: $ gem install rad Run the rad command to create a new project: $ rad my_project Write a sketch that will blink a single LED every 500ms: ```ruby class MyProject < ArduinoSketch output_pin 13, :as => led def loop blink led, 500 end end ``` Attach your Arduino and use rake to complile and upload your sketch: $ rake make:upload ##Installing the Arduino Software Installing RAD and the Arduino software on Linux can be a little more difficult than on OS X. Thankfully, the RAD command line tool can help. Run: $ rad install arduino And RAD will do its best to get the Arduino software installed on your system. #Get Involved ##Note on Patches/Pull Requests * Fork the project. * Make your feature addition or bug fix on a new topic branch * Add specs and cukes for it. This is important so I don't break it in a future version unintentionally. * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) * Issue a pull request. ##Cheers? Jeers? Questions? Comments? Contact Greg Borenstein - greg [dot] borenstein [at] gmail [dot] com Matthew Williams - matthew [dot] williams [at] gmail [dot] com Also, please don't hesitate to submit issues! ================================================ FILE: Rakefile ================================================ require 'rubygems' require 'rake' require 'rake/clean' require 'rake/testtask' require 'rake/packagetask' require 'rake/gempackagetask' require 'rake/rdoctask' require 'rake/contrib/rubyforgepublisher' require 'fileutils' require 'hoe' RAD_ROOT = File.expand_path(File.dirname(__FILE__)) begin require 'spec/rake/spectask' rescue LoadError puts 'To use rspec for testing you must install rspec gem:' puts '$ sudo gem install rspec' exit end include FileUtils require File.join(File.dirname(__FILE__), 'lib', 'rad', 'version') BIN = "rad" AUTHOR = 'Greg Borenstein' # can also be an array of Authors EMAIL = "greg@mfdz.com" DESCRIPTION = "A framework for programming the Arduino physcial computing platform using Ruby. RAD converts Ruby scripts written using a set of Rails-like conventions and helpers into C source code which can be compiled and run on the Arduino microcontroller." GEM_NAME = 'rad' # what ppl will type to install your gem @config_file = "~/.rubyforge/user-config.yml" @config = nil def rubyforge_username unless @config begin @config = YAML.load(File.read(File.expand_path(@config_file))) rescue puts <<-EOS ERROR: No rubyforge config file found: #{@config_file}" Run 'rubyforge setup' to prepare your env for access to Rubyforge - See http://newgem.rubyforge.org/rubyforge.html for more details EOS exit end end @rubyforge_username ||= @config["username"] end RUBYFORGE_PROJECT = 'rad' # The unix name for your project HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org" DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}" NAME = "rad" REV = nil # UNCOMMENT IF REQUIRED: # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil VERS = Rad::VERSION::STRING + (REV ? ".#{REV}" : "") CLEAN.include ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] RDOC_OPTS = ['--quiet', '--title', 'rad documentation', "--opname", "index.html", "--line-numbers", "--main", "README", "--inline-source"] class Hoe def extra_deps @extra_deps.reject { |x| Array(x).first == 'hoe' } end end # Generate all the Rake tasks # Run 'rake -T' to see list of generated tasks (from gem root directory) hoe = Hoe.new(GEM_NAME, VERS) do |p| p.author = AUTHOR p.description = DESCRIPTION p.email = EMAIL p.summary = DESCRIPTION p.url = HOMEPATH p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT p.test_globs = ["test/**/test_*.rb"] p.clean_globs |= CLEAN #An array of file patterns to delete on clean. # == Optional p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n") p.extra_deps = [ ['RubyToC', '>= 1.0.0'] ] #p.spec_extras = {} # A hash of extra values to set in the gemspec. end CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\n\n") PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}" hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc') desc 'Generate website files' task :website_generate do Dir['website/**/*.txt'].each do |txt| sh %{ ruby scripts/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} } end end desc 'Upload website files to rubyforge' task :website_upload do host = "#{rubyforge_username}@rubyforge.org" remote_dir = "/var/www/gforge-projects/#{PATH}/" local_dir = 'website' sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}} end desc 'Generate and upload website files' task :website => [:website_generate, :website_upload, :publish_docs] desc 'Release the website and new gem version' task :deploy => [:check_version, :website, :release] do puts "Remember to create SVN tag:" puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " + "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} " puts "Suggested comment:" puts "Tagging release #{CHANGES}" end desc 'Runs tasks website_generate and install_gem as a local deployment of the gem' task :local_deploy => [:website_generate, :install_gem] task :check_version do unless ENV['VERSION'] puts 'Must pass a VERSION=x.y.z release version' exit end unless ENV['VERSION'] == VERS puts "Please update your version.rb to match the release version, currently #{VERS}" exit end end desc "Run the specs under spec/models" Spec::Rake::SpecTask.new do |t| t.spec_opts = ['--options', "spec/spec.opts"] t.spec_files = FileList['spec/models/*_spec.rb'] end desc "Default task is to run specs" task :default => :spec ================================================ FILE: bin/rad ================================================ #!/usr/bin/env ruby begin require 'rubygems' rescue LoadError # no rubygems to load, so we fail silently end require 'optparse' require 'fileutils' require 'yaml' require 'open-uri' require 'readline' require File.expand_path(File.dirname(__FILE__)) + "/../lib/rad/version.rb" require File.expand_path(File.dirname(__FILE__)) + "/../lib/rad/progressbar.rb" require File.expand_path(File.dirname(__FILE__)) + "/../lib/rad/linux_installer.rb" require File.expand_path(File.dirname(__FILE__)) + "/../lib/rad/darwin_installer.rb" class OptionParser #:nodoc: def self.parse(args) # defaults options = {"hardware" => { "serial_port" => '/dev/tty.usbserial*', "mcu" => "atmega168", "physical_reset" => false }, "software" => { "arduino_root" => "/Applications/arduino-0012" } } opts = OptionParser.new do |opts| opts.banner = <<-BANNER Build a directory for your RAD Project and install RAD in its vendor sub-directory. Usage: #{File.basename($0)} BANNER opts.on("-p", "--port [SERIAL PORT]", "Path to your serial port", " (default: #{options['hardware']['serial_port']})") do |port| options["hardware"]["serial_port"] = port if port end opts.on("-m", "--mcu [PROCESSOR TYPE]", "Type of processor on your board", " (default: #{options['hardware']['mcu']})") do |port| options["hardware"]["serial_port"] = port if port end opts.on("-r", "--reset [RESET REQUIRED]", "Require a hardware reset before uploading?", " (default: #{options['hardware']['physical_reset']})") do |no_reset| options["hardware"]["physical_reset"] = true unless no_reset end opts.on("-a", "--arduino [ARDUINO DIR]", "Path to your Arduino install", " (default: #{options['software']['arduino_root']})") do |arduino| options["software"]["arduino_root"] = arduino if arduino end opts.on("-v", "--version [VERSION]", "RAD version number", " (#{Rad::VERSION::STRING})") do puts Rad::VERSION::STRING exit end opts.on_tail("-h", "--help", "Show this message") do puts opts exit end end opts.parse!(args) [options, opts] end end # home = ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH'] # begin # config = YAML::load open(home + "/.rad") # rescue # config = false # end # if ARGV[0] == "install" case RUBY_PLATFORM when /linux/ LinuxInstaller.install! when /darwin/ DarwinInstaller.install! else raise "Sorry. Can only install Arduino on Mac OS X. See here for Linux instructions: http://www.arduino.cc/playground/Learning/Linux" end elsif ARGV[0] == "test" test_dir = File.expand_path(File.dirname(__FILE__)) + "/../test/hello_world_test" puts "Compiling hello_world.cpp to test your Arduino." puts "cd #{test_dir}; make depend; make;" `cd #{test_dir}; make depend; make;` puts puts "Compilation successful." puts puts "Make sure your Arduino is connected and then hit return." Readline::readline('') `cd #{test_dir}; make upload` # find the USB port to make sure the Arduino's actually plugged in options, parser = OptionParser.parse(ARGV) usb_port = options["hardware"]["serial_port"] port_name = usb_port.split("/").last port_dir = usb_port.split("/")[0..(usb_port.split("/").length-2)].join("/") unless `ls #{port_dir}`.split(/\n/).any?{|d| d.match(/#{port_name}/)} puts puts "******************************************************" puts "*** It looks like your Arduino is not plugged in. ***" puts "*** Plug it in and try again. ***" puts "*** ***" puts "*** NOTE: If your usb port is not /dev/tty.usb* ***" puts "*** pass it in to this script with the -p option. ***" puts "******************************************************" else puts puts "******************************************************" puts "*** Success! ***" puts "*** If your Arduino's light starts blinking soon, ***" puts "*** then your Arduino environment is ***" puts "*** correctly configured. ***" puts "*** ***" puts "*** Otherwise something is not hooked up properly. ***" puts "******************************************************" end puts puts "cleaning up..." `rm #{test_dir}/hello_world.hex #{test_dir}/core.a #{test_dir}/hello_world.elf` else # Handle options: options, parser = OptionParser.parse(ARGV) sketch_name = ARGV[0] parser.parse!(["-h"]) unless sketch_name # Build vendor/rad: FileUtils.mkdir_p "#{sketch_name}/vendor/rad" puts "Successfully created your sketch directory." FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/rad/.", "#{sketch_name}/vendor/rad" puts "Installed RAD into #{sketch_name}/vendor/rad" puts # Build vendor/libraries: FileUtils.mkdir_p "#{sketch_name}/vendor/libraries" puts "Successfully created your libraries directory." FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/AF_XPort/.", "#{sketch_name}/vendor/libraries/AF_XPort" puts "Installed AF_XPort into #{sketch_name}/vendor/libraries" puts FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/AFSoftSerial/.", "#{sketch_name}/vendor/libraries/AFSoftSerial" puts "Installed AFSoftSerial into #{sketch_name}/vendor/libraries" puts FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/DS1307/.", "#{sketch_name}/vendor/libraries/DS1307" puts "Installed DS1307 into #{sketch_name}/vendor/libraries" puts FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/FrequencyTimer2/.", "#{sketch_name}/vendor/libraries/FrequencyTimer2" puts "Installed FrequencyTimer2 into #{sketch_name}/vendor/libraries" puts FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/I2CEEPROM/.", "#{sketch_name}/vendor/libraries/I2CEEPROM" puts "Installed I2CEEPROM into #{sketch_name}/vendor/libraries" puts FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/LoopTimer/.", "#{sketch_name}/vendor/libraries/LoopTimer" puts "Installed LoopTimer into #{sketch_name}/vendor/libraries" puts FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/OneWire/.", "#{sketch_name}/vendor/libraries/OneWire" puts "Installed OneWire into #{sketch_name}/vendor/libraries" puts FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/Servo/.", "#{sketch_name}/vendor/libraries/Servo" puts "Installed Servo into #{sketch_name}/vendor/libraries" puts FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/Stepper/.", "#{sketch_name}/vendor/libraries/Stepper" puts "Installed Stepper into #{sketch_name}/vendor/libraries" puts FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/SWSerLCDpa/.", "#{sketch_name}/vendor/libraries/SWSerLCDpa" puts "Installed SWSerLCDpa into #{sketch_name}/vendor/libraries" puts FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/SWSerLCDsf/.", "#{sketch_name}/vendor/libraries/SWSerLCDsf" puts "Installed SWSerLCDsf into #{sketch_name}/vendor/libraries" puts FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/Wire/.", "#{sketch_name}/vendor/libraries/Wire" puts "Installed Wire into #{sketch_name}/vendor/libraries" puts # Build examples -- used for basic testing FileUtils.mkdir_p "#{sketch_name}/vendor/libraries" puts "Successfully created your examples directory." FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/examples/.", "#{sketch_name}/examples" puts "Installed examples into #{sketch_name}/examples" puts # Build test -- used testing # FIXME: this should put the tests into the vendor/tests directory instead. # FileUtils.mkdir_p "#{sketch_name}/test" # puts "Successfully created your test directory." # # FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/test/.", "#{sketch_name}/test" # puts "Installed tests into #{sketch_name}/test" # puts # Build vendor/plugins: FileUtils.mkdir_p "#{sketch_name}/vendor/plugins" puts "Successfully created your plugins directory." FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/plugins/.", "#{sketch_name}/vendor/plugins" puts "Installed Default plugins into #{sketch_name}/vendor/plugins" puts # Add an default sketch directory # needed to run test:compile FileUtils.mkdir_p "#{sketch_name}/#{sketch_name}" puts "Successfully created your default sketch directory." # Build sketch files, etc.: FileUtils.touch "#{sketch_name}/#{sketch_name}.rb" File.open("#{sketch_name}/#{sketch_name}.rb", "w") do |file| file << <<-EOS class #{sketch_name.split("_").collect{|c| c.capitalize}.join("")} < ArduinoSketch # looking for hints? check out the examples directory # example sketches can be uploaded to your arduino with # rake make:upload sketch=examples/hello_world # just replace hello_world with other examples def loop # your code here end end EOS end puts "Added #{sketch_name}/#{sketch_name}.rb" File.open("#{sketch_name}/Rakefile", 'w') do |file| file << <<-EOS require 'vendor/rad/init.rb' EOS end puts "Added #{sketch_name}/Rakefile" FileUtils.mkdir_p "#{sketch_name}/config" puts "Added #{sketch_name}/config" File.open("#{sketch_name}/config/hardware.yml", 'w') do |file| file << options["hardware"].to_yaml end puts "Added #{sketch_name}/config/hardware.yml" File.open("#{sketch_name}/config/software.yml", 'w') do |file| file << options["software"].to_yaml end puts "Added #{sketch_name}/config/software.yml" puts puts "Run 'rake -T' inside your sketch dir to learn how to compile and upload it." puts "***************************************************" puts "*** Please note: This version supports ***" puts "*** Arduino 12 only! ***" puts "*** run rad install arduino to upgrade ***" puts "***************************************************" end ================================================ FILE: lib/examples/add_hysteresis.rb ================================================ class AddHysteresis < ArduinoSketch input_pin 3, :as => :sensor output_pin 13, :as => :led def loop reading = add_hysteresis sensor, 8 blink led, 100 if reading > 100 blink led, 1000 if reading <= 100 end end ================================================ FILE: lib/examples/basic_blink.rb ================================================ class BasicBlink < ArduinoSketch # hello world (uncomment to run) output_pin 13, :as => :led def loop blink led, 100 x = 4 end end ================================================ FILE: lib/examples/blink_m_address_assignment.rb ================================================ class BlinkMAddressAssignment < ArduinoSketch # want to use more than one blink m? # since each blink m arrives with the same address, # we can't address each one individually # # so the first thing we need to do is give each one a new address # that's the purpose of this sketch # # install one blinkm at a time # a pa_lcd screen makes this easier # the screen will start at address ten and increment approximately every # four seconds. Pressing during the first four seconds sets the blnikm # address to 10, during the next four seconds to 11 and so on # difficult without a screen. # if you need to, program an led to help with the timing @blink_m_start_address = 10 @flag = false @addr1 = "10, byte" @addr2 = "11, byte" @addr3 = "12, byte" output_pin 19, :as => :wire, :device => :i2c, :enable => :true # reminder, true issues wire.begin input_pin 7, :as => :button_one, :device => :button input_pin 8, :as => :button_two, :device => :button input_pin 9, :as => :button_three, :device => :button output_pin 5, :as => :my_lcd, :device => :pa_lcd, :rate => 19200, :clear_screen => :true def setup delay 1000 my_lcd.setxy 0,0, "bienvenue" delay 5000 end def loop if @flag == false staging else test_address end delay 100 end def staging my_lcd.setxy 0,0, "press button one to" my_lcd.setxy 0,1, "set address to " my_lcd.print @blink_m_start_address my_lcd.setxy 0,2, "or two for status" delay 60 my_lcd.setxy 0,3, " " my_lcd.setxy 0,3 800.times do |i| return 0 if @flag == true my_lcd.print "." if i % 50 == 0 delay 5 if button_one.read_input assign_address elsif button_two.read_input test_address end end @blink_m_start_address += 1 end def assign_address @flag = true my_lcd.clearscr "setting to " my_lcd.print @blink_m_start_address delay 100 BlinkM_setAddress @blink_m_start_address my_lcd.clearscr "done" control_it end def control_it delay 500 my_lcd.clearscr "stopping script" BlinkM_stopScript @blink_m_start_address my_lcd.clearscr "stopping script.." delay 500 my_lcd.clearscr "fade to purple.." BlinkM_fadeToRGB(@blink_m_start_address, 0xff,0x00,0xff) my_lcd.clearscr "fade to purple" delay 500 BlinkM_fadeToRGB(@blink_m_start_address, 0xff,0x00,0xff) end def test_address my_lcd.clearscr my_lcd.setxy 0,0, "testing address" my_lcd.setxy 0,1 my_lcd.print blink_m_check_address_message @blink_m_start_address delay 5000 end end ================================================ FILE: lib/examples/blink_m_hello.rb ================================================ class BlinkMHello < ArduinoSketch # just a scaffolding for blink_m_demo output_pin 19, :as => :wire, :device => :i2c, :enable => :true def loop x = 4 end end ================================================ FILE: lib/examples/blink_m_multi.rb ================================================ class BlinkMMulti < ArduinoSketch # demonstrate control of individual blinkms # this assumes the leds have been assigned addresses 10, 11, 12 # which can be done with blink m address assignment # two ways to address the blinkms, array and individual variables @blink_addresses = [10,11,12] @addr_all = "0, byte" @addr1 = "10, byte" @addr2 = "11, byte" @addr3 = "12, byte" output_pin 19, :as => :wire, :device => :i2c, :enable => :true # reminder, true issues wire.begin input_pin 7, :as => :button_one, :device => :button input_pin 8, :as => :button_two, :device => :button input_pin 9, :as => :button_three, :device => :button input_pin 10, :as => :button_four, :device => :button # display the action on a 4x20 pa_lcd, yours may be 9200 instead of 19,200 output_pin 5, :as => :my_lcd, :device => :pa_lcd, :rate => 19200, :clear_screen => :true def loop stop_and_fade(@addr1) if button_one.read_input stop_and_fade(@addr2) if button_two.read_input stop_and_fade(@addr3) if button_three.read_input dance if button_four.read_input end def stop_and_fade(addr) f = 1 + addr # hack to coerce addr to int my_lcd.clearscr my_lcd.setxy 0,0, "blinkm # " my_lcd.print addr delay 700 BlinkM_stopScript addr my_lcd.setxy 0,1, "stopping script.." delay 700 my_lcd.setxy 0,2, "fade to purple.." BlinkM_fadeToRGB(addr, 0xff,0x00,0xff) end def dance BlinkM_setFadeSpeed(@addr_all, 20) # 1-255, with 1 producing the slowest fade my_lcd.clearscr my_lcd.setxy 0,0, "Do the shimmy.." my_lcd.setxy 0,1 @blink_addresses.each do |a| BlinkM_fadeToRGB(a, 1,166,138) delay 100 end @blink_addresses.each do |a| BlinkM_fadeToRGB(a, 35,0,112) delay 100 end end end ================================================ FILE: lib/examples/blink_with_serial.rb ================================================ class BlinkWithSerial < ArduinoSketch # hello world (uncomment to run) @i = "0, long" output_pin 13, :as => :led serial_begin def loop @i += 1 serial_println @i blink led, 100 end end ================================================ FILE: lib/examples/configure_pa_lcd_boot.rb ================================================ class ConfigurePaLcdBoot < ArduinoSketch ## important! ## most pa_lcd rates are set to 9200, but there are some newer at 19200 ## if you have a 19200, uncomment the end of line 38 ## purpose: ## change cursor to none ## and add custom boot screen ## ## jd's preferred setup for pa_lcd ## ## assumes 4 x 20 pa_lcd ## ## no blinking cursor press button 1 ## configure custom start up screen - press button 2 ## configure lcd to use custom startup screen - press button 3 ## ## press buttons one, two and three ## or season to taste ## ## refernce ## K107 LCD Controller Board Manual ## page 11 for cursors ## page 13 for custom boot ## http://wulfden.org/downloads/manuals/K107manual.pdf ## ## ## set pins to your setup input_pin 8, :as => :button_one, :device => :button input_pin 9, :as => :button_two, :device => :button input_pin 10, :as => :button_three, :device => :button ## note, most of these controllers are set to 9200 output_pin 14, :as => :my_lcd, :device => :pa_lcd #, :rate => 19200 def loop set_cursor if button_one.read_input set_custom_screen if button_two.read_input change_boot_to_custom if button_three.read_input end ## assumes 4 x 20 screen ## maintain 20 characters after ?Cn ## wny delays? the controller needs them to give it ## enough time to write 20 bytes to internl EEPROM def set_custom_screen my_lcd.clearscr my_lcd.print "?C0 RAD & Arduino " delay 400 my_lcd.print "?C1 Development " delay 400 my_lcd.print "?C2 " delay 400 my_lcd.print "?C3 v0.3.0 " end ## ?c0 for no cursor ## ?c2 for non blinking cursor ## ?c3 for blinking cursor def set_cursor my_lcd.clearscr my_lcd.print "Changing to " my_lcd.setxy 0,1 my_lcd.print "no cursor. " my_lcd.setxy 0,3 my_lcd.print "Reboot to view... " my_lcd.print("?c0") end ## "?S0 for blank screen ## ?S1 for configuration settings ## ?S2 for custom text screen def change_boot_to_custom my_lcd.clearscr my_lcd.print "Changing to " my_lcd.setxy 0,1 my_lcd.print "custom boot screen. " my_lcd.setxy 0,3 my_lcd.print "Reboot to view... " my_lcd.print("?S2") end end ================================================ FILE: lib/examples/debounce_methods.rb ================================================ class DebounceMethods < ArduinoSketch output_pin 13, :as => :led input_pin 6, :as => :button_one, :device => :button # can also :adjust => 300 input_pin 7, :as => :button_two, :device => :button input_pin 8, :as => :button_three, :device => :button input_pin 9, :as => :button_four, :device => :button input_pin 10, :as => :button_five, :device => :button # depressing and releasing button_one, button_two or button_four do the same thing # with a slightly different syntax and number of blinks # button_three simply toggles the led with the read_and_toggle method # button_five does it with a twist def loop blink_twice if read_input button_one blink_three_times if read_input button_two button_three.read_and_toggle led # blink_three_times_basic if read_input button_four blink_with_a_twist if read_input button_five end def blink_twice 2.times do |i| led.blink 200 + i end end def blink_three_times 3.times { led.blink 200 } end # no blink helper def blink_three_times_basic 4.times do led.digitalWrite HIGH delay 200 led.digitalWrite LOW delay 200 end end def blink_with_a_twist 20.times do |i| led.blink i * 10 end end end ================================================ FILE: lib/examples/external_variable_fu.rb ================================================ class ExternalVariableFu < ArduinoSketch @one = int @two = long @three = unsigned @four = short @five = byte @six = 1 @seven = 1.2 @eight = "0x00" @nine = "arduino" @ten = true @eleven = false @twelve = "1, long" @thirteen = "1, unsigned" @fourteen = "1, byte" @fifteen = HIGH @sixteen = LOW @seventeen = ON @eighteen = OFF def loop delay @six end end ================================================ FILE: lib/examples/external_variables.rb ================================================ class ExternalVariables < ArduinoSketch define "KOOL 10" define "TRUE 1" define "COMMENT true" define "DS1307_CTRL 7" define "DS1308_CTRL 7" array "char buffer[32];" array "char bufferz[32];" @foo = 1 @bidda = "badda" @boom = "1, int" @rad = "1.00" def loop delay 1 @foo = 2 @foo = KOOL end def setup # special one time only method delay 100 delay 100 @foo = 10 5.times { delay 200 } end end ================================================ FILE: lib/examples/first_sound.rb ================================================ class FirstSound < ArduinoSketch output_pin 11, :as => :myTone, :device => :freq_out, :frequency => 100 # frequency required def loop myTone.disable 1.upto(400) { |x| tone_out x } # run up the scale to 4000 Hz in 10 Hz steps 399.downto(1) { |x| tone_out x } # come back down in 10 Hz steps delay 2000 end def tone_out(n) myTone.set_frequency 10*n myTone.enable delay 80 myTone.disable delay 10 end end ================================================ FILE: lib/examples/frequency_generator.rb ================================================ class FrequencyGenerator < ArduinoSketch # need explaination output_pin 11, :as => :myTone, :device => :freq_out, :frequency => 100 def loop uh_oh 4 end def uh_oh(n) n.times do myTone.enable myTone.set_frequency 1800 delay 500 myTone.disable delay 100 myTone.enable myTone.set_frequency 1800 delay 800 myTone.enable end # hack to help translator guess that n is an int f = n + 0 end end ================================================ FILE: lib/examples/hello_array.rb ================================================ class HelloArray < ArduinoSketch # still working this out... # for example, new instance style array declaration naming # is at odds with original style array naming # for simple integer, string, float, and boolean arrays @toppings = [1,2,3] @names = ["ciero", "bianca", "antica"] # when we just need to declare an array, or need more control, such as specific type requirements array "int ingredients[10]" array "int pizzas[] = {1,2,3,4}" output_pin 5, :as => :my_lcd, :device => :pa_lcd, :rate => 19200, :clear_screen => :true def loop my_lcd.clearscr "toppings: " delay 500 @toppings.each do |a| my_lcd.print a my_lcd.print " " delay 500 end my_lcd.setxy 0,1, "pizzas: " pizzas.each do |p| my_lcd.print p my_lcd.print " " delay 500 end my_lcd.setxy 0,2, "names: " @names.each do |p| my_lcd.print p my_lcd.print " " delay 500 end end end ================================================ FILE: lib/examples/hello_array2.rb ================================================ class HelloArray2 < ArduinoSketch # ---------------------------------------------------------------------- # Checking out various array operations # # JD Barnhart - Seattle, WA July 2008 # Brian Riley - Underhill Center, VT, USA July 2008 # # # ---------------------------------------------------------------------- # still working this out... # for example, new instance style array declaration naming # is at odds with original style array naming define "THROWAWAY 0" # for simple integer, string, float, and boolean arrays @toppings = [1,2,3] @names = ["ciero", "bianca", "zeus", "athena", "apollo"] # when we just need to declare an array, or need more control, such as specific type requirements array "int ingredients[10]" array "int pizzas[] = {1,2,3,4}" array "byte buffer[20] = {'A', 'B', 'Z', 'C', 'Y', 'D', 'W', 'E', '%', 'H', '*', '!', ')', '=', 'P', '-', '+', 'R', 'I', 'K'}" ## multidimensional arrays array 'int @my_numbers[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}' array 'char* @pizzas[2][4] = {{"margherita","funghi","napoletana","prosciutto cotto"},{"veggie","pepperoni","cheese","kitchen sink"}}' output_pin 5, :as => :my_lcd, :device => :pa_lcd, :rate => 19200, :clear_screen => :true def setup my_lcd.clearscr "toppings: " delay 500 @toppings.each do |a| my_lcd.print a my_lcd.print " " delay 500 end my_lcd.setxy 0,1, "pizzas: " pizzas.each do |p| my_lcd.print p my_lcd.print " " delay 500 end my_lcd.setxy 0,2, "names: " @names.each do |p| my_lcd.print p my_lcd.print " " delay 500 end delay 3000 my_lcd.clearline 1, @names[2] my_lcd.print " [ " my_lcd.print pizzas[1] my_lcd.print " ]" delay 2000 my_lcd.clearscr "Multidimensional ?n" 0.upto(2) do |f| 0.upto(3) do |s| my_lcd.print @my_numbers[f][s] my_lcd.print ", " delay 500 end end delay 1000 my_lcd.clearscr 0.upto(1) do |f| 0.upto(3) do |s| my_lcd.print @pizzas[f][s] my_lcd.print ", " delay 500 end end delay 2000 my_lcd.clearscr "Array Load?n" 1.upto(20) do |x| # buffer[x] = 64 + x # we cannot set array elements yet except to initialize in declaration my_lcd.print buffer[x-1] my_lcd.print " " end end def loop x = THROWAWAY end end ================================================ FILE: lib/examples/hello_array_eeprom.rb ================================================ class HelloArrayEeprom < ArduinoSketch # ---------------------------------------------------------------------- # Checking out various array operations with I2C serial EEPROM # doing block writes and bloack readbacks with byte arrays # # JD Barnhart - Seattle, WA July 2008 # Brian Riley - Underhill Center, VT, USA July 2008 # # # ---------------------------------------------------------------------- # still working this out... # for example, new instance style array declaration naming # is at odds with original style array naming define "THROWAWAY 0" # when we just need to declare an array, or need more control, such as specific type requirements array "byte page_data[20] = {'R', 'A', 'D', ' ', 'i', 's', ' ', 'B', 'A', 'D', '*', '!', ')', '=', 'P', '-', '+', 'R', 'I', 'K'}" array "byte in_buffer[20]" output_pin 19, :as => :mem0, :device => :i2c_eeprom, :address => 1 # w/o :address defaults to :address => 0 which is 0x50 output_pin 14, :as => :my_lcd, :device => :pa_lcd, :rate => 19200 def setup my_lcd.clearscr " I2C EEPROM Demo" my_lcd.setxy 0, 1, "block write and read" my_lcd.setxy 0, 2, " back and display" my_lcd.setxy 0, 3, " to the LCD" delay 2000 my_lcd.clearscr " I2C EEPROM Demo?n block write" mem0.write_page 0x0100, page_data, 20 delay 1000 my_lcd.clearline 1, " block readback" mem0.read_buffer 0x0100, in_buffer, 20 my_lcd.setxy 0, 2 1.upto(20) do |x| my_lcd.print in_buffer[x-1] my_lcd.print " " end end def loop x = THROWAWAY end end ================================================ FILE: lib/examples/hello_clock.rb ================================================ class HelloClock < ArduinoSketch # ---------------------------------------------------------------------------------- # Time and Temp (20 July 2008) # Example #1 - Brian Riley, Underhill Center, VT USA # # Connections # I2C bus - DS1307 Real Time Clock chip # Analog 0 (a.k.a Digital 14) - Wulfden K107 seria LCD Controller # Peter Anderson chip # # Comment # - This is a straight forward program to read the Real Time Clock and Display # delay() calls waiting for temperature conversion readings # # - for the external data busses make sure you have 4.7K pullup resistors on the # the SDA/SCL (I2C) # # ---------------------------------------------------------------------------------- @flag = int array "byte clock[8]" @days = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"] @months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"] # implicit in :device => :ds1307 is that this i i2c # :enable => true issues the Wire.begin to ick over i2c output_pin 19, :as => :rtc, :device => :i2c_ds1307, :enable => :true # software serial tx drives LCD display, screen cleared at startup # defines the softare protocol for controller as Peter Anderson output_pin 14, :as => :myLCD, :device => :pa_lcd, :rate => 19200, :clear_screen => :true loop_timer :as => :mainloop def setup myLCD.clearscr " ----" myLCD.setxy 1,3, "looptime = " rtc.get clock, 1 print_main @flag = 1 end def loop mainloop.track myLCD.setxy 12,3, mainloop.get_total rtc.get clock, 1 if clock[0] == 0 if @flag == 0 print_main @flag = 1 end else @flag = 0 end myLCD.setxy 6,2 printlz clock[2] myLCD.print ":" printlz clock[1] myLCD.print ":" printlz clock[0] delay 50 end def printlz(w) myLCD.print "0" if w < 10 myLCD.print w end def print_main myLCD.setxy 1,1, @days[clock[3]-1] myLCD.print ", " myLCD.print @months[clock[5]-1] myLCD.print " " printlz clock[4] myLCD.print ", " printlz clock[6] + 2000 end end ================================================ FILE: lib/examples/hello_eeprom.rb ================================================ class HelloEeprom < ArduinoSketch output_pin 19, :as => :rtc, :device => :i2c_ds1307, :enable => :true output_pin 19, :as => :mem0, :device => :i2c_eeprom output_pin 14, :as => :myLCD, :device => :pa_lcd, :rate => 19200 def loop myLCD.setxy 0,0 # set to 0,0 myLCD.print rtc.get(5, 1) # refresh registers (=1) get month myLCD.print "/" myLCD.print rtc.get(4, 0) # no need to refresh (=0) get day myLCD.print "/" myLCD.print rtc.get(6, 0) # get year myLCD.setxy(0,1) # set in 1 byte line 1 (second line) printlz 2 # print hours with lead zero myLCD.print ":" printlz 1 # print minutes with lead zero myLCD.print ":" printlz 0 # print seconds with lead zero myLCD.setxy 10,0 myLCD.print "write test" myLCD.setxy 0,2 32.upto(109) do # write address of byte to that b yte |x| mem0.write_byte x, x myLCD.print(".") if x%2 delay 10 end delay 2000 myLCD.clearline 2 # clears bottom two lines myLCD.clearline 3 myLCD.setxy 10,0, "read test " myLCD.setxy 0,2 # read and print 39 addresses with printable numbers 75.upto(113) { |x| myLCD.print(mem0.read_byte(x)) } delay 10000 myLCD.clearscr end def printlz(w) i = 0 + rtc.get(w,0) # the '0 +' is YARH (Yet Another RubyToc Hack) myLCD.print "0" if i < 10 myLCD.print i end end ================================================ FILE: lib/examples/hello_eeprom_lcdpa.rb ================================================ class HelloEepromLcdpa < ArduinoSketch # ----------------------------------------------------------------------- # Simple Byte Write and Byte Read-back of I2C EEPROM # # Brian Riley - Underhill Center, VT, USA July 2008 # # # I2C Routines are in a plugin not a library # No block reads and write yet # Displays to PH Anderson based serial LCD Display # # I2C Serial EEPROM - Byte Read and Byte Write # # i2c_eeprom_write_byte dev_addr, chip_addr, value # # dev_addr (byte) - range 0x50 to 0x57 determined by hardware wiring # chip_addr (unsigned) - 0 to as much as 64K, depends on chip # value (byte) - 0 to 255 (0x00 to 0xFF) # # returns - nothing # # i2c_eeprom_read_byte dev_addr, chip_addr # # dev_addr (byte) - range 0x50 to 0x57 determined by hardware wiring # chip_addr (unsigned) - 0 to as much as 64K, depends on chip # # returns - byte value # # # http://www.arduino.cc/playground/Code/I2CEEPROM # ---------------------------------------------------------------------- output_pin 19, :as => :mem0, :device => :i2c_eeprom, :enable => :true output_pin 14, :as => :myLCD, :device => :pa_lcd, :rate => 19200 def setup delay 1500 # give startup screen time to finish and clear myLCD.clearscr " I2C EEPROM Demo" myLCD.setxy 0, 1, "byte write then read" myLCD.setxy 0, 2, " back and display" myLCD.setxy 0, 3, " to the LCD" clear_off_test myLCD.clearline 1, " byte write test" myLCD.setxy 0, 2 32.upto(109) do # write address of byte to that b yte |x| mem0.write_byte x, x+7 myLCD.print(".") if x%2 delay 10 # EEPROM write _requires_ 3-10 ms pause end clear_off_test myLCD.clearline 1, " byte read test " myLCD.setxy 0, 2 # read and print 39 addresses with printable numbers 70.upto(105) { |x| myLCD.print(mem0.read_byte(x)) } delay 2000 clear_off_test myLCD.clearline 1, "-< tests complete >- " end def loop x = 4 # loop has to have _something_ end def clear_off_test # clears bottom two lines delay 2000 myLCD.clearline 3 myLCD.clearline 2 # leaves you at start of a # cleared third line end end ================================================ FILE: lib/examples/hello_format_print.rb ================================================ class HelloFormatPrint < ArduinoSketch # ---------------------------------------------------------------------- # Demonstrattion of Crude Adaptaion of C Function sprintf() # to do formatted printing. For now there are some absolutes: # The write_line method atkes as arguemnst the formatting string # and the appropriate arguments. It format them to an internal # buffer sepcified and created when you invoke formatted printing # formatted_print :as => :line_buf, :buffer_size => 80 # now, to actual do it you use write_line # write_line "Pies $%02d.%02d", pie_cents/100, pie_cents%100 # then print the string pointed at by string_line # my_lcd.setxy 3, 2, line_buf # # Brian Riley - Underhill Center, VT, USA Aug 2008 # # # ---------------------------------------------------------------------- # demonstrate 4 x 20 pa_lcd toggle between normal and Bignum mode # with @toggle external variable thrown in for fun # change your pins to suit your setup @toggle = "0, int" @pie_cents = "403, int" @pie_price = "7.08" input_pin 8, :as => :button_one, :device => :button input_pin 9, :as => :button_two, :device => :button input_pin 10, :as => :button_three, :device => :button formatted_print :as => :string_line, :buffer_size => 65 # generally this statement should precede any serial_begin or # LCD display directive output_pin 14, :as => :my_lcd, :device => :pa_lcd, :rate => 19200, :clear_screen => :true def setup my_lcd.clearscr " ----?nOne, Two, or Three" end def loop if millis % 500 == 0 write_line "millis()= %ld", millis my_lcd.setxy 1, 2, string_line end say_hello if button_one.read_input say_more if button_two.read_input say_it_large if button_three.read_input end def say_hello @toggle = true my_lcd.clearscr "This sketch has?nbeen running for?n " write_line "%ld mins and %d secs?n", millis/60000, (millis/1000)%60 my_lcd.print string_line delay 3000 my_lcd.clearscr " ----?nOne, Two, or Three" end def say_more # passing print strings to home and setxy (also works on clearscr) @toggle = false my_lcd.clearscr "Food Store Prices" write_line "Pies $%2d.%02d", @pie_cents/100, @pie_cents%100 # write_line "Pies $%6.2f", @pie_price # float doessn't seem to work ..... my_lcd.setxy 2, 1, string_line # write_line "toggle state is [%s]", @toggle ? "ON" : "OFF" # RubyToC screws this construct up and RAD mistajekl put 1 ad 0 # in place of "ON" and "OFF" write_line "toggle state is [%d]", @toggle my_lcd.setxy 2, 3, string_line delay 3000 my_lcd.clearscr " ----?nOne, Two, or Three" end def say_it_large my_lcd.intoBignum my_lcd.clearscr # line 0, col 0 1.upto(32) do |i| my_lcd.setxy 0,1 my_lcd.print i * i delay 200 end my_lcd.outofBignum delay 3000 my_lcd.clearscr " ----?nOne, Two, or Three" end end ================================================ FILE: lib/examples/hello_lcd_charset.rb ================================================ class HelloLcdCharset < ArduinoSketch # ------------------------------------------------------------------------- # Program to Display the entire lower half (under 0x80) character set # # The class variable @a defined as byte is needed to make RubyToC put # the value to be 'printed' as a byte and thus give us the character # that value represents. # # Brian Riley - Underhill Center, VT, USA July 2008 # # # ---------------------------------------------------------------------- @a = byte output_pin 14, :as => :myLCD, :device => :pa_lcd, :rate => 19200 output_pin 13, :as => :led def loop myLCD.clearscr "Alphabet Chars?n" 0x41.upto(0x5a) do |i| # A to Z @a = i # forces 'byte' typing to variable myLCD.print @a # so print rouien prints character represented delay 50 # by the index value end 0x61.upto(0x7a) do |i| # a to z @a = i myLCD.print @a delay 50 end delay 3000 myLCD.clearscr "Numeric Chars?n" 0x30.upto(0x39) do |i| # 0 to 9 @a = i myLCD.print @a delay 50 end delay 3000 myLCD.clearscr "Other Chars?n" 0x21.upto(0x2f) do |i| # punctuation et al @a = i myLCD.print @a delay 50 end 0x3a.upto(0x40) do |i| @a = i myLCD.print @a delay 50 end 0x5b.upto(0x60) do |i| @a = i myLCD.print @a delay 50 end 0x7b.upto(0x7f) do |i| @a = i myLCD.print @a delay 50 end delay 3000 end end ================================================ FILE: lib/examples/hello_pa_lcd.rb ================================================ class HelloPaLcd < ArduinoSketch # demonstrate 4 x 20 pa_lcd toggle between normal and Bignum mode # with @toggle external variable thrown in for fun # change your pins to suit your setup @toggle = false input_pin 6, :as => :button_one, :device => :button input_pin 7, :as => :button_two, :device => :button input_pin 8, :as => :button_three, :device => :button output_pin 5, :as => :my_lcd, :device => :pa_lcd, :rate => 19200, :clear_screen => :true def setup delay 3000 my_lcd.setxy 0,0 my_lcd.print "Press button" my_lcd.setxy 0,1 my_lcd.print "One, two or three...." end def loop say_hello if button_one.read_input say_more if button_two.read_input say_it_large if button_three.read_input end def say_hello @toggle = true my_lcd.clearscr "Any sufficiently advanced technology" my_lcd.setxy 0,2 my_lcd.setxy 0,3, "toggle state: " my_lcd.print @toggle end def say_more # passing print strings to home and setxy (also works on clearscr) @toggle = false my_lcd.clearscr "is indistinguishablefrom magic" my_lcd.setxy 0,3, "toggle state: " my_lcd.print @toggle end def say_it_large my_lcd.intoBignum my_lcd.clearscr # line 0, col 0 1.upto(32) do |i| my_lcd.setxy 0,1 my_lcd.print i * i delay 200 end my_lcd.outofBignum end end ================================================ FILE: lib/examples/hello_servos.rb ================================================ class HelloServos < ArduinoSketch output_pin 2, :as => :servo_1, :max => 2400, :min => 800 output_pin 3, :as => :servo_2, :max => 2400, :min => 800 output_pin 4, :as => :servo_3, :max => 2400, :min => 800 # time to go old school def loop song_sheet_two end def song_sheet_two e d e d c d d c b c b a e a e a e a b c b c d d c d e d e end def a pulse_servo servo_1, 1450 delay 100 home servo_1 delay 20 end def b pulse_servo servo_1, 1350 delay 100 home servo_1 delay 20 end def c pulse_servo servo_2, 1450 delay 100 home servo_2 delay 20 end def d pulse_servo servo_2, 1350 delay 100 home servo_2 delay 20 end def e pulse_servo servo_3, 1500 delay 100 home servo_3 delay 20 end # center servos def home(s) pulse_servo s, 1400 f = s + 0 end end ================================================ FILE: lib/examples/hello_spectra_sound.rb ================================================ class HelloSpectraSound < ArduinoSketch # demonstrate capability to use soft pot as traditional pot # the last pot reading remains "locked" to the last touch point # similar same behavior as ipod # # this sketch assumes a pa_lcd operating at 19200 and one # spectra symbol softpot connected to analog pin 3 # @reading = int output_pin 14, :as => :my_lcd, :device => :pa_lcd, :rate => 9600, :clear_screen => :true output_pin 11, :as => :sound, :device => :freq_out, :frequency => 100, :enable => :true input_pin 3, :as => :sensor_one, :device => :spectra def setup delay 1000 my_lcd.setxy 0,0, "spectra symbol" my_lcd.setxy 0,1, "soft pot sound" delay 3000 my_lcd.clearscr end def loop my_lcd.setxy 0,1 # since lcd's have issues clearing tens and hundreds digits when reading ones, # we use pad_int_to_str, which is a hack to display these cleanly # pad_int_to_str takes two arguments: an integer and the final string length # # my_lcd.print pad_int_to_str analogRead(sensor_one), 5 @reading = sensor_one.soft_lock sound.set_frequency @reading * 10 my_lcd.print pad_int_to_str @reading, 3 delay 30 end end ================================================ FILE: lib/examples/hello_world.rb ================================================ class HelloWorld < ArduinoSketch output_pin 13, :as => :led def loop blink led, 100 end end ================================================ FILE: lib/examples/hello_xbee.rb ================================================ class HelloXbee < ArduinoSketch output_pin 13, :as => :led serial_begin def loop led.blink 200 serial_print "...testing..." delay 1000 end end ================================================ FILE: lib/examples/hysteresis_duel.rb ================================================ class HysteresisDuel < ArduinoSketch # purpose # side by side demo of affect of hysteresis on two different sensor readings # # # requires one pa_lcd # two sensors or potentiometers output_pin 5, :as => :my_lcd, :device => :pa_lcd, :rate => 19200, :clear_screen => :true input_pin 1, :as => :sensor_one, :device => :sensor input_pin 2, :as => :sensor_two, :device => :sensor def setup delay 1000 my_lcd.setxy 0,0, "hysteresis duel" delay 5000 my_lcd.clearscr end def loop my_lcd.setxy 0,0, "direct" my_lcd.setxy 0,1, "one: " my_lcd.print analogRead sensor_one my_lcd.print " two: " my_lcd.print analogRead sensor_two my_lcd.setxy 0,2, "with hysteresis" my_lcd.setxy 0,3, "one: " my_lcd.print sensor_one.with_hyst 4 my_lcd.print " two: " my_lcd.print sensor_two.with_hyst 4 delay 230 end end ================================================ FILE: lib/examples/i2c_with_clock_chip.rb ================================================ class I2cWithClockChip < ArduinoSketch # ---------------------------------------------------------------------------------- # Time and Temp (20 July 2008) # Example #1 - Brian Riley, Underhill Center, VT USA # # Connections # I2C bus - DS1307 Real Time Clock chip # Analog 0 (a.k.a Digital 14) - Wulfden K107 seria LCD Controller # Peter Anderson chip # Digital 8 - Dallas SemiConductor DS18B20 One-Wire temperature Sensor (12 bit) # # Comment # - This is a straight forward, program with minimal error checking and brute force # delay() calls waiting for temperature conversion readings # # - for the external data busses make sure you have 4.7K pullup resistors on the # data line (OnewWire) and the SDA/SCL (I2C) # ---------------------------------------------------------------------------------- @hi_byte = int @lo_byte = int @t_reading = int @device_crc = int @sign_bit = int @tc_100 = int # implicit in :device => Z:ds1307 is that this i i2c # :enable => true issues the Wire.begin to ick over i2c output_pin 19, :as => :rtc, :device => :i2c_ds1307, :enable => :true # software serial tx drives LCD display, screen cleared at startup # defines the softare protocol for controller as Peter Anderson output_pin 14, :as => :myLCD, :device => :pa_lcd, :rate => 19200, :clear_screen => :true # defines this pin as being connected to a DalSemi 1-Wire device # no specific device drivers yet, the specific device code is on you output_pin 8, :as => :myTemp, :device => :onewire def loop until myTemp.reset do # reset bus, verify its clear and high clear_bottom_line myLCD.print " <1Wire Buss Error>" delay 2000 end myTemp.skip # "listen up - everybody!" myTemp.write 0x44, 1 # temperature sensors, strta conversion myLCD.setxy 6,0 # while they do that, lets print date/time myLCD.print rtc.get(5, 1) myLCD.print "/" myLCD.print rtc.get(4, 0) myLCD.print "/" myLCD.print rtc.get(6, 0) myLCD.setxy 6,1 printlz rtc.get(2, 0) myLCD.print ":" printlz rtc.get(1, 0) myLCD.print ":" printlz rtc.get(0, 0) delay 800 # conversion takes about 750 msecs until myTemp.reset do # reset bus, verify its clear and high clear_bottom_line myLCD.print " <1Wire Buss Error>" delay 2000 end myTemp.skip # listen up! myTemp.write 0xBE, 1 # send me your data conversions @lo_byte = myTemp.read # get irst byte @hi_byte = myTemp.read # get second byte # ------------------------------------------------------------- clear_bottom_line # this code is debug - not necessary myLCD.setxy 4,3 # raw hex display of temp value myLCD.print "raw = 0x" print_hexbyte @hi_byte # prints 2 digit hex w/lead 0 print_hexbyte @lo_byte # ------------------------------------------------------------- 7.times { @device_crc = myTemp.read } # get next 6 bytes, drop them on floor # next byte the ninth byte is the CRC # DS18B20 brings data temperature back as 12 bits # in degrees centigrade with 4 bits fractional, that is # each bit s 1/16 of a degreeC @t_reading = build_int @hi_byte, @lo_byte @sign_bit = bit_and @t_reading, 0x8000 @t_reading = twos_comp @t_reading if @sign_bit # negative @tc_100 = (6 * @t_reading) + (@t_reading / 4) #multiply by (100 * 0.0625) or 6.25 myLCD.setxy 2,2 if @sign_bit myLCD.print "-" else myLCD.print " " end myLCD.print(@tc_100 / 100) # separate off the whole myLCD.print "." printlz(@tc_100 % 100) # and fractional portions myLCD.print " degrees C" end def printlz(w) myLCD.print "0" if w < 10 myLCD.print w end def print_hexbyte(w) myLCD.print "0" if w < 0x10 myLCD.print w, 0x10 end def clear_bottom_line myLCD.setxy 0,3 myLCD.print "?l" end end ================================================ FILE: lib/examples/midi_beat_box.rb ================================================ class MidiBeatBox < ArduinoSketch # midi synthesiser output on channel 2 # with speed controlled by spectra soft pot @channel = 2 input_pin 1, :as => :sensor_one, :device => :spectra output_pin 13, :as => :led serial_begin :rate => 31250 def setup delay 3000 end def loop 8.times {first} 2.times do second third end 4.times {first} 2.times {second} end def first play 39, 52, 37 play 0, 0, 0 play 36, 52, 0 play 37, 52, 39 play 37, 0, 0 play 36, 0, 0 play 39, 50, 0 play 0, 0, 0 play 52, 36, 37 play 0, 0, 0 play 39, 0, 0 play 36, 37, 0 play 36, 37, 39 play 36, 38, 0 play 50, 0, 0 play 0, 0, 0 end def second play 39, 52, 37 play 36, 0, 0 play 0, 0, 0 play 37, 52, 39 play 38, 0, 0 play 36, 0, 0 play 39, 50, 0 play 0, 0, 0 end def third play 0, 36, 37 play 0, 0, 0 play 39, 36, 0 play 36, 37, 50 play 36, 37, 39 play 36, 37, 0 play 50, 0, 0 play 39, 0, 0 end def play(one, two, three) n = 1 + one + two + three # ack to coerce parameters to int note_on(@channel, one, 127) unless one == 0 note_on(@channel, two, 127) unless two == 0 note_on(@channel, three, 127) unless three == 0 delay 310 - sensor_one.soft_lock # start slowly note_off(@channel, one, 0) unless one == 0 note_off(@channel, two, 0) unless two == 0 note_off(@channel, three, 0) unless three == 0 end end ================================================ FILE: lib/examples/midi_scales.rb ================================================ class MidiScales < ArduinoSketch # purpose # trigger midi output with buttons and # spectra soft pots # # @current_note = int @last_note_one = 0 @last_note_two = 0 @last_note_three = 0 @note = int input_pin 1, :as => :sensor_one, :device => :spectra input_pin 2, :as => :sensor_two, :device => :spectra input_pin 3, :as => :sensor_three, :device => :spectra input_pin 7, :as => :button_one, :device => :button input_pin 8, :as => :button_two, :device => :button input_pin 9, :as => :button_three, :device => :button output_pin 13, :as => :led serial_begin :rate => 31250 def setup delay 3000 end def loop change_tone if button_one.read_input change_pressure if button_two.read_input change_channels if button_three.read_input read_sensor_one read_sensor_two read_sensor_three end def change_tone 110.upto(127) do |note| play 0, note, 127 end end def change_pressure 110.upto(127) do |pressure| play 0, 45, pressure end end def change_channels 0.upto(6) do |channel| play channel, 50, 100 end end def read_sensor_one @current_note = sensor_one.soft_lock pre_play(@current_note, @last_note_one, 13) @last_note_one = @current_note end def read_sensor_two @current_note = sensor_two.soft_lock pre_play(@current_note, @last_note_two, 14) @last_note_two = @current_note end def read_sensor_three @current_note = sensor_three.soft_lock pre_play(@current_note, @last_note_three, 15) @last_note_three = @current_note end def pre_play(current_note, last_note, channel) # warning, don't use last as a parameter... n = 1 + channel unless current_note == last_note @note = ((current_note /16) + 40) play_with_no_delay( channel, @note, 100 ) end end def play(chan, note, pressure) note_on(chan, note, pressure) delay 100 # adjust to need note_off(chan, note, 0) end def play_with_no_delay(chan, note, pressure) # note is not turned off note_on(chan, note, pressure) end end ================================================ FILE: lib/examples/motor_knob.rb ================================================ class MotorKnob < ArduinoSketch # ---------------------------------------------------------- # MotorKnob adapted from Tom Igoe's Arduino Sketch # # Brian Riley - Underhill Center, VT, USA July 2008 # # # A stepper motor follows the turns of a potentiometer # (or other sensor) on analog input 0. # # http://www.arduino.cc/en/Reference/Stepper # ---------------------------------------------------------- fourwire_stepper 8, 9, 10, 11, :as => :mystepper, :speed => 31, :steps => 200 input_pin 0, :as => :sensor @previous = "0, int" @value = "0, int" def loop @value = analogRead(sensor) mystepper.set_steps @value - @previous @previous = @value end end ================================================ FILE: lib/examples/servo_buttons.rb ================================================ class ServoButtons < ArduinoSketch # original syntax input_pin 6, :as => :button_one, :latch => :off # preferred syntax input_pin 7, :as => :button_two, :device => :button input_pin 8, :as => :button_three, :device => :button output_pin 13, :as => :led output_pin 2, :as => :my_servo, :device => :servo def loop check_buttons servo_refresh end def check_buttons read_and_toggle button_one, led my_servo.position 180 if read_input button_two my_servo.position 60 if read_input button_three end end ================================================ FILE: lib/examples/servo_calibrate_continuous.rb ================================================ class ServoCalibrateContinuous < ArduinoSketch # ---------------------------------------------------------------------- # Program to calibrate a 'continuous' or 'modified' hobby servo # # Basically uses teh servo 'spped' command to send a speed # of zero (0) to the servo continuously. You then use a small # screwdriver to adjust the potentiometer on the sero until there # is no motion whatsoever. # # The program strats off by commanding max speed clockwise and then # counter clockwise. First the LED blinks rapidly for 2 seconds as # a warning that motion is coming. Then the LED is turned on solid # Then 2 seconds max rev clockwise, then two seconds max rev counter- # clockwise. Then the LED is turned off and this followed by twenty # second of the servo commanded to zero (0) speed. During this time # you may adjust the servo for no motion. If you stilll have more # adjustmenst to make you will be warned by the flashing LED to # back off while it moves back and forth. This full speed motion # is to let you knwo you have it right, # # The 20 second timer uses the Arduino millis() counter which # rolls over after a couple million milliseconds. I made no attempt # to allow for ths. If your servo isn't calibrated after a couple # million milliseconds and the prgram jams up then (a) hit the reset # button, or (b) give up! # # Brian Riley - Underhill Center, VT, USA July 2008 # # # ---------------------------------------------------------------------- @test_state = "2, int" @cycle_time = "0, long" # This sets up to do four units at once # You can comment the extra lines out or leave them in, if there's nothing # connected, no harm, no foul! output_pin 12, :as => :servo4, :device => :servo, :minp => 400, :maxp => 2600 output_pin 11, :as => :servo3, :device => :servo, :minp => 400, :maxp => 2600 output_pin 10, :as => :servo2, :device => :servo, :minp => 400, :maxp => 2600 output_pin 9, :as => :servo1, :device => :servo, :minp => 400, :maxp => 2600 output_pin 13, :as => :led def loop if @test_state == 2 40.times { blink led, 50 } # 40 x 50 ms is a 2 second blinking light # ** Warning! ** "... danger Will Robinson!" toggle led # turn it on keep it on -- keep hands away servo1.speed -90 servo2.speed -90 servo3.speed -90 servo4.speed -90 delay_servo 2000 # two full seconds max clockwise servo1.speed 90 servo2.speed 90 servo3.speed 90 servo4.speed 90 delay_servo 2000 # two full seconds max counter clockwise @test_state = 1 # setup for zero speed test/adjust @cycle_time = millis + 20000 servo1.speed 0 servo2.speed 0 servo3.speed 0 servo4.speed 0 toggle led # lights off, OK you have 20 seconds to adjust end if @cycle_time - millis <= 0 @test_state = 2 else servo_refresh end end def delay_servo(t) t.times do delay 1 servo_refresh end end end ================================================ FILE: lib/examples/servo_throttle.rb ================================================ class ServoThrottle < ArduinoSketch # updated 20080731 # replaced external variables with instance style variables # potentiometer to control servo # with a bit of hysteresis # use analog pin for sensor # need to format the output of sensor_position and sensor_amount @sensor_position = 0 @servo_amount = 0 output_pin 5, :as => :my_lcd, :device => :sf_lcd input_pin 1, :as => :sensor output_pin 2, :as => :my_servo, :device => :servo def loop servo_refresh #delay 9 # comment out if using servo status, since it will add enough delay @sensor_position = analogRead(sensor) @servo_amount = (add_hysteresis(@sensor_position, 10)*0.36) my_servo.position @servo_amount servo_status end def servo_status my_lcd.setxy 0,0 # line 0, col 0 my_lcd.print "Read Send" my_lcd.setxy 0,1 # line 1, col 0 my_lcd.print @sensor_position # need method of blanking out previous reading my_lcd.setxy 6,1 my_lcd.print @servo_amount end end ================================================ FILE: lib/examples/software_serial.rb ================================================ class SoftwareSerial < ArduinoSketch output_pin 13, :as => :led software_serial 6, 7, :as => :gps serial_begin def loop digitalWrite(led, true) serial_print(gps.read) end end ================================================ FILE: lib/examples/sparkfun_lcd.rb ================================================ class SparkfunLcd < ArduinoSketch input_pin 6, :as => :button_one, :latch => :off input_pin 7, :as => :button_two, :latch => :off input_pin 8, :as => :button_three, :latch => :off output_pin 13, :as => :led swser_LCDsf 5, :as => :my_lcd #serial_begin # not necessary when using :device => :sf_lcd or :pa_lcd def loop check_buttons end # need a bit def say_hello my_lcd.setxy 0,0 # line 0, col 0 my_lcd.print "All your base " my_lcd.setxy 0,1 # line 1, col 0 my_lcd.print "are belong to us" end def say_ruby my_lcd.setxy 0,0 # line 0, col 0 my_lcd.print " Ruby + Arduino " my_lcd.setxy 0,1 # line 1, col 0 my_lcd.print " RAD 0.2.4+ " # un comment to change display startup #myLCD.setcmd 0x7C, 10 end def check_buttons read_and_toggle button_one, led say_hello if read_input button_two say_ruby if read_input button_three end end ================================================ FILE: lib/examples/spectra_soft_pot.rb ================================================ class SpectraSoftPot < ArduinoSketch # demonstrate capability to use soft pot as traditional pot # the last pot reading remains "locked" to the last touch point # similar same behavior as ipod # # this sketch assumes a pa_lcd operating at 19200 and one # spectra symbol softpot connected to analog pin 3 # output_pin 5, :as => :my_lcd, :device => :pa_lcd, :rate => 19200, :clear_screen => :true input_pin 3, :as => :sensor_one, :device => :spectra def setup delay 1000 my_lcd.setxy 0,0, "spectra symbol" my_lcd.setxy 0,1, "soft pot" delay 5000 my_lcd.clearscr end def loop my_lcd.setxy 0,1 # since lcd's have issues clearing tens and hundreds digits when reading ones, # we use pad_int_to_str, which is a hack to display these cleanly # pad_int_to_str takes two arguments: an integer and the final string length # my_lcd.print pad_int_to_str sensor_one.soft_lock, 3 delay 100 end end ================================================ FILE: lib/examples/times_method.rb ================================================ class TimesMethod < ArduinoSketch def loop 5.times { delay 200 } end end ================================================ FILE: lib/examples/toggle.rb ================================================ class Toggle < ArduinoSketch output_pin 13, :as => :led def loop led.toggle delay 300 end end ================================================ FILE: lib/examples/twitter.rb ================================================ class Twitter < ArduinoSketch #include #include define "TWEETLEN 141" define "HOSTNAME www.twitter.com" define 'IPADDR "128.121.146.100"' # twitter.com define "PORT 80" # // HTTP define "HTTPPATH /atduskgreg/" # // the person we want to follow define "TWEETLEN 141" array "char linebuffer[256]" # // our large buffer for data array "char tweet[TWEETLEN]" # // the tweet @lines = 0 define "XPORT_RXPIN 2" define "XPORT_TXPIN 3" define "XPORT_RESETPIN 4" define "XPORT_DTRPIN 5" define "XPORT_CTSPIN 6" define "XPORT_RTSPIN 7" @errno = 0 @laststatus = 0 @currstatus = 0 # in setup #xport = AF_XPort(XPORT_RX, XPORT_TX, XPORT_RESET, XPORT_DTR, XPORT_RTS, XPORT_CTS) output_pin 10, :as => :shield, :device => :ethernet serial_begin :rate => 57600 def loop # local_connect() # kind of a problem... fixed get_tweet fetchtweet delay 30000 end end ================================================ FILE: lib/examples/two_wire.rb ================================================ class TwoWire < ArduinoSketch # just a demo that two_wire loads output_pin 19, :as => :wire, :device => :i2c, :enable => :true def loop x = 4 end end ================================================ FILE: lib/libraries/Wire/utility/twi.c ================================================ /* twi.c - TWI/I2C library for Wiring & Arduino Copyright (c) 2006 Nicholas Zambetti. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif #include "twi.h" static volatile uint8_t twi_state; static uint8_t twi_slarw; static void (*twi_onSlaveTransmit)(void); static void (*twi_onSlaveReceive)(uint8_t*, int); static uint8_t* twi_masterBuffer; static volatile uint8_t twi_masterBufferIndex; static uint8_t twi_masterBufferLength; static uint8_t* twi_txBuffer; static volatile uint8_t twi_txBufferIndex; static volatile uint8_t twi_txBufferLength; static uint8_t* twi_rxBuffer; static volatile uint8_t twi_rxBufferIndex; /* * Function twi_init * Desc readys twi pins and sets twi bitrate * Input none * Output none */ void twi_init(void) { // initialize state twi_state = TWI_READY; #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) // activate internal pull-ups for twi // as per note from atmega8 manual pg167 sbi(PORTC, 4); sbi(PORTC, 5); #else // activate internal pull-ups for twi // as per note from atmega128 manual pg204 sbi(PORTD, 0); sbi(PORTD, 1); #endif // initialize twi prescaler and bit rate cbi(TWSR, TWPS0); cbi(TWSR, TWPS1); TWBR = ((CPU_FREQ / TWI_FREQ) - 16) / 2; /* twi bit rate formula from atmega128 manual pg 204 SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR)) note: TWBR should be 10 or higher for master mode It is 72 for a 16mhz Wiring board with 100kHz TWI */ // enable twi module, acks, and twi interrupt TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA); // allocate buffers twi_masterBuffer = (uint8_t*) calloc(TWI_BUFFER_LENGTH, sizeof(uint8_t)); twi_txBuffer = (uint8_t*) calloc(TWI_BUFFER_LENGTH, sizeof(uint8_t)); twi_rxBuffer = (uint8_t*) calloc(TWI_BUFFER_LENGTH, sizeof(uint8_t)); } /* * Function twi_slaveInit * Desc sets slave address and enables interrupt * Input none * Output none */ void twi_setAddress(uint8_t address) { // set twi slave address (skip over TWGCE bit) TWAR = address << 1; } /* * Function twi_readFrom * Desc attempts to become twi bus master and read a * series of bytes from a device on the bus * Input address: 7bit i2c device address * data: pointer to byte array * length: number of bytes to read into array * Output byte: 0 ok, 1 length too long for buffer */ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length) { uint8_t i; // ensure data will fit into buffer if(TWI_BUFFER_LENGTH < length){ return 1; } // wait until twi is ready, become master receiver while(TWI_READY != twi_state){ continue; } twi_state = TWI_MRX; // initialize buffer iteration vars twi_masterBufferIndex = 0; twi_masterBufferLength = length; // build sla+w, slave device address + w bit twi_slarw = TW_READ; twi_slarw |= address << 1; // send start condition TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); // wait for read operation to complete while(TWI_MRX == twi_state){ continue; } // copy twi buffer to data for(i = 0; i < length; ++i){ data[i] = twi_masterBuffer[i]; } return 0; } /* * Function twi_writeTo * Desc attempts to become twi bus master and write a * series of bytes to a device on the bus * Input address: 7bit i2c device address * data: pointer to byte array * length: number of bytes in array * wait: boolean indicating to wait for write or not * Output byte: 0 ok, 1 length too long for buffer */ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait) { uint8_t i; // ensure data will fit into buffer if(TWI_BUFFER_LENGTH < length){ return 1; } // wait until twi is ready, become master transmitter while(TWI_READY != twi_state){ continue; } twi_state = TWI_MTX; // initialize buffer iteration vars twi_masterBufferIndex = 0; twi_masterBufferLength = length; // copy data to twi buffer for(i = 0; i < length; ++i){ twi_masterBuffer[i] = data[i]; } // build sla+w, slave device address + w bit twi_slarw = TW_WRITE; twi_slarw |= address << 1; // send start condition TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); // wait for write operation to complete while(wait && (TWI_MTX == twi_state)){ continue; } return 0; } /* * Function twi_transmit * Desc fills slave tx buffer with data * must be called in slave tx event callback * Input data: pointer to byte array * length: number of bytes in array * Output 1 length too long for buffer * 2 not slave transmitter * 0 ok */ uint8_t twi_transmit(uint8_t* data, uint8_t length) { uint8_t i; // ensure data will fit into buffer if(TWI_BUFFER_LENGTH < length){ return 1; } // ensure we are currently a slave transmitter if(TWI_STX != twi_state){ return 2; } // set length and copy data into tx buffer twi_txBufferLength = length; for(i = 0; i < length; ++i){ twi_txBuffer[i] = data[i]; } return 0; } /* * Function twi_attachSlaveRxEvent * Desc sets function called before a slave read operation * Input function: callback function to use * Output none */ void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) ) { twi_onSlaveReceive = function; } /* * Function twi_attachSlaveTxEvent * Desc sets function called before a slave write operation * Input function: callback function to use * Output none */ void twi_attachSlaveTxEvent( void (*function)(void) ) { twi_onSlaveTransmit = function; } /* * Function twi_reply * Desc sends byte or readys receive line * Input ack: byte indicating to ack or to nack * Output none */ void twi_reply(uint8_t ack) { // transmit master read ready signal, with or without ack if(ack){ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); }else{ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); } } /* * Function twi_stop * Desc relinquishes bus master status * Input none * Output none */ void twi_stop(void) { // send stop condition TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); // wait for stop condition to be exectued on bus // TWINT is not set after a stop condition! while(TWCR & _BV(TWSTO)){ continue; } // update twi state twi_state = TWI_READY; } /* * Function twi_releaseBus * Desc releases bus control * Input none * Output none */ void twi_releaseBus(void) { // release bus TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); // update twi state twi_state = TWI_READY; } SIGNAL(SIG_2WIRE_SERIAL) { switch(TW_STATUS){ // All Master case TW_START: // sent start condition case TW_REP_START: // sent repeated start condition // copy device address and r/w bit to output register and ack TWDR = twi_slarw; twi_reply(1); break; // Master Transmitter case TW_MT_SLA_ACK: // slave receiver acked address case TW_MT_DATA_ACK: // slave receiver acked data // if there is data to send, send it, otherwise stop if(twi_masterBufferIndex < twi_masterBufferLength){ // copy data to output register and ack TWDR = twi_masterBuffer[twi_masterBufferIndex++]; twi_reply(1); }else{ twi_stop(); } break; case TW_MT_SLA_NACK: // address sent, nack received case TW_MT_DATA_NACK: // data sent, nack received twi_stop(); break; case TW_MT_ARB_LOST: // lost bus arbitration twi_releaseBus(); break; // Master Receiver case TW_MR_DATA_ACK: // data received, ack sent // put byte into buffer twi_masterBuffer[twi_masterBufferIndex++] = TWDR; case TW_MR_SLA_ACK: // address sent, ack received // ack if more bytes are expected, otherwise nack if(twi_masterBufferIndex < twi_masterBufferLength){ twi_reply(1); }else{ twi_reply(0); } break; case TW_MR_DATA_NACK: // data received, nack sent // put final byte into buffer twi_masterBuffer[twi_masterBufferIndex++] = TWDR; case TW_MR_SLA_NACK: // address sent, nack received twi_stop(); break; // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case // Slave Receiver case TW_SR_SLA_ACK: // addressed, returned ack case TW_SR_GCALL_ACK: // addressed generally, returned ack case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack // enter slave receiver mode twi_state = TWI_SRX; // indicate that rx buffer can be overwritten and ack twi_rxBufferIndex = 0; twi_reply(1); break; case TW_SR_DATA_ACK: // data received, returned ack case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack // if there is still room in the rx buffer if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ // put byte in buffer and ack twi_rxBuffer[twi_rxBufferIndex++] = TWDR; twi_reply(1); }else{ // otherwise nack twi_reply(0); } break; case TW_SR_STOP: // stop or repeated start condition received // put a null char after data if there's room if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ twi_rxBuffer[twi_rxBufferIndex] = '\0'; } // callback to user defined callback twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); // ack future responses twi_reply(1); // leave slave receiver state twi_state = TWI_READY; break; case TW_SR_DATA_NACK: // data received, returned nack case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack // nack back at master twi_reply(0); break; // Slave Transmitter case TW_ST_SLA_ACK: // addressed, returned ack case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack // enter slave transmitter mode twi_state = TWI_STX; // ready the tx buffer index for iteration twi_txBufferIndex = 0; // set tx buffer length to be zero, to verify if user changes it twi_txBufferLength = 0; // request for txBuffer to be filled and length to be set // note: user must call twi_transmit(bytes, length) to do this twi_onSlaveTransmit(); // if they didn't change buffer & length, initialize it if(0 == twi_txBufferLength){ twi_txBufferLength = 1; twi_txBuffer[0] = 0x00; } // transmit first byte from buffer, fall case TW_ST_DATA_ACK: // byte sent, ack returned // copy data to output register TWDR = twi_txBuffer[twi_txBufferIndex++]; // if there is more to send, ack, otherwise nack if(twi_txBufferIndex < twi_txBufferLength){ twi_reply(1); }else{ twi_reply(0); } break; case TW_ST_DATA_NACK: // received nack, we are done case TW_ST_LAST_DATA: // received ack, but we are done already! // ack future responses twi_reply(1); // leave slave receiver state twi_state = TWI_READY; break; // All case TW_NO_INFO: // no state information break; case TW_BUS_ERROR: // bus error, illegal stop/start twi_stop(); break; } } ================================================ FILE: lib/libraries/Wire/utility/twi.h ================================================ /* twi.h - TWI/I2C library for Wiring & Arduino Copyright (c) 2006 Nicholas Zambetti. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef twi_h #define twi_h #include //#define ATMEGA8 #ifndef CPU_FREQ #define CPU_FREQ 16000000L #endif #ifndef TWI_FREQ #define TWI_FREQ 100000L #endif #ifndef TWI_BUFFER_LENGTH #define TWI_BUFFER_LENGTH 32 #endif #define TWI_READY 0 #define TWI_MRX 1 #define TWI_MTX 2 #define TWI_SRX 3 #define TWI_STX 4 void twi_init(void); void twi_setAddress(uint8_t); uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t); uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t); uint8_t twi_transmit(uint8_t*, uint8_t); void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) ); void twi_attachSlaveTxEvent( void (*)(void) ); void twi_reply(uint8_t); void twi_stop(void); void twi_releaseBus(void); #endif ================================================ FILE: lib/plugins/bitwise_ops.rb ================================================ class BitwiseOps < ArduinoPlugin # RAD plugins are c methods, directives, external variables and assignments and calls # that may be added to the main setup method # function prototypes not needed since we generate them automatically # directives, external variables and setup assignments and calls can be added rails style (not c style) # add to directives # add to external variables # add the following to the setup method # add_to_setup int build_int(int hibyte, int lobyte) { return((hibyte << 8) + lobyte); } int i_shiftleft(int val, int shift) { return(val << shift); } int i_shiftright(int val, int shift) { return(val >> shift); } byte b_shiftleft(byte val, byte shift) { return(val << shift); } byte b_shiftright(byte val, byte shift) { return(val >> shift); } int bit_and(int val, int mask) { return(val & mask); } int bit_or(int val, int mask) { return(val | mask); } int bit_xor(int val, int mask) { return(val ^ mask); } int twos_comp(int val) { return((val ^ 0xffff) + 1); } end ================================================ FILE: lib/plugins/blink.rb ================================================ class Blink < ArduinoPlugin # RAD plugins are c methods, directives, external variables and assignments and calls # that may be added to the main setup method # function prototypes not needed since we generate them automatically # directives, external variables and setup assignments and calls can be added rails style (not c style) # add to directives # add to external variables # add the following to the setup method # add_to_setup void blink(int pin, int ms) { digitalWrite( pin, HIGH ); delay( ms ); digitalWrite( pin, LOW ); delay( ms ); } end ================================================ FILE: lib/plugins/blink_m.rb ================================================ class BlinkM < ArduinoPlugin # # # BlinkM_funcs.h -- Arduino library to control BlinkM # -------------- # # # Note: original version of this file lives with the BlinkMTester sketch # # 2007, Tod E. Kurt, ThingM, http://thingm.com/ # # version: 20080203 # # history: # 20080101 - initial release # 20080203 - added setStartupParam(), bugfix receiveBytes() from Dan Julio # 20080727 - ported to rad jd barnhart # # first step, declare output pin 19 as i2c ## output_pin 19, :as => :wire, :device => :i2c, :enable => :true # reminder, true issues wire.begin include_wire add_blink_m_struct # Not needed when pin is declared with :enable => :true # In fact, declaring it twice causes nothing but problems static void BlinkM_begin() { Wire.begin(); // join i2c bus (address optional for master) } // General version of BlinkM_beginWithPower(). static void BlinkM_beginWithPowerPins(byte pwrpin, byte gndpin) { DDRC |= _BV(pwrpin) | _BV(gndpin); // make outputs PORTC &=~ _BV(gndpin); PORTC |= _BV(pwrpin); delay(100); // wait for things to stabilize Wire.begin(); } // Call this first when BlinkM is plugged directly into Arduino // The BlinkMs PWR (power) pins should line up with pins 2 and 3 of the connector, // while the I2C (communications) pins should line up with pins 4 and 5. static void BlinkM_beginWithPower() { BlinkM_beginWithPowerPins( PC3, PC2 ); } // sends a generic command static void BlinkM_sendCmd(byte addr, byte* cmd, int cmdlen) { Wire.beginTransmission(addr); for( byte i=0; i :optional { char message[50]; char status[5]; strcpy(message, "received 0x"); //Serial.print("Checking BlinkM address..."); int b = BlinkM_getAddress(addr); if( b==-1 ) { //Serial.println("No response, that's not good"); return "No response, that's not good"; // no response } itoa(b, status ,16); //Serial.print("received addr: 0x"); //Serial.print(b,HEX); if( b != addr ) return "error, mismatch"; // error, addr mismatch else return strcat(message, status); // match, everything okay } // Demonstrates how to verify you-re talking to a BlinkM // and that you know its address -- digital version static int BlinkM_checkAddress(byte addr) { //Serial.print("Checking BlinkM address..."); int b = BlinkM_getAddress(addr); if( b==-1 ) { //Serial.println("No response, that's not good"); return -1; // no response } //Serial.print("received addr: 0x"); //Serial.print(b,HEX); if( b != addr ) return 1; // error, addr mismatch else return 0; // match, everything okay } // Sets the speed of fading between colors. // Higher numbers means faster fading, 255 == instantaneous fading static void BlinkM_setFadeSpeed(byte addr, byte fadespeed) { Wire.beginTransmission(addr); Wire.send('f'); Wire.send(fadespeed); Wire.endTransmission(); } // Sets the light script playback time adjust // The timeadj argument is signed, and is an additive value to all // durations in a light script. Set to zero to turn off time adjust. static void BlinkM_setTimeAdj(byte addr, byte timeadj) { Wire.beginTransmission(addr); Wire.send('t'); Wire.send(timeadj); Wire.endTransmission(); } // Fades to an RGB color static void BlinkM_fadeToRGB(byte addr, byte red, byte grn, byte blu) { Wire.beginTransmission(addr); Wire.send('c'); Wire.send(red); Wire.send(grn); Wire.send(blu); Wire.endTransmission(); } // Fades to an HSB color static void BlinkM_fadeToHSB(byte addr, byte hue, byte saturation, byte brightness) { Wire.beginTransmission(addr); Wire.send('h'); Wire.send(hue); Wire.send(saturation); Wire.send(brightness); Wire.endTransmission(); } // Sets an RGB color immediately static void BlinkM_setRGB(byte addr, byte red, byte grn, byte blu) { Wire.beginTransmission(addr); Wire.send('n'); Wire.send(red); Wire.send(grn); Wire.send(blu); Wire.endTransmission(); } // Fades to a random RGB color static void BlinkM_fadeToRandomRGB(byte addr, byte rrnd, byte grnd, byte brnd) { Wire.beginTransmission(addr); Wire.send('C'); Wire.send(rrnd); Wire.send(grnd); Wire.send(brnd); Wire.endTransmission(); } // Fades to a random HSB color static void BlinkM_fadeToRandomHSB(byte addr, byte hrnd, byte srnd, byte brnd) { Wire.beginTransmission(addr); Wire.send('H'); Wire.send(hrnd); Wire.send(srnd); Wire.send(brnd); Wire.endTransmission(); } static void BlinkM_getRGBColor(byte addr, byte* r, byte* g, byte* b) { Wire.beginTransmission(addr); Wire.send('g'); Wire.endTransmission(); Wire.requestFrom(addr, (byte)3); if( Wire.available() ) { *r = Wire.receive(); *g = Wire.receive(); *b = Wire.receive(); } } static void BlinkM_playScript(byte addr, byte script_id, byte reps, byte pos) { Wire.beginTransmission(addr); Wire.send('p'); Wire.send(script_id); Wire.send(reps); Wire.send(pos); Wire.endTransmission(); } static void BlinkM_stopScript(byte addr) { Wire.beginTransmission(addr); Wire.send('o'); Wire.endTransmission(); } static void BlinkM_setScriptLengthReps(byte addr, byte script_id, byte len, byte reps) { Wire.beginTransmission(addr); Wire.send('L'); Wire.send(script_id); Wire.send(len); Wire.send(reps); Wire.endTransmission(); } static void BlinkM_writeScriptLine(byte addr, byte script_id, byte pos, byte dur, byte cmd, byte arg1, byte arg2, byte arg3) { #ifdef BLINKM_FUNCS_DEBUG Serial.print("writing line:"); Serial.print(pos,DEC); Serial.print(" with cmd:"); Serial.print(cmd); Serial.print(" arg1:"); Serial.println(arg1,HEX); #endif Wire.beginTransmission(addr); Wire.send('W'); Wire.send(script_id); Wire.send(pos); Wire.send(dur); Wire.send(cmd); Wire.send(arg1); Wire.send(arg2); Wire.send(arg3); Wire.endTransmission(); } static void BlinkM_writeScript(byte addr, byte script_id, byte len, byte reps, blinkm_script_line* lines) { #ifdef BLINKM_FUNCS_DEBUG Serial.print("writing script to addr:"); Serial.print(addr,DEC); Serial.print(", script_id:"); Serial.println(script_id,DEC); #endif for(byte i=0; i < len; i++) { blinkm_script_line l = lines[i]; BlinkM_writeScriptLine( addr, script_id, i, l.dur, l.cmd[0], l.cmd[1], l.cmd[2], l.cmd[3]); } BlinkM_setScriptLengthReps(addr, script_id, len, reps); } static void BlinkM_setStartupParams(byte addr, byte mode, byte script_id, byte reps, byte fadespeed, byte timeadj) { Wire.beginTransmission(addr); Wire.send('B'); Wire.send(mode); Wire.send(script_id); Wire.send(reps); Wire.send(fadespeed); Wire.send(timeadj); Wire.endTransmission(); } end ================================================ FILE: lib/plugins/debounce.rb ================================================ class Debounce < ArduinoPlugin # RAD plugins are c methods, directives, external variables and assignments and calls # that may be added to the main setup method # function prototypes not needed since we generate them automatically # directives, external variables and setup assignments and calls can be added rails style (not c style) # hack from http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1209050315 # plugin_directives "#undef int", "#include ", "char _str[32];", "#define writeln(...) sprintf(_str, __VA_ARGS__); Serial.println(_str)" # add to directives #plugin_directives "#define EXAMPLE 10" # add to external variables # ok, we need to deal with # what about variables # need to loose the colon... # external_variables "char status_message[40] = \"very cool\"", "char* msg[40]" # add the following to the setup method # add_to_setup "foo = 1";, "bar = 1;" "sub_setup();" # one or more methods may be added and prototypes are generated automatically with rake make:upload # call pulse(us) to pulse a servo ##################### ## How this works ## The cast: ## a normally open push button (circuit is closed when button is depressed) ## variables [input]. ## [input]read: or current read -- what we see from the input pin HIGH (1) untouched or LOW (1) depressed ## [input]prev: or previous read – assigned to current reading at the end of the method ## [input]state: the stored state HIGH (1) or LOW (0) ## [input]time: the time when we last had a true ## millis: number of milliseconds since the Arduino began running the current program ## So…. ## If HIGH and the [input]read was LOW (button was depressed since the last time we looped) AND If millis() - [input]time > 200 ## Flip the state ## And assign [input]time millis() ## Else Set the pin to [input]state ## Assign [input]prev to [input]read ## abstract summary: ## So 99%+ of the time, we always see a HIGH (unless the button is pushed) ## If the button is pushed, we record this LOW to [input]prev, so the next time we enter the loop and the button is not being pushed we see true as long as millis() minus the [input]time of the last toggle is greater the 200 (adjust, which can be set with an adjust option) ###################### add_debounce_struct # increase the debounce_setting, increase if the output flickers # need docs.. # and testing # # remember these are being called from the loop (typically) # # NOTE: if two buttons are controlling one output, today, strange # things will happen since each button tries to assert its own state # suggestion: we can fix this with an array of structs for shared outputs # ie: output_pin 5, :as => :yellow_led, :shared => :yes # default no # this would put the state at the output which could be compared to # the inputs_state and override and set it if different int toggle(int output) { return toggle_output(output); } int toggle_output(int output) { if (dbce[output].state == HIGH) dbce[output].state = LOW; else dbce[output].state = HIGH; digitalWrite(output, dbce[output].state); return dbce[output].state; } int read_input(int input) { int state = LOW; dbce[input].read = digitalRead(input); if (dbce[input].read == HIGH && dbce[input].prev == LOW && millis() - dbce[input].time > dbce[input].adjust) { dbce[input].time = millis(); state = HIGH; } else state = LOW; dbce[input].prev = dbce[input].read; return state; } int toggle(int input, int output) { return read_and_toggle(input, output); } int read_and_toggle(int input, int output) { dbce[input].read = digitalRead(input); // did we just release a button which was depressed the last time we checked and over 200 millseconds has passed since this statement was last true? if (dbce[input].read == HIGH && dbce[input].prev == LOW && millis() - dbce[input].time > dbce[input].adjust) { // ... flip the output if (dbce[input].state == HIGH) dbce[input].state = LOW; else dbce[input].state = HIGH; /* save time of last press */ dbce[input].time = millis(); } digitalWrite(output, dbce[input].state); dbce[input].prev = dbce[input].read; return dbce[input].state; } end ================================================ FILE: lib/plugins/debug_output_to_lcd.rb ================================================ class DebugOutputToLcd < ArduinoPlugin # RAD plugins are c methods, directives, external variables and assignments and calls # that may be added to the main setup method # function prototypes not needed since we generate them automatically # directives, external variables and setup assignments and calls can be added rails style (not c style) # add to directives #plugin_directives "#define ARY_SIZE 10" # add to external variables #external_variables "unsigned long start_loop_time = 0;", "unsigned long total_loop_time = 0;" # add the following to the setup method #add_to_setup "scan = &sm_ary[0];", "cur = &sm_ary[0];", "start = &sm_ary[0];", "end = &sm_ary[ARY_SIZE-1];" # add an element to the array and return the average # need a nice home for these void send_servo_debug_to_lcd(int servo) { lcd_first_line(); Serial.print("pw "); Serial.print( find_servo_pulse_width(servo)); Serial.print(" lp "); Serial.print( find_servo_last_pulse(servo)); Serial.print("s"); Serial.print( find_servo_start_pulse(servo)); // Serial.print(" t"); // Serial.print( find_debounce_time(servo)); lcd_second_line(); Serial.print("d"); // Serial.print( millis() - find_debounce_time(servo)); Serial.print(" m"); Serial.print(millis()); } void send_button_debug_to_lcd(int button) { lcd_first_line(); Serial.print("r"); Serial.print( find_debounce_read(button)); Serial.print("p"); Serial.print( find_debounce_prev(button)); Serial.print("s"); Serial.print( find_debounce_state(button)); Serial.print(" t"); Serial.print( find_debounce_time(button)); lcd_second_line(); Serial.print("d"); Serial.print( millis() - find_debounce_time(button)); Serial.print(" m"); Serial.print(millis()); } end ================================================ FILE: lib/plugins/hysteresis.rb ================================================ class Hysteresis < ArduinoPlugin # jdbarnhart # 20080728 # # # purpose # # add hysteresis to analog readings, typically sensors or potentiometers # # use # two steps # # one # declare :device => :sensor # example: # input_pin 1, :as => :sensor_one, :device => :sensor # # two # instead of: # my_lcd.print analogRead sensor_two # use add_hyst # my_lcd.print sensor_one.with_hyst 4 # # # note, 4 is the amount of hysteresis # # void with_hysteresis(int pin, int amt) { with_hyst(pin, amt); } int with_hyst(int pin, int amt) { int read; unsigned int i; read = analogRead(pin); for (i = 0; i < (int) (sizeof(hyst) / sizeof(hyst[0])); i++) { if (pin == hyst[i].pin) { if (((read - hyst[i].state) > amt ) || ((hyst[i].state - read) > amt )) { hyst[i].state = read; return hyst[i].state; } else return hyst[i].state; } } } end ================================================ FILE: lib/plugins/input_output_state.rb ================================================ class InputOutputState < ArduinoPlugin # RAD plugins are c methods, directives, external variables and assignments and calls # that may be added to the main setup method # function prototypes not needed since we generate them automatically # directives, external variables and setup assignments and calls can be added rails style (not c style) # add to directives #plugin_directives "#define ARY_SIZE 10" # add to external variables #external_variables "int *cur, *scan, *start, *end;", "int sm_ary[ARY_SIZE];" # add the following to the setup method #add_to_setup "scan = &sm_ary[0];", "cur = &sm_ary[0];", "start = &sm_ary[0];", "end = &sm_ary[ARY_SIZE-1];" # return states of button and servo output stored in # array structs dbcd (debounce) and serv (servo) # need error catch ... # how about auto generating documentation from plugins # at least showing int find_debounce_state(int input) { return dbce[input].state; } int find_debounce_read(int input) { return dbce[input].read; } int find_debounce_prev(int input) { return dbce[input].prev; } unsigned long find_debounce_time(int input) { return dbce[input].time; } int find_debounce_adjust(int input) { return dbce[input].adjust; } long unsigned find_servo_pulse_width(int input) { return serv[input].pulseWidth; } unsigned long find_servo_last_pulse(int input) { return serv[input].lastPulse; } unsigned long find_servo_start_pulse(int input) { return serv[input].startPulse; } unsigned long find_servo_refresh_time(int input) { return serv[input].refreshTime; } int find_servo_min(int input) { return serv[input].min; } int find_servo_max(int input) { return serv[input].max; } end ================================================ FILE: lib/plugins/lcd_padding.rb ================================================ class LCDPadding < ArduinoPlugin # jdbarnhart # 20080729 # # # purpose # simple integer padding for lcd display pad # # example # my_lcd.print pad_int_to_str 29, 5 # # result # " 29" static char* pad_int_to_str(int num, int length) { int i = 0; int start; char plain[20]; char space[5] = " "; char* pretty = " "; itoa(num, plain ,10); start = length - strlen(plain); while (i <= length) { if (i >= start) pretty[i] = plain[i - start]; else pretty[i] = space[0]; i++; } return pretty; } static char* pad_int_to_str_w_zeros(int num, int length) { int i = 0; int start; char plain[20]; char space[5] = "0 "; char* pretty = " "; itoa(num, plain ,10); start = length - strlen(plain); while (i <= length) { if (i >= start) pretty[i] = plain[i - start]; else pretty[i] = space[0]; i++; } return pretty; } end ================================================ FILE: lib/plugins/mem_test.rb ================================================ class MemTest < ArduinoPlugin # RAD plugins are c methods, directives, external variables and assignments and calls # that may be added to the main setup method # function prototypes not needed since we generate them automatically # directives, external variables and setup assignments and calls can be added rails style (not c style) # add to directives #plugin_directives "#define EXAMPLE 10" # add to external variables # external_variables "int foo, bar" # add the following to the setup method # add_to_setup "foo = 1";, "bar = 1;" "sub_setup();" # one or more methods may be added and prototypes are generated automatically with rake make:upload # test the memory on your arduino uncommenting the following: # add_to_setup "memoryTest();" # or adding "memoryTest()" (no semicolon) to your main sketch int memoryTest() { int byteCounter = 0; // initialize a counter byte *byteArray; // create a pointer to a byte array while ( (byteArray = (byte*) malloc (byteCounter * sizeof(byte))) != NULL ) { byteCounter++; // if allocation was successful, then up the count for the next try free(byteArray); // free memory after allocating it } free(byteArray); // also free memory after the function finishes" return byteCounter; // send back the highest number of bytes successfully allocated } end ================================================ FILE: lib/plugins/midi.rb ================================================ class Midi < ArduinoPlugin # reference # To send MIDI, attach a MIDI out jack (female DIN-5) to Arduino. # DIN-5 pinout is: _____ # pin 2 - Gnd / \ # pin 4 - 220 ohm resistor to +5V | 3 1 | Female MIDI jack # pin 5 - Arduino D1 (TX) | 5 4 | # all other pins - unconnected \__2__/ # Adapted from Tom Igoe's work at: # http://itp.nyu.edu/physcomp/Labs/MIDIOutput # And Tod E. Kurt 'int, 7' # # def loop # serial_println(ping(sig_pin)) # delay(200) # end # end # Triggers a pulse and returns the delay in microseconds for the echo. int ping(int pin) { pinMode(pin, OUTPUT); digitalWrite(pin, LOW); delayMicroseconds(2); digitalWrite(pin, HIGH); delayMicroseconds(5); digitalWrite(pin, LOW); pinMode(pin, INPUT); return pulseIn(pin, HIGH); } end ================================================ FILE: lib/plugins/servo_pulse.rb ================================================ class ServoPulse < ArduinoPlugin # RAD plugins are c methods, directives, external variables and assignments and calls # that may be added to the main setup method # function prototypes not needed since we generate them automatically # directives, external variables and setup assignments and calls can be added rails style (not c style) # add to directives #plugin_directives "#define EXAMPLE 10" # add to external variables # external_variables "int foo, bar" # add the following to the setup method # add_to_setup "foo = 1";, "bar = 1;" "sub_setup();" # one or more methods may be added and prototypes are generated automatically with rake make:upload # call pulse(us) to pulse a servo # this can be eliminate since we have an identical pulse_servo in servo_setup void pulse(int pin, int us) { digitalWrite( pin, HIGH ); delayMicroseconds( us ); digitalWrite( pin, LOW ); serv[pin].pulseWidth = us; } end ================================================ FILE: lib/plugins/servo_setup.rb ================================================ class ServoSetup < ArduinoPlugin # RAD plugins are c methods, directives, external variables and assignments and calls # that may be added to the main setup method # function prototypes not needed since we generate them automatically # directives, external variables and setup assignments and calls can be added rails style (not c style) # add to directives #plugin_directives "#define EXAMPLE 10" # add to external variables # external_variables "int foo, bar" # add the following to the setup method # add_to_setup "foo = 1";, "bar = 1;" "sub_setup();" # one or more methods may be added and prototypes are generated automatically with rake make:upload # one line servo control # # move_servo my_servo, amount # # example: # # class MoveServo < ArduinoSketch # # external_vars :sensor_position => "int, 0", :servo_amount => "int, 0" # # output_pin 4, :as => :my_servo, :min => 700, :max => 2200 # input_pin 1, :as => :sensor # def loop # sensor_position = analogRead(sensor) # servo_amount = (sensor_position*2 + 500) # move_servo my_servo, servo_amount # end # end # # # supports multiple servos by storing variables in the serv struc array that is constructed when # the :min and :max options are added to the output_pin method add_servo_struct void move_servo(int servo_num, int pulse_width) { struct servo servo_name = serv[servo_num]; int pw = pulse_width; /* apply the servo limits */ if (pw > servo_name.max) pw = servo_name.max; if (pw < servo_name.min) pw = servo_name.min; if (millis() - servo_name.lastPulse >= servo_name.refreshTime) { pulse_servo(servo_name.pin, pw); servo_name.lastPulse = millis(); // if (find_total_loop_time() < 10) // for debug: // digitalWrite( 5, HIGH ); // 18 seems optimal, but we should let the users adjust with a servo option delay(18); } } void pulse_servo(int pin, int us) { digitalWrite( pin, HIGH ); // pulseWidth delayMicroseconds( us ); digitalWrite( pin, LOW ); serv[pin].pulseWidth = us; } end ================================================ FILE: lib/plugins/smoother.rb ================================================ class Smoother < ArduinoPlugin # RAD plugins are c methods, directives, external variables and assignments and calls # that may be added to the main setup method # function prototypes not needed since we generate them automatically # directives, external variables and setup assignments and calls can be added rails style (not c style) # add to directives plugin_directives "#define ARY_SIZE 10" # add to external variables external_variables "int *cur, *scan, *start, *end;", "int sm_ary[ARY_SIZE];", "int last_reading = 0;" # add the following to the setup method add_to_setup "scan = &sm_ary[0];", "cur = &sm_ary[0];", "start = &sm_ary[0];", "end = &sm_ary[ARY_SIZE-1];" # add an element to the array and return the average int add_hysteresis(int reading, int hysteresis) { if ( ((reading - last_reading) > hysteresis) || ((last_reading - reading) > hysteresis)) { last_reading = reading; return reading; } else return last_reading; } int smooth_average(int reading) { int sum, cnt; cnt = 0; sum = 0; *cur = reading; cur++; for (scan = &sm_ary[0]; scan < &sm_ary[ARY_SIZE-1]; cnt++, scan++) sum += *scan; ptr_reset(); return sum/cnt; } void ptr_reset(void) { if (cur == end) { cur = &sm_ary[0]; } } end ================================================ FILE: lib/plugins/spark_fun_serial_lcd.rb ================================================ class SparkFunSerialLcd < ArduinoPlugin # RAD plugins are c methods, directives, external variables and assignments and calls # that may be added to the main setup method # function prototypes not needed since we generate them automatically # directives, external variables and setup assignments and calls can be added rails style (not c style) # hack from http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1209050315 plugin_directives "#undef int", "#include ", "char _str[32];", "#define writeln(...) sprintf(_str, __VA_ARGS__); Serial.println(_str)" # add to directives #plugin_directives "#define EXAMPLE 10" # add to external variables external_variables "char status_message[40] = \"very cool\"", "char* msg[40]" # add the following to the setup method # add_to_setup "foo = 1";, "bar = 1;" "sub_setup();" # one or more methods may be added and prototypes are generated automatically with rake make:upload # methods for sparkfun serial lcd SerLCD v2.5 void print_sensor_position_plus(int reading){ /* writeln("sensor: %d ", reading); */ Serial.print("sensor: "); Serial.print(reading); } void print_sensor_position(long pos){ Serial.print(pos); } void lcd_first_line(){ //puts the cursor at line 0 char 0. Serial.print(0xFE, BYTE); //command flag Serial.print(128, BYTE); //position } void lcd_second_line(){ //puts the cursor at line 0 char 0. Serial.print(0xFE, BYTE); //command flag Serial.print(192, BYTE); //position } void selectLineOne(){ //puts the cursor at line 0 char 0. Serial.print(0xFE, BYTE); //command flag Serial.print(128, BYTE); //position } void selectLineTwo(){ //puts the cursor at line 0 char 0. Serial.print(0xFE, BYTE); //command flag Serial.print(192, BYTE); //position } void clearLCD(){ Serial.print(0xFE, BYTE); //command flag Serial.print(0x01, BYTE); //clear command. } void backlightOn(){ //turns on the backlight Serial.print(0x7C, BYTE); //command flag for backlight stuff Serial.print(157, BYTE); //light level. } void set_backlight_level(int level){ //turns on the backlight if (level > 29) level = 29; Serial.print(0x7C, BYTE); //command flag for backlight stuff Serial.print(157 + level, BYTE); //light level. } void toggle_backlight(){ //turns off the backlight Serial.print(0x7C, BYTE); //command flag for backlight stuff Serial.print("|"); //light level for off. Serial.print(1); } void set_splash(){ selectLineOne(); Serial.print(" Ruby + Auduino"); selectLineTwo(); Serial.print(" RAD 0.2.4+ "); Serial.print(0x7C, BYTE); // decimal 124, command flag for backlight stuff Serial.print(10, BYTE); } void backlightOff(){ //turns off the backlight Serial.print(0x7C, BYTE); // decimal 124, command flag for backlight stuff Serial.print(128, BYTE); //light level for off. } void serCommand(){ // decimal 254, a general function to call the command flag for issuing all other commands Serial.print(0xFE, BYTE); } end ================================================ FILE: lib/plugins/spectra_symbol.rb ================================================ class SpectraSymbol < ArduinoPlugin # jdbarnhart # 20080729 # # crazy experiment in progress # purpose # # retain last reading after finger is removed from spectrasymbol # soft pot # # use # two steps # # one # declare :device => :sensor # example: # input_pin 1, :as => :sensor_one, :device => :spectra # # two # instead of: # my_lcd.print analogRead sensor_two # use soft_lock # my_lcd.print sensor_one.spectra_lock # # # notes: # experimental settings for 100mm spectrasymbol # # hysteresis is set at 5 # amount of sensor drop is set to 3 # delay time (dtime) is 4 # cutoff set to 10 # int soft_lock(int pin) { int hyst = 5; int drop = 3; int dtime = 4; int cutoff = 10; int read; int r1; int r2; int r3; unsigned int i; read = analogRead(pin)/4; delay(dtime); r1 = analogRead(pin)/4; delay(dtime); r2 = analogRead(pin)/4; delay(dtime); r3 = analogRead(pin)/4; delay(dtime); for (i = 0; i < (int) (sizeof(spec) / sizeof(spec[0])); i++) { if (pin == spec[i].pin) { if (((r3 - r2) > drop) && ((r2 - r1) > drop) && ((r1 - read) > drop)) return spec[i].state - 10; else { if (read < cutoff) return spec[i].state - 10; else { if (((read - spec[i].state) > hyst ) || ((spec[i].state - read) > hyst )) { spec[i].state = read; return spec[i].state - 10; } else return spec[i].state - 10; } } } } } end ================================================ FILE: lib/plugins/twitter_connect.rb ================================================ class TwitterConnect < ArduinoPlugin void get_tweet() { // hack to pull } uint32_t parsenumber(char *str) { uint32_t num = 0; char c; // grabs a number out of a string while (c = str[0]) { if ((c < '0') || (c > '9')) return num; num *= 10; num += c - '0'; str++; } return num; } char * fetchtweet(void) { Serial.print("... fetching tweets...."); uint8_t ret; char *found=0, *start=0, *end=0; tweet[0] = 0; // reset the tweet ret = xport.reset(); //Serial.print("Ret: "); Serial.print(ret, HEX); switch (ret) { case ERROR_TIMEDOUT: { Serial.println("Timed out on reset!"); return 0; } case ERROR_BADRESP: { Serial.println("Bad response on reset!"); return 0; } case ERROR_NONE: { Serial.println("Reset OK!"); break; } default: Serial.println("Unknown error"); return 0; } // time to connect... ret = xport.connect(IPADDR, PORT); switch (ret) { case ERROR_TIMEDOUT: { Serial.println("Timed out on connect"); return 0; } case ERROR_BADRESP: { Serial.println("Failed to connect"); return 0; } case ERROR_NONE: { Serial.println("Connected..."); break; } default: Serial.println("Unknown error"); return 0; } // send the HTTP command, ie "GET /username/" xport.print("GET "); xport.println(HTTPPATH); // the following works with instiki, but not on twitter... // xport.print("GET "); // xport.print(HTTPPATH); // xport.println(" HTTP/1.1"); // xport.print("Host: "); xport.println(HOSTNAME); // xport.println(""); while (1) { // read one line from the xport at a time ret = xport.readline_timeout(linebuffer, 255, 4000); // 3s timeout // if we're using flow control, we can actually dump the line at the same time! // Serial.print(linebuffer); // look for an entry (the first one) found = strstr(linebuffer, "entry-title entry-content"); if (((int)found) != 0) { start = strstr(found, ">") + 1; end = strstr(found, "

"); if ((start != 0) && (end != 0)) { Serial.println("\n******Found first entry!*******"); end[0] = 0; Serial.print(start); // save the tweet so we can display it later strncpy(tweet, start, TWEETLEN); tweet[TWEETLEN-1] = 0; } } // next we look for a status ID (which should correspond to the previous tweet)e // Serial.print("."); // Serial.print(linebuffer); found = strstr(linebuffer, "
"); if ((start != 0) && (end != 0)) { Serial.println("\n******Found status ID!*******"); end[0] = 0; Serial.println(start); // turn the string into a number __currstatus = parsenumber(start); Serial.println(__currstatus, DEC); // check if this is a nu tweet if (__currstatus > __laststatus) { __laststatus = __currstatus; Serial.println("New message"); Serial.print(tweet); } else { tweet[0] = 0; } // flush the conn xport.flush(5000); // 5 second timeout if (tweet[0] == 0) { return 0; } else {return tweet; } } } if (((__errno == ERROR_TIMEDOUT) && xport.disconnected()) || ((XPORT_DTRPIN == 0) && (linebuffer[0] == 'D') && (linebuffer[1] == 0))) { Serial.println("\nDisconnected..."); return 0; } } } end ================================================ FILE: lib/rad/README.rdoc ================================================ =Welcome to RAD (Ruby Arduino Development) Quick Start Documentation ArduinoSketch is the main access point for working with RAD. Sub-classes of ArduinoSketch have access to a wide array of convenient class methods (documented below) for doing the most common kinds of setup needed when programming the Arduino such as configuring input and output pins and establishing serial connections. Here is the canonical 'hello world' example of blinking a single LED in RAD: test... to be continued if it works.. ================================================ FILE: lib/rad/antiquated_todo.txt ================================================ -framework for translation to C (wrapper for RubyToAnsiC) -framework for translation testing (want to test that each Rad method translates to the expected C) -have to replace symbol & str definitions with "char name[]" ? -maybe can't build rad.c dynamically? can use as helpers in writing it statically rad.rb and RubyToAnsiC as helpers in writing it. . . -maybe there's a way to give RubyToC prototypes for the arduino library methods (or maybe include them directly) so that it will be able to figure out the signatures for my methods (otherwise it breaks because, for example, it can't figure out what read returns). -speaking of which: all rad methods need to have a statically typed return value or else they won't be translatable to C. For example, as it stands #read may return a bool (if it calls digitalRead) or an int (if it calls analogRead). This may force me to take away much of the syntactic sugar -how to handle setting up named pins: declare the name with an underscore: int _led = 1; and define an accessor for it: int led(){ _led; } Then, calling the method will get you the int. -drop read and write custom methods (at least for now)? save time, save a whole step. Make it trivial to implement the whole library. . . ====================================================================================================== -the Arduino DSL is pretty good. Don't try to reinvent it for the board's api, add value on top of it! ====================================================================================================== -add constants HIGH, LOW, etc. -design directory structure -->where do we put the sketch files -->where do the .c files get compiled to? -design rad lib directory structure /sketch my_sketch.rb /build my_sketch.c rad.c /rad /lib /specs Rakefile -helper methods like blink -proof of concept of build process ================================================ FILE: lib/rad/arduino_plugin.rb ================================================ ## RAD plugins -- the start ## June 25, 2008 ## jd@jdbarnhart.com ## # Disclaimer: This is only a first run at the notion of plugins and started off as just a way to keep from adding everything to ArduinoSketch. # ArduinoPlugin is the RAD class for adding "plugins" which add functionality such as servo control, special lcd screen methods, debounce methods, etc.. Sub-classes of ArduinoPlugin (the plugins) add class methods for doing thing beyond the most common kinds of setup needed when programming the Arduino. Here is an example of controlling a servo: # # class MoveServo < ArduinoSketch # # external_vars :sensor_position => "int, 0", :servo_amount => "int, 0" # # output_pin 4, :as => :my_servo, :min => 700, :max => 2200 # input_pin 1, :as => :sensor # def loop # sensor_position = analogRead(sensor) # servo_amount = (sensor_position*2 + 500) # move_servo my_servo, servo_amount # end # end # # # Here's one for latching an led # output_pin 5, :as => :red_led # input_pin 8, :as => :red_button, :latch => :off, # optional adjustment to amount of time for debounce (default 200) :adjust => 250 # # latch sets the led as on or off initially and sets up a array of structs to keep timing and state # # def loop # debounce_toggle(red_button, red_led) # end # end # # Since this is a first pass, there is work to do here, such as # checking if plugin methods are needed and only loading those that are, # more compreshensive plugin organization (more railsish with tests, etc) # a scheme to encourage plugin authors and provide an easy way to avoid method and variable namespace collisions # a scheme to flag when a prerequisite plugin is required # on with the show: class ArduinoPlugin def initialize #:nodoc: $plugin_directives = $plugin_directives || [] $plugin_external_variables = $plugin_external_variables || [] # moved to check_for_plugin_use $plugin_structs = $plugin_structs || {} $plugin_signatures = $plugin_signatures || [] $plugin_methods = $plugin_methods || [] # $plugin_methods_hash = $plugin_methods_hash || {} ### new # $plugins_to_load = $plugins_to_load || [] ### new $add_to_setup = $add_to_setup || [] $load_libraries = $load_libraries || [] end # c declarations are automatic # you won't need them in the plugins # so, the first thing we can do is gather all the plugin methods, and scan the # sketch available plugins... # if the sketch has them, we include the plugins in the build... # otherwise not.. def include_wire $load_libraries << "Wire" unless $load_libraries.include?("Wire") end def add_to_setup(*args) if args args.each do |arg| $add_to_setup << arg end end end def plugin_directives(*args) if args args.each do |arg| $plugin_directives << arg end end end def external_variables(*args) if args args.each do |arg| puts self.class puts "\tadding plugin external variables: #{arg}" # colons aptional colon = arg[arg.length - 1, 1] == ";" ? '' : ';' $plugin_external_variables << "#{arg}#{colon}" end end end def add_blink_m_struct $plugin_structs[:blink_m] = <<-STR typedef struct _blinkm_script_line { uint8_t dur; uint8_t cmd[4]; // cmd,arg1,arg2,arg3 } blinkm_script_line; STR end def self.add_blink_m_struct $plugin_structs[:blink_m] = <<-STR typedef struct _blinkm_script_line { uint8_t dur; uint8_t cmd[4]; // cmd,arg1,arg2,arg3 } blinkm_script_line; STR end def add_debounce_struct $plugin_structs[:debounce] = <<-STR struct debounce { int state; int read; int prev; unsigned long time; unsigned long adjust; }; STR end def add_servo_struct $plugin_structs[:servo] = <<-STR struct servo { int pin; long unsigned pulseWidth; long unsigned lastPulse; long unsigned startPulse; long unsigned refreshTime; int min; int max; }; STR end def self.add_debounce_struct $plugin_structs[:debounce] = <<-STR struct debounce { int state; int read; int prev; unsigned long time; unsigned long adjust; }; STR end def self.add_servo_struct $plugin_structs[:servo] = <<-STR struct servo { int pin; long unsigned pulseWidth; long unsigned lastPulse; long unsigned startPulse; long unsigned refreshTime; int min; int max; }; STR end def self.add_sensor_struct $plugin_structs[:sensor] = <<-STR struct hysteresis { int pin; int state; }; STR end def self.add_spectra_struct $plugin_structs[:spectra] = <<-STR struct spectra { int pin; int state; int r1; int r2; int r3; }; STR end def self.check_for_plugin_use(sketch_string, plugin_string, file_name) # rename klass to filename $plugin_structs = $plugin_structs || {} $plugin_methods_hash = $plugin_methods_hash || {} $plugins_to_load = $plugins_to_load || [] plugin_signatures = [] plugin_methods = [] ## need a test for this ## fails on string interpolation, but since ruby_to_c also currently fails ... sketch_string = sketch_string.gsub(/#(?!\{.*\}).*/, "") plugin_signatures << plugin_string.scan(/^\s*(((#{PLUGIN_C_VAR_TYPES})\s*)+\w*\(.*\))/) # gather just the method name and then add to #plugin_methods_hash plugin_signatures[0].map {|sig| "#{sig[0]}"}.each {|m| plugin_methods << m.gsub!(/^.*\s(\w*)\(.*\)/, '\1')} # we don't know the methods yet, so... $plugin_methods_hash[file_name] = plugin_methods $plugin_methods_hash.each do |k,meths| meths.each do |meth| if sketch_string.include?(meth) # load this plugin... $plugins_to_load << k unless $plugins_to_load.include?(k) end end end end def self.process(plugin_string) plugin_signatures = [] first_process = plugin_string # todo: need to add plugin names to the methods, so we can add them as comments in the c code # gather the c methods $plugin_methods << first_process.scan(/^\s*(((#{PLUGIN_C_VAR_TYPES}).*\)).*(\n.*)*^\s*\})/) plugin_signatures << first_process.scan(/^\s((#{PLUGIN_C_VAR_TYPES}).*\(.*\))/) $plugin_signatures << plugin_signatures[0].map {|sig| "#{sig[0]};"} ## strip out the methods and pass it back result = plugin_string # strip out the c methods so we have only ruby before eval result.gsub(/^\s*(#{PLUGIN_C_VAR_TYPES}).*(\n.*)*^\s*\}/, "" ) end private def add_struct(struct) end end ================================================ FILE: lib/rad/arduino_sketch.rb ================================================ # ArduinoSketch is the main access point for working with RAD. Sub-classes of ArduinoSketch have access to a wide array of convenient class methods (documented below) for doing the most common kinds of setup needed when programming the Arduino such as configuring input and output pins and establishing serial connections. Here is the canonical 'hello world' example of blinking a single LED in RAD: # # class HelloWorld < ArduinoSketch # output_pin 13, :as => :led # # def loop # blink 13, 500 # end # end # # As you can see from this example, your ArduinoSketch sub-class can be dividied into two-parts: class methods for doing configuration and a loop method which will be run repeatedly at the Arduino's clock rate. Documentation for the various available class methods is below. The ArduinoSketch base class is designed to work with a series of rake tasks to automatically translate your loop method into C++ for compilation by the Arduino toolchain (see link://files/lib/rad/tasks/build_and_make_rake.html for details). See http://rad.rubyforge.org/examples for lots more examples of usage. # # ==Arduino built-in methods # Thanks to this translation process you can take advantage of the complete Arduino software API (full docs here: http://www.arduino.cc/en/Reference/HomePage). What follows is the core of a RAD-Arduino dictionary for translating between RAD methods and the Arduino functionality they invoke, N.B. many Arduino methods have been left out (including the libraries for Time, Math, and Random Numbers, as the translation between them and their RAD counterparts should be relatively straightforward after perusing the examples here). For further details on each method, visit their Arduino documenation. # # Digital I/O # # digital_write(pin, value) # # Arduino method: digitalWrite(pin, value) # # Description: "Ouputs either HIGH or LOW at a specified pin." # # Documentation: http://www.arduino.cc/en/Reference/DigitalWrite # # digital_read(pin) # # Arduino method: digitalRead(pin) # # Description: "Reads the value from a specified pin, it will be either HIGH or LOW." # # Documentation: http://www.arduino.cc/en/Reference/DigitalRead # # Analog I/O # # analog_read(pin) # # Arduino method: analogRead(pin) # # Description: "Reads the value from the specified analog pin. The Arduino board contains a 6 channel # (8 channels on the Mini), 10-bit analog to digital converter. This means that it will map input # voltages between 0 and 5 volts into integer values between 0 and 1023. This yields a resolution # between readings of: 5 volts / 1024 units or, .0049 volts (4.9 mV) per unit. It takes about 100 # us (0.0001 s) to read an analog input, so the maximum reading rate is about 10,000 times a second." # # Documentation: http://www.arduino.cc/en/Reference/AnalogRead # # analog_write(pin, value) # # Arduino method: analogWrite(pin, value) # # Description: "Writes an analog value (PWM wave) to a pin. On newer Arduino boards (including the Mini # and BT) with the ATmega168 chip, this function works on pins 3, 5, 6, 9, 10, and 11. Older USB and # serial Arduino boards with an ATmega8 only support analogWrite() on pins 9, 10, and 11. Can be used # to light a LED at varying brightnesses or drive a motor at various speeds. After a call to analogWrite, # the pin will generate a steady wave until the next call to analogWrite (or a call to digitalRead or # digitalWrite on the same pin)." # # Documentation: http://www.arduino.cc/en/Reference/AnalogWrite # # Serial Communication # # serial_available() # # Arduino method: Serial.available() # # Description: "Get the number of bytes (characters) available for reading over the serial port. # Returns the number of bytes available to read in the serial buffer, or 0 if none are # available. If any data has come in, Serial.available() will be greater than 0. The serial buffer # can hold up to 128 bytes." # # Documentation: http://www.arduino.cc/en/Serial/Available # # serial_read() # # Arduino method: Serial.read() # # Description: "Reads incoming serial data and returns the first byte of incoming serial data # available (or -1 if no data is available)" # # Documentation: http://www.arduino.cc/en/Serial/Read # # serial_print(data) # # Arduino method: Serial.print(data) # # Description: "Prints data to the serial port." # # Documentation: http://www.arduino.cc/en/Serial/Print # # serial_println(data) # # Arduino method: Serial.println(data) # # Description: "Prints a data to the serial port, followed by a carriage return character # (ASCII 13, or '\r') and a newline character (ASCII 10, or '\n'). This command takes the # same forms as Serial.print():" # # Documentation: http://www.arduino.cc/en/Serial/Println # # serial_flush() # # Arduino method: Serial.flush() # # Description: "Flushes the buffer of incoming serial data. That is, any call to Serial.read() # or Serial.available() will return only data received after the most recent call # to Serial.flush()." # # Documentation: http://www.arduino.cc/en/Serial/Flush # # June 25, 2008 # Added a new external variable method which keeps track # external_vars :sensor_position => "int, 0", :feedback => "int", :pulseTime => "unsigned long, 0" # # added ability to write additional methods besides loop in the sketch # since there is quite a bit of work to do with the c translation, it is easy to write a method that # won't compile or even translate into c, but for basics, it works. # Note: stay basic and mindful that c is picky about variables and must make a decision # which will not always be what you want # also: for now, don't leave empty methods (something like foo = 1 cures this) # # Example: # # class HelloMethods < ArduinoSketch # output_pin 13, :as => :led # # def loop # blink_it # end # 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 # # class ArduinoSketch include ExternalVariableProcessing # find another way to do this @@twowire_inc = FALSE @@hwserial_inc = FALSE def initialize #:nodoc: @servo_settings = [] # need modular way to add this @debounce_settings = [] # need modular way to add this @hysteresis_settings = [] @spectra_settings = [] @servo_pins = [] @debounce_pins = [] @hysteresis_pins = [] @spectra_pins = [] $external_array_vars = [] $external_vars =[] $external_var_identifiers = [] $sketch_methods = [] $load_libraries ||= [] $defines ||= [] $define_types = {} $array_types = {} $array_index_helpers = ('a'..'zz').to_a @declarations = [] @pin_modes = {:output => [], :input => []} @pullups = [] @other_setup = [] # specifically, Serial.begin @assembler_declarations = [] @accessors = [] @signatures = ["int main();"] helper_methods = [] @helper_methods = helper_methods.join( "\n" ) end # array "char buffer[32]" # result: char buffer[32]; # array "char buffer[32]" # result: char buffer[32]; # 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) def array(arg) if arg arg = arg.chomp.rstrip.lstrip arg.sub!("@","__") 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 # 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 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 # 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 # 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 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 # 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 ArduinoSketch#input_pin but configure more than one input pin simultaneously. Takes an array of pin numbers. def input_pins(nums) ar = Array(nums) ar.each {|n| input_pin(n)} end def add(st) #:nodoc: @helper_methods << "\n#{st}\n" end # Configure Arduino for serial communication. Optionally, set the baud rate: # # serial_begin :rate => 2400 # # default is 9600. See http://www.arduino.cc/en/Serial/Begin for more details. # def serial_begin(opts={}) rate = opts[:rate] ? opts[:rate] : 9600 @other_setup << "Serial.begin(#{rate});" @@hwserial_inc = TRUE end 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 " accessor << "#define write_line(...) sprintf(#{opts[:as]},__VA_ARGS__);" @accessors << accessor.join( "\n" ) array("char #{opts[:as]}[#{buffer_size}]") end end end def compose_setup #:nodoc: also composes headers and signatures declarations = [] plugin_directives = [] signatures = [] external_vars = [] setup = [] additional_setup =[] helpers = [] main = [] result = [] declarations << comment_box( "Auto-generated by RAD" ) declarations << "#include \n" declarations << "#include \n" $load_libraries.each { |lib| declarations << "#include <#{lib}.h>" } unless $load_libraries.nil? $defines.each { |d| declarations << d } plugin_directives << comment_box( 'plugin directives' ) $plugin_directives.each {|dir| plugin_directives << dir } unless $plugin_directives.nil? || $plugin_directives.empty? signatures << comment_box( 'method signatures' ) signatures << "void loop();" signatures << "void setup();" signatures << "// sketch signatures" @signatures.each {|sig| signatures << sig} signatures << "// plugin signatures" $plugin_signatures.each {|sig| signatures << sig } unless $plugin_signatures.nil? || $plugin_signatures.empty? external_vars << "\n" + comment_box( "plugin external variables" ) $plugin_external_variables.each { |meth| external_vars << meth } unless $plugin_external_variables.nil? || $plugin_external_variables.empty? signatures << "\n" + comment_box( "plugin structs" ) $plugin_structs.each { |k,v| signatures << v } unless $plugin_structs.nil? || $plugin_structs.empty? external_vars << "\n" + comment_box( "sketch external variables" ) $external_vars.each {|v| external_vars << v } external_vars << "" external_vars << "// servo_settings array" array_size = @servo_settings.empty? ? 1 : @servo_pins.max + 1 # conserve space if no variables needed external_vars << "struct servo serv[#{array_size}] = { #{@servo_settings.join(", ")} };" if $plugin_structs[:servo] external_vars << "" external_vars << "// debounce array" array_size = @debounce_settings.empty? ? 1 : @debounce_pins.max + 1 # conserve space if no variables needed external_vars << "struct debounce dbce[#{array_size}] = { #{@debounce_settings.join(", ")} };" if $plugin_structs[:debounce] external_vars << "" external_vars << "// hysteresis array" h_array_size = @hysteresis_settings.empty? ? 1 : @hysteresis_pins.length + 1 # conserve space if no variables needed external_vars << "struct hysteresis hyst[#{h_array_size}] = { #{@hysteresis_settings.join(", ")} };" if $plugin_structs[:sensor] external_vars << "" external_vars << "// spectrasymbol soft pot array" sp_array_size = @spectra_settings.empty? ? 1 : @spectra_pins.length + 1 # conserve space if no variables needed external_vars << "struct spectra spec[#{sp_array_size}] = { #{@spectra_settings.join(", ")} };" if $plugin_structs[:spectra] external_vars << "" $external_array_vars.each { |var| external_vars << var } if $external_array_vars external_vars << "\n" + comment_box( "variable and accessors" ) @declarations.each {|dec| external_vars << dec} external_vars << "" @accessors.each {|ac| external_vars << ac} # fix naming external_vars << "\n" + comment_box( "assembler declarations" ) unless @assembler_declarations.empty? external_vars << <<-CODE extern "C" { #{@assembler_declarations.join("\n")} } CODE end external_vars << "\n" + comment_box( "setup" ) setup << "void setup() {" setup << "\t// pin modes" @pin_modes.each do |k,v| v.each do |value| setup << "\tpinMode(#{value}, #{k.to_s.upcase});" end end @pullups.each do |pin| setup << "\tdigitalWrite( #{pin}, HIGH ); // enable pull-up resistor for input" end unless $add_to_setup.nil? || $add_to_setup.empty? setup << "\t// setup from plugins via add_to_setup method" $add_to_setup.each {|item| setup << "\t#{item}"} end unless @other_setup.empty? setup << "\t// other setup" setup << @other_setup.join( "\n" ) end additional_setup << "}\n" helpers << comment_box( "helper methods" ) helpers << "\n// RAD built-in helpers" helpers << @helper_methods.lstrip helpers << "\n" + comment_box( "plugin methods" ) # need to add plugin name to this... $plugin_methods.each { |meth| helpers << "#{meth[0][0]}\n" } unless $plugin_methods.nil? || $plugin_methods.empty? if @@hwserial_inc == TRUE helpers << "\n// serial helpers" helpers << serial_boilerplate.lstrip end main << "\n" + comment_box( "main() function" ) main << "int main() {" main << "\tinit();" main << "\tsetup();" main << "\tfor( ;; ) { loop(); }" main << "\treturn 0;" main << "}" main << "\n" + comment_box( "loop! Autogenerated by RubyToC, sorry it's ugly." ) return [declarations, plugin_directives, signatures, external_vars, setup, additional_setup, helpers, main] 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: http://rad.rubyforge.org/examples/assembler_test.html 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 def self.pre_process(sketch_string) #:nodoc: result = sketch_string # add external vars to each method (needed for better translation, will be removed in make:upload) result.gsub!(/(^\s*def\s.\w*(\(.*\))?)/, '\1' + " \n #{$external_vars.join(" \n ")}" ) # gather method names sketch_methods = result.scan(/^\s*def\s.\w*/) sketch_methods.each {|m| $sketch_methods << m.gsub(/\s*def\s*/, "") } result.gsub!("HIGH", "1") result.gsub!("LOW", "0") result.gsub!("ON", "1") result.gsub!("OFF", "0") result end def self.add_to_setup(meth) meth = meth.gsub("setup", "additional_setup") post_process_ruby_to_c_methods(meth) end 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 def comment_box( content ) #:nodoc: out = [] out << "/" * 74 out << "// " + content out << "/" * 74 return out.join( "\n" ) end end ================================================ FILE: lib/rad/darwin_installer.rb ================================================ class DarwinInstaller def self.install! puts "Downloading arduino-0012 for Mac from Arduino.cc" File.open("/Applications/arduino-0012.zip", "w") do |file| pbar = nil file << open("http://www.arduino.cc/files/arduino-0012-mac.zip", :content_length_proc => lambda {|t| if t && 0 < t pbar = ProgressBar.new(" Progress", t) pbar.file_transfer_mode end }, :progress_proc => lambda {|s| pbar.set s if pbar }).read pbar.finish end puts "Unzipping..." `cd /Applications; unzip arduino-0012.zip` `rm /Applications/arduino-0012.zip` puts "installed Arduino here: /Applications/arduino-0012" end end ================================================ FILE: lib/rad/generators/makefile/makefile.erb ================================================ # Arduino makefile # # This makefile allows you to build sketches from the command line # without the Arduino environment (or Java). # # The Arduino environment does preliminary processing on a sketch before # compiling it. If you're using this makefile instead, you'll need to do # a few things differently: # # - Give your program's file a .cpp extension (e.g. foo.cpp). # # - Put this line at top of your code: #include # # - Write prototypes for all your functions (or define them before you # call them). A prototype declares the types of parameters a # function will take and what type of value it will return. This # means that you can have a call to a function before the definition # of the function. A function prototype looks like the first line of # the function, with a semi-colon at the end. For example: # int digitalRead(int pin); # # - Write a main() function for your program that returns an int, calls # init() and setup() once (in that order), and then calls loop() # repeatedly(): # # int main() # { # init(); # setup(); # # for (;;) # loop(); # # return 0; # } # # Instructions for using the makefile: # # 1. Copy this file into the folder with your sketch. # # 2. Below, modify the line containing "TARGET" to refer to the name of # of your program's file without an extension (e.g. TARGET = foo). # # 3. Modify the line containg "ARDUINO" to point the directory that # contains the Arduino core (for normal Arduino installations, this # is the hardware/cores/arduino sub-directory). # # 4. Modify the line containing "PORT" to refer to the filename # representing the USB or serial connection to your Arduino board # (e.g. PORT = /dev/tty.USB0). If the exact name of this file # changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*). # # 5. At the command line, change to the directory containing your # program's file and the makefile. # # 6. Type "make" and press enter to compile/verify your program. # # 7. Type "make upload", reset your Arduino board, and press enter to # upload your program to the Arduino board. # # $Id$ PORT = <%= params['serial_port'] %> TARGET = <%= params['target'] %> ARDUINO = <%= params['arduino_root'] %>/hardware/cores/arduino SOFTWARE_SERIAL = <%= params['arduino_root'] %>/hardware/libraries/SoftwareSerial LIBRARY_ROOT = <%= params['libraries_root'] %> SRC = $(ARDUINO)/pins_arduino.c $(ARDUINO)/wiring.c \ $(ARDUINO)/wiring_analog.c $(ARDUINO)/wiring_digital.c \ $(ARDUINO)/wiring_pulse.c $(ARDUINO)/wiring_serial.c \ $(ARDUINO)/wiring_shift.c $(ARDUINO)/WInterrupts.c <%= params['twi_c'] %> CXXSRC = $(ARDUINO)/HardwareSerial.cpp $(SOFTWARE_SERIAL)/SoftwareSerial.cpp $(ARDUINO)/Print.cpp<%= params['libraries'].collect{|l| " $(LIBRARY_ROOT)/#{ l }/#{l }.cpp"}.join('') %> MCU = <%= params['mcu'] %> <% if params['asm_files'] %>ASRC = <%= params['asm_files'].join(' ') %><% end %> F_CPU = 16000000 FORMAT = ihex UPLOAD_RATE = 19200 BIN_DIR = <%= params['arduino_root'] %>/hardware/tools/avr/bin # Name of this Makefile (used for "make depend"). MAKEFILE = Makefile # Debugging format. # Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. # AVR (extended) COFF requires stabs, plus an avr-objcopy run. DEBUG = stabs OPT = s # Place -D or -U options here CDEFS = -DF_CPU=$(F_CPU) CXXDEFS = -DF_CPU=$(F_CPU) # Place -I options here CINCS = -I$(ARDUINO) -I$(SOFTWARE_SERIAL)<% params['libraries'].each do |l| %> -I$(LIBRARY_ROOT)/<%= l %><% end %> +CXXINCS = -I$(ARDUINO) -I$(SOFTWARE_SERIAL)<% params['libraries'].each do |l| %> -I$(LIBRARY_ROOT)/<%= l %><% end %> # Compiler flag to set the C Standard level. # c89 - "ANSI" C # gnu89 - c89 plus GCC extensions # c99 - ISO C99 standard (not yet fully implemented) # gnu99 - c99 plus GCC extensions CSTANDARD = -std=gnu99 CDEBUG = -g$(DEBUG) CWARN = -Wall -Wstrict-prototypes CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums #CEXTRA = -Wa,-adhlns=$(<:.c=.lst) CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) CXXFLAGS = $(CDEFS) $(CINCS) -O$(OPT) #ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs LDFLAGS = -lm # Programming support using avrdude. Settings and variables. AVRDUDE_PROGRAMMER = stk500 AVRDUDE_PORT = $(PORT) AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ -b $(UPLOAD_RATE) -C <%= params['arduino_root'] %>/hardware/tools/avr/etc/avrdude.conf # Program settings CC = $(BIN_DIR)/avr-gcc CXX = $(BIN_DIR)/avr-g++ OBJCOPY = $(BIN_DIR)/avr-objcopy OBJDUMP = $(BIN_DIR)/avr-objdump AR = $(BIN_DIR)/avr-ar SIZE = $(BIN_DIR)/avr-size NM = $(BIN_DIR)/avr-nm AVRDUDE = $(BIN_DIR)/avrdude REMOVE = rm -f MV = mv -f # Define all object files. OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) # Define all listing files. LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) # Combine all necessary flags and optional flags. # Add target processor to flags. ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) # Default target. all: build build: elf hex elf: $(TARGET).elf hex: $(TARGET).hex eep: $(TARGET).eep lss: $(TARGET).lss sym: $(TARGET).sym # Program the device. upload: $(TARGET).hex $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) # Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. COFFCONVERT=$(OBJCOPY) --debugging \ --change-section-address .data-0x800000 \ --change-section-address .bss-0x800000 \ --change-section-address .noinit-0x800000 \ --change-section-address .eeprom-0x810000 coff: $(TARGET).elf $(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof extcoff: $(TARGET).elf $(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof .SUFFIXES: .elf .hex .eep .lss .sym .elf.hex: $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ .elf.eep: -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ # Create extended listing file from ELF output file. .elf.lss: $(OBJDUMP) -h -S $< > $@ # Create a symbol table from ELF output file. .elf.sym: $(NM) -n $< > $@ core.a: $(OBJ) @for i in $(OBJ); do echo $(AR) rcs core.a $$i; $(AR) rcs core.a $$i; done # Link: create ELF output file from library. $(TARGET).elf: core.a $(CC) $(ALL_CFLAGS) -o $@ $(TARGET).cpp -L. core.a $(LDFLAGS) # Compile: create object files from C++ source files. .cpp.o: $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ # Compile: create object files from C source files. .c.o: $(CC) -c $(ALL_CFLAGS) $< -o $@ # Compile: create assembler files from C source files. .c.s: $(CC) -S $(ALL_CFLAGS) $< -o $@ # Assemble: create object files from assembler source files. .S.o: $(CC) -c $(ALL_ASFLAGS) $< -o $@ # Target: clean project. clean: $(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \ $(TARGET).map $(TARGET).sym $(TARGET).lss core.a \ $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) depend: if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ then \ sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ $(MAKEFILE).$$$$ && \ $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ fi echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ >> $(MAKEFILE); \ $(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE) .PHONY: all build elf hex eep lss sym program coff extcoff clean depend ================================================ FILE: lib/rad/generators/makefile/makefile.rb ================================================ require 'erb' require 'yaml' class Makefile class << self # build the sketch Makefile for the given template based on the values in its software and hardware config files def compose_for_sketch(build_dir) params = hardware_params.merge software_params params['target'] = build_dir.split("/").last params['libraries_root'] = "#{File.expand_path(RAD_ROOT)}/vendor/libraries" params['libraries'] = $load_libraries # load only libraries used # needed along with ugly hack of including another copy of twi.h in wire, when using the Wire.h library params['twi_c'] = $load_libraries.include?("Wire") ? "#{params['arduino_root']}/hardware/libraries/Wire/utility/twi.c" : "" params['asm_files'] = Dir.entries( File.expand_path(RAD_ROOT) + "/" + PROJECT_DIR_NAME ).select{|e| e =~ /\.S/} e = ERB.new File.read("#{File.dirname(__FILE__)}/makefile.erb") File.open("#{build_dir}/Makefile", "w") do |f| f << e.result(binding) end end def hardware_params return @hardware_params if @hardware_params return @hardware_params = YAML.load_file( "#{RAD_ROOT}/config/hardware.yml") end def software_params return @software_params if @software_params return @software_params = YAML.load_file( "#{RAD_ROOT}/config/software.yml" ) end end end ================================================ FILE: lib/rad/hardware_library.rb ================================================ class HardwareLibrary < ArduinoSketch def initialize super end # Treat a pair of digital I/O pins as a serial line. See: http://www.arduino.cc/en/Tutorial/SoftwareSerial def software_serial(rx, tx, opts={}) raise ArgumentError, "can only define rx from Fixnum, got #{rx.class}" unless rx.is_a?(Fixnum) raise ArgumentError, "can only define tx from Fixnum, got #{tx.class}" unless tx.is_a?(Fixnum) output_pin(tx) input_pin(rx) rate = opts[:rate] ? opts[:rate] : 9600 if opts[:as] @declarations << "SoftwareSerial _#{opts[ :as ]} = SoftwareSerial(#{rx}, #{tx});" accessor = <<-STR SoftwareSerial& #{opts[ :as ]}() { return _#{opts[ :as ]}; } STR @@swser_inc ||= FALSE if (@@swser_inc == FALSE) # on second instance this stuff can't be repeated @@swser_inc = TRUE accessor += <<-STR int read(SoftwareSerial& s) { return s.read(); } void println( SoftwareSerial& s, char* str ) { return s.println( str ); } void print( SoftwareSerial& s, char* str ) { return s.print( str ); } void println( SoftwareSerial& s, int i ) { return s.println( i ); } void print( SoftwareSerial& s, int i ) { return s.print( i ); } STR end @accessors << accessor @signatures << "SoftwareSerial& #{opts[ :as ]}();" @other_setup << "\t_#{opts[ :as ]}.begin(#{rate});" end end # use the pa lcd library def pa_lcd_setup(num, opts) if opts[:geometry] raise ArgumentError, "can only define pin from Fixnum, got #{opts[:geometry]}" unless opts[:geometry].is_a?(Fixnum) raise ArgumentError, "pa_lcd geometry must be 216, 220, 224, 240, 416, 420, got #{opts[:geometry]}" unless opts[:geometry].to_s =~ /(216|220|224|240|416|420)/ end # move to plugin and load plugin # what's the default? opts[:rate] ||= 9600 rate = opts[:rate] ? opts[:rate] : 9600 swser_LCDpa(num, opts) end def swser_LCDpa(tx, opts={}) raise ArgumentError, "can only define tx from Fixnum, got #{tx.class}" unless tx.is_a?(Fixnum) rate = opts[:rate] ? opts[:rate] : 9600 geometry = opts[:geometry] ? opts[:geometry] : 0 if opts[:as] @declarations << "SWSerLCDpa _#{opts[ :as ]} = SWSerLCDpa(#{tx}, #{geometry});" $load_libraries << "SWSerLCDpa" accessor = <<-STR SWSerLCDpa& #{opts[ :as ]}() { return _#{opts[ :as ]}; } STR @@slcdpa_inc ||= FALSE if (@@slcdpa_inc == FALSE) # on second instance this stuff can't be repeated - BBR @@slcdpa_inc = TRUE # ------------------- print generics ------------------------------- accessor += <<-STR void print( SWSerLCDpa& s, uint8_t b ) { return s.print( b ); } void print( SWSerLCDpa& s, const char *str ) { return s.print( str ); } void print( SWSerLCDpa& s, char c ) { return s.print( c ); } void print( SWSerLCDpa& s, int i ) { return s.print( i ); } void print( SWSerLCDpa& s, unsigned int i ) { return s.print( i ); } void print( SWSerLCDpa& s, long i ) { return s.print( i ); } void print( SWSerLCDpa& s, unsigned long i ) { return s.print( i ); } void print( SWSerLCDpa& s, long i, int b ) { return s.print( i, b ); } STR # ------------------ PA-LCD specific functions --------------------------------- accessor += <<-STR void clearscr(SWSerLCDpa& s) { return s.clearscr(); } void clearscr(SWSerLCDpa& s, const char *str) { return s.clearscr(str); } void clearscr(SWSerLCDpa& s, int n) { return s.clearscr(n); } void clearscr(SWSerLCDpa& s, long n, int b) { return s.clearscr(n, b); } void clearline(SWSerLCDpa& s, int line) { return s.clearline( line ); } void clearline(SWSerLCDpa& s, int line, const char *str) { return s.clearline( line, str ); } void clearline(SWSerLCDpa& s, int line, int n) { return s.clearline( line, n ); } void clearline(SWSerLCDpa& s, int line, long n, int b) { return s.clearline( line, n, b ); } void home( SWSerLCDpa& s) { return s.home(); } void home( SWSerLCDpa& s, const char *str) { return s.home( str ); } void home( SWSerLCDpa& s, int n) { return s.home( n ); } void home( SWSerLCDpa& s, long n, int b) { return s.home( n, b ); } void setxy( SWSerLCDpa& s, int x, int y) { return s.setxy( x, y ); } void setxy( SWSerLCDpa& s, int x, int y, const char *str) { return s.setxy( x, y, str ); } void setxy( SWSerLCDpa& s, int x, int y, long n, int b) { return s.setxy( x, y, n, b ); } void setxy( SWSerLCDpa& s, int x, int y, int n) { return s.setxy( x, y, n ); } void setgeo( SWSerLCDpa& s, int g) { return s.setgeo( g ); } void setintensity( SWSerLCDpa& s, int i ) { return s.setintensity( i ); } void intoBignum(SWSerLCDpa& s) { return s.intoBignum(); } void outofBignum(SWSerLCDpa& s) { return s.outofBignum(); } STR end @accessors << accessor @signatures << "SWSerLCDpa& #{opts[ :as ]}();" @other_setup << "\t_#{opts[ :as ]}.begin(#{rate});" @other_setup << "\t_#{opts[ :as ]}.clearscr();" if :clear_screen == :true end end # use the sf (sparkfun) library def sf_lcd_setup(num, opts) if opts[:geometry] raise ArgumentError, "can only define pin from Fixnum, got #{opts[:geometry]}" unless opts[:geometry].is_a?(Fixnum) raise ArgumentError, "sf_lcd geometry must be 216, 220, 416, 420, got #{opts[:geometry]}" unless opts[:geometry].to_s =~ /(216|220|416|420)/ end # move to plugin and load plugin opts[:rate] ||= 9600 rate = opts[:rate] ? opts[:rate] : 9600 swser_LCDsf(num, opts) end def swser_LCDsf(tx, opts={}) raise ArgumentError, "can only define tx from Fixnum, got #{tx.class}" unless tx.is_a?(Fixnum) rate = opts[:rate] ? opts[:rate] : 9600 geometry = opts[:geometry] ? opts[:geometry] : 0 if opts[:as] @declarations << "SWSerLCDsf _#{opts[ :as ]} = SWSerLCDsf(#{tx}, #{geometry});" $load_libraries << "SWSerLCDsf" accessor = <<-STR SWSerLCDsf& #{opts[ :as ]}() { return _#{opts[ :as ]}; } STR @@slcdsf_inc ||= FALSE # assign only if nil if (@@slcdsf_inc == FALSE) # on second instance this stuff can't be repeated - BBR @@slcdsf_inc = TRUE accessor += <<-STR void print( SWSerLCDsf& s, uint8_t b ) { return s.print( b ); } void print( SWSerLCDsf& s, const char *str ) { return s.print( str ); } void print( SWSerLCDsf& s, char c ) { return s.print( c ); } void print( SWSerLCDsf& s, int i ) { return s.print( i ); } void print( SWSerLCDsf& s, unsigned int i ) { return s.print( i ); } void print( SWSerLCDsf& s, long i ) { return s.print( i ); } void print( SWSerLCDsf& s, unsigned long i ) { return s.print( i ); } void print( SWSerLCDsf& s, long i, int b ) { return s.print( i, b ); } STR # ------------------ Spark Fun Specific Functions --------------------------------- accessor += <<-STR void clearscr(SWSerLCDsf& s) { return s.clearscr(); } void clearscr(SWSerLCDsf& s, const char *str) { return s.clearscr(str); } void clearscr(SWSerLCDsf& s, int n) { return s.clearscr(n); } void clearscr(SWSerLCDsf& s, long n, int b) { return s.clearscr(n, b); } void home( SWSerLCDsf& s) { return s.home(); } void home( SWSerLCDsf& s, const char *str) { return s.home( str ); } void home( SWSerLCDsf& s, int n) { return s.home( n ); } void home( SWSerLCDsf& s, long n, int b) { return s.home( n, b ); } void setxy( SWSerLCDsf& s, int x, int y) { return s.setxy( x, y ); } void setxy( SWSerLCDsf& s, int x, int y, const char *str) { return s.setxy( x, y, str ); } void setxy( SWSerLCDsf& s, int x, int y, int n) { return s.setxy( x, y, n ); } void setxy( SWSerLCDsf& s, int x, int y, long n, int b) { return s.setxy( x, y, n, b ); } void setgeo( SWSerLCDsf& s, int g) { return s.setgeo( g ); } void setintensity( SWSerLCDsf& s, int i ) { return s.setintensity( i ); } void setcmd( SWSerLCDsf& s, uint8_t a, uint8_t b) { return s.setcmd( a, b ); } STR end @accessors << accessor @signatures << "SWSerLCDsf& #{opts[ :as ]}();" @other_setup << "\t_#{opts[ :as ]}.begin(#{rate});" @other_setup << "\t_#{opts[ :as ]}.clearscr();" if :clear_screen == :true end end def loop_timer(opts={}) # loop timer methods # if opts[:as] @declarations << "LoopTimer _#{opts[ :as ]} = LoopTimer();" $load_libraries << "LoopTimer" accessor = <<-STR LoopTimer& #{opts[ :as ]}() { return _#{opts[ :as ]}; } STR @@loptim_inc ||= FALSE if (@@loptim_inc == FALSE) # on second instance this stuff can't be repeated - BBR @@limtim_inc = TRUE accessor += <<-STR void track( LoopTimer& s ) { return s.track(); } unsigned long get_total( LoopTimer& s ) { return s.get_total(); } STR end @accessors << accessor @signatures << "LoopTimer& #{opts[ :as ]}();" end end # use the servo library def servo_setup(num, opts) if opts[:position] raise ArgumentError, "position must be an integer from 0 to 360, got #{opts[:position].class}" unless opts[:position].is_a?(Fixnum) raise ArgumentError, "position must be an integer from 0 to 360---, got #{opts[:position]}" if opts[:position] < 0 || opts[:position] > 360 end servo(num, opts) # move this to better place ... # should probably go along with servo code into plugin @@servo_dh ||= FALSE if (@@servo_dh == FALSE) # on second instance this stuff can't be repeated - BBR @@servo_dh = TRUE @declarations << "void servo_refresh(void);" helper_methods = [] helper_methods << "void servo_refresh(void)" helper_methods << "{" helper_methods << "\tServo::refresh();" helper_methods << "}" @helper_methods += "\n#{helper_methods.join("\n")}" end end def servo(pin, opts={}) # servo motor routines # raise ArgumentError, "can only define pin from Fixnum, got #{pin.class}" unless pin.is_a?(Fixnum) minp = opts[:min] ? opts[:min] : 544 maxp = opts[:max] ? opts[:max] : 2400 if opts[:as] @declarations << "Servo _#{opts[ :as ]} = Servo();" $load_libraries << "Servo" accessor = <<-STR Servo& #{opts[ :as ]}() { return _#{opts[ :as ]}; } STR @@servo_inc ||= FALSE if (@@servo_inc == FALSE) # on second instance this stuff can't be repeated - BBR @@servo_inc = TRUE accessor += <<-STR uint8_t attach( Servo& s, int p ) { return s.attach(p); } uint8_t attach( Servo& s, int p, int pos ) { return s.attach(p, pos ); } uint8_t attach( Servo& s, int p, uint16_t mn, uint16_t mx ) { return s.attach(p, mn, mx); } uint8_t attach( Servo& s, int p, int pos, uint16_t mn, uint16_t mx ) { return s.attach(p, pos, mn, mx); } void detach( Servo& s ) { return s.detach(); } void position( Servo& s, int b ) { return s.position( b ); } void speed( Servo& s, int b ) { return s.speed( b ); } uint8_t read( Servo& s ) { return s.read(); } uint8_t attached( Servo& s ) { return s.attached(); } static void refresh( Servo& s ) { return s.refresh(); } STR end @accessors << accessor @signatures << "Servo& #{opts[ :as ]}();" @other_setup << "\t_#{opts[ :as ]}.attach(#{pin}, #{opts[:position]}, #{minp}, #{maxp});" if opts[:position] @other_setup << "\t_#{opts[ :as ]}.attach(#{pin}, #{minp}, #{maxp});" unless opts[:position] end end def twowire_stepper(pin1, pin2, opts={}) # servo motor routines # raise ArgumentError, "can only define pin1 from Fixnum, got #{pin1.class}" unless pin1.is_a?(Fixnum) raise ArgumentError, "can only define pin2 from Fixnum, got #{pin2.class}" unless pin2.is_a?(Fixnum) st_speed = opts[:speed] ? opts[:speed] : 30 st_steps = opts[:steps] ? opts[:steps] : 100 if opts[:as] @declarations << "Stepper _#{opts[ :as ]} = Stepper(#{st_steps},#{pin1},#{pin2});" $load_libraries << "Stepper" accessor = <<-STR Stepper& #{opts[ :as ]}() { return _#{opts[ :as ]}; } STR @@stepr_inc ||= FALSE if (@@stepr_inc == FALSE) # on second instance this stuff can't be repeated - BBR @@stepr_inc = TRUE accessor = <<-STR void set_speed( Stepper& s, long sp ) { return s.set_speed( sp ); } void set_steps( Stepper& s, int b ) { return s.set_steps( b ); } int version( Stepper& s ) { return s.version(); } STR end @accessors << accessor @signatures << "Stepper& #{opts[ :as ]}();" @other_setup << "\t_#{opts[ :as ]}.set_speed(#{st_speed});" if opts[:speed] end end def fourwire_stepper( pin1, pin2, pin3, pin4, opts={}) # servo motor routines # raise ArgumentError, "can only define pin1 from Fixnum, got #{pin1.class}" unless pin1.is_a?(Fixnum) raise ArgumentError, "can only define pin2 from Fixnum, got #{pin2.class}" unless pin2.is_a?(Fixnum) raise ArgumentError, "can only define pin3 from Fixnum, got #{pin3.class}" unless pin3.is_a?(Fixnum) raise ArgumentError, "can only define pin4 from Fixnum, got #{pin4.class}" unless pin4.is_a?(Fixnum) st_speed = opts[:speed] ? opts[:speed] : 30 st_steps = opts[:steps] ? opts[:steps] : 100 if opts[:as] @declarations << "Stepper _#{opts[ :as ]} = Stepper(#{st_steps},#{pin1},#{pin2},#{pin3},#{pin4});" $load_libraries << "Stepper" accessor = <<-STR Stepper& #{opts[ :as ]}() { return _#{opts[ :as ]}; } STR @@stepr_inc ||= FALSE if (@@stepr_inc == FALSE) # on second instance this stuff can't be repeated - BBR @@stepr_inc = TRUE accessor += <<-STR void set_speed( Stepper& s, long sp ) { return s.set_speed( sp ); } void set_steps( Stepper& s, int b ) { return s.set_steps( b ); } int version( Stepper& s ) { return s.version(); } STR end @accessors << accessor @signatures << "Stepper& #{opts[ :as ]}();" @other_setup << "\t_#{opts[ :as ]}.set_speed(#{st_speed});" if opts[:speed] end end def frequency_timer(pin, opts={}) # frequency timer routines @@frequency_inc ||= FALSE raise ArgumentError, "there can be only one instance of Frequency Timer2" if @@frequency_inc == TRUE @@frequency_inc = TRUE raise ArgumentError, "can only define pin from Fixnum, got #{pin.class}" unless pin.is_a?(Fixnum) raise ArgumentError, "only pin 11 may be used for freq_out, got #{pin}" unless pin == 11 if opts[:enable] raise ArgumentError, "enable option must include the frequency or period option" unless opts[:frequency] || opts[:period] end if opts[:frequency] raise ArgumentError, "the frequency option must be an integer, got #{opts[:frequency].class}" unless opts[:frequency].is_a?(Fixnum) end if opts[:period] raise ArgumentError, "the frequency option must be an integer, got #{opts[:period].class}" unless opts[:period].is_a?(Fixnum) end # refer to: http://www.arduino.cc/playground/Code/FrequencyTimer2 if opts[:as] @declarations << "FrequencyTimer2 _#{opts[ :as ]} = FrequencyTimer2();" $load_libraries << "FrequencyTimer2" accessor = <<-STR FrequencyTimer2& #{opts[ :as ]}() { return _#{opts[ :as ]}; } void set_frequency( FrequencyTimer2& s, int b ) { return s.setPeriod( 1000000L/b ); } void set_period( FrequencyTimer2& s, int b ) { return s.setPeriod( b ); } void enable( FrequencyTimer2& s ) { return s.enable(); } void disable( FrequencyTimer2& s ) { return s.disable(); } STR @accessors << accessor @signatures << "FrequencyTimer2& #{opts[ :as ]}();" @other_setup << "\tFrequencyTimer2::setPeriod(0L);" unless opts[:frequency] || opts[:period] @other_setup << "\tFrequencyTimer2::setPeriod(1000000L/#{opts[:frequency]});" if opts[:frequency] @other_setup << "\tFrequencyTimer2::setPeriod(#{opts[:period]});" if opts[:period] @other_setup << "\tFrequencyTimer2::enable();" if opts[:enable] == :true end end def one_wire(pin, opts={}) raise ArgumentError, "can only define pin from Fixnum, got #{pin.class}" unless pin.is_a?(Fixnum) if opts[:as] @declarations << "OneWire _#{opts[ :as ]} = OneWire(#{pin});" accessor = [] $load_libraries << "OneWire" accessor = <<-STR OneWire& #{opts[ :as ]}() { return _#{opts[ :as ]}; } STR @@onewire_inc ||= FALSE if (@@onewire_inc == FALSE) # on second instance this stuff can't be repeated - BBR @@onewire_inc = TRUE accessor += <<-STR uint8_t reset(OneWire& s) { return s.reset(); } void skip(OneWire& s) { return s.skip(); } void write(OneWire& s, uint8_t v, uint8_t p = 0) { return s.write( v, p ); } uint8_t read(OneWire& s) { return s.read(); } void write_bit( OneWire& s, uint8_t b ) { return s.write_bit( b ); } uint8_t read_bit(OneWire& s) { return s.read_bit(); } void depower(OneWire& s) { return s.depower(); } STR end @accessors << accessor @signatures << "OneWire& #{opts[ :as ]}();" end end def two_wire (pin, opts={}) # i2c Two-Wire raise ArgumentError, "can only define pin from Fixnum, got #{pin.class}" unless pin.is_a?(Fixnum) raise ArgumentError, "only pin 19 may be used for i2c, got #{pin}" unless pin == 19 if opts[:as] @@twowire_inc = TRUE @declarations << "TwoWire _wire = TwoWire();" $load_libraries << "Wire" accessor = <<-STR TwoWire& wire() { return _wire; } void begin( TwoWire& s) { return s.begin(); } void begin( TwoWire& s, uint8_t a) { return s.begin(a); } void begin( TwoWire& s, int a) { return s.begin(a); } void beginTransmission( TwoWire& s, uint8_t a ) { return s.beginTransmission( a ); } void beginTransmission( TwoWire& s, int a ) { return s.beginTransmission( a ); } void endTransmission( TwoWire& s ) { return s.endTransmission(); } void requestFrom( TwoWire& s, uint8_t a, uint8_t q) { return s.requestFrom( a, q ); } void requestFrom( TwoWire& s, int a, int q) { return s.requestFrom( a, q ); } void send( TwoWire& s, uint8_t d) { return s.send(d); } void send( TwoWire& s, int d) { return s.send(d); } void send( TwoWire& s, char* d) { return s.send(d); } void send( TwoWire& s, uint8_t* d, uint8_t q) { return s.send( d, q ); } uint8_t available( TwoWire& s) { return s.available(); } uint8_t receive( TwoWire& s) { return s.receive(); } STR @accessors << accessor @signatures << "TwoWire& wire();" @other_setup << "\t_wire.begin();" # We never get here a second time. If we go to the trouble # of setting up i2c, we gotta start it and it never gets # stopped. This is not 'optional!' end end # work in progress def ethernet(pin, opts={}) raise ArgumentError, "can only define pin from Fixnum, got #{pin.class}" unless pin.is_a?(Fixnum) if opts[:as] accessor = [] $load_libraries << "AF_XPort" $load_libraries << "AFSoftSerial" # needs to be more granular: accessor << "AF_XPort xport = AF_XPort(XPORT_RXPIN, XPORT_TXPIN, XPORT_RESETPIN, XPORT_DTRPIN, XPORT_RTSPIN, XPORT_CTSPIN);" rate = opts[:rate] ? opts[:rate] : 57600 @other_setup << "xport.begin(#{rate});" @accessors << accessor.join( "\n" ) end end def i2c_eeprom(pin, opts={}) # i2c serial eeprom routines # dev_addr = opts[:address] ? opts[:address] : 0 if opts[:as] @declarations << "I2CEEPROM _#{opts[ :as ]} = I2CEEPROM(#{dev_addr});" $load_libraries << "I2CEEPROM" accessor = <<-STR I2CEEPROM& #{opts[ :as ]}() { return _#{opts[ :as ]}; } STR @@i2cepr_inc ||= FALSE if (@@i2cepr_inc == FALSE) # on second instance this stuff can't be repeated - BBR @@i2cepr_inc = TRUE accessor += <<-STR void write_byte( I2CEEPROM& s, unsigned int addr, byte b ) { return s.write_byte( addr, b ); } void write_page( I2CEEPROM& s, unsigned int addr, byte* d, int l ) { return s.write_page( addr, d, l ); } byte read_byte( I2CEEPROM& s, unsigned int addr ) { return s.read_byte( addr ); } void read_buffer( I2CEEPROM& s, unsigned int addr, byte *d, int l ) { return s.read_buffer( addr, d, l ); } STR end @accessors << accessor @signatures << "I2CEEPROM& #{opts[ :as ]}();" end end def ds1307(pin, opts={}) # DS1307 real time clock routines routines @@ds1307_inc ||= FALSE raise ArgumentError, "only one DS1307 may be used for i2c" unless @@ds1307_inc == FALSE @@ds1307_inc = TRUE raise ArgumentError, "can only define pin from Fixnum, got #{pin.class}" unless pin.is_a?(Fixnum) raise ArgumentError, "only pin 19 may be used for i2c, got #{pin}" unless pin == 19 if opts[:as] @declarations << "DS1307 _#{opts[ :as ]} = DS1307();" $load_libraries << "DS1307" accessor = <<-STR DS1307& #{opts[ :as ]}() { return _#{opts[ :as ]}; } void get( DS1307& s, byte *buf, boolean r ) { return s.get( buf, r ); } byte get( DS1307& s, int b, boolean r ) { return s.get( b, r ); } void set( DS1307& s, int b, int r ) { return s.set( b, r ); } void start( DS1307& s ) { return s.start(); } void stop( DS1307& s ) { return s.stop(); } STR @accessors << accessor @signatures << "DS1307& #{opts[ :as ]}();" @other_setup << "\t_#{opts[ :as ]}.start();" if opts[:rtcstart] end end private def serial_boilerplate #:nodoc: out = <<-STR int serial_available() { return (Serial.available() > 0); } char serial_read() { return (char) Serial.read(); } void serial_flush() { return Serial.flush(); } void serial_print( char str ) { return Serial.print( str ); } void serial_print( char* str ) { return Serial.print( str ); } void serial_print( int i ) { return Serial.print( i ); } void serial_print( long i ) { return Serial.print( i ); } void serial_println( char* str ) { return Serial.println( str ); } void serial_println( char str ) { return Serial.println( str ); } void serial_println( int i ) { return Serial.println( i ); } void serial_println( long i ) { return Serial.println( i ); } void serial_print( unsigned long i ) { return Serial.print( i ); } STR return out end end ================================================ FILE: lib/rad/init.rb ================================================ RAD_ROOT = "#{File.dirname(__FILE__)}/../.." unless defined?(RAD_ROOT) unless defined?(PROJECT_DIR_NAME) a = File.expand_path(File.expand_path("#{RAD_ROOT}")).split("/") PROJECT_DIR_NAME = a[a.length-1] end PLUGIN_C_VAR_TYPES = "int|void|unsigned|long|short|uint8_t|static|byte|char\\*|uint8_t" gem "ParseTree", "=2.2" %w(generators/makefile/makefile.rb rad_processor.rb rad_rewriter.rb rad_type_checker.rb variable_processing.rb arduino_sketch.rb arduino_plugin.rb hardware_library.rb tasks/rad.rb sketch_compiler.rb).each do |path| require File.expand_path("#{RAD_ROOT}/vendor/rad/#{path}") end ================================================ FILE: lib/rad/linux_installer.rb ================================================ class LinuxInstaller # this is the thing we actually run to make something happen def self.install! puts "Welcome to the RAD Linux Installer!" puts "-----------------------------------" puts "Let's begin." puts check_or_warn_for_usb_driver # of course we need rubygems # maybe just rely on the user installing rubygems, because the ubuntu one sux #check_or_install_package("rubygems") #%x{gem update --system} # we need java to make this ship float check_or_nag_package("sun-java5-jre") # remove a package that interferes with the arduino usb/serial driver check_or_remove_package("brltty") # install pre-requisites check_or_install_package("binutils-avr") check_or_install_package("gcc-avr") check_or_install_package("avr-libc") check_or_install_package("unzip") check_or_install_package("wget") # remove a probably out of date avrdude check_or_remove_package("avrdude") # install pre-requisites for avrdude if we wanted to build from source # nah, it comes with the arduino binary #check_or_install_package("gcc") #check_or_install_package("bison") #check_or_install_package("flex") check_or_install_arduino end def self.check_or_install_package(package_name) package = %x{dpkg --get-selections | grep #{package_name}} if package.include?("\tinstall") puts "#{package_name} installed!" else puts "installing #{package_name}..." %x{apt-get install -y #{package_name}} end end def self.check_or_nag_package(package_name, custom_msg = nil) package = %x{dpkg --get-selections | grep #{package_name}} if package.include?("\tinstall") puts "#{package_name} installed!" else puts "you will need to manually install #{package_name}! use the command below." if custom_msg puts custom_msg else puts "sudo apt-get install #{package_name}" end exit end end def self.check_or_remove_package(package_name) package = %x{dpkg --get-selections | grep #{package_name}} #an easier way to check for installed packages? if package.include?("\tinstall") puts "removing #{package_name}..." %x{apt-get remove -y #{package_name}} else puts "#{package_name} previously uninstalled!" end end def self.check_or_warn_for_usb_driver # check if usb device recognized by system puts "Please plug in your arduino to your usb port... [hit enter to continue]" STDIN.gets # we patiently wait usb = %x{dmesg | tail | grep "FTDI USB Serial" | grep -c "now attached"} if usb.to_i == 0 # maybe we can be nice here and offer to download and install the driver package puts "the system is not recognizing your usb-serial driver, please re-install" exit end end def self.check_or_install_arduino if File.exist?("/usr/local/arduino-0012") puts "arduino software previously installed at /usr/local/arduino-0012 !" else puts "installing arduino software..." %x{cd /usr/local/; wget http://arduino.cc/files/arduino-0012-linux.tgz} %x{tar -C /usr/local -xzf /usr/local/arduino-0012-linux.tgz} %x{ln -s /usr/local/arduino-0012/arduino ~/Desktop/arduino} # gotta patch it so it can run from command line or anywhere arduino_file = File.open("/usr/local/arduino-0012/arduino") {|f| f.read} new_doc = arduino_file.split("\n") new_doc[1] = "cd /usr/local/arduino-0012" File.open("/usr/local/arduino-0012/arduino", "w") {|f| f.puts new_doc } %x{mkdir -p /usr/local/arduino-0012/hardware/tools/avr/bin} # there is a difference from what the makefile expects to where it is %x{ln -s /usr/bin/avr-gcc /usr/local/arduino-0012/hardware/tools/avr/bin/avr-gcc} %x{ln -s /usr/bin/avr-g++ /usr/local/arduino-0012/hardware/tools/avr/bin/avr-g++} %x{ln -s /usr/bin/avr-ar /usr/local/arduino-0012/hardware/tools/avr/bin/avr-ar} %x{ln -s /usr/bin/avr-objcopy /usr/local/arduino-0012/hardware/tools/avr/bin/avr-objcopy} %x{ln -s /usr/local/arduino-0012/hardware/tools/avrdude /usr/local/arduino-0012/hardware/tools/avr/bin/avrdude} %x{ln -s /usr/local/arduino-0012/hardware/tools/avrdude.conf /usr/local/arduino-0012/hardware/tools/avr/etc/avrdude.conf} puts puts "************************************************************************" puts "** please add /usr/local/arduino-0012 to your path! **" puts "** you will also need to run sudo update-alternatives --config java **" puts "** to choose java-1.50-sun as the default java **" puts "************************************************************************" puts end end end ================================================ FILE: lib/rad/progressbar.rb ================================================ # # Ruby/ProgressBar - a text progress bar library # # Copyright (C) 2001-2005 Satoru Takabayashi # All rights reserved. # This is free software with ABSOLUTELY NO WARRANTY. # # You can redistribute it and/or modify it under the terms # of Ruby's license. # class ProgressBar VERSION = "0.9" def initialize (title, total, out = STDERR) @title = title @total = total @out = out @terminal_width = 80 @bar_mark = "o" @current = 0 @previous = 0 @finished_p = false @start_time = Time.now @previous_time = @start_time @title_width = 14 @format = "%-#{@title_width}s %3d%% %s %s" @format_arguments = [:title, :percentage, :bar, :stat] clear show end attr_reader :title attr_reader :current attr_reader :total attr_accessor :start_time private def fmt_bar bar_width = do_percentage * @terminal_width / 100 sprintf("|%s%s|", @bar_mark * bar_width, " " * (@terminal_width - bar_width)) end def fmt_percentage do_percentage end def fmt_stat if @finished_p then elapsed else eta end end def fmt_stat_for_file_transfer if @finished_p then sprintf("%s %s %s", bytes, transfer_rate, elapsed) else sprintf("%s %s %s", bytes, transfer_rate, eta) end end def fmt_title @title[0,(@title_width - 1)] + ":" end def convert_bytes (bytes) if bytes < 1024 sprintf("%6dB", bytes) elsif bytes < 1024 * 1000 # 1000kb sprintf("%5.1fKB", bytes.to_f / 1024) elsif bytes < 1024 * 1024 * 1000 # 1000mb sprintf("%5.1fMB", bytes.to_f / 1024 / 1024) else sprintf("%5.1fGB", bytes.to_f / 1024 / 1024 / 1024) end end def transfer_rate bytes_per_second = @current.to_f / (Time.now - @start_time) sprintf("%s/s", convert_bytes(bytes_per_second)) end def bytes convert_bytes(@current) end def format_time (t) t = t.to_i sec = t % 60 min = (t / 60) % 60 hour = t / 3600 sprintf("%02d:%02d:%02d", hour, min, sec); end # ETA stands for Estimated Time of Arrival. def eta if @current == 0 "ETA: --:--:--" else elapsed = Time.now - @start_time eta = elapsed * @total / @current - elapsed; sprintf("ETA: %s", format_time(eta)) end end def elapsed elapsed = Time.now - @start_time sprintf("Time: %s", format_time(elapsed)) end def eol if @finished_p then "\n" else "\r" end end def do_percentage if @total.zero? 100 else @current * 100 / @total end end def get_width # FIXME: I don't know how portable it is. default_width = 80 begin tiocgwinsz = 0x5413 data = [0, 0, 0, 0].pack("SSSS") if @out.ioctl(tiocgwinsz, data) >= 0 then rows, cols, xpixels, ypixels = data.unpack("SSSS") if cols >= 0 then cols else default_width end else default_width end rescue Exception default_width end end def show arguments = @format_arguments.map {|method| method = sprintf("fmt_%s", method) send(method) } line = sprintf(@format, *arguments) width = get_width if line.length == width - 1 @out.print(line + eol) @out.flush elsif line.length >= width @terminal_width = [@terminal_width - (line.length - width + 1), 0].max if @terminal_width == 0 then @out.print(line + eol) else show end else # line.length < width - 1 @terminal_width += width - line.length + 1 show end @previous_time = Time.now end def show_if_needed if @total.zero? cur_percentage = 100 prev_percentage = 0 else cur_percentage = (@current * 100 / @total).to_i prev_percentage = (@previous * 100 / @total).to_i end # Use "!=" instead of ">" to support negative changes if cur_percentage != prev_percentage || Time.now - @previous_time >= 1 || @finished_p show end end public def clear @out.print "\r" @out.print(" " * (get_width - 1)) @out.print "\r" end def finish @current = @total @finished_p = true show end def finished? @finished_p end def file_transfer_mode @format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer] end def format= (format) @format = format end def format_arguments= (arguments) @format_arguments = arguments end def halt @finished_p = true show end def inc (step = 1) @current += step @current = @total if @current > @total show_if_needed @previous = @current end def set (count) if count < 0 || count > @total raise "invalid count: #{count} (total: #{@total})" end @current = count show_if_needed @previous = @current end def inspect "#" end end class ReversedProgressBar < ProgressBar def do_percentage 100 - super end end ================================================ FILE: lib/rad/rad_processor.rb ================================================ require 'rubygems' require 'ruby_to_ansi_c' class RADProcessor < RubyToAnsiC def self.translator unless defined? @translator then @translator = CompositeSexpProcessor.new @translator << RADRewriter.new @translator << RADTypeChecker.new @translator << R2CRewriter.new @translator << self.new @translator.on_error_in(:defn) do |processor, exp, err| result = processor.expected.new case result when Array then result << :error end msg = "// ERROR: #{err.class}: #{err}" msg += " in #{exp.inspect}" unless exp.nil? or $TESTING msg += " from #{caller.join(', ')}" unless $TESTING result << msg result end end @translator end def process_iasgn(exp) name = exp.shift val = process exp.shift "__#{name.to_s.sub(/^@/, '')} = #{val}" end def process_ivar(exp) name = exp.shift "__#{name.to_s.sub(/^@/, '')}" end def process_iter(exp) # the array identifer may be in one of two locations # when using the instance variable (ivar) style it is located at exp[0][1][1] if exp[0][1][1] enum = exp[0][1][1] enum = "__#{enum.to_s.sub(/^@/, '')}" if enum.to_s =~ /^@/ # for local variables it is located at exp[0][1][2] elsif exp[0][1][2] enum = exp[0][1][2] end out = [] # Only support enums in C-land # not sure if this comment if valid anymore raise UnsupportedNodeError if exp[0][1].nil? # HACK ugly @env.scope do call = process exp.shift var = process(exp.shift).intern # semi-HACK-y body = process exp.shift # array types from varible_processing>post_process_arrays and arduino_sketch>array $array_types.each do |k,v| @array_type = v if k == enum.to_s.sub(/^__/,"") end index_helper = $array_index_helpers.shift index = "index_#{index_helper}" # solves redeclaration issue body += ";" unless body =~ /[;}]\Z/ body.gsub!(/\n\n+/, "\n") out << "unsigned int #{index};" # shouldn't need more than int out << "for (#{index} = 0; #{index} < (int) (sizeof(#{enum}) / sizeof(#{enum}[0])); #{index}++) {" out << "#{@array_type} #{var} = #{enum}[#{index}];" out << body out << "}" end return out.join("\n") end def process_lasgn(exp) out = "" var = exp.shift value = exp.shift # grab the size of the args, if any, before process converts to a string arg_count = 0 arg_count = value.length - 1 if value.first == :array args = value exp_type = exp.sexp_type @env.add var.to_sym, exp_type var_type = self.class.c_type exp_type if exp_type.list? then assert_type args, :array raise "array must be of one type" unless args.sexp_type == Type.homo # HACK: until we figure out properly what to do w/ zarray # before we know what its type is, we will default to long. array_type = args.sexp_types.empty? ? 'void *' : self.class.c_type(args.sexp_types.first) # we can fix array here.. args.shift # :arglist out << "#{var} = (#{array_type}) malloc(sizeof(#{array_type}) * #{args.length});\n" args.each_with_index do |o,i| out << "#{var}[#{i}] = #{process o};\n" end else out << "#{var} = #{process args}" end out.sub!(/;\n\Z/, '') return out end def process_str(exp) s = exp.shift.gsub(/\n/, '\\n') if s.size == 1 return "\'#{s}\'" else return "\"#{s}\"" end end end ================================================ FILE: lib/rad/rad_rewriter.rb ================================================ require 'ruby_to_ansi_c' class RADRewriter < Rewriter def process_iter(exp) call = process exp.shift var = process exp.shift body = process exp.shift var = s(:dasgn_curr, Unique.next) if var.nil? assert_type call, :call if call[2] != :each then # TODO: fix call[n] (api) call.shift # :call lhs = call.shift method_name = call.shift case method_name when :downto then var.shift # start_value = lhs finish_value = call.pop.pop # not sure about this var_name = var.shift body.find_and_replace_all(:dvar, :lvar) result = s(:dummy, s(:lasgn, var_name, start_value), s(:while, s(:call, s(:lvar, var_name), :>=, s(:arglist, finish_value)), s(:block, body, s(:lasgn, var_name, s(:call, s(:lvar, var_name), :-, s(:arglist, s(:lit, 1))))), true)) when :upto then # REFACTOR: completely duped from above and direction changed var.shift # start_value = lhs finish_value = call.pop.pop # not sure about this var_name = var.shift body.find_and_replace_all(:dvar, :lvar) result = s(:dummy, s(:lasgn, var_name, start_value), s(:while, s(:call, s(:lvar, var_name), :<=, s(:arglist, finish_value)), s(:block, body, s(:lasgn, var_name, s(:call, s(:lvar, var_name), :+, s(:arglist, s(:lit, 1))))), true)) when :times then # REFACTOR: mostly duped from above and gave default start value of 0 # and a finish value that was the start value above var.shift start_value = s(:lit, 0) finish_value = lhs var_name = var.shift body.find_and_replace_all(:dvar, :lvar) result = s(:dummy, s(:lasgn, var_name, start_value), s(:while, s(:call, s(:lvar, var_name), :<, s(:arglist, finish_value)), s(:block, body, s(:lasgn, var_name, s(:call, s(:lvar, var_name), :+, s(:arglist, s(:lit, 1))))), true)) when :define_method then # BEFORE: [:iter, [:call, nil, :define_method, [:array, [:lit, :bmethod_added]]], [:dasgn_curr, :x], [:call, [:dvar, :x], :+, [:array, [:lit, 1]]]] # we want to get it rewritten for the scope/block context, so: # - throw call away # - rewrite to args # - plop body into a scope # AFTER: [:block, [:args, :x], [:call, [:lvar, :x], :+, [:arglist, [:lit, 1]]]] var.find_and_replace_all(:dasgn_curr, :args) body.find_and_replace_all(:dvar, :lvar) result = s(:block, var, body) else # HACK we butchered call up top result = s(:iter, s(:call, lhs, method_name, call.shift), var, body) end else if var.nil? then var = s(:lvar, Unique.next) end s(:iter, call, var, body) end end end ================================================ FILE: lib/rad/rad_type_checker.rb ================================================ require 'ruby_to_ansi_c' class RADTypeChecker < TypeChecker def process_const(exp) c = exp.shift if c.to_s =~ /^[A-Z]/ then # TODO: validate that it really is a const? # uber hackery # since constants are defined in the arduino_sketch define method and # we can't inject them into the methods # transport them here with a $define_types hash $define_types.each do |k,v| if k == c.to_s @const_type = eval "Type.#{v}" end end return t(:const, c, @const_type) else raise "I don't know what to do with const #{c.inspect}. It doesn't look like a class." end raise "need to finish process_const in #{self.class}" end end ================================================ FILE: lib/rad/sim/arduino_sketch.rb ================================================ ON = true OFF = !ON HIGH = ON LOW = !HIGH class ArduinoSketch attr_accessor :pins def initialize @pins = self.class.instance_variable_get("@pins") end 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 def loop end def digitalWrite( pin, value ) to_change = pins.select{|p| p.num == pin.num}.first to_change.value = value end def delay( millis ) end # def serial_read # end # def serial_available # end # def blink # end end class Pin attr_accessor :num, :type, :value def initialize num, opts @num = num @type = opts[:type] @value = opts[:value] || false end end ================================================ FILE: lib/rad/sketch_compiler.rb ================================================ # TODO: # compilation # gather pieces of code we need as strings # translate non-loop methods # do plugin stuff # deal with examples/ exception # manage upload process # compose_setup should move in here entirely # require 'arduino_sketch' class SketchCompiler attr_accessor :path, :body, :klass, :target_dir, :name def initialize path_to_sketch @path = File.expand_path(path_to_sketch) @body = open(@path).read @name = @path.split("/").last.split(".").first @klass = @name.split(".").first.split("_").collect{|c| c.capitalize}.join("") @target_dir = parent_dir end def parent_dir self.path.split("/")[0..@path.split("/").length-2].join("/") end def build_dir "#{self.target_dir}/#{self.name}" end def create_build_dir! optional_path_prefix=nil self.target_dir = optional_path_prefix if optional_path_prefix mkdir_p build_dir end def process_constants self.body.gsub!("HIGH", "1") self.body.gsub!("LOW", "0") self.body.gsub!("ON", "1") self.body.gsub!("OFF", "0") end def sketch_methods self.body.scan(/^\s*def\s.\w*/).collect{ |m| m.gsub(/\s*def\s*/, "") } end end ================================================ FILE: lib/rad/tasks/build_and_make.rake ================================================ require File.expand_path(File.dirname(__FILE__) + "/../init.rb") require 'ruby_to_ansi_c' C_VAR_TYPES = "unsigned|int|long|double|str|char|byte|bool" # incredibly primitive tests # rake test:compile or rake test:upload # runs through all sketches in the example directory def run_tests(sketch, type) sh %{rake make:#{type} sketch=examples/#{sketch}} end namespace :test do desc "iterate through all the sketches in the example directory" task :upload => :gather do @examples.each {|e| run_tests(e, "upload")} end task :compile => :gather do @examples.each {|e| run_tests(e, "compile")} end desc "gather all tests" task :gather do # => "make:upload" do @examples = [] if ENV['sketch'] @examples << ENV['sketch'] else Dir.entries( File.expand_path("#{RAD_ROOT}/examples/") ).each do |f| @examples << f.split('.').first if (f =~ /\.rb$/) end end end end namespace :make do desc "compile the sketch and then upload it to your Arduino board" task :upload => :compile do if Makefile.hardware_params['physical_reset'] puts "Reset the Arduino and hit enter.\n==If your board doesn't need it, you can turn off this prompt in config/software.yml==" STDIN.gets.chomp end sh %{cd #{@sketch.build_dir}; make upload} end desc "generate a makefile and use it to compile the .cpp" task :compile => [:clean_sketch_dir, "build:sketch"] do # should also depend on "build:sketch" Makefile.compose_for_sketch( @sketch.build_dir ) # not allowed? sh %{export PATH=#{Makefile.software_params[:arduino_root]}/tools/avr/bin:$PATH} sh %{cd #{@sketch.build_dir}; make depend; make} end desc "generate a makefile and use it to compile the .cpp using the current .cpp file" task :compile_cpp => ["build:sketch_dir", "build:gather_required_plugins", "build:plugin_setup", "build:setup", :clean_sketch_dir] do # should also depend on "build:sketch" Makefile.compose_for_sketch( @sketch.build_dir ) # not allowed? sh %{export PATH=#{Makefile.software_params[:arduino_root]}/tools/avr/bin:$PATH} sh %{cd #{@sketch.build_dir}; make depend; make} end desc "generate a makefile and use it to compile the .cpp and upload it using current .cpp file" task :upload_cpp => ["build:sketch_dir", "build:gather_required_plugins", "build:plugin_setup", "build:setup", :clean_sketch_dir] do # should also depend on "build:sketch" Makefile.compose_for_sketch( @sketch.build_dir ) # not allowed? sh %{export PATH=#{Makefile.software_params[:arduino_root]}/tools/avr/bin:$PATH} sh %{cd #{@sketch.build_dir}; make depend; make upload} end task :clean_sketch_dir => ["build:file_list", "build:sketch_dir"] do FileList.new(Dir.entries("#{@sketch.build_dir}")).exclude("#{@sketch.name}.cpp").exclude(/^\./).each do |f| sh %{rm #{@sketch.build_dir}/#{f}} end end end namespace :build do desc "actually build the sketch" task :sketch => [:file_list, :sketch_dir, :gather_required_plugins, :plugin_setup, :setup] do c_methods = [] sketch_signatures = [] # until we better understand RubyToC let's see what's happening on errors @sketch.sketch_methods.each do |meth| raw_rtc_meth = RADProcessor.translate(constantize(@sketch.klass), meth) puts "Translator Error: #{raw_rtc_meth.inspect}" if raw_rtc_meth =~ /\/\/ ERROR:/ c_methods << raw_rtc_meth unless meth == "setup" # treat the setup method differently @additional_setup = [] if meth == "setup" raw_rtc_meth.each {|m| @additional_setup << ArduinoSketch.add_to_setup(m) } if meth == "setup" end c_methods.each {|meth| sketch_signatures << "#{meth.scan(/^\w*\s?\*?\n.*\)/)[0].gsub("\n", " ")};" } clean_c_methods = [] # remove external variables that were previously injected c_methods.join("\n").each { |meth| clean_c_methods << ArduinoSketch.post_process_ruby_to_c_methods(meth) } c_methods_with_timer = clean_c_methods.join.gsub(/loop\(\)\s\{/,"loop() {") # last chance to add/change setup @setup[2] << sketch_signatures.join("\n") unless sketch_signatures.empty? # add special setup method to existing setup if present if @additional_setup @setup[2] << "void additional_setup();" # declaration @setup[4] << "\tadditional_setup();" # call from setup @setup[5] << @additional_setup.join("") # end result = "#{@setup.join( "\n" )}\n#{c_methods_with_timer}\n" File.open("#{@sketch.build_dir}/#{@sketch.name}.cpp", "w"){|f| f << result} end # needs to write the library include and the method signatures desc "build setup function" task :setup do eval "class #{@sketch.klass} < ArduinoSketch; end;" @@as = HardwareLibrary.new delegate_methods = @@as.methods - Object.new.methods delegate_methods.reject!{|m| m == "compose_setup"} delegate_methods.each do |meth| constantize(@sketch.klass).module_eval <<-CODE def self.#{meth}(*args) @@as.#{meth}(*args) end CODE end # allow variable declaration without quotes: @foo = int ["long","unsigned","int","byte","short"].each do |type| constantize(@sketch.klass).module_eval <<-CODE def self.#{type} return "#{type}" end CODE end @sketch.process_constants eval ArduinoSketch.pre_process(@sketch.body) @@as.process_external_vars(constantize(@sketch.klass)) @setup = @@as.compose_setup end desc "add plugin methods" task :plugin_setup do $plugins_to_load.each do |name| klass = name.split(".").first.split("_").collect{|c| c.capitalize}.join("") eval "class #{klass} < ArduinoPlugin; end;" @@ps = ArduinoPlugin.new plugin_delegate_methods = @@ps.methods - Object.new.methods plugin_delegate_methods.reject!{|m| m == "compose_setup"} plugin_delegate_methods.each do |meth| constantize(klass).module_eval <<-CODE def self.#{meth}(*args) @@ps.#{meth}(*args) end CODE end eval ArduinoPlugin.process(File.read("vendor/plugins/#{name}")) end @@no_plugins = ArduinoPlugin.new if @plugin_names.empty? end desc "determine which plugins to load based on use of methods in sketch" task :gather_required_plugins do @plugin_names.each do |name| ArduinoPlugin.check_for_plugin_use(@sketch.body, File.read("vendor/plugins/#{name}"), name ) end puts "#{$plugins_to_load.length} of #{$plugin_methods_hash.length} plugins are being loaded: #{$plugins_to_load.join(", ")}" end desc "setup target directory named after your sketch class" task :sketch_dir => [:file_list] do @sketch.create_build_dir! end task :file_list do # take another look at this, since if the root directory name is changed, everything breaks # perhaps we generate a constant when the project is generated an pop it here or in the init file if ENV['sketch'] @sketch = SketchCompiler.new File.expand_path("#{ENV['sketch']}.rb") else # assume the only .rb file in the sketch dir is the sketch: @sketch = SketchCompiler.new Dir.glob("#{File.expand_path(File.dirname(__FILE__))}/../../../*.rb").first end @plugin_names = [] Dir.entries( File.expand_path("#{RAD_ROOT}/vendor/plugins/") ).each do |f| if (f =~ /\.rb$/) @plugin_names << f end end end end #yoinked from Rails def constantize(camel_cased_word) unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!" end Object.module_eval("::#{$1}", __FILE__, __LINE__) end ================================================ FILE: lib/rad/tasks/rad.rb ================================================ require 'rake' Dir["#{File.dirname(__FILE__)}/*.rake"].each { |ext| load ext } ================================================ FILE: lib/rad/todo.txt ================================================ TODO: ===== Future: - complete library system: script/install library some_library - bin/rad: - setup and use a ~/.rad for new project defaults - put repository on git - project gallery (examples with movies) - testing framework - implement wire lib - subclasses of ArduinoSketch (should just work, but what are they for?) - simulator ================================================ FILE: lib/rad/variable_processing.rb ================================================ module ExternalVariableProcessing # issues # testing # add checking for colon ## need to clean this up ## need to test def process_external_vars(klass) vars = eval "#{klass}.instance_variables" local_vars = [] vars.each { |v| local_vars << ":#{v.gsub("@", "")}" } loc_vars = local_vars.join(", ") # add accessors  klass.module_eval "class << self; attr_accessor #{loc_vars} end" local_vars.each do |symbol| name = symbol.gsub(":","") t_var = eval "#{klass}.#{name}" pre_process_vars(name, t_var) end end def pre_process_vars(name, var) # puts # puts case var when Integer # puts "pre_process: #{name}, #{var}, #{var.inspect} got #{var.class} 29" value = var type = "int" post_process_vars(name, type, value) when Float # puts "pre_process: #{name}, #{var}, #{var.inspect} got #{var.class} 34" value = var type = "float" post_process_vars(name, type, value) when String # puts "pre_process: #{name}, #{var.inspect} got #{var.class} on 39" if var.match(",").nil? && var =~ /long|byte|unsigned|int|short/ # puts "pre_process #{name}, #{var.inspect} got #{var.class} level three sublevel" type = var value = nil post_process_vars(name, type, value) else value = var.split(",").first.lstrip type = var.split(",")[1].nil? ? nil : var.split(",")[1].lstrip translate_variables( name , type, value ) end when TrueClass # puts "pre_process: #{name}, #{var}, #{var.inspect} got #{var.class} on 50" value = 1 type = "bool" post_process_vars(name, type, value) when FalseClass # puts "pre_process: #{name}, #{var}, #{var.inspect} got #{var.class} on 55" value = 0 type = "bool" post_process_vars(name, type, value) when Array post_process_arrays(name, var) else raise ArgumentError, "not sure what to do here... got #{name} with value #{var} which is a #{var.class}" end end def translate_variables(name, type = nil, value = nil) unless type.nil? check_variable_type(type) end # classify the values if value.class == Fixnum # puts "translate_variables: #{name}, #{value}, #{type} is a fixnum, got #{value.class} on 74" elsif value.class == Float # puts "translate_variables: #{name}, #{value}, #{type} is a float, got #{value.class} on 76" elsif value =~ /^-(\d|x)*$/ value = value.to_i type = "int" if type.nil? elsif value =~ /^-(\d|\.|x)*$/ value = value.to_f unless type.nil? raise ArgumentError, "#{value} should be a float got #{type}" unless type == "float" end type = "float" if type.nil? elsif value[0,1] !~ /\d/ # puts value[0,1] # puts "translate_variables: #{name}, #{value}, #{type} is a number of some type, got #{value.class} on 79" type = "char*" value = "\"#{value}\"" elsif value !~ /(\.|x)/ # puts "translate_variables: #{name}, #{value}, #{type} is an integer, got #{value.class} on 83" value = value.to_i type = "int" if type.nil? elsif value =~ /(\d*\.\d*)/ # and no # puts "translate_variables: #{name}, #{value}, #{type} is a float, got #{value.class} on 87" value = value.to_f type = "float" elsif value =~ /0x\d\d/ # puts "translate_variables: #{name}, #{value}, #{type} is a byte, got #{value.class} on 91" type = "byte" else raise ArgumentError, "not sure what to do with a value of #{value} with a type like #{type}" end post_process_vars(name, type, value) end def post_process_vars(name, type, value = nil) value = " = #{value}" if value $external_var_identifiers << "__#{name}" unless $external_var_identifiers.include?("__#{name}") $external_vars << "#{type} __#{name}#{value};" end def post_process_arrays(name, var) type = c_type(var[0]) $array_types[name] = type assignment = var.inspect.gsub("[","{").gsub("]","}") c_style_array = "#{type} __#{name}[] = #{assignment};" $external_var_identifiers << "__#{name}" unless $external_var_identifiers.include?("__#{name}") $external_array_vars << c_style_array unless $external_array_vars.include?(c_style_array) end def check_variable_type(type) unless type =~ /#{C_VAR_TYPES}/ raise ArgumentError, "the following variable types are supported \n #{C_VAR_TYPES.gsub("|",", ")} got #{type}" end end def c_type(typ) type = case typ when Integer "int" when String "char*" when TrueClass "bool" when FalseClass "bool" else raise "Bug! Unknown type #{typ.inspect} in c_type" end type end end ================================================ FILE: lib/rad/version.rb ================================================ module Rad #:nodoc: module VERSION #:nodoc: MAJOR = 0 MINOR = 3 TINY = 1 STRING = [MAJOR, MINOR, TINY].join('.') end end ================================================ FILE: lib/rad.rb ================================================ module Rad end require 'rad/version' require 'rad/init' ================================================ FILE: rad.gemspec ================================================ Gem::Specification.new do |s| s.name = %q{rad} s.version = "0.3.1" s.date = %q{2008-08-18} s.default_executable = %q{rad} s.summary = "RAD: Ruby Arduino Development - 0.3.1" s.email = "greg@grabb.it" s.executables = ["rad"] s.homepage = "http://github.com/atduskreg/rad" s.description = "Ruby Arduino Development: a framework for programming the Arduino physcial computing platform using Ruby" s.has_rdoc = true s.authors = ["Greg Borenstein", "plugins+: JD Barnhart"] s.extra_rdoc_files = ["History.txt", "License.txt", "Manifest.txt", "lib/libraries/AFSoftSerial/keywords.txt", "lib/libraries/DS1307/keywords.txt", "lib/libraries/FrequencyTimer2/keywords.txt", "lib/libraries/I2CEEPROM/keywords.txt", "lib/libraries/LoopTimer/keywords.txt", "lib/libraries/OneWire/keywords.txt", "lib/libraries/OneWire/readme.txt", "lib/libraries/Stepper/keywords.txt", "lib/libraries/Wire/keywords.txt", "lib/rad/todo.txt", "website/index.txt"] s.files = ["History.txt", "License.txt", "Manifest.txt", "README.rdoc", "Rakefile", "test/hello_world_test/Makefile", "test/hello_world_test/hello_world.cpp", "bin/rad", "lib/examples/add_hysteresis.rb", "lib/examples/basic_blink.rb", "lib/examples/blink_m_address_assignment.rb", "lib/examples/blink_m_hello.rb", "lib/examples/blink_m_multi.rb", "lib/examples/blink_with_serial.rb", "lib/examples/configure_pa_lcd_boot.rb", "lib/examples/debounce_methods.rb", "lib/examples/external_variable_fu.rb", "lib/examples/external_variables.rb", "lib/examples/first_sound.rb", "lib/examples/frequency_generator.rb", "lib/examples/hello_array.rb", "lib/examples/hello_array2.rb", "lib/examples/hello_array_eeprom.rb", "lib/examples/hello_clock.rb", "lib/examples/hello_eeprom.rb", "lib/examples/hello_eeprom_lcdpa.rb", "lib/examples/hello_format_print.rb", "lib/examples/hello_lcd_charset.rb", "lib/examples/hello_pa_lcd.rb", "lib/examples/hello_servos.rb", "lib/examples/hello_spectra_sound.rb", "lib/examples/hello_world.rb", "lib/examples/hello_xbee.rb", "lib/examples/hysteresis_duel.rb", "lib/examples/i2c_with_clock_chip.rb", "lib/examples/midi_beat_box.rb", "lib/examples/midi_scales.rb", "lib/examples/motor_knob.rb", "lib/examples/servo_buttons.rb", "lib/examples/servo_calibrate_continuous.rb", "lib/examples/servo_throttle.rb", "lib/examples/software_serial.rb", "lib/examples/sparkfun_lcd.rb", "lib/examples/spectra_soft_pot.rb", "lib/examples/times_method.rb", "lib/examples/toggle.rb", "lib/examples/twitter.rb", "lib/examples/two_wire.rb", "lib/libraries/AFSoftSerial/AFSoftSerial.cpp", "lib/libraries/AFSoftSerial/AFSoftSerial.h", "lib/libraries/AFSoftSerial/keywords.txt", "lib/libraries/AF_XPort/AF_XPort.cpp", "lib/libraries/AF_XPort/AF_XPort.h", "lib/libraries/DS1307/DS1307.cpp", "lib/libraries/DS1307/DS1307.h", "lib/libraries/DS1307/keywords.txt", "lib/libraries/FrequencyTimer2/FrequencyTimer2.cpp", "lib/libraries/FrequencyTimer2/FrequencyTimer2.h", "lib/libraries/FrequencyTimer2/keywords.txt", "lib/libraries/I2CEEPROM/I2CEEPROM.cpp", "lib/libraries/I2CEEPROM/I2CEEPROM.h", "lib/libraries/I2CEEPROM/keywords.txt", "lib/libraries/LoopTimer/LoopTimer.cpp", "lib/libraries/LoopTimer/LoopTimer.h", "lib/libraries/LoopTimer/keywords.txt", "lib/libraries/OneWire/OneWire.cpp", "lib/libraries/OneWire/OneWire.h", "lib/libraries/OneWire/keywords.txt", "lib/libraries/OneWire/readme.txt", "lib/libraries/SWSerLCDpa/SWSerLCDpa.cpp", "lib/libraries/SWSerLCDpa/SWSerLCDpa.h", "lib/libraries/SWSerLCDsf/SWSerLCDsf.cpp", "lib/libraries/SWSerLCDsf/SWSerLCDsf.h", "lib/libraries/Servo/Servo.cpp", "lib/libraries/Servo/Servo.h", "lib/libraries/Stepper/Stepper.cpp", "lib/libraries/Stepper/Stepper.h", "lib/libraries/Stepper/keywords.txt", "lib/libraries/Wire/Wire.cpp", "lib/libraries/Wire/Wire.h", "lib/libraries/Wire/keywords.txt", "lib/libraries/Wire/twi.h", "lib/libraries/Wire/utility/twi.c", "lib/libraries/Wire/utility/twi.h", "lib/plugins/bitwise_ops.rb", "lib/plugins/blink.rb", "lib/plugins/blink_m.rb", "lib/plugins/debounce.rb", "lib/plugins/debug_output_to_lcd.rb", "lib/plugins/hysteresis.rb", "lib/plugins/input_output_state.rb", "lib/plugins/lcd_padding.rb", "lib/plugins/mem_test.rb", "lib/plugins/midi.rb", "lib/plugins/parallax_ping.rb", "lib/plugins/servo_pulse.rb", "lib/plugins/servo_setup.rb", "lib/plugins/smoother.rb", "lib/plugins/spark_fun_serial_lcd.rb", "lib/plugins/spectra_symbol.rb", "lib/plugins/twitter_connect.rb", "lib/rad.rb", "lib/rad/README.rdoc", "lib/rad/arduino_plugin.rb", "lib/rad/arduino_sketch.rb", "lib/rad/generators/makefile/makefile.erb", "lib/rad/generators/makefile/makefile.rb", "lib/rad/hardware_library.rb", "lib/rad/init.rb", "lib/rad/progressbar.rb", "lib/rad/rad_processor.rb", "lib/rad/linux_installer.rb", "lib/rad/darwin_installer.rb", "lib/rad/rad_rewriter.rb", "lib/rad/rad_type_checker.rb", "lib/rad/sim/arduino_sketch.rb", "lib/rad/sketch_compiler.rb", "lib/rad/tasks/build_and_make.rake", "lib/rad/tasks/rad.rb", "lib/rad/todo.txt", "lib/rad/variable_processing.rb", "lib/rad/version.rb", "scripts/txt2html", "setup.rb", "spec/examples/hello_world.rb", "spec/examples/serial_motor.rb", "spec/models/arduino_sketch_spec.rb", "spec/models/sketch_compiler_spec.rb", "spec/models/spec_helper.rb", "spec/sim/hello_world_spec.rb", "spec/spec.opts", "test/test_array_processing.rb", "test/test_plugin_loading.rb", "test/test_translation_post_processing.rb", "test/test_variable_processing.rb", "website/index.html", "website/index.txt", "website/javascripts/rounded_corners_lite.inc.js", "website/stylesheets/screen.css", "website/template.rhtml", "website/examples/assembler_test.rb.html", "website/examples/gps_reader.rb.html", "website/examples/hello_world.rb.html", "website/examples/serial_motor.rb.html"] s.test_files = [] s.rdoc_options = ["--main", "README.rdoc"] s.require_paths = ["lib"] s.rubyforge_project = %q{rad} s.rubygems_version = %q{1.2.0} s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc"] s.add_dependency("mime-types", ["> 0.0.0"]) if s.respond_to? :specification_version then current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION s.specification_version = 2 if current_version >= 3 then s.add_runtime_dependency(%q, [">= 1.0.0"]) else s.add_dependency(%q, [">= 1.0.0"]) end else s.add_dependency(%q, [">= 1.0.0"]) end end ================================================ FILE: scripts/txt2html ================================================ #!/usr/bin/env ruby require 'rubygems' require 'redcloth' require 'syntax/convertors/html' require 'erb' require File.dirname(__FILE__) + '/../lib/rad/version.rb' version = Rad::VERSION::STRING download = 'http://rubyforge.org/projects/rad' class Fixnum def ordinal # teens return 'th' if (10..19).include?(self % 100) # others case self % 10 when 1: return 'st' when 2: return 'nd' when 3: return 'rd' else return 'th' end end end class Time def pretty return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}" end end def convert_syntax(syntax, source) return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^
|
$!,'') end if ARGV.length >= 1 src, template = ARGV template ||= File.dirname(__FILE__) + '/../website/template.rhtml' else puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html") exit! end template = ERB.new(File.open(template).read) title = nil body = nil File.open(src) do |fsrc| title_text = fsrc.readline body_text = fsrc.read syntax_items = [] body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)!m){ ident = syntax_items.length element, syntax, source = $1, $2, $3 syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}" "syntax-temp-#{ident}" } title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip body = RedCloth.new(body_text).to_html body.gsub!(%r!(?:
)?syntax-temp-(d+)(?:
)?!){ syntax_items[$1.to_i] } end stat = File.stat(src) created = stat.ctime modified = stat.mtime $stdout << template.result(binding) ================================================ FILE: setup.rb ================================================ # # setup.rb # # Copyright (c) 2000-2005 Minero Aoki # # This program is free software. # You can distribute/modify this program under the terms of # the GNU LGPL, Lesser General Public License version 2.1. # unless Enumerable.method_defined?(:map) # Ruby 1.4.6 module Enumerable alias map collect end end unless File.respond_to?(:read) # Ruby 1.6 def File.read(fname) open(fname) {|f| return f.read } end end unless Errno.const_defined?(:ENOTEMPTY) # Windows? module Errno class ENOTEMPTY # We do not raise this exception, implementation is not needed. end end end def File.binread(fname) open(fname, 'rb') {|f| return f.read } end # for corrupted Windows' stat(2) def File.dir?(path) File.directory?((path[-1,1] == '/') ? path : path + '/') end class ConfigTable include Enumerable def initialize(rbconfig) @rbconfig = rbconfig @items = [] @table = {} # options @install_prefix = nil @config_opt = nil @verbose = true @no_harm = false end attr_accessor :install_prefix attr_accessor :config_opt attr_writer :verbose def verbose? @verbose end attr_writer :no_harm def no_harm? @no_harm end def [](key) lookup(key).resolve(self) end def []=(key, val) lookup(key).set val end def names @items.map {|i| i.name } end def each(&block) @items.each(&block) end def key?(name) @table.key?(name) end def lookup(name) @table[name] or setup_rb_error "no such config item: #{name}" end def add(item) @items.push item @table[item.name] = item end def remove(name) item = lookup(name) @items.delete_if {|i| i.name == name } @table.delete_if {|name, i| i.name == name } item end def load_script(path, inst = nil) if File.file?(path) MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path end end def savefile '.config' end def load_savefile begin File.foreach(savefile()) do |line| k, v = *line.split(/=/, 2) self[k] = v.strip end rescue Errno::ENOENT setup_rb_error $!.message + "\n#{File.basename($0)} config first" end end def save @items.each {|i| i.value } File.open(savefile(), 'w') {|f| @items.each do |i| f.printf "%s=%s\n", i.name, i.value if i.value? and i.value end } end def load_standard_entries standard_entries(@rbconfig).each do |ent| add ent end end def standard_entries(rbconfig) c = rbconfig rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT']) major = c['MAJOR'].to_i minor = c['MINOR'].to_i teeny = c['TEENY'].to_i version = "#{major}.#{minor}" # ruby ver. >= 1.4.4? newpath_p = ((major >= 2) or ((major == 1) and ((minor >= 5) or ((minor == 4) and (teeny >= 4))))) if c['rubylibdir'] # V > 1.6.3 libruby = "#{c['prefix']}/lib/ruby" librubyver = c['rubylibdir'] librubyverarch = c['archdir'] siteruby = c['sitedir'] siterubyver = c['sitelibdir'] siterubyverarch = c['sitearchdir'] elsif newpath_p # 1.4.4 <= V <= 1.6.3 libruby = "#{c['prefix']}/lib/ruby" librubyver = "#{c['prefix']}/lib/ruby/#{version}" librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" siteruby = c['sitedir'] siterubyver = "$siteruby/#{version}" siterubyverarch = "$siterubyver/#{c['arch']}" else # V < 1.4.4 libruby = "#{c['prefix']}/lib/ruby" librubyver = "#{c['prefix']}/lib/ruby/#{version}" librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" siterubyver = siteruby siterubyverarch = "$siterubyver/#{c['arch']}" end parameterize = lambda {|path| path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') } if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } makeprog = arg.sub(/'/, '').split(/=/, 2)[1] else makeprog = 'make' end [ ExecItem.new('installdirs', 'std/site/home', 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ {|val, table| case val when 'std' table['rbdir'] = '$librubyver' table['sodir'] = '$librubyverarch' when 'site' table['rbdir'] = '$siterubyver' table['sodir'] = '$siterubyverarch' when 'home' setup_rb_error '$HOME was not set' unless ENV['HOME'] table['prefix'] = ENV['HOME'] table['rbdir'] = '$libdir/ruby' table['sodir'] = '$libdir/ruby' end }, PathItem.new('prefix', 'path', c['prefix'], 'path prefix of target environment'), PathItem.new('bindir', 'path', parameterize.call(c['bindir']), 'the directory for commands'), PathItem.new('libdir', 'path', parameterize.call(c['libdir']), 'the directory for libraries'), PathItem.new('datadir', 'path', parameterize.call(c['datadir']), 'the directory for shared data'), PathItem.new('mandir', 'path', parameterize.call(c['mandir']), 'the directory for man pages'), PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), 'the directory for system configuration files'), PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), 'the directory for local state data'), PathItem.new('libruby', 'path', libruby, 'the directory for ruby libraries'), PathItem.new('librubyver', 'path', librubyver, 'the directory for standard ruby libraries'), PathItem.new('librubyverarch', 'path', librubyverarch, 'the directory for standard ruby extensions'), PathItem.new('siteruby', 'path', siteruby, 'the directory for version-independent aux ruby libraries'), PathItem.new('siterubyver', 'path', siterubyver, 'the directory for aux ruby libraries'), PathItem.new('siterubyverarch', 'path', siterubyverarch, 'the directory for aux ruby binaries'), PathItem.new('rbdir', 'path', '$siterubyver', 'the directory for ruby scripts'), PathItem.new('sodir', 'path', '$siterubyverarch', 'the directory for ruby extentions'), PathItem.new('rubypath', 'path', rubypath, 'the path to set to #! line'), ProgramItem.new('rubyprog', 'name', rubypath, 'the ruby program using for installation'), ProgramItem.new('makeprog', 'name', makeprog, 'the make program to compile ruby extentions'), SelectItem.new('shebang', 'all/ruby/never', 'ruby', 'shebang line (#!) editing mode'), BoolItem.new('without-ext', 'yes/no', 'no', 'does not compile/install ruby extentions') ] end private :standard_entries def load_multipackage_entries multipackage_entries().each do |ent| add ent end end def multipackage_entries [ PackageSelectionItem.new('with', 'name,name...', '', 'ALL', 'package names that you want to install'), PackageSelectionItem.new('without', 'name,name...', '', 'NONE', 'package names that you do not want to install') ] end private :multipackage_entries ALIASES = { 'std-ruby' => 'librubyver', 'stdruby' => 'librubyver', 'rubylibdir' => 'librubyver', 'archdir' => 'librubyverarch', 'site-ruby-common' => 'siteruby', # For backward compatibility 'site-ruby' => 'siterubyver', # For backward compatibility 'bin-dir' => 'bindir', 'bin-dir' => 'bindir', 'rb-dir' => 'rbdir', 'so-dir' => 'sodir', 'data-dir' => 'datadir', 'ruby-path' => 'rubypath', 'ruby-prog' => 'rubyprog', 'ruby' => 'rubyprog', 'make-prog' => 'makeprog', 'make' => 'makeprog' } def fixup ALIASES.each do |ali, name| @table[ali] = @table[name] end @items.freeze @table.freeze @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ end def parse_opt(opt) m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" m.to_a[1,2] end def dllext @rbconfig['DLEXT'] end def value_config?(name) lookup(name).value? end class Item def initialize(name, template, default, desc) @name = name.freeze @template = template @value = default @default = default @description = desc end attr_reader :name attr_reader :description attr_accessor :default alias help_default default def help_opt "--#{@name}=#{@template}" end def value? true end def value @value end def resolve(table) @value.gsub(%r<\$([^/]+)>) { table[$1] } end def set(val) @value = check(val) end private def check(val) setup_rb_error "config: --#{name} requires argument" unless val val end end class BoolItem < Item def config_type 'bool' end def help_opt "--#{@name}" end private def check(val) return 'yes' unless val case val when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes' when /\An(o)?\z/i, /\Af(alse)\z/i then 'no' else setup_rb_error "config: --#{@name} accepts only yes/no for argument" end end end class PathItem < Item def config_type 'path' end private def check(path) setup_rb_error "config: --#{@name} requires argument" unless path path[0,1] == '$' ? path : File.expand_path(path) end end class ProgramItem < Item def config_type 'program' end end class SelectItem < Item def initialize(name, selection, default, desc) super @ok = selection.split('/') end def config_type 'select' end private def check(val) unless @ok.include?(val.strip) setup_rb_error "config: use --#{@name}=#{@template} (#{val})" end val.strip end end class ExecItem < Item def initialize(name, selection, desc, &block) super name, selection, nil, desc @ok = selection.split('/') @action = block end def config_type 'exec' end def value? false end def resolve(table) setup_rb_error "$#{name()} wrongly used as option value" end undef set def evaluate(val, table) v = val.strip.downcase unless @ok.include?(v) setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" end @action.call v, table end end class PackageSelectionItem < Item def initialize(name, template, default, help_default, desc) super name, template, default, desc @help_default = help_default end attr_reader :help_default def config_type 'package' end private def check(val) unless File.dir?("packages/#{val}") setup_rb_error "config: no such package: #{val}" end val end end class MetaConfigEnvironment def initialize(config, installer) @config = config @installer = installer end def config_names @config.names end def config?(name) @config.key?(name) end def bool_config?(name) @config.lookup(name).config_type == 'bool' end def path_config?(name) @config.lookup(name).config_type == 'path' end def value_config?(name) @config.lookup(name).config_type != 'exec' end def add_config(item) @config.add item end def add_bool_config(name, default, desc) @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) end def add_path_config(name, default, desc) @config.add PathItem.new(name, 'path', default, desc) end def set_config_default(name, default) @config.lookup(name).default = default end def remove_config(name) @config.remove(name) end # For only multipackage def packages raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer @installer.packages end # For only multipackage def declare_packages(list) raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer @installer.packages = list end end end # class ConfigTable # This module requires: #verbose?, #no_harm? module FileOperations def mkdir_p(dirname, prefix = nil) dirname = prefix + File.expand_path(dirname) if prefix $stderr.puts "mkdir -p #{dirname}" if verbose? return if no_harm? # Does not check '/', it's too abnormal. dirs = File.expand_path(dirname).split(%r<(?=/)>) if /\A[a-z]:\z/i =~ dirs[0] disk = dirs.shift dirs[0] = disk + dirs[0] end dirs.each_index do |idx| path = dirs[0..idx].join('') Dir.mkdir path unless File.dir?(path) end end def rm_f(path) $stderr.puts "rm -f #{path}" if verbose? return if no_harm? force_remove_file path end def rm_rf(path) $stderr.puts "rm -rf #{path}" if verbose? return if no_harm? remove_tree path end def remove_tree(path) if File.symlink?(path) remove_file path elsif File.dir?(path) remove_tree0 path else force_remove_file path end end def remove_tree0(path) Dir.foreach(path) do |ent| next if ent == '.' next if ent == '..' entpath = "#{path}/#{ent}" if File.symlink?(entpath) remove_file entpath elsif File.dir?(entpath) remove_tree0 entpath else force_remove_file entpath end end begin Dir.rmdir path rescue Errno::ENOTEMPTY # directory may not be empty end end def move_file(src, dest) force_remove_file dest begin File.rename src, dest rescue File.open(dest, 'wb') {|f| f.write File.binread(src) } File.chmod File.stat(src).mode, dest File.unlink src end end def force_remove_file(path) begin remove_file path rescue end end def remove_file(path) File.chmod 0777, path File.unlink path end def install(from, dest, mode, prefix = nil) $stderr.puts "install #{from} #{dest}" if verbose? return if no_harm? realdest = prefix ? prefix + File.expand_path(dest) : dest realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) str = File.binread(from) if diff?(str, realdest) verbose_off { rm_f realdest if File.exist?(realdest) } File.open(realdest, 'wb') {|f| f.write str } File.chmod mode, realdest File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| if prefix f.puts realdest.sub(prefix, '') else f.puts realdest end } end end def diff?(new_content, path) return true unless File.exist?(path) new_content != File.binread(path) end def command(*args) $stderr.puts args.join(' ') if verbose? system(*args) or raise RuntimeError, "system(#{args.map{|a| a.inspect }.join(' ')}) failed" end def ruby(*args) command config('rubyprog'), *args end def make(task = nil) command(*[config('makeprog'), task].compact) end def extdir?(dir) File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") end def files_of(dir) Dir.open(dir) {|d| return d.select {|ent| File.file?("#{dir}/#{ent}") } } end DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) def directories_of(dir) Dir.open(dir) {|d| return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT } end end # This module requires: #srcdir_root, #objdir_root, #relpath module HookScriptAPI def get_config(key) @config[key] end alias config get_config # obsolete: use metaconfig to change configuration def set_config(key, val) @config[key] = val end # # srcdir/objdir (works only in the package directory) # def curr_srcdir "#{srcdir_root()}/#{relpath()}" end def curr_objdir "#{objdir_root()}/#{relpath()}" end def srcfile(path) "#{curr_srcdir()}/#{path}" end def srcexist?(path) File.exist?(srcfile(path)) end def srcdirectory?(path) File.dir?(srcfile(path)) end def srcfile?(path) File.file?(srcfile(path)) end def srcentries(path = '.') Dir.open("#{curr_srcdir()}/#{path}") {|d| return d.to_a - %w(. ..) } end def srcfiles(path = '.') srcentries(path).select {|fname| File.file?(File.join(curr_srcdir(), path, fname)) } end def srcdirectories(path = '.') srcentries(path).select {|fname| File.dir?(File.join(curr_srcdir(), path, fname)) } end end class ToplevelInstaller Version = '3.4.1' Copyright = 'Copyright (c) 2000-2005 Minero Aoki' TASKS = [ [ 'all', 'do config, setup, then install' ], [ 'config', 'saves your configurations' ], [ 'show', 'shows current configuration' ], [ 'setup', 'compiles ruby extentions and others' ], [ 'install', 'installs files' ], [ 'test', 'run all tests in test/' ], [ 'clean', "does `make clean' for each extention" ], [ 'distclean',"does `make distclean' for each extention" ] ] def ToplevelInstaller.invoke config = ConfigTable.new(load_rbconfig()) config.load_standard_entries config.load_multipackage_entries if multipackage? config.fixup klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller) klass.new(File.dirname($0), config).invoke end def ToplevelInstaller.multipackage? File.dir?(File.dirname($0) + '/packages') end def ToplevelInstaller.load_rbconfig if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } ARGV.delete(arg) load File.expand_path(arg.split(/=/, 2)[1]) $".push 'rbconfig.rb' else require 'rbconfig' end ::Config::CONFIG end def initialize(ardir_root, config) @ardir = File.expand_path(ardir_root) @config = config # cache @valid_task_re = nil end def config(key) @config[key] end def inspect "#<#{self.class} #{__id__()}>" end def invoke run_metaconfigs case task = parsearg_global() when nil, 'all' parsearg_config init_installers exec_config exec_setup exec_install else case task when 'config', 'test' ; when 'clean', 'distclean' @config.load_savefile if File.exist?(@config.savefile) else @config.load_savefile end __send__ "parsearg_#{task}" init_installers __send__ "exec_#{task}" end end def run_metaconfigs @config.load_script "#{@ardir}/metaconfig" end def init_installers @installer = Installer.new(@config, @ardir, File.expand_path('.')) end # # Hook Script API bases # def srcdir_root @ardir end def objdir_root '.' end def relpath '.' end # # Option Parsing # def parsearg_global while arg = ARGV.shift case arg when /\A\w+\z/ setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) return arg when '-q', '--quiet' @config.verbose = false when '--verbose' @config.verbose = true when '--help' print_usage $stdout exit 0 when '--version' puts "#{File.basename($0)} version #{Version}" exit 0 when '--copyright' puts Copyright exit 0 else setup_rb_error "unknown global option '#{arg}'" end end nil end def valid_task?(t) valid_task_re() =~ t end def valid_task_re @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/ end def parsearg_no_options unless ARGV.empty? task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1) setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" end end alias parsearg_show parsearg_no_options alias parsearg_setup parsearg_no_options alias parsearg_test parsearg_no_options alias parsearg_clean parsearg_no_options alias parsearg_distclean parsearg_no_options def parsearg_config evalopt = [] set = [] @config.config_opt = [] while i = ARGV.shift if /\A--?\z/ =~ i @config.config_opt = ARGV.dup break end name, value = *@config.parse_opt(i) if @config.value_config?(name) @config[name] = value else evalopt.push [name, value] end set.push name end evalopt.each do |name, value| @config.lookup(name).evaluate value, @config end # Check if configuration is valid set.each do |n| @config[n] if @config.value_config?(n) end end def parsearg_install @config.no_harm = false @config.install_prefix = '' while a = ARGV.shift case a when '--no-harm' @config.no_harm = true when /\A--prefix=/ path = a.split(/=/, 2)[1] path = File.expand_path(path) unless path[0,1] == '/' @config.install_prefix = path else setup_rb_error "install: unknown option #{a}" end end end def print_usage(out) out.puts 'Typical Installation Procedure:' out.puts " $ ruby #{File.basename $0} config" out.puts " $ ruby #{File.basename $0} setup" out.puts " # ruby #{File.basename $0} install (may require root privilege)" out.puts out.puts 'Detailed Usage:' out.puts " ruby #{File.basename $0} " out.puts " ruby #{File.basename $0} [] []" fmt = " %-24s %s\n" out.puts out.puts 'Global options:' out.printf fmt, '-q,--quiet', 'suppress message outputs' out.printf fmt, ' --verbose', 'output messages verbosely' out.printf fmt, ' --help', 'print this message' out.printf fmt, ' --version', 'print version and quit' out.printf fmt, ' --copyright', 'print copyright and quit' out.puts out.puts 'Tasks:' TASKS.each do |name, desc| out.printf fmt, name, desc end fmt = " %-24s %s [%s]\n" out.puts out.puts 'Options for CONFIG or ALL:' @config.each do |item| out.printf fmt, item.help_opt, item.description, item.help_default end out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" out.puts out.puts 'Options for INSTALL:' out.printf fmt, '--no-harm', 'only display what to do if given', 'off' out.printf fmt, '--prefix=path', 'install path prefix', '' out.puts end # # Task Handlers # def exec_config @installer.exec_config @config.save # must be final end def exec_setup @installer.exec_setup end def exec_install @installer.exec_install end def exec_test @installer.exec_test end def exec_show @config.each do |i| printf "%-20s %s\n", i.name, i.value if i.value? end end def exec_clean @installer.exec_clean end def exec_distclean @installer.exec_distclean end end # class ToplevelInstaller class ToplevelInstallerMulti < ToplevelInstaller include FileOperations def initialize(ardir_root, config) super @packages = directories_of("#{@ardir}/packages") raise 'no package exists' if @packages.empty? @root_installer = Installer.new(@config, @ardir, File.expand_path('.')) end def run_metaconfigs @config.load_script "#{@ardir}/metaconfig", self @packages.each do |name| @config.load_script "#{@ardir}/packages/#{name}/metaconfig" end end attr_reader :packages def packages=(list) raise 'package list is empty' if list.empty? list.each do |name| raise "directory packages/#{name} does not exist"\ unless File.dir?("#{@ardir}/packages/#{name}") end @packages = list end def init_installers @installers = {} @packages.each do |pack| @installers[pack] = Installer.new(@config, "#{@ardir}/packages/#{pack}", "packages/#{pack}") end with = extract_selection(config('with')) without = extract_selection(config('without')) @selected = @installers.keys.select {|name| (with.empty? or with.include?(name)) \ and not without.include?(name) } end def extract_selection(list) a = list.split(/,/) a.each do |name| setup_rb_error "no such package: #{name}" unless @installers.key?(name) end a end def print_usage(f) super f.puts 'Inluded packages:' f.puts ' ' + @packages.sort.join(' ') f.puts end # # Task Handlers # def exec_config run_hook 'pre-config' each_selected_installers {|inst| inst.exec_config } run_hook 'post-config' @config.save # must be final end def exec_setup run_hook 'pre-setup' each_selected_installers {|inst| inst.exec_setup } run_hook 'post-setup' end def exec_install run_hook 'pre-install' each_selected_installers {|inst| inst.exec_install } run_hook 'post-install' end def exec_test run_hook 'pre-test' each_selected_installers {|inst| inst.exec_test } run_hook 'post-test' end def exec_clean rm_f @config.savefile run_hook 'pre-clean' each_selected_installers {|inst| inst.exec_clean } run_hook 'post-clean' end def exec_distclean rm_f @config.savefile run_hook 'pre-distclean' each_selected_installers {|inst| inst.exec_distclean } run_hook 'post-distclean' end # # lib # def each_selected_installers Dir.mkdir 'packages' unless File.dir?('packages') @selected.each do |pack| $stderr.puts "Processing the package `#{pack}' ..." if verbose? Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") Dir.chdir "packages/#{pack}" yield @installers[pack] Dir.chdir '../..' end end def run_hook(id) @root_installer.run_hook id end # module FileOperations requires this def verbose? @config.verbose? end # module FileOperations requires this def no_harm? @config.no_harm? end end # class ToplevelInstallerMulti class Installer FILETYPES = %w( bin lib ext data conf man ) include FileOperations include HookScriptAPI def initialize(config, srcroot, objroot) @config = config @srcdir = File.expand_path(srcroot) @objdir = File.expand_path(objroot) @currdir = '.' end def inspect "#<#{self.class} #{File.basename(@srcdir)}>" end def noop(rel) end # # Hook Script API base methods # def srcdir_root @srcdir end def objdir_root @objdir end def relpath @currdir end # # Config Access # # module FileOperations requires this def verbose? @config.verbose? end # module FileOperations requires this def no_harm? @config.no_harm? end def verbose_off begin save, @config.verbose = @config.verbose?, false yield ensure @config.verbose = save end end # # TASK config # def exec_config exec_task_traverse 'config' end alias config_dir_bin noop alias config_dir_lib noop def config_dir_ext(rel) extconf if extdir?(curr_srcdir()) end alias config_dir_data noop alias config_dir_conf noop alias config_dir_man noop def extconf ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt end # # TASK setup # def exec_setup exec_task_traverse 'setup' end def setup_dir_bin(rel) files_of(curr_srcdir()).each do |fname| update_shebang_line "#{curr_srcdir()}/#{fname}" end end alias setup_dir_lib noop def setup_dir_ext(rel) make if extdir?(curr_srcdir()) end alias setup_dir_data noop alias setup_dir_conf noop alias setup_dir_man noop def update_shebang_line(path) return if no_harm? return if config('shebang') == 'never' old = Shebang.load(path) if old $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1 new = new_shebang(old) return if new.to_s == old.to_s else return unless config('shebang') == 'all' new = Shebang.new(config('rubypath')) end $stderr.puts "updating shebang: #{File.basename(path)}" if verbose? open_atomic_writer(path) {|output| File.open(path, 'rb') {|f| f.gets if old # discard output.puts new.to_s output.print f.read } } end def new_shebang(old) if /\Aruby/ =~ File.basename(old.cmd) Shebang.new(config('rubypath'), old.args) elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby' Shebang.new(config('rubypath'), old.args[1..-1]) else return old unless config('shebang') == 'all' Shebang.new(config('rubypath')) end end def open_atomic_writer(path, &block) tmpfile = File.basename(path) + '.tmp' begin File.open(tmpfile, 'wb', &block) File.rename tmpfile, File.basename(path) ensure File.unlink tmpfile if File.exist?(tmpfile) end end class Shebang def Shebang.load(path) line = nil File.open(path) {|f| line = f.gets } return nil unless /\A#!/ =~ line parse(line) end def Shebang.parse(line) cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ') new(cmd, args) end def initialize(cmd, args = []) @cmd = cmd @args = args end attr_reader :cmd attr_reader :args def to_s "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}") end end # # TASK install # def exec_install rm_f 'InstalledFiles' exec_task_traverse 'install' end def install_dir_bin(rel) install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755 end def install_dir_lib(rel) install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644 end def install_dir_ext(rel) return unless extdir?(curr_srcdir()) install_files rubyextentions('.'), "#{config('sodir')}/#{File.dirname(rel)}", 0555 end def install_dir_data(rel) install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644 end def install_dir_conf(rel) # FIXME: should not remove current config files # (rename previous file to .old/.org) install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644 end def install_dir_man(rel) install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644 end def install_files(list, dest, mode) mkdir_p dest, @config.install_prefix list.each do |fname| install fname, dest, mode, @config.install_prefix end end def libfiles glob_reject(%w(*.y *.output), targetfiles()) end def rubyextentions(dir) ents = glob_select("*.#{@config.dllext}", targetfiles()) if ents.empty? setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" end ents end def targetfiles mapdir(existfiles() - hookfiles()) end def mapdir(ents) ents.map {|ent| if File.exist?(ent) then ent # objdir else "#{curr_srcdir()}/#{ent}" # srcdir end } end # picked up many entries from cvs-1.11.1/src/ignore.c JUNK_FILES = %w( core RCSLOG tags TAGS .make.state .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb *~ *.old *.bak *.BAK *.orig *.rej _$* *$ *.org *.in .* ) def existfiles glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.'))) end def hookfiles %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| %w( config setup install clean ).map {|t| sprintf(fmt, t) } }.flatten end def glob_select(pat, ents) re = globs2re([pat]) ents.select {|ent| re =~ ent } end def glob_reject(pats, ents) re = globs2re(pats) ents.reject {|ent| re =~ ent } end GLOB2REGEX = { '.' => '\.', '$' => '\$', '#' => '\#', '*' => '.*' } def globs2re(pats) /\A(?:#{ pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|') })\z/ end # # TASK test # TESTDIR = 'test' def exec_test unless File.directory?('test') $stderr.puts 'no test in this package' if verbose? return end $stderr.puts 'Running tests...' if verbose? begin require 'test/unit' rescue LoadError setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.' end runner = Test::Unit::AutoRunner.new(true) runner.to_run << TESTDIR runner.run end # # TASK clean # def exec_clean exec_task_traverse 'clean' rm_f @config.savefile rm_f 'InstalledFiles' end alias clean_dir_bin noop alias clean_dir_lib noop alias clean_dir_data noop alias clean_dir_conf noop alias clean_dir_man noop def clean_dir_ext(rel) return unless extdir?(curr_srcdir()) make 'clean' if File.file?('Makefile') end # # TASK distclean # def exec_distclean exec_task_traverse 'distclean' rm_f @config.savefile rm_f 'InstalledFiles' end alias distclean_dir_bin noop alias distclean_dir_lib noop def distclean_dir_ext(rel) return unless extdir?(curr_srcdir()) make 'distclean' if File.file?('Makefile') end alias distclean_dir_data noop alias distclean_dir_conf noop alias distclean_dir_man noop # # Traversing # def exec_task_traverse(task) run_hook "pre-#{task}" FILETYPES.each do |type| if type == 'ext' and config('without-ext') == 'yes' $stderr.puts 'skipping ext/* by user option' if verbose? next end traverse task, type, "#{task}_dir_#{type}" end run_hook "post-#{task}" end def traverse(task, rel, mid) dive_into(rel) { run_hook "pre-#{task}" __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') directories_of(curr_srcdir()).each do |d| traverse task, "#{rel}/#{d}", mid end run_hook "post-#{task}" } end def dive_into(rel) return unless File.dir?("#{@srcdir}/#{rel}") dir = File.basename(rel) Dir.mkdir dir unless File.dir?(dir) prevdir = Dir.pwd Dir.chdir dir $stderr.puts '---> ' + rel if verbose? @currdir = rel yield Dir.chdir prevdir $stderr.puts '<--- ' + rel if verbose? @currdir = File.dirname(rel) end def run_hook(id) path = [ "#{curr_srcdir()}/#{id}", "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) } return unless path begin instance_eval File.read(path), path, 1 rescue raise if $DEBUG setup_rb_error "hook #{path} failed:\n" + $!.message end end end # class Installer class SetupError < StandardError; end def setup_rb_error(msg) raise SetupError, msg end if $0 == __FILE__ begin ToplevelInstaller.invoke rescue SetupError raise if $DEBUG $stderr.puts $!.message $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." exit 1 end end ================================================ FILE: spec/examples/hello_world.rb ================================================ # Hardware: LED connected on pin 7 class HelloWorld < ArduinoSketch output_pin 7, :as => :led def loop digitalWrite led, ON delay 500 digitalWrite led, OFF delay 500 end end ================================================ FILE: spec/examples/serial_motor.rb ================================================ # Hardware: motor control circuit (i.e. TIP-120 control pin) # connected at pin 7. # Demo: http://www.youtube.com/watch?v=7OguEBfdTe0 class SerialMotor < ArduinoSketch output_pin 7, :as => :motor serial_begin def loop digitalWrite(motor, serial_read) if serial_available end end ================================================ FILE: spec/models/arduino_sketch_spec.rb ================================================ require File.dirname(__FILE__) + '/spec_helper.rb' require File.expand_path(File.dirname(__FILE__) + "/../../lib/rad/arduino_sketch.rb") context "Arduino#serial_begin" do setup do @as = ArduinoSketch.new end specify "should default baud_rate to 9600" do @as.serial_begin @as.instance_variable_get("@other_setup").should include("Serial.begin(9600);") end specify "should set an alternate baud_rate if told" do @as.serial_begin :rate => 2400 @as.instance_variable_get("@other_setup").should include("Serial.begin(2400);") end specify "should add the correct function call to the composed_setup" do @as.serial_begin @as.compose_setup.should match(Regexp.new(Regexp.escape("Serial.begin(9600);"))) end end context "Arduino Base" do setup do @as = ArduinoSketch.new end specify "output_pin method without :as arg. should add the pin to the pin_mode hash's output list and leave the declarations alone" do @as.output_pin 1 @as.instance_variable_get("@declarations").first.should == nil @as.instance_variable_get("@pin_modes")[:output].should include(1) end specify "output_pin method with :as arg. should add the pin to the pin_mode hash's output list write the appropriate declaration and accessor" do @as.output_pin 3, :as => :led @as.instance_variable_get("@declarations").first.should == "int _led = 3;" @as.instance_variable_get("@accessors").first.should == "int led(){\nreturn _led;\n}" @as.instance_variable_get("@pin_modes")[:output].should include(3) end specify "output_pins method should add the pin to the pin_mode hash's output list and leave the declarations and accessors alone" do @as.output_pins [5,4,3,2] @as.instance_variable_get("@pin_modes")[:output].should include(5) @as.instance_variable_get("@pin_modes")[:output].should include(4) @as.instance_variable_get("@pin_modes")[:output].should include(3) @as.instance_variable_get("@pin_modes")[:output].should include(2) @as.instance_variable_get("@declarations").first.should == nil @as.instance_variable_get("@accessors").first.should == nil end specify "input_pin method with :as arg. should add the pin to the pin_mode hash's input list write the appropriate declaration and accessor" do @as.input_pin 1, :as => :knob @as.instance_variable_get("@declarations").first.should == "int _knob = 1;" @as.instance_variable_get("@accessors").first.should == "int knob(){\nreturn _knob;\n}" @as.instance_variable_get("@pin_modes")[:input].should include(1) end specify "input_pins method should add the pins to the pin_mode hash's input list and leave the declarations and accessors alone" do @as.input_pins [5,4,3,2] @as.instance_variable_get("@pin_modes")[:input].should include(5) @as.instance_variable_get("@pin_modes")[:input].should include(4) @as.instance_variable_get("@pin_modes")[:input].should include(3) @as.instance_variable_get("@pin_modes")[:input].should include(2) @as.instance_variable_get("@declarations").first.should == nil @as.instance_variable_get("@accessors").first.should == nil end specify "compose_setup should append each appropriate pinMode statement and :as accessor to the setup_function string with a newline" do @as.output_pins [1, 2] @as.input_pin 3, :as => :button result = @as.send :compose_setup result.should match(Regexp.new(Regexp.escape("pinMode(1, OUTPUT);\n"))) result.should match(Regexp.new(Regexp.escape("pinMode(2, OUTPUT);\n"))) result.should match(Regexp.new(Regexp.escape("pinMode(3, INPUT);\n"))) result.should match(Regexp.new(Regexp.escape("int _button = 3;\n"))) result.should match(Regexp.new(Regexp.escape("int button(){\nreturn _button;\n}"))) end end ================================================ FILE: spec/models/sketch_compiler_spec.rb ================================================ require File.dirname(__FILE__) + '/spec_helper.rb' require File.expand_path(File.dirname(__FILE__) + "/../../lib/rad/sketch_compiler.rb") context "SketchCompiler#sketch_methods" do before do @as = File.expand_path(File.dirname(__FILE__)) + "/../../lib/examples/i2c_with_clock_chip.rb" @sc = SketchCompiler.new @as end it "should locate all the methods defined in the sketch" do @sc.sketch_methods.should include( "loop") @sc.sketch_methods.should include( "printlz") @sc.sketch_methods.should include( "print_hexbyte") @sc.sketch_methods.should include( "clear_bottom_line") end end context "SketchCompiler#process_constants" do before do @as = File.expand_path(File.dirname(__FILE__)) + "/../../lib/examples/external_variable_fu.rb" @sc = SketchCompiler.new @as end it "should correctly process constants" do @sc.process_constants @sc.body.should_not match(/HIGH/) @sc.body.should_not match(/LOW/) @sc.body.should_not match(/ON/) @sc.body.should_not match(/OFF/) end end context "SketchCompiler.new" do before do @as = File.expand_path(File.dirname(__FILE__)) + "/../../lib/examples/add_hysteresis.rb" end it "should correctly absolutize a path with /../ that starts at /" do SketchCompiler.new(@as).path.should == "/Users/greg/code/rad/lib/examples/add_hysteresis.rb" end it "should correct absolutize a relative path" do SketchCompiler.new("lib/examples/add_hysteresis.rb").path.should == "/Users/greg/code/rad/lib/examples/add_hysteresis.rb" end it "should load the body of the sketch" do sc = SketchCompiler.new @as sc.body.should == open(@as).read end end context "SketchCompiler#sketch_class" do before do @sc = SketchCompiler.new File.expand_path(File.dirname(__FILE__)) + "/../../lib/examples/add_hysteresis.rb" end it "should calculate correctly from the path" do @sc.klass.should == "AddHysteresis" end end context "SketchCompiler#create_build_dir! without a path prefix" do before do @sc = SketchCompiler.new("lib/examples/add_hysteresis.rb") end it "should create the sketch dir in the correct place" do @sc.should_receive( :mkdir_p ).with( "/Users/greg/code/rad/lib/examples/add_hysteresis" ) @sc.create_build_dir! end end context "SketchCompiler#create_build_dir! with a path prefix" do before do @sc = SketchCompiler.new("lib/examples/add_hysteresis.rb") end it "should create the sketch dir in the correct place" do @sc.should_receive( :mkdir_p ).with( "prefix/add_hysteresis" ) @sc.create_build_dir! "prefix" end end context "SketchCompiler#build_dir" do before do @sc = SketchCompiler.new("lib/examples/add_hysteresis.rb") end it "should be correct with a default target_dir" do @sc.build_dir.should == "/Users/greg/code/rad/lib/examples/add_hysteresis" end it "should be correct with an altered target_dir" do @sc.target_dir = "examples" @sc.build_dir.should == "examples/add_hysteresis" end end ================================================ FILE: spec/models/spec_helper.rb ================================================ require 'rubygems' require 'spec' ================================================ FILE: spec/sim/hello_world_spec.rb ================================================ require File.dirname(__FILE__) + './models/spec_helper.rb' require File.expand_path(File.dirname(__FILE__) + "/../../lib/rad/sim/arduino_sketch.rb") require File.expand_path(File.dirname(__FILE__) + "/../examples/hello_world.rb" ) context "ArduinoSketch running HelloWorld example" do it "should successfully make an instance" do lambda{HelloWorld.new}.should_not raise_error end end context "HelloWorld#led" do it "should return a correctly configured Pin" do p = HelloWorld.new.led p.type.should == :output p.num.should == 7 p.value.should == false end end context "HelloWorld#digitalWrite" do setup do @h = HelloWorld.new end it "should set the value of the pin to true if told to" do @h.digitalWrite(@h.led, ON) @h.led.value.should == true end it "should set the value of the pin to false if told to" do @h.digitalWrite(@h.led, OFF) @h.led.value.should == false end end context "HelloWorld#delay" do it "should maybe keep track of the time in some way?" end context "HelloWorld#loop" do it "should execute the loop in the context of the instance" end ================================================ FILE: spec/spec.opts ================================================ --colour ================================================ FILE: test/hello_world_test/Makefile ================================================ # Arduino makefile # # This makefile allows you to build sketches from the command line # without the Arduino environment (or Java). # # The Arduino environment does preliminary processing on a sketch before # compiling it. If you're using this makefile instead, you'll need to do # a few things differently: # # - Give your program's file a .cpp extension (e.g. foo.cpp). # # - Put this line at top of your code: #include # # - Write prototypes for all your functions (or define them before you # call them). A prototype declares the types of parameters a # function will take and what type of value it will return. This # means that you can have a call to a function before the definition # of the function. A function prototype looks like the first line of # the function, with a semi-colon at the end. For example: # int digitalRead(int pin); # # - Write a main() function for your program that returns an int, calls # init() and setup() once (in that order), and then calls loop() # repeatedly(): # # int main() # { # init(); # setup(); # # for (;;) # loop(); # # return 0; # } # # Instructions for using the makefile: # # 1. Copy this file into the folder with your sketch. # # 2. Below, modify the line containing "TARGET" to refer to the name of # of your program's file without an extension (e.g. TARGET = foo). # # 3. Modify the line containg "ARDUINO" to point the directory that # contains the Arduino core (for normal Arduino installations, this # is the hardware/cores/arduino sub-directory). # # 4. Modify the line containing "PORT" to refer to the filename # representing the USB or serial connection to your Arduino board # (e.g. PORT = /dev/tty.USB0). If the exact name of this file # changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*). # # 5. At the command line, change to the directory containing your # program's file and the makefile. # # 6. Type "make" and press enter to compile/verify your program. # # 7. Type "make upload", reset your Arduino board, and press enter to # upload your program to the Arduino board. # # $Id$ PORT = /dev/tty.usb* TARGET = hello_world ARDUINO = /Applications/arduino-0012/hardware/cores/arduino SOFTWARE_SERIAL = /Applications/arduino-0012/hardware/libraries/SoftwareSerial SRC = $(ARDUINO)/pins_arduino.c $(ARDUINO)/wiring.c \ $(ARDUINO)/wiring_analog.c $(ARDUINO)/wiring_digital.c \ $(ARDUINO)/wiring_pulse.c $(ARDUINO)/wiring_serial.c \ $(ARDUINO)/wiring_shift.c $(ARDUINO)/WInterrupts.c CXXSRC = $(ARDUINO)/HardwareSerial.cpp $(SOFTWARE_SERIAL)/SoftwareSerial.cpp $(ARDUINO)/Print.cpp MCU = atmega168 ASRC = F_CPU = 16000000 FORMAT = ihex UPLOAD_RATE = 19200 BIN_DIR = /Applications/arduino-0012/hardware/tools/avr/bin # Name of this Makefile (used for "make depend"). MAKEFILE = Makefile # Debugging format. # Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. # AVR (extended) COFF requires stabs, plus an avr-objcopy run. DEBUG = stabs OPT = s # Place -D or -U options here CDEFS = -DF_CPU=$(F_CPU) CXXDEFS = -DF_CPU=$(F_CPU) # Place -I options here CINCS = -I$(ARDUINO) -I$(SOFTWARE_SERIAL) +CXXINCS = -I$(ARDUINO) -I$(SOFTWARE_SERIAL) # Compiler flag to set the C Standard level. # c89 - "ANSI" C # gnu89 - c89 plus GCC extensions # c99 - ISO C99 standard (not yet fully implemented) # gnu99 - c99 plus GCC extensions CSTANDARD = -std=gnu99 CDEBUG = -g$(DEBUG) CWARN = -Wall -Wstrict-prototypes CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums #CEXTRA = -Wa,-adhlns=$(<:.c=.lst) CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) CXXFLAGS = $(CDEFS) $(CINCS) -O$(OPT) #ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs LDFLAGS = -lm # Programming support using avrdude. Settings and variables. AVRDUDE_PROGRAMMER = stk500 AVRDUDE_PORT = $(PORT) AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ -b $(UPLOAD_RATE) -C /Applications/arduino-0012/hardware/tools/avr/etc/avrdude.conf # Program settings CC = $(BIN_DIR)/avr-gcc CXX = $(BIN_DIR)/avr-g++ OBJCOPY = $(BIN_DIR)/avr-objcopy OBJDUMP = $(BIN_DIR)/avr-objdump AR = $(BIN_DIR)/avr-ar SIZE = $(BIN_DIR)/avr-size NM = $(BIN_DIR)/avr-nm AVRDUDE = $(BIN_DIR)/avrdude REMOVE = rm -f MV = mv -f # Define all object files. OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) # Define all listing files. LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) # Combine all necessary flags and optional flags. # Add target processor to flags. ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) # Default target. all: build build: elf hex elf: $(TARGET).elf hex: $(TARGET).hex eep: $(TARGET).eep lss: $(TARGET).lss sym: $(TARGET).sym # Program the device. upload: $(TARGET).hex $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) # Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. COFFCONVERT=$(OBJCOPY) --debugging \ --change-section-address .data-0x800000 \ --change-section-address .bss-0x800000 \ --change-section-address .noinit-0x800000 \ --change-section-address .eeprom-0x810000 coff: $(TARGET).elf $(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof extcoff: $(TARGET).elf $(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof .SUFFIXES: .elf .hex .eep .lss .sym .elf.hex: $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ .elf.eep: -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ # Create extended listing file from ELF output file. .elf.lss: $(OBJDUMP) -h -S $< > $@ # Create a symbol table from ELF output file. .elf.sym: $(NM) -n $< > $@ core.a: $(OBJ) @for i in $(OBJ); do echo $(AR) rcs core.a $$i; $(AR) rcs core.a $$i; done # Link: create ELF output file from library. $(TARGET).elf: core.a $(CC) $(ALL_CFLAGS) -o $@ $(TARGET).cpp -L. core.a $(LDFLAGS) # Compile: create object files from C++ source files. .cpp.o: $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ # Compile: create object files from C source files. .c.o: $(CC) -c $(ALL_CFLAGS) $< -o $@ # Compile: create assembler files from C source files. .c.s: $(CC) -S $(ALL_CFLAGS) $< -o $@ # Assemble: create object files from assembler source files. .S.o: $(CC) -c $(ALL_ASFLAGS) $< -o $@ # Target: clean project. clean: $(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \ $(TARGET).map $(TARGET).sym $(TARGET).lss core.a \ $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) depend: if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ then \ sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ $(MAKEFILE).$$$$ && \ $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ fi echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ >> $(MAKEFILE); \ $(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE) .PHONY: all build elf hex eep lss sym program coff extcoff clean depend # DO NOT DELETE THIS LINE -- make depend depends on it. pins_arduino.o: \ /Applications/arduino-0012/hardware/cores/arduino/pins_arduino.c \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/io.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/sfr_defs.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/inttypes.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdint.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iom168.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iomx8.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/portpins.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/common.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/version.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/fuse.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/lock.h \ /Applications/arduino-0012/hardware/cores/arduino/wiring_private.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/interrupt.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay_basic.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdio.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stdarg.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stddef.h \ /Applications/arduino-0012/hardware/cores/arduino/wiring.h \ /Applications/arduino-0012/hardware/cores/arduino/binary.h \ /Applications/arduino-0012/hardware/cores/arduino/pins_arduino.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/pgmspace.h wiring.o: /Applications/arduino-0012/hardware/cores/arduino/wiring.c \ /Applications/arduino-0012/hardware/cores/arduino/wiring_private.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/io.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/sfr_defs.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/inttypes.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdint.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iom168.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iomx8.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/portpins.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/common.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/version.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/fuse.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/lock.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/interrupt.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay_basic.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdio.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stdarg.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stddef.h \ /Applications/arduino-0012/hardware/cores/arduino/wiring.h \ /Applications/arduino-0012/hardware/cores/arduino/binary.h wiring_analog.o: \ /Applications/arduino-0012/hardware/cores/arduino/wiring_analog.c \ /Applications/arduino-0012/hardware/cores/arduino/wiring_private.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/io.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/sfr_defs.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/inttypes.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdint.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iom168.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iomx8.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/portpins.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/common.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/version.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/fuse.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/lock.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/interrupt.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay_basic.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdio.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stdarg.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stddef.h \ /Applications/arduino-0012/hardware/cores/arduino/wiring.h \ /Applications/arduino-0012/hardware/cores/arduino/binary.h \ /Applications/arduino-0012/hardware/cores/arduino/pins_arduino.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/pgmspace.h wiring_digital.o: \ /Applications/arduino-0012/hardware/cores/arduino/wiring_digital.c \ /Applications/arduino-0012/hardware/cores/arduino/wiring_private.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/io.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/sfr_defs.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/inttypes.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdint.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iom168.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iomx8.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/portpins.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/common.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/version.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/fuse.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/lock.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/interrupt.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay_basic.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdio.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stdarg.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stddef.h \ /Applications/arduino-0012/hardware/cores/arduino/wiring.h \ /Applications/arduino-0012/hardware/cores/arduino/binary.h \ /Applications/arduino-0012/hardware/cores/arduino/pins_arduino.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/pgmspace.h wiring_pulse.o: \ /Applications/arduino-0012/hardware/cores/arduino/wiring_pulse.c \ /Applications/arduino-0012/hardware/cores/arduino/wiring_private.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/io.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/sfr_defs.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/inttypes.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdint.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iom168.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iomx8.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/portpins.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/common.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/version.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/fuse.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/lock.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/interrupt.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay_basic.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdio.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stdarg.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stddef.h \ /Applications/arduino-0012/hardware/cores/arduino/wiring.h \ /Applications/arduino-0012/hardware/cores/arduino/binary.h \ /Applications/arduino-0012/hardware/cores/arduino/pins_arduino.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/pgmspace.h wiring_serial.o: \ /Applications/arduino-0012/hardware/cores/arduino/wiring_serial.c \ /Applications/arduino-0012/hardware/cores/arduino/wiring_private.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/io.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/sfr_defs.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/inttypes.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdint.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iom168.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iomx8.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/portpins.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/common.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/version.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/fuse.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/lock.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/interrupt.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay_basic.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdio.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stdarg.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stddef.h \ /Applications/arduino-0012/hardware/cores/arduino/wiring.h \ /Applications/arduino-0012/hardware/cores/arduino/binary.h wiring_shift.o: \ /Applications/arduino-0012/hardware/cores/arduino/wiring_shift.c \ /Applications/arduino-0012/hardware/cores/arduino/wiring_private.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/io.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/sfr_defs.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/inttypes.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdint.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iom168.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iomx8.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/portpins.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/common.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/version.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/fuse.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/lock.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/interrupt.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay_basic.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdio.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stdarg.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stddef.h \ /Applications/arduino-0012/hardware/cores/arduino/wiring.h \ /Applications/arduino-0012/hardware/cores/arduino/binary.h WInterrupts.o: \ /Applications/arduino-0012/hardware/cores/arduino/WInterrupts.c \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/inttypes.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdint.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/io.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/sfr_defs.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iom168.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/iomx8.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/portpins.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/common.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/version.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/fuse.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/lock.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/interrupt.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/pgmspace.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stddef.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdio.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/include/stdarg.h \ /Applications/arduino-0012/hardware/cores/arduino/WConstants.h \ /Applications/arduino-0012/hardware/cores/arduino/wiring.h \ /Applications/arduino-0012/hardware/cores/arduino/binary.h \ /Applications/arduino-0012/hardware/cores/arduino/wiring_private.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/avr/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay.h \ /Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/util/delay_basic.h ================================================ FILE: test/hello_world_test/hello_world.cpp ================================================ #include void loop(); void setup(); int main(); void setup() { pinMode(13, OUTPUT); } int main() { init(); setup(); for( ;; ) { loop(); } return 0; } void loop() { digitalWrite( 13, HIGH ); delay( 500 ); digitalWrite( 13, LOW ); delay( 500 ); } ================================================ FILE: test/test_array_processing.rb ================================================ $TESTING = true # need to tell it where we are # lets review these # neee to remove this constant from tests and pull it from rad C_VAR_TYPES = "unsigned|int|long|double|str|char|byte|float|bool" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/variable_processing" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/arduino_sketch" require 'test/unit' class TestArrayProcessing < Test::Unit::TestCase def setup @t = ArduinoSketch.new # vars end # with July 25 2008 rework of arrays, this needs reworking/pruning def test_int_array name = "foo_a" value_string = "int tomatoes[]" expected = "int tomatoes[];" result = @t.array(value_string) assert_equal(expected, result[0]) end def test_int_array_with_semi name = "foo_b" value_string = "int tomatoes[];" expected = "int tomatoes[];" result = @t.array(value_string) assert_equal(expected, result[0]) end def test_int_array_with_assignment name = "foo_c" value_string = "int tomatoes[] = {1,2,3,4}" expected = "int tomatoes[] = {1,2,3,4};" result = @t.array(value_string) assert_equal(expected, result[0]) end def test_int_array_with_assignment_and_semi name = "foo_d" value_string = "int tomatoes[] = {1,2,3};" expected = "int tomatoes[] = {1,2,3};" result = @t.array(value_string) assert_equal(expected, result[0]) end def test_unsigned_int_array name = "foo_e" value_string = "unsigned int tomatoes[]" expected = "unsigned int tomatoes[];" result = @t.array(value_string) assert_equal(expected, result[0]) end def test_unsigned_int_array_with_assignment name = "foo_f" value_string = "unsigned int tomatoes[] = {1,2,3};" expected = "unsigned int tomatoes[] = {1,2,3};" result = @t.array(value_string) assert_equal(expected, result[0]) end ### adding defines def test_define_numbers name = "foo_g" value_string = "NUMBERS 10" expected = "#define NUMBERS 10" result = @t.define(value_string) assert_equal(expected, result[0]) end def test_define_numbers_type name = "foo_gg" value_string = "NUMBERS 10" expected = "long" result = @t.define(value_string) assert_equal(expected, result[1]) end def test_define_value_type_long_via_gvar name = "foo_ggg" value_string = "NUMBERS 10" expected = "long" result = @t.define(value_string) assert_equal(expected, $define_types["NUMBERS"]) end def test_define_string name = "foo_h" value_string = "TEXT word" expected = "#define TEXT \"word\"" result = @t.define(value_string) assert_equal(expected, result[0]) end def test_define_string_type name = "foo_hh" value_string = "TEXT word" expected = "str" result = @t.define(value_string) assert_equal(expected, result[1]) end def test_define_string_type__via_gvar name = "foo_hhh" value_string = "TEXT word" expected = "str" result = @t.define(value_string) assert_equal(expected, $define_types["TEXT"]) end def test_define_stings_with_spaces name = "foo_i" value_string = "TEXT words with spaces" expected = "#define TEXT \"words with spaces\"" result = @t.define(value_string) assert_equal(expected, result[0]) end def test_define_stings_with_spaces_type name = "foo_ii" value_string = "TEXT words with spaces" expected = "str" result = @t.define(value_string) assert_equal(expected, result[1]) end def test_define_stings_with_spaces_type_via_gvar name = "foo_iii" value_string = "TEXT words with spaces" expected = "str" result = @t.define(value_string) assert_equal(expected, $define_types["TEXT"]) end def test_define_float name = "foo_j" value_string = "FLOAT 10.0" expected = "#define FLOAT 10.0" result = @t.define(value_string) assert_equal(expected, result[0]) end def test_define_float_type name = "foo_jj" value_string = "FLOAT 10.0" expected = "float" result = @t.define(value_string) assert_equal(expected, result[1]) end def test_define_float_type_via_gvar name = "foo_jjj" value_string = "FLOAT 10.0" expected = "float" result = @t.define(value_string) assert_equal(expected, $define_types["FLOAT"]) end # # question for brian... do we need variable assignment with no value when # we have "" and 0 end ================================================ FILE: test/test_plugin_loading.rb ================================================ #!/usr/local/bin/ruby -w $TESTING = true # this is a test stub for now # lets review these # neee to remove this constant from tests and pull it from rad PLUGIN_C_VAR_TYPES = "int|void|unsigned|long|short|uint8_t|static|char\\*|byte" require "rubygems" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/rad_processor.rb" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/rad_rewriter.rb" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/rad_type_checker.rb" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/variable_processing" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/arduino_sketch" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/arduino_plugin" require 'test/unit' class TestPluginLoading < Test::Unit::TestCase def setup $external_var_identifiers = ["__foo", "__toggle", "wiggle"] $define_types = { "KOOL" => "long", "ZAK" => "str"} $array_types = { "my_array" => "int"} $plugin_directives = [] $plugin_external_variables = [] $plugin_signatures =[] $plugin_methods = [] $add_to_setup = [] $load_libraries = [] $plugin_structs = {} $plugin_methods_hash = {} $plugins_to_load = [] plugin_signatures = [] plugin_methods = [] @plugin_string =<<-STR class PluginTesting < ArduinoPlugin # # # BlinkM_funcs.h -- Arduino library to control BlinkM # -------------- # # # Note: original version of this file lives with the BlinkMTester sketch # # 2007, Tod E. Kurt, ThingM, http://thingm.com/ # # version: 20080203 # # history: # 20080101 - initial release # 20080203 - added setStartupParam(), bugfix receiveBytes() from Dan Julio # 20080727 - ported to rad jd barnhart # # first step, declare output pin 19 as i2c ## output_pin 19, :as => :wire, :device => :i2c, :enable => :true # reminder, true issues wire.begin include_wire add_blink_m_struct # Not needed when pin is declared with :enable => :true static int BlinkM_sendBack(byte addr) { int num = 0x11; char buf[5]; itoa(num, buf, 16); return "cool" } static char* another_method(byte addr) { int num = 0x11; char buf[5]; itoa(num, buf, 16); return "cool" } end STR @sketch_string =<<-STR class SanMiquel < ArduinoSketch # looking for hints? check out the examples directory # example sketches can be uploaded to your arduino with # rake make:upload sketch=examples/hello_world # just replace hello_world with other examples def loop delay 100 my_lcd.home "k" my_lcd.setxy 0,1 BlinkM_sendBack 10 delay 1000 test_address end end STR end # remove these external variables and parens on variables # need to actually run code through ruby_to_c for some of these tests def test_int name = "foo_a" # check_for_plugin_use(sketch_string, plugin_string, file_name) ArduinoPlugin.check_for_plugin_use(@sketch_string, @plugin_string, "hello_plugins") value_string = "int(__toggle = 0);" expected = ["hello_plugins"] result = $plugins_to_load assert_equal(expected, result) end def test_two name = "foo_a" # check_for_plugin_use(sketch_string, plugin_string, file_name) ArduinoPlugin.check_for_plugin_use(@sketch_string, @plugin_string, "hello_plugins") value_string = "int(__toggle = 0);" expected = {"hello_plugins"=>["BlinkM_sendBack", "another_method"]} result = $plugin_methods_hash assert_equal(expected, result) end ## need to look at unsigned long ## need parens removal tests end ================================================ FILE: test/test_translation_post_processing.rb ================================================ #!/usr/local/bin/ruby -w $TESTING = true # this is a test stub for now # lets review these # neee to remove this constant from tests and pull it from rad C_VAR_TYPES = "unsigned|int|long|double|str|char|byte|float|bool" require "rubygems" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/rad_processor.rb" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/rad_rewriter.rb" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/rad_type_checker.rb" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/variable_processing" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/arduino_sketch" require 'test/unit' class TranslationTesting < ArduinoSketch def one delay 1 end def two delay 1 @foo = 1 end def three @foo = 1 bar = 2 baz = wha end def four @foo = 1 bar = 2 wiggle = wha end def five @foo = 1 f = KOOL end def six a = ZAK end def seven(int) # coerce int to long int a = int * 2 end def eight(str) # coerce str to string a = ZAK + str end def nine @my_array.each do |a| delay a end end end class TestTranslationPostProcessing < Test::Unit::TestCase def setup $external_var_identifiers = ["__foo", "__toggle", "wiggle"] $define_types = { "KOOL" => "long", "ZAK" => "str"} $array_types = { "my_array" => "int"} end # remove these external variables and parens on variables # need to actually run code through ruby_to_c for some of these tests def test_int name = "foo_a" value_string = "int(__toggle = 0);" expected = "" result = ArduinoSketch.post_process_ruby_to_c_methods(value_string) assert_equal(expected, result) end def test_bool name = "foo_b" value_string = "bool(__toggle = 0);" expected = "" result = ArduinoSketch.post_process_ruby_to_c_methods(value_string) assert_equal(expected, result) end def test_long name = "foo_c" value_string = "long(__foo = 0);" expected = "" result = ArduinoSketch.post_process_ruby_to_c_methods(value_string) assert_equal(expected, result) end def test_trans_one name = "foo_d" expected = "void\none() {\ndelay(1);\n}" result = raw_rtc_meth = RADProcessor.translate(TranslationTesting, "one") assert_equal(expected, result) end # notice the nice behavior of @foo def test_trans_two name = "foo_e" expected = "void\ntwo() {\ndelay(1);\n__foo = 1;\n}" result = raw_rtc_meth = RADProcessor.translate(TranslationTesting, "two") assert_equal(expected, result) end # notice the nice behavior of @foo def test_trans_three name = "foo_f" expected = "void\nthree() {\nlong bar;\nvoid * baz;\n__foo = 1;\nbar = 2;\nbaz = wha();\n}" result = raw_rtc_meth = RADProcessor.translate(TranslationTesting, "three") assert_equal(expected, result) end # need to take a closer look at this ... include "void * wiggle" regex? # def test_trans_four name = "foo_f" expected = "void\nfour() {\nlong bar;\nvoid * wiggle;\n__foo = 1;\nbar = 2;\nwiggle = wha();\n}" result = raw_rtc_meth = RADProcessor.translate(TranslationTesting, "four") assert_equal(expected, result) end def test_trans_five name = "foo_f" expected = "void\nfive() {\nlong f;\n__foo = 1;\nf = KOOL;\n}" result = raw_rtc_meth = RADProcessor.translate(TranslationTesting, "five") assert_equal(expected, result) end def test_trans_six name = "foo_f" expected = "void\nsix() {\nstr a;\na = ZAK;\n}" result = raw_rtc_meth = RADProcessor.translate(TranslationTesting, "six") assert_equal(expected, result) end def test_trans_seven name = "foo_f" expected = "void\nseven(long int) {\nlong a;\na = int * 2;\n}" result = raw_rtc_meth = RADProcessor.translate(TranslationTesting, "seven") assert_equal(expected, result) end def test_trans_eight name = "foo_f" expected = "void\neight(long str) {\nvoid * a;\na = ZAK + str;\n}" result = raw_rtc_meth = RADProcessor.translate(TranslationTesting, "eight") assert_equal(expected, result) end def test_trans_nine name = "foo_f" expected = "void\nnine() {\nunsigned int index_a;\nfor (index_a = 0; index_a < (int) (sizeof(__my_array) / sizeof(__my_array[0])); index_a++) {\nint a = __my_array[index_a];\ndelay(a);\n}\n}" result = raw_rtc_meth = RADProcessor.translate(TranslationTesting, "nine") assert_equal(expected, result) end ## need to look at unsigned long ## need parens removal tests end ================================================ FILE: test/test_variable_processing.rb ================================================ #!/usr/local/bin/ruby -w $TESTING = true # need to tell it where we are # lets review these # neee to remove this constant from tests and pull it from rad C_VAR_TYPES = "unsigned|int|long|double|str|char|byte|float|bool" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/variable_processing" require "#{File.expand_path(File.dirname(__FILE__))}/../lib/rad/arduino_sketch" require 'test/unit' class TestVariableProcessing < Test::Unit::TestCase def setup @t = ArduinoSketch.new end # question for brian... do we need variable assignment with no value when # we have "" and 0 def test_int_as_int name = "foo_a" value_string = 1 expected = "int __foo_a = 1;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_string_as_int name = "foo_b" value_string = "1" expected = "int __foo_b = 1;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_float_as_float name = "foo_c" value_string = 0.10 expected = "float __foo_c = 0.1;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_string_as_float name = "foo_d" value_string = "0.10" expected = "float __foo_d = 0.1;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_byte # would this to return hex name = "foo_f" value_string = 0x00 expected = "int __foo_f = 0;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_byte_with_string_input name = "foo_g" value_string = "0x00" expected = "byte __foo_g = 0x00;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_string name = "foo_h" value_string = "arduino" expected = "char* __foo_h = \"arduino\";" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_int_with_type name = "foo_i" value_string = "int" expected = "int __foo_i;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_odd_name name = "bacon_j" value_string = "arduino" expected = "char* __bacon_j = \"arduino\";" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_int_with_type_two name = "foo_k" value_string = "2, int" expected = "int __foo_k = 2;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_int_with_long name = "foo_l" value_string = "2, int" expected = "int __foo_l = 2;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_int_with_byte name = "foo_m" value_string = "2, byte" expected = "byte __foo_m = 2;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_int_with_unsigned_int name = "foo_n" value_string = "2, unsigned int" expected = "unsigned int __foo_n = 2;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_int_with_unsigned_long name = "foo_o" value_string = "2, unsigned long" expected = "unsigned long __foo_o = 2;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_int_with_short_int name = "foo_q" value_string = "2, short int" expected = "short int __foo_q = 2;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_int_with_unsigned_short_int name = "foo_r" value_string = "2, unsigned short int" expected = "unsigned short int __foo_r = 2;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_float_with_type name = "foo_s" value_string = "2.0, float" expected = "float __foo_s = 2.0;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_true name = "foo_t" value_string = true expected = "bool __foo_t = 1;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_false name = "foo_v" value_string = false expected = "bool __foo_v = 0;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_negative_int_string name = "foo_w" value_string = "-1, int" expected = "int __foo_w = -1;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_negative_float_string name = "foo_x" value_string = "-0.1, float" expected = "float __foo_x = -0.1;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_negative_larger_float_string name = "foo_y" value_string = "-1000.01, float" expected = "float __foo_y = -1000.01;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_negative_long_string name = "foo_z" value_string = "-.0991, float" expected = "float __foo_z = -0.0991;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_negative_float_string_two name = "foo_aa" value_string = "-.01, float" expected = "float __foo_aa = -0.01;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_negative_interter_string name = "foo_bb" value_string = "-.01, float" expected = "float __foo_bb = -0.01;" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end def test_dash_string name = "foo_cc" value_string = "-hmmm" expected = "char* __foo_cc = \"-hmmm\";" result = @t.pre_process_vars(name, value_string) assert_equal(expected, result[0]) end end ================================================ FILE: website/examples/assembler_test.rb.html ================================================ assembler_test.rb.html .ruby .normal {} .ruby .comment { color: #888; font-style: italic; } .ruby .keyword { color: #A00; font-weight: bold; } .ruby .method { color: #077; } .ruby .class { color: #074; } .ruby .module { color: #050; } .ruby .punct { color: #447; font-weight: bold; } .ruby .symbol { color: #099; } .ruby .string { color: #944; } .ruby .char { color: #F07; } .ruby .ident { color: #004; } .ruby .constant { color: #07F; } .ruby .regex { color: #B66; } .ruby .number { color: #D55; } .ruby .attribute { color: #377; } .ruby .global { color: #3B7; } .ruby .expr { color: #227; }
# Hardware: Connect to serial output with screen:
#           $ screen /dev/tty/path.to.your.usb 9600

class AssemblerTest < ArduinoSketch
  vars :a => 10, :b => 4
  serial_begin
  
  def loop
    serial_println product(a,b)
  end
  
  assembler( :product, "int product(int a, int b);",
    <<-CODE
    product:
      	mov  r18,r24	; move a to another register
      	ldi  r24,0		; clear running sum, used to coalesce product
      	ldi  r25,0		; sum = 0
      
      .loop:
      	tst  r18		  ; is a = 0? if so, we're done
      	breq .end
      
      	mov  r19,r18	; copy a
      	andi r19,1		; is a % 2 == 0
      	breq .skip		
      
      	add  r24,r22	; add b to sum
      	adc  r25,r23
      
      .skip:
      	lsr  r18		  ; divide a by 2
      
      	clc			
      	rol  r22		  ; multiply b by 2
      	rol  r23
      	rjmp .loop
      
      .end:
      	ret
      	.size product, .-product
    CODE
  )
end
================================================ FILE: website/examples/gps_reader.rb.html ================================================ gps_reader.rb.html .ruby .normal {} .ruby .comment { color: #888; font-style: italic; } .ruby .keyword { color: #A00; font-weight: bold; } .ruby .method { color: #077; } .ruby .class { color: #074; } .ruby .module { color: #050; } .ruby .punct { color: #447; font-weight: bold; } .ruby .symbol { color: #099; } .ruby .string { color: #944; } .ruby .char { color: #F07; } .ruby .ident { color: #004; } .ruby .constant { color: #07F; } .ruby .regex { color: #B66; } .ruby .number { color: #D55; } .ruby .attribute { color: #377; } .ruby .global { color: #3B7; } .ruby .expr { color: #227; }
class GpsReader < ArduinoSketch
  output_pin 13, :as => :led
  software_serial 6, 7, :as => :gps
  serial_begin

  def loop
    digitalWrite(led, true)
    serial_print(gps.read)
  end
end
================================================ FILE: website/examples/hello_world.rb.html ================================================ hello_world.rb.html .ruby .normal {} .ruby .comment { color: #888; font-style: italic; } .ruby .keyword { color: #A00; font-weight: bold; } .ruby .method { color: #077; } .ruby .class { color: #074; } .ruby .module { color: #050; } .ruby .punct { color: #447; font-weight: bold; } .ruby .symbol { color: #099; } .ruby .string { color: #944; } .ruby .char { color: #F07; } .ruby .ident { color: #004; } .ruby .constant { color: #07F; } .ruby .regex { color: #B66; } .ruby .number { color: #D55; } .ruby .attribute { color: #377; } .ruby .global { color: #3B7; } .ruby .expr { color: #227; }
# Hardware: LED connected on pin 7

class HelloWorld < ArduinoSketch
  output_pin 7, :as => :led
  def loop
    blink led, 500
  end
end
================================================ FILE: website/examples/serial_motor.rb.html ================================================ serial_motor.rb.html .ruby .normal {} .ruby .comment { color: #888; font-style: italic; } .ruby .keyword { color: #A00; font-weight: bold; } .ruby .method { color: #077; } .ruby .class { color: #074; } .ruby .module { color: #050; } .ruby .punct { color: #447; font-weight: bold; } .ruby .symbol { color: #099; } .ruby .string { color: #944; } .ruby .char { color: #F07; } .ruby .ident { color: #004; } .ruby .constant { color: #07F; } .ruby .regex { color: #B66; } .ruby .number { color: #D55; } .ruby .attribute { color: #377; } .ruby .global { color: #3B7; } .ruby .expr { color: #227; }
# Hardware: motor control circuit (i.e. TIP-120 control pin)
#           connected at pin 7.
#     Demo: http://www.youtube.com/watch?v=7OguEBfdTe0

class SerialMotor < ArduinoSketch
  output_pin 7, :as => :motor
  serial_begin
  
  def loop
    digitalWrite(motor, serial_read) if serial_available
  end
end
================================================ FILE: website/index.html ================================================ RAD

Get Version

0.2.2

Sponsored by:

The Shoppe at Wulfden


Totally Open Arduino-Compatible Hardware

RAD

→ ‘Ruby Arduino Development’

What?

RAD is a framework for programming the Arduino physcial computing platform using Ruby. RAD converts Ruby scripts written using a set of Rails-like conventions and helpers into C source code which can be compiled and run on the Arduino microcontroller. It also provides a set of Rake tasks for automating the compilation and upload process.


Demo: 'Hello World'

Here's a basic demo of RAD in action. In this movie, we'll write, compile, and upload the universal physical computing 'Hello World': a single flashing LED.

Note: This movie was made using an old version of the Arduino board which required a hardware reset before being able to accept a new sketch. More recent versions of the board don't have this requirement and hence as of version 0.2.0, RAD no longer prompts for reset when running 'rake make:upload' (thought the option is still available for older boards.)


Why?

While duplicating the functionality of the well-designed Arduino software interface in Ruby may seem like an odd or redundant goal, RAD has further ambitions! Bootstrapping the ability to write microcontroller code in a high level dynamic language like Ruby could greatly ease the creation of all the luxurious development aids the users of such a language have come to expect: developer testing, platform independence, easy metaprogramming, etc.

Installing

$ sudo gem install rad

You’ll also need to have the Arduino environment installed, which you can get from the Arduino website. RAD currently requires Arduino 0011, but we try to keep it up-to-date with new Arduino releases.

The Basics

$ rad my_sketch

This command will create a new RAD project directory (my_sketch/) inside of the current directory that contains a blank script in which you can write your own RAD code, as well as a full install of the RAD support infrastructure (in vendor/). A sample ‘hello world’ script in RAD will look like this:

class MySketch < ArduinoSketch
  output_pin 7, :as => :led
  def loop
    blink led, 500
  end
end

Once your code is written, your relevant local configuration properly setup in config/hardware.rb and config/software.rb, and an Arduino with the corresponding circuit (a 220ohm resistor and an LED wired in series between Arduino pin 7 and ground) is connected to your computer via serial, run:

$ rake make:upload

This will:

  • generate the correct Arduino C++ code from your sketch
  • dynamically prepare a localized version of the default Arduino Makefile
  • compile your sketch
  • prompt you to hit the reset button on your Arduino (if necessary!)
  • upload your compiled binary onto your Arduino

Documentation and The Arduino API

Most of the Arduino software API should be working correctly at this point. Documentation for RAD's version of things and details about usage of the wider Arduino API are available in the RAD rDocs.

Demo: Serial Communication

To demonstrate some of the more advanced features of RAD, here's a movie showing how to program the Arduino to listen to serial communication from a computer.

Note: The same comment from above applies here about the hardware reset. Also, extra points are available if you recognize the logo on the flag in the video.


For more examples of RAD in action, see the RAD example directory.

RAD Needs You!

All the many discipline-crossing skills required for a project like RAD make for lots of opportunities to help out: Have you written lots of sketches exploring the obscure depths of the Arduino library? Do you run the Arduino development tool chain on an obscure (i.e., non-OS X) platform? Do you develop for other AVR or PIC microcontrollers? Are you a C/C++ ninja? Or even C/C++ competent?

There’s lots to do.

If you’re looking for a place to dive in and don’t know quite where, email the RAD Google Group; we're friendly! If you want to start by taking a look at the code, check out RAD on GitHub: http://github.com/atduskgreg/rad/tree/master.

License

This code is free to use under the terms of the GPL 2.0 license, just like the Arduino software library itself.

Contact

Comments, questions, heckles, attacks, praises, and, (most especially) patches and contributions are welcome! Send email to the RAD mailing list.

Who

Greg Borenstein is RAD's original author and main maintainer with significant contributions from Ben Bleything and Brian Riley, patches from Scott Windsor and David Michael, and the support of the the Ruby Arduino Development Google Group.

Dr Nic, 18th November 2007
Theme extended from Paul Battley

================================================ FILE: website/index.txt ================================================ h1. RAD h1. → 'Ruby Arduino Development' h2. What? RAD is a framework for programming the Arduino physcial computing platform using Ruby. RAD converts Ruby scripts written using a set of Rails-like conventions and helpers into C source code which can be compiled and run on the Arduino microcontroller. It also provides a set of Rake tasks for automating the compilation and upload process. h2. Why? While duplicating the functionality of the well-designed Arduino software interface in Ruby may seem like an odd or redundant goal, RAD has further ambitions! Bootstrapping the ability to write microcontroller code in a high level dynamic language like Ruby could greatly ease the creation of all the luxurious development aids the users of such a language have come to expect: developer testing, platform independence, easy metaprogramming, etc. h2. Installing @$ sudo gem install rad@ You'll also need to have the Arduino environment installed, which you can get from "the Arduino website":http://www.arduino.cc/en/Main/Software. RAD currently requires Arduino 0010, but we try to keep it up-to-date with new Arduino releases. h2. The Basics @$ rad my_sketch@ This command will create a new RAD project directory (my_sketch/) inside of the current directory that contains a blank script in which you can write your own RAD code, as well as a full install of the RAD support infrastructure (in vendor/). A sample 'hello world' script in RAD will look like this:
class MySketch < ArduinoSketch
  output_pin 7, :as => :led
  def loop
    blink led, 500
  end
end
Once your code is written, your relevant local configuration properly setup in @config/hardware.rb@ and @config/software.rb@, and an Arduino with the corresponding circuit (a 220ohm resistor and an LED wired in series between Arduino pin 7 and ground) is connected to your computer via serial, run: @$ rake make:upload@ This will: * generate the correct Arduino C++ code from your sketch * dynamically prepare a localized version of the default Arduino Makefile * compile your sketch * prompt you to hit the reset button on your Arduino (if necessary!) * upload your compiled binary onto your Arduino h2. The Arduino API With the exception of the still-experimental Serial interface, most of the Arduino software API should be working correctly at this point. Documentation for the Ruby versions of the methods is forthcoming, but it is mostly what you'd expect: methods with identical names and arguments to their Arduino counterparts with the exception of using 'true' and 'false' for HIGH and LOW. h2. RAD Needs You! All the many discipline-crossing skills required for a project like RAD make for lots of opportunities to help out: Have you written lots of sketches exploring the obscure depths of the Arduino library? Do you run the Arduino development tool chain on an obscure (i.e., non-OS X) platform? Do you develop for other AVR or PIC microcontrollers? Are you a C/C++ ninja? Or even C/C++ competent? There's lots to do. If you're looking for a place to dive in and don't know quite where, "email Greg":mailto:greg@grabb.it. If you want to start by taking a log at the code, the trunk repository is @svn://rubyforge.org/var/svn/rad/trunk@ for anonymous access. h2. License This code is free to use under the terms of the GPL 2.0 license, just like the Arduino software library itself. h2. Contact Comments, questions, heckles, attacks, praises, and, (most especially) patches and contributions are welcome! Send email to "Greg Borenstein":mailto:greg@grabb.it. ================================================ FILE: website/javascripts/rounded_corners_lite.inc.js ================================================ /**************************************************************** * * * curvyCorners * * ------------ * * * * This script generates rounded corners for your divs. * * * * Version 1.2.9 * * Copyright (c) 2006 Cameron Cooke * * By: Cameron Cooke and Tim Hutchison. * * * * * * Website: http://www.curvycorners.net * * Email: info@totalinfinity.com * * Forum: http://www.curvycorners.net/forum/ * * * * * * This library is free software; you can redistribute * * it and/or modify it under the terms of the GNU * * Lesser General Public License as published by the * * Free Software Foundation; either version 2.1 of the * * License, or (at your option) any later version. * * * * This library 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 Lesser General Public * * License for more details. * * * * You should have received a copy of the GNU Lesser * * General Public License along with this library; * * Inc., 59 Temple Place, Suite 330, Boston, * * MA 02111-1307 USA * * * ****************************************************************/ var isIE = navigator.userAgent.toLowerCase().indexOf("msie") > -1; var isMoz = document.implementation && document.implementation.createDocument; var isSafari = ((navigator.userAgent.toLowerCase().indexOf('safari')!=-1)&&(navigator.userAgent.toLowerCase().indexOf('mac')!=-1))?true:false; function curvyCorners() { if(typeof(arguments[0]) != "object") throw newCurvyError("First parameter of curvyCorners() must be an object."); if(typeof(arguments[1]) != "object" && typeof(arguments[1]) != "string") throw newCurvyError("Second parameter of curvyCorners() must be an object or a class name."); if(typeof(arguments[1]) == "string") { var startIndex = 0; var boxCol = getElementsByClass(arguments[1]);} else { var startIndex = 1; var boxCol = arguments;} var curvyCornersCol = new Array(); if(arguments[0].validTags) var validElements = arguments[0].validTags; else var validElements = ["div"]; for(var i = startIndex, j = boxCol.length; i < j; i++) { var currentTag = boxCol[i].tagName.toLowerCase(); if(inArray(validElements, currentTag) !== false) { curvyCornersCol[curvyCornersCol.length] = new curvyObject(arguments[0], boxCol[i]);} } this.objects = curvyCornersCol; this.applyCornersToAll = function() { for(var x = 0, k = this.objects.length; x < k; x++) { this.objects[x].applyCorners();} } } function curvyObject() { this.box = arguments[1]; this.settings = arguments[0]; this.topContainer = null; this.bottomContainer = null; this.masterCorners = new Array(); this.contentDIV = null; var boxHeight = get_style(this.box, "height", "height"); var boxWidth = get_style(this.box, "width", "width"); var borderWidth = get_style(this.box, "borderTopWidth", "border-top-width"); var borderColour = get_style(this.box, "borderTopColor", "border-top-color"); var boxColour = get_style(this.box, "backgroundColor", "background-color"); var backgroundImage = get_style(this.box, "backgroundImage", "background-image"); var boxPosition = get_style(this.box, "position", "position"); var boxPadding = get_style(this.box, "paddingTop", "padding-top"); this.boxHeight = parseInt(((boxHeight != "" && boxHeight != "auto" && boxHeight.indexOf("%") == -1)? boxHeight.substring(0, boxHeight.indexOf("px")) : this.box.scrollHeight)); this.boxWidth = parseInt(((boxWidth != "" && boxWidth != "auto" && boxWidth.indexOf("%") == -1)? boxWidth.substring(0, boxWidth.indexOf("px")) : this.box.scrollWidth)); this.borderWidth = parseInt(((borderWidth != "" && borderWidth.indexOf("px") !== -1)? borderWidth.slice(0, borderWidth.indexOf("px")) : 0)); this.boxColour = format_colour(boxColour); this.boxPadding = parseInt(((boxPadding != "" && boxPadding.indexOf("px") !== -1)? boxPadding.slice(0, boxPadding.indexOf("px")) : 0)); this.borderColour = format_colour(borderColour); this.borderString = this.borderWidth + "px" + " solid " + this.borderColour; this.backgroundImage = ((backgroundImage != "none")? backgroundImage : ""); this.boxContent = this.box.innerHTML; if(boxPosition != "absolute") this.box.style.position = "relative"; this.box.style.padding = "0px"; if(isIE && boxWidth == "auto" && boxHeight == "auto") this.box.style.width = "100%"; if(this.settings.autoPad == true && this.boxPadding > 0) this.box.innerHTML = ""; this.applyCorners = function() { for(var t = 0; t < 2; t++) { switch(t) { case 0: if(this.settings.tl || this.settings.tr) { var newMainContainer = document.createElement("DIV"); newMainContainer.style.width = "100%"; newMainContainer.style.fontSize = "1px"; newMainContainer.style.overflow = "hidden"; newMainContainer.style.position = "absolute"; newMainContainer.style.paddingLeft = this.borderWidth + "px"; newMainContainer.style.paddingRight = this.borderWidth + "px"; var topMaxRadius = Math.max(this.settings.tl ? this.settings.tl.radius : 0, this.settings.tr ? this.settings.tr.radius : 0); newMainContainer.style.height = topMaxRadius + "px"; newMainContainer.style.top = 0 - topMaxRadius + "px"; newMainContainer.style.left = 0 - this.borderWidth + "px"; this.topContainer = this.box.appendChild(newMainContainer);} break; case 1: if(this.settings.bl || this.settings.br) { var newMainContainer = document.createElement("DIV"); newMainContainer.style.width = "100%"; newMainContainer.style.fontSize = "1px"; newMainContainer.style.overflow = "hidden"; newMainContainer.style.position = "absolute"; newMainContainer.style.paddingLeft = this.borderWidth + "px"; newMainContainer.style.paddingRight = this.borderWidth + "px"; var botMaxRadius = Math.max(this.settings.bl ? this.settings.bl.radius : 0, this.settings.br ? this.settings.br.radius : 0); newMainContainer.style.height = botMaxRadius + "px"; newMainContainer.style.bottom = 0 - botMaxRadius + "px"; newMainContainer.style.left = 0 - this.borderWidth + "px"; this.bottomContainer = this.box.appendChild(newMainContainer);} break;} } if(this.topContainer) this.box.style.borderTopWidth = "0px"; if(this.bottomContainer) this.box.style.borderBottomWidth = "0px"; var corners = ["tr", "tl", "br", "bl"]; for(var i in corners) { if(i > -1 < 4) { var cc = corners[i]; if(!this.settings[cc]) { if(((cc == "tr" || cc == "tl") && this.topContainer != null) || ((cc == "br" || cc == "bl") && this.bottomContainer != null)) { var newCorner = document.createElement("DIV"); newCorner.style.position = "relative"; newCorner.style.fontSize = "1px"; newCorner.style.overflow = "hidden"; if(this.backgroundImage == "") newCorner.style.backgroundColor = this.boxColour; else newCorner.style.backgroundImage = this.backgroundImage; switch(cc) { case "tl": newCorner.style.height = topMaxRadius - this.borderWidth + "px"; newCorner.style.marginRight = this.settings.tr.radius - (this.borderWidth*2) + "px"; newCorner.style.borderLeft = this.borderString; newCorner.style.borderTop = this.borderString; newCorner.style.left = -this.borderWidth + "px"; break; case "tr": newCorner.style.height = topMaxRadius - this.borderWidth + "px"; newCorner.style.marginLeft = this.settings.tl.radius - (this.borderWidth*2) + "px"; newCorner.style.borderRight = this.borderString; newCorner.style.borderTop = this.borderString; newCorner.style.backgroundPosition = "-" + (topMaxRadius + this.borderWidth) + "px 0px"; newCorner.style.left = this.borderWidth + "px"; break; case "bl": newCorner.style.height = botMaxRadius - this.borderWidth + "px"; newCorner.style.marginRight = this.settings.br.radius - (this.borderWidth*2) + "px"; newCorner.style.borderLeft = this.borderString; newCorner.style.borderBottom = this.borderString; newCorner.style.left = -this.borderWidth + "px"; newCorner.style.backgroundPosition = "-" + (this.borderWidth) + "px -" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + "px"; break; case "br": newCorner.style.height = botMaxRadius - this.borderWidth + "px"; newCorner.style.marginLeft = this.settings.bl.radius - (this.borderWidth*2) + "px"; newCorner.style.borderRight = this.borderString; newCorner.style.borderBottom = this.borderString; newCorner.style.left = this.borderWidth + "px" newCorner.style.backgroundPosition = "-" + (botMaxRadius + this.borderWidth) + "px -" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + "px"; break;} } } else { if(this.masterCorners[this.settings[cc].radius]) { var newCorner = this.masterCorners[this.settings[cc].radius].cloneNode(true);} else { var newCorner = document.createElement("DIV"); newCorner.style.height = this.settings[cc].radius + "px"; newCorner.style.width = this.settings[cc].radius + "px"; newCorner.style.position = "absolute"; newCorner.style.fontSize = "1px"; newCorner.style.overflow = "hidden"; var borderRadius = parseInt(this.settings[cc].radius - this.borderWidth); for(var intx = 0, j = this.settings[cc].radius; intx < j; intx++) { if((intx +1) >= borderRadius) var y1 = -1; else var y1 = (Math.floor(Math.sqrt(Math.pow(borderRadius, 2) - Math.pow((intx+1), 2))) - 1); if(borderRadius != j) { if((intx) >= borderRadius) var y2 = -1; else var y2 = Math.ceil(Math.sqrt(Math.pow(borderRadius,2) - Math.pow(intx, 2))); if((intx+1) >= j) var y3 = -1; else var y3 = (Math.floor(Math.sqrt(Math.pow(j ,2) - Math.pow((intx+1), 2))) - 1);} if((intx) >= j) var y4 = -1; else var y4 = Math.ceil(Math.sqrt(Math.pow(j ,2) - Math.pow(intx, 2))); if(y1 > -1) this.drawPixel(intx, 0, this.boxColour, 100, (y1+1), newCorner, -1, this.settings[cc].radius); if(borderRadius != j) { for(var inty = (y1 + 1); inty < y2; inty++) { if(this.settings.antiAlias) { if(this.backgroundImage != "") { var borderFract = (pixelFraction(intx, inty, borderRadius) * 100); if(borderFract < 30) { this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, 0, this.settings[cc].radius);} else { this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, -1, this.settings[cc].radius);} } else { var pixelcolour = BlendColour(this.boxColour, this.borderColour, pixelFraction(intx, inty, borderRadius)); this.drawPixel(intx, inty, pixelcolour, 100, 1, newCorner, 0, this.settings[cc].radius, cc);} } } if(this.settings.antiAlias) { if(y3 >= y2) { if (y2 == -1) y2 = 0; this.drawPixel(intx, y2, this.borderColour, 100, (y3 - y2 + 1), newCorner, 0, 0);} } else { if(y3 >= y1) { this.drawPixel(intx, (y1 + 1), this.borderColour, 100, (y3 - y1), newCorner, 0, 0);} } var outsideColour = this.borderColour;} else { var outsideColour = this.boxColour; var y3 = y1;} if(this.settings.antiAlias) { for(var inty = (y3 + 1); inty < y4; inty++) { this.drawPixel(intx, inty, outsideColour, (pixelFraction(intx, inty , j) * 100), 1, newCorner, ((this.borderWidth > 0)? 0 : -1), this.settings[cc].radius);} } } this.masterCorners[this.settings[cc].radius] = newCorner.cloneNode(true);} if(cc != "br") { for(var t = 0, k = newCorner.childNodes.length; t < k; t++) { var pixelBar = newCorner.childNodes[t]; var pixelBarTop = parseInt(pixelBar.style.top.substring(0, pixelBar.style.top.indexOf("px"))); var pixelBarLeft = parseInt(pixelBar.style.left.substring(0, pixelBar.style.left.indexOf("px"))); var pixelBarHeight = parseInt(pixelBar.style.height.substring(0, pixelBar.style.height.indexOf("px"))); if(cc == "tl" || cc == "bl"){ pixelBar.style.left = this.settings[cc].radius -pixelBarLeft -1 + "px";} if(cc == "tr" || cc == "tl"){ pixelBar.style.top = this.settings[cc].radius -pixelBarHeight -pixelBarTop + "px";} switch(cc) { case "tr": pixelBar.style.backgroundPosition = "-" + Math.abs((this.boxWidth - this.settings[cc].radius + this.borderWidth) + pixelBarLeft) + "px -" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + "px"; break; case "tl": pixelBar.style.backgroundPosition = "-" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + "px -" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + "px"; break; case "bl": pixelBar.style.backgroundPosition = "-" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + "px -" + Math.abs((this.boxHeight + this.settings[cc].radius + pixelBarTop) -this.borderWidth) + "px"; break;} } } } if(newCorner) { switch(cc) { case "tl": if(newCorner.style.position == "absolute") newCorner.style.top = "0px"; if(newCorner.style.position == "absolute") newCorner.style.left = "0px"; if(this.topContainer) this.topContainer.appendChild(newCorner); break; case "tr": if(newCorner.style.position == "absolute") newCorner.style.top = "0px"; if(newCorner.style.position == "absolute") newCorner.style.right = "0px"; if(this.topContainer) this.topContainer.appendChild(newCorner); break; case "bl": if(newCorner.style.position == "absolute") newCorner.style.bottom = "0px"; if(newCorner.style.position == "absolute") newCorner.style.left = "0px"; if(this.bottomContainer) this.bottomContainer.appendChild(newCorner); break; case "br": if(newCorner.style.position == "absolute") newCorner.style.bottom = "0px"; if(newCorner.style.position == "absolute") newCorner.style.right = "0px"; if(this.bottomContainer) this.bottomContainer.appendChild(newCorner); break;} } } } var radiusDiff = new Array(); radiusDiff["t"] = Math.abs(this.settings.tl.radius - this.settings.tr.radius) radiusDiff["b"] = Math.abs(this.settings.bl.radius - this.settings.br.radius); for(z in radiusDiff) { if(z == "t" || z == "b") { if(radiusDiff[z]) { var smallerCornerType = ((this.settings[z + "l"].radius < this.settings[z + "r"].radius)? z +"l" : z +"r"); var newFiller = document.createElement("DIV"); newFiller.style.height = radiusDiff[z] + "px"; newFiller.style.width = this.settings[smallerCornerType].radius+ "px" newFiller.style.position = "absolute"; newFiller.style.fontSize = "1px"; newFiller.style.overflow = "hidden"; newFiller.style.backgroundColor = this.boxColour; switch(smallerCornerType) { case "tl": newFiller.style.bottom = "0px"; newFiller.style.left = "0px"; newFiller.style.borderLeft = this.borderString; this.topContainer.appendChild(newFiller); break; case "tr": newFiller.style.bottom = "0px"; newFiller.style.right = "0px"; newFiller.style.borderRight = this.borderString; this.topContainer.appendChild(newFiller); break; case "bl": newFiller.style.top = "0px"; newFiller.style.left = "0px"; newFiller.style.borderLeft = this.borderString; this.bottomContainer.appendChild(newFiller); break; case "br": newFiller.style.top = "0px"; newFiller.style.right = "0px"; newFiller.style.borderRight = this.borderString; this.bottomContainer.appendChild(newFiller); break;} } var newFillerBar = document.createElement("DIV"); newFillerBar.style.position = "relative"; newFillerBar.style.fontSize = "1px"; newFillerBar.style.overflow = "hidden"; newFillerBar.style.backgroundColor = this.boxColour; newFillerBar.style.backgroundImage = this.backgroundImage; switch(z) { case "t": if(this.topContainer) { if(this.settings.tl.radius && this.settings.tr.radius) { newFillerBar.style.height = topMaxRadius - this.borderWidth + "px"; newFillerBar.style.marginLeft = this.settings.tl.radius - this.borderWidth + "px"; newFillerBar.style.marginRight = this.settings.tr.radius - this.borderWidth + "px"; newFillerBar.style.borderTop = this.borderString; if(this.backgroundImage != "") newFillerBar.style.backgroundPosition = "-" + (topMaxRadius + this.borderWidth) + "px 0px"; this.topContainer.appendChild(newFillerBar);} this.box.style.backgroundPosition = "0px -" + (topMaxRadius - this.borderWidth) + "px";} break; case "b": if(this.bottomContainer) { if(this.settings.bl.radius && this.settings.br.radius) { newFillerBar.style.height = botMaxRadius - this.borderWidth + "px"; newFillerBar.style.marginLeft = this.settings.bl.radius - this.borderWidth + "px"; newFillerBar.style.marginRight = this.settings.br.radius - this.borderWidth + "px"; newFillerBar.style.borderBottom = this.borderString; if(this.backgroundImage != "") newFillerBar.style.backgroundPosition = "-" + (botMaxRadius + this.borderWidth) + "px -" + (this.boxHeight + (topMaxRadius + this.borderWidth)) + "px"; this.bottomContainer.appendChild(newFillerBar);} } break;} } } if(this.settings.autoPad == true && this.boxPadding > 0) { var contentContainer = document.createElement("DIV"); contentContainer.style.position = "relative"; contentContainer.innerHTML = this.boxContent; contentContainer.className = "autoPadDiv"; var topPadding = Math.abs(topMaxRadius - this.boxPadding); var botPadding = Math.abs(botMaxRadius - this.boxPadding); if(topMaxRadius < this.boxPadding) contentContainer.style.paddingTop = topPadding + "px"; if(botMaxRadius < this.boxPadding) contentContainer.style.paddingBottom = botMaxRadius + "px"; contentContainer.style.paddingLeft = this.boxPadding + "px"; contentContainer.style.paddingRight = this.boxPadding + "px"; this.contentDIV = this.box.appendChild(contentContainer);} } this.drawPixel = function(intx, inty, colour, transAmount, height, newCorner, image, cornerRadius) { var pixel = document.createElement("DIV"); pixel.style.height = height + "px"; pixel.style.width = "1px"; pixel.style.position = "absolute"; pixel.style.fontSize = "1px"; pixel.style.overflow = "hidden"; var topMaxRadius = Math.max(this.settings["tr"].radius, this.settings["tl"].radius); if(image == -1 && this.backgroundImage != "") { pixel.style.backgroundImage = this.backgroundImage; pixel.style.backgroundPosition = "-" + (this.boxWidth - (cornerRadius - intx) + this.borderWidth) + "px -" + ((this.boxHeight + topMaxRadius + inty) -this.borderWidth) + "px";} else { pixel.style.backgroundColor = colour;} if (transAmount != 100) setOpacity(pixel, transAmount); pixel.style.top = inty + "px"; pixel.style.left = intx + "px"; newCorner.appendChild(pixel);} } function insertAfter(parent, node, referenceNode) { parent.insertBefore(node, referenceNode.nextSibling);} function BlendColour(Col1, Col2, Col1Fraction) { var red1 = parseInt(Col1.substr(1,2),16); var green1 = parseInt(Col1.substr(3,2),16); var blue1 = parseInt(Col1.substr(5,2),16); var red2 = parseInt(Col2.substr(1,2),16); var green2 = parseInt(Col2.substr(3,2),16); var blue2 = parseInt(Col2.substr(5,2),16); if(Col1Fraction > 1 || Col1Fraction < 0) Col1Fraction = 1; var endRed = Math.round((red1 * Col1Fraction) + (red2 * (1 - Col1Fraction))); if(endRed > 255) endRed = 255; if(endRed < 0) endRed = 0; var endGreen = Math.round((green1 * Col1Fraction) + (green2 * (1 - Col1Fraction))); if(endGreen > 255) endGreen = 255; if(endGreen < 0) endGreen = 0; var endBlue = Math.round((blue1 * Col1Fraction) + (blue2 * (1 - Col1Fraction))); if(endBlue > 255) endBlue = 255; if(endBlue < 0) endBlue = 0; return "#" + IntToHex(endRed)+ IntToHex(endGreen)+ IntToHex(endBlue);} function IntToHex(strNum) { base = strNum / 16; rem = strNum % 16; base = base - (rem / 16); baseS = MakeHex(base); remS = MakeHex(rem); return baseS + '' + remS;} function MakeHex(x) { if((x >= 0) && (x <= 9)) { return x;} else { switch(x) { case 10: return "A"; case 11: return "B"; case 12: return "C"; case 13: return "D"; case 14: return "E"; case 15: return "F";} } } function pixelFraction(x, y, r) { var pixelfraction = 0; var xvalues = new Array(1); var yvalues = new Array(1); var point = 0; var whatsides = ""; var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x,2))); if ((intersect >= y) && (intersect < (y+1))) { whatsides = "Left"; xvalues[point] = 0; yvalues[point] = intersect - y; point = point + 1;} var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y+1,2))); if ((intersect >= x) && (intersect < (x+1))) { whatsides = whatsides + "Top"; xvalues[point] = intersect - x; yvalues[point] = 1; point = point + 1;} var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x+1,2))); if ((intersect >= y) && (intersect < (y+1))) { whatsides = whatsides + "Right"; xvalues[point] = 1; yvalues[point] = intersect - y; point = point + 1;} var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y,2))); if ((intersect >= x) && (intersect < (x+1))) { whatsides = whatsides + "Bottom"; xvalues[point] = intersect - x; yvalues[point] = 0;} switch (whatsides) { case "LeftRight": pixelfraction = Math.min(yvalues[0],yvalues[1]) + ((Math.max(yvalues[0],yvalues[1]) - Math.min(yvalues[0],yvalues[1]))/2); break; case "TopRight": pixelfraction = 1-(((1-xvalues[0])*(1-yvalues[1]))/2); break; case "TopBottom": pixelfraction = Math.min(xvalues[0],xvalues[1]) + ((Math.max(xvalues[0],xvalues[1]) - Math.min(xvalues[0],xvalues[1]))/2); break; case "LeftBottom": pixelfraction = (yvalues[0]*xvalues[1])/2; break; default: pixelfraction = 1;} return pixelfraction;} function rgb2Hex(rgbColour) { try{ var rgbArray = rgb2Array(rgbColour); var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); var hexColour = "#" + IntToHex(red) + IntToHex(green) + IntToHex(blue);} catch(e){ alert("There was an error converting the RGB value to Hexadecimal in function rgb2Hex");} return hexColour;} function rgb2Array(rgbColour) { var rgbValues = rgbColour.substring(4, rgbColour.indexOf(")")); var rgbArray = rgbValues.split(", "); return rgbArray;} function setOpacity(obj, opacity) { opacity = (opacity == 100)?99.999:opacity; if(isSafari && obj.tagName != "IFRAME") { var rgbArray = rgb2Array(obj.style.backgroundColor); var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); obj.style.backgroundColor = "rgba(" + red + ", " + green + ", " + blue + ", " + opacity/100 + ")";} else if(typeof(obj.style.opacity) != "undefined") { obj.style.opacity = opacity/100;} else if(typeof(obj.style.MozOpacity) != "undefined") { obj.style.MozOpacity = opacity/100;} else if(typeof(obj.style.filter) != "undefined") { obj.style.filter = "alpha(opacity:" + opacity + ")";} else if(typeof(obj.style.KHTMLOpacity) != "undefined") { obj.style.KHTMLOpacity = opacity/100;} } function inArray(array, value) { for(var i = 0; i < array.length; i++){ if (array[i] === value) return i;} return false;} function inArrayKey(array, value) { for(key in array){ if(key === value) return true;} return false;} function addEvent(elm, evType, fn, useCapture) { if (elm.addEventListener) { elm.addEventListener(evType, fn, useCapture); return true;} else if (elm.attachEvent) { var r = elm.attachEvent('on' + evType, fn); return r;} else { elm['on' + evType] = fn;} } function removeEvent(obj, evType, fn, useCapture){ if (obj.removeEventListener){ obj.removeEventListener(evType, fn, useCapture); return true;} else if (obj.detachEvent){ var r = obj.detachEvent("on"+evType, fn); return r;} else { alert("Handler could not be removed");} } function format_colour(colour) { var returnColour = "#ffffff"; if(colour != "" && colour != "transparent") { if(colour.substr(0, 3) == "rgb") { returnColour = rgb2Hex(colour);} else if(colour.length == 4) { returnColour = "#" + colour.substring(1, 2) + colour.substring(1, 2) + colour.substring(2, 3) + colour.substring(2, 3) + colour.substring(3, 4) + colour.substring(3, 4);} else { returnColour = colour;} } return returnColour;} function get_style(obj, property, propertyNS) { try { if(obj.currentStyle) { var returnVal = eval("obj.currentStyle." + property);} else { if(isSafari && obj.style.display == "none") { obj.style.display = ""; var wasHidden = true;} var returnVal = document.defaultView.getComputedStyle(obj, '').getPropertyValue(propertyNS); if(isSafari && wasHidden) { obj.style.display = "none";} } } catch(e) { } return returnVal;} function getElementsByClass(searchClass, node, tag) { var classElements = new Array(); if(node == null) node = document; if(tag == null) tag = '*'; var els = node.getElementsByTagName(tag); var elsLen = els.length; var pattern = new RegExp("(^|\s)"+searchClass+"(\s|$)"); for (i = 0, j = 0; i < elsLen; i++) { if(pattern.test(els[i].className)) { classElements[j] = els[i]; j++;} } return classElements;} function newCurvyError(errorMessage) { return new Error("curvyCorners Error:\n" + errorMessage) } ================================================ FILE: website/stylesheets/code.css ================================================ .ruby .normal {} .ruby .comment { color: #888; font-style: italic; } .ruby .keyword { color: #A00; font-weight: bold; } .ruby .method { color: #077; } .ruby .class { color: #074; } .ruby .module { color: #050; } .ruby .punct { color: #447; font-weight: bold; } .ruby .symbol { color: #099; } .ruby .string { color: #944; } .ruby .char { color: #F07; } .ruby .ident { color: #004; } .ruby .constant { color: #07F; } .ruby .regex { color: #B66; } .ruby .number { color: #D55; } .ruby .attribute { color: #377; } .ruby .global { color: #3B7; } .ruby .expr { color: #227; }) ================================================ FILE: website/stylesheets/screen.css ================================================ body { background-color: #E1D1F1; font-family: "Georgia", sans-serif; font-size: 16px; line-height: 1.6em; padding: 1.6em 0 0 0; color: #333; } h1, h2, h3, h4, h5, h6 { color: #444; } h1 { font-family: sans-serif; font-weight: normal; font-size: 4em; line-height: 0.8em; letter-spacing: -0.1ex; margin: 5px; } li { padding: 0; margin: 0; list-style-type: square; } a { color: #5E5AFF; background-color: #DAC; font-weight: normal; text-decoration: underline; } blockquote { font-size: 90%; font-style: italic; border-left: 1px solid #111; padding-left: 1em; } #buy-arduino { float:left; margin-right: 10px; border: 8px solid #000; background-color: #fff; padding: 5px; text-align:center; } #buy-arduino h4{ font-size: 12px; margin: 0; } #buy-arduino a { background-color: #fff; } #buy-arduino img{ width: 190px; border: none; } .caps { font-size: 80%; } #main { width: 45em; padding: 0; margin: 0 auto; } .coda { text-align: right; color: #77f; font-size: smaller; } table { font-size: 90%; line-height: 1.4em; color: #ff8; background-color: #111; padding: 2px 10px 2px 10px; border-style: dashed; } th { color: #fff; } td { padding: 2px 10px 2px 10px; } .success { color: #0CC52B; } .failed { color: #E90A1B; } .unknown { color: #995000; } pre, code { font-family: monospace; font-size: 90%; line-height: 1.4em; color: #ff8; background-color: #111; padding: 2px 10px 2px 10px; } .comment { color: #aaa; font-style: italic; } .keyword { color: #eff; font-weight: bold; } .punct { color: #eee; font-weight: bold; } .symbol { color: #0bb; } .string { color: #6b4; } .ident { color: #ff8; } .constant { color: #66f; } .regex { color: #ec6; } .number { color: #F99; } .expr { color: #227; } #metadata { float: left; margin-right: 20px; } #version { width:210px; text-align: right; font-family: sans-serif; font-weight: normal; background-color: #B3ABFF; color: #141331; padding: 15px 20px 10px 20px; margin: 0 auto; margin-top: 15px; border: 3px solid #141331; margin-bottom: 20px; } #version .numbers { display: block; font-size: 4em; line-height: 0.8em; letter-spacing: -0.1ex; margin-bottom: 15px; } #version p { text-decoration: none; color: #141331; background-color: #B3ABFF; margin: 0; padding: 0; } #version a { text-decoration: none; color: #141331; background-color: #B3ABFF; } .clickable { cursor: pointer; cursor: hand; } ================================================ FILE: website/template.rhtml ================================================ <%= title %>

<%= title %>

Get Version

<%= version %>
<%= body %>

Dr Nic, <%= modified.pretty %>
Theme extended from Paul Battley