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)}#{element}>"
"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 9600class AssemblerTest<ArduinoSketchvars:a=>10,:b=>4serial_begindef loopserial_printlnproduct(a,b)endassembler(: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
# Hardware: motor control circuit (i.e. TIP-120 control pin)# connected at pin 7.# Demo: http://www.youtube.com/watch?v=7OguEBfdTe0class SerialMotor<ArduinoSketchoutput_pin7,:as=>:motorserial_begindef loopdigitalWrite(motor,serial_read)ifserial_availableendend
================================================
FILE: website/index.html
================================================
RAD
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.
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.
================================================
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 %>