atduskgreg-rad 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. data/History.txt +104 -0
  2. data/License.txt +282 -0
  3. data/Manifest.txt +142 -0
  4. data/README.rdoc +55 -0
  5. data/Rakefile +142 -0
  6. data/bin/hello_world_test/Makefile +436 -0
  7. data/bin/hello_world_test/hello_world.cpp +23 -0
  8. data/bin/rad +302 -0
  9. data/lib/examples/add_hysteresis.rb +13 -0
  10. data/lib/examples/basic_blink.rb +10 -0
  11. data/lib/examples/blink_m_address_assignment.rb +104 -0
  12. data/lib/examples/blink_m_hello.rb +14 -0
  13. data/lib/examples/blink_m_multi.rb +61 -0
  14. data/lib/examples/blink_with_serial.rb +16 -0
  15. data/lib/examples/configure_pa_lcd_boot.rb +91 -0
  16. data/lib/examples/debounce_methods.rb +49 -0
  17. data/lib/examples/external_variable_fu.rb +26 -0
  18. data/lib/examples/external_variables.rb +32 -0
  19. data/lib/examples/first_sound.rb +23 -0
  20. data/lib/examples/frequency_generator.rb +30 -0
  21. data/lib/examples/hello_array.rb +48 -0
  22. data/lib/examples/hello_array2.rb +79 -0
  23. data/lib/examples/hello_array_eeprom.rb +59 -0
  24. data/lib/examples/hello_clock.rb +84 -0
  25. data/lib/examples/hello_eeprom.rb +51 -0
  26. data/lib/examples/hello_eeprom_lcdpa.rb +81 -0
  27. data/lib/examples/hello_format_print.rb +94 -0
  28. data/lib/examples/hello_lcd_charset.rb +75 -0
  29. data/lib/examples/hello_pa_lcd.rb +59 -0
  30. data/lib/examples/hello_servos.rb +88 -0
  31. data/lib/examples/hello_spectra_sound.rb +38 -0
  32. data/lib/examples/hello_world.rb +11 -0
  33. data/lib/examples/hello_xbee.rb +12 -0
  34. data/lib/examples/hysteresis_duel.rb +39 -0
  35. data/lib/examples/i2c_with_clock_chip.rb +124 -0
  36. data/lib/examples/midi_beat_box.rb +86 -0
  37. data/lib/examples/midi_scales.rb +94 -0
  38. data/lib/examples/motor_knob.rb +30 -0
  39. data/lib/examples/servo_buttons.rb +23 -0
  40. data/lib/examples/servo_calibrate_continuous.rb +92 -0
  41. data/lib/examples/servo_throttle.rb +40 -0
  42. data/lib/examples/software_serial.rb +10 -0
  43. data/lib/examples/sparkfun_lcd.rb +48 -0
  44. data/lib/examples/spectra_soft_pot.rb +34 -0
  45. data/lib/examples/times_method.rb +8 -0
  46. data/lib/examples/toggle.rb +10 -0
  47. data/lib/examples/twitter.rb +57 -0
  48. data/lib/examples/two_wire.rb +14 -0
  49. data/lib/libraries/AFSoftSerial/AFSoftSerial.cpp +321 -0
  50. data/lib/libraries/AFSoftSerial/AFSoftSerial.h +61 -0
  51. data/lib/libraries/AFSoftSerial/keywords.txt +18 -0
  52. data/lib/libraries/AF_XPort/AF_XPort.cpp +166 -0
  53. data/lib/libraries/AF_XPort/AF_XPort.h +48 -0
  54. data/lib/libraries/DS1307/DS1307.cpp +162 -0
  55. data/lib/libraries/DS1307/DS1307.h +66 -0
  56. data/lib/libraries/DS1307/keywords.txt +18 -0
  57. data/lib/libraries/FrequencyTimer2/FrequencyTimer2.cpp +144 -0
  58. data/lib/libraries/FrequencyTimer2/FrequencyTimer2.h +42 -0
  59. data/lib/libraries/FrequencyTimer2/keywords.txt +22 -0
  60. data/lib/libraries/I2CEEPROM/I2CEEPROM.cpp +120 -0
  61. data/lib/libraries/I2CEEPROM/I2CEEPROM.h +70 -0
  62. data/lib/libraries/I2CEEPROM/keywords.txt +21 -0
  63. data/lib/libraries/LoopTimer/LoopTimer.cpp +35 -0
  64. data/lib/libraries/LoopTimer/LoopTimer.h +34 -0
  65. data/lib/libraries/LoopTimer/keywords.txt +27 -0
  66. data/lib/libraries/OneWire/OneWire.cpp +194 -0
  67. data/lib/libraries/OneWire/OneWire.h +63 -0
  68. data/lib/libraries/OneWire/keywords.txt +35 -0
  69. data/lib/libraries/OneWire/readme.txt +13 -0
  70. data/lib/libraries/SWSerLCDpa/SWSerLCDpa.cpp +296 -0
  71. data/lib/libraries/SWSerLCDpa/SWSerLCDpa.h +69 -0
  72. data/lib/libraries/SWSerLCDsf/SWSerLCDsf.cpp +311 -0
  73. data/lib/libraries/SWSerLCDsf/SWSerLCDsf.h +67 -0
  74. data/lib/libraries/Servo/Servo.cpp +192 -0
  75. data/lib/libraries/Servo/Servo.h +61 -0
  76. data/lib/libraries/Stepper/Stepper.cpp +220 -0
  77. data/lib/libraries/Stepper/Stepper.h +86 -0
  78. data/lib/libraries/Stepper/keywords.txt +28 -0
  79. data/lib/libraries/Wire/Wire.cpp +262 -0
  80. data/lib/libraries/Wire/Wire.h +67 -0
  81. data/lib/libraries/Wire/keywords.txt +31 -0
  82. data/lib/libraries/Wire/twi.h +57 -0
  83. data/lib/libraries/Wire/utility/twi.c +449 -0
  84. data/lib/libraries/Wire/utility/twi.h +57 -0
  85. data/lib/plugins/bitwise_ops.rb +54 -0
  86. data/lib/plugins/blink.rb +25 -0
  87. data/lib/plugins/blink_m.rb +356 -0
  88. data/lib/plugins/debounce.rb +138 -0
  89. data/lib/plugins/debug_output_to_lcd.rb +71 -0
  90. data/lib/plugins/hysteresis.rb +52 -0
  91. data/lib/plugins/input_output_state.rb +84 -0
  92. data/lib/plugins/lcd_padding.rb +58 -0
  93. data/lib/plugins/mem_test.rb +37 -0
  94. data/lib/plugins/midi.rb +60 -0
  95. data/lib/plugins/parallax_ping.rb +50 -0
  96. data/lib/plugins/servo_pulse.rb +31 -0
  97. data/lib/plugins/servo_setup.rb +86 -0
  98. data/lib/plugins/smoother.rb +54 -0
  99. data/lib/plugins/spark_fun_serial_lcd.rb +100 -0
  100. data/lib/plugins/spectra_symbol.rb +79 -0
  101. data/lib/plugins/twitter_connect.rb +145 -0
  102. data/lib/rad.rb +5 -0
  103. data/lib/rad/README.rdoc +5 -0
  104. data/lib/rad/arduino_plugin.rb +246 -0
  105. data/lib/rad/arduino_sketch.rb +627 -0
  106. data/lib/rad/generators/makefile/makefile.erb +243 -0
  107. data/lib/rad/generators/makefile/makefile.rb +38 -0
  108. data/lib/rad/hardware_library.rb +813 -0
  109. data/lib/rad/init.rb +14 -0
  110. data/lib/rad/progressbar.rb +236 -0
  111. data/lib/rad/rad_processor.rb +128 -0
  112. data/lib/rad/rad_rewriter.rb +94 -0
  113. data/lib/rad/rad_type_checker.rb +26 -0
  114. data/lib/rad/sim/arduino_sketch.rb +57 -0
  115. data/lib/rad/sketch_compiler.rb +47 -0
  116. data/lib/rad/tasks/build_and_make.rake +210 -0
  117. data/lib/rad/tasks/rad.rb +2 -0
  118. data/lib/rad/todo.txt +13 -0
  119. data/lib/rad/variable_processing.rb +153 -0
  120. data/lib/rad/version.rb +9 -0
  121. data/scripts/txt2html +67 -0
  122. data/setup.rb +1585 -0
  123. data/spec/examples/hello_world.rb +11 -0
  124. data/spec/examples/serial_motor.rb +12 -0
  125. data/spec/models/arduino_sketch_spec.rb +82 -0
  126. data/spec/models/sketch_compiler_spec.rb +96 -0
  127. data/spec/models/spec_helper.rb +2 -0
  128. data/spec/sim/hello_world_spec.rb +42 -0
  129. data/spec/spec.opts +1 -0
  130. data/test/test_array_processing.rb +179 -0
  131. data/test/test_plugin_loading.rb +151 -0
  132. data/test/test_translation_post_processing.rb +185 -0
  133. data/test/test_variable_processing.rb +238 -0
  134. data/website/examples/assembler_test.rb.html +73 -0
  135. data/website/examples/gps_reader.rb.html +39 -0
  136. data/website/examples/hello_world.rb.html +38 -0
  137. data/website/examples/serial_motor.rb.html +41 -0
  138. data/website/index.html +178 -0
  139. data/website/index.txt +64 -0
  140. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  141. data/website/stylesheets/screen.css +169 -0
  142. data/website/template.rhtml +48 -0
  143. metadata +217 -0
@@ -0,0 +1,145 @@
1
+ class TwitterConnect < ArduinoPlugin
2
+
3
+
4
+
5
+
6
+ void get_tweet() {
7
+ // hack to pull
8
+ }
9
+
10
+ uint32_t parsenumber(char *str) {
11
+ uint32_t num = 0;
12
+ char c;
13
+
14
+ // grabs a number out of a string
15
+ while (c = str[0]) {
16
+ if ((c < '0') || (c > '9'))
17
+ return num;
18
+ num *= 10;
19
+ num += c - '0';
20
+ str++;
21
+ }
22
+ return num;
23
+ }
24
+
25
+
26
+ char * fetchtweet(void) {
27
+ Serial.print("... fetching tweets....");
28
+ uint8_t ret;
29
+ char *found=0, *start=0, *end=0;
30
+
31
+ tweet[0] = 0; // reset the tweet
32
+ ret = xport.reset();
33
+ //Serial.print("Ret: "); Serial.print(ret, HEX);
34
+ switch (ret) {
35
+ case ERROR_TIMEDOUT: {
36
+ Serial.println("Timed out on reset!");
37
+ return 0;
38
+ }
39
+ case ERROR_BADRESP: {
40
+ Serial.println("Bad response on reset!");
41
+ return 0;
42
+ }
43
+ case ERROR_NONE: {
44
+ Serial.println("Reset OK!");
45
+ break;
46
+ }
47
+ default:
48
+ Serial.println("Unknown error");
49
+ return 0;
50
+ }
51
+
52
+ // time to connect...
53
+
54
+ ret = xport.connect(IPADDR, PORT);
55
+ switch (ret) {
56
+ case ERROR_TIMEDOUT: {
57
+ Serial.println("Timed out on connect");
58
+ return 0;
59
+ }
60
+ case ERROR_BADRESP: {
61
+ Serial.println("Failed to connect");
62
+ return 0;
63
+ }
64
+ case ERROR_NONE: {
65
+ Serial.println("Connected..."); break;
66
+ }
67
+ default:
68
+ Serial.println("Unknown error");
69
+ return 0;
70
+ }
71
+
72
+ // send the HTTP command, ie "GET /username/"
73
+
74
+ xport.print("GET "); xport.println(HTTPPATH);
75
+ // the following works with instiki, but not on twitter...
76
+ // xport.print("GET ");
77
+ // xport.print(HTTPPATH);
78
+ // xport.println(" HTTP/1.1");
79
+ // xport.print("Host: "); xport.println(HOSTNAME);
80
+ // xport.println("");
81
+
82
+
83
+
84
+ while (1) {
85
+ // read one line from the xport at a time
86
+ ret = xport.readline_timeout(linebuffer, 255, 4000); // 3s timeout
87
+ // if we're using flow control, we can actually dump the line at the same time!
88
+ // Serial.print(linebuffer);
89
+
90
+ // look for an entry (the first one)
91
+ found = strstr(linebuffer, "entry-title entry-content");
92
+ if (((int)found) != 0) {
93
+ start = strstr(found, ">") + 1;
94
+ end = strstr(found, "</p>");
95
+ if ((start != 0) && (end != 0)) {
96
+ Serial.println("\n******Found first entry!*******");
97
+ end[0] = 0;
98
+ Serial.print(start);
99
+ // save the tweet so we can display it later
100
+ strncpy(tweet, start, TWEETLEN);
101
+ tweet[TWEETLEN-1] = 0;
102
+ }
103
+ }
104
+
105
+ // next we look for a status ID (which should correspond to the previous tweet)e
106
+ // Serial.print(".");
107
+ // Serial.print(linebuffer);
108
+ found = strstr(linebuffer, "<div id=\"status_actions_");
109
+ if (((int)found) != 0) {
110
+ start = found + 25; // strlen("<span id=\"status_actions_")
111
+ end = strstr(found, "\">");
112
+ if ((start != 0) && (end != 0)) {
113
+ Serial.println("\n******Found status ID!*******");
114
+ end[0] = 0;
115
+ Serial.println(start);
116
+ // turn the string into a number
117
+ __currstatus = parsenumber(start);
118
+ Serial.println(__currstatus, DEC);
119
+
120
+ // check if this is a nu tweet
121
+ if (__currstatus > __laststatus) {
122
+ __laststatus = __currstatus;
123
+ Serial.println("New message");
124
+ Serial.print(tweet);
125
+ } else {
126
+ tweet[0] = 0;
127
+ }
128
+ // flush the conn
129
+ xport.flush(5000); // 5 second timeout
130
+
131
+ if (tweet[0] == 0) { return 0; }
132
+ else {return tweet; }
133
+ }
134
+ }
135
+
136
+ if (((__errno == ERROR_TIMEDOUT) && xport.disconnected()) ||
137
+ ((XPORT_DTRPIN == 0) &&
138
+ (linebuffer[0] == 'D') && (linebuffer[1] == 0))) {
139
+ Serial.println("\nDisconnected...");
140
+ return 0;
141
+ }
142
+ }
143
+ }
144
+
145
+ end
data/lib/rad.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Rad
2
+ end
3
+
4
+ require 'rad/version'
5
+ require 'rad/init'
@@ -0,0 +1,5 @@
1
+ =Welcome to RAD (Ruby Arduino Development) Quick Start Documentation
2
+
3
+ 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:
4
+
5
+ test... to be continued if it works..
@@ -0,0 +1,246 @@
1
+ ## RAD plugins -- the start
2
+
3
+ ## June 25, 2008
4
+ ## jd@jdbarnhart.com
5
+ ##
6
+
7
+
8
+ # 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.
9
+ # 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:
10
+ #
11
+ # class MoveServo < ArduinoSketch
12
+ #
13
+ # external_vars :sensor_position => "int, 0", :servo_amount => "int, 0"
14
+ #
15
+ # output_pin 4, :as => :my_servo, :min => 700, :max => 2200
16
+ # input_pin 1, :as => :sensor
17
+ # def loop
18
+ # sensor_position = analogRead(sensor)
19
+ # servo_amount = (sensor_position*2 + 500)
20
+ # move_servo my_servo, servo_amount
21
+ # end
22
+ # end
23
+ #
24
+ #
25
+ # Here's one for latching an led
26
+
27
+ # output_pin 5, :as => :red_led
28
+ # input_pin 8, :as => :red_button, :latch => :off, # optional adjustment to amount of time for debounce (default 200) :adjust => 250
29
+ # # latch sets the led as on or off initially and sets up a array of structs to keep timing and state
30
+ #
31
+ # def loop
32
+ # debounce_toggle(red_button, red_led)
33
+ # end
34
+ # end
35
+ #
36
+ # Since this is a first pass, there is work to do here, such as
37
+ # checking if plugin methods are needed and only loading those that are,
38
+ # more compreshensive plugin organization (more railsish with tests, etc)
39
+ # a scheme to encourage plugin authors and provide an easy way to avoid method and variable namespace collisions
40
+ # a scheme to flag when a prerequisite plugin is required
41
+ # on with the show:
42
+
43
+
44
+
45
+ class ArduinoPlugin
46
+
47
+ def initialize #:nodoc:
48
+
49
+ $plugin_directives = $plugin_directives || []
50
+ $plugin_external_variables = $plugin_external_variables || []
51
+ # moved to check_for_plugin_use $plugin_structs = $plugin_structs || {}
52
+ $plugin_signatures = $plugin_signatures || []
53
+ $plugin_methods = $plugin_methods || []
54
+ # $plugin_methods_hash = $plugin_methods_hash || {} ### new
55
+ # $plugins_to_load = $plugins_to_load || [] ### new
56
+ $add_to_setup = $add_to_setup || []
57
+ $load_libraries = $load_libraries || []
58
+
59
+
60
+ end
61
+
62
+ # c declarations are automatic
63
+ # you won't need them in the plugins
64
+ # so, the first thing we can do is gather all the plugin methods, and scan the
65
+ # sketch available plugins...
66
+ # if the sketch has them, we include the plugins in the build...
67
+ # otherwise not..
68
+
69
+ def include_wire
70
+ $load_libraries << "Wire" unless $load_libraries.include?("Wire")
71
+ end
72
+
73
+
74
+ def add_to_setup(*args)
75
+ if args
76
+ args.each do |arg|
77
+ $add_to_setup << arg
78
+ end
79
+ end
80
+ end
81
+
82
+
83
+ def plugin_directives(*args)
84
+ if args
85
+ args.each do |arg|
86
+ $plugin_directives << arg
87
+ end
88
+ end
89
+ end
90
+
91
+
92
+ def external_variables(*args)
93
+ if args
94
+ args.each do |arg|
95
+ puts self.class
96
+ puts "\tadding plugin external variables: #{arg}"
97
+ # colons aptional
98
+ colon = arg[arg.length - 1, 1] == ";" ? '' : ';'
99
+ $plugin_external_variables << "#{arg}#{colon}"
100
+ end
101
+ end
102
+ end
103
+
104
+ def add_blink_m_struct
105
+ $plugin_structs[:blink_m] = <<-STR
106
+ typedef struct _blinkm_script_line {
107
+ uint8_t dur;
108
+ uint8_t cmd[4]; // cmd,arg1,arg2,arg3
109
+ } blinkm_script_line;
110
+ STR
111
+ end
112
+
113
+ def self.add_blink_m_struct
114
+ $plugin_structs[:blink_m] = <<-STR
115
+ typedef struct _blinkm_script_line {
116
+ uint8_t dur;
117
+ uint8_t cmd[4]; // cmd,arg1,arg2,arg3
118
+ } blinkm_script_line;
119
+ STR
120
+ end
121
+
122
+ def add_debounce_struct
123
+ $plugin_structs[:debounce] = <<-STR
124
+ struct debounce {
125
+ int state;
126
+ int read;
127
+ int prev;
128
+ unsigned long time;
129
+ unsigned long adjust;
130
+ };
131
+ STR
132
+ end
133
+
134
+
135
+ def add_servo_struct
136
+ $plugin_structs[:servo] = <<-STR
137
+ struct servo {
138
+ int pin;
139
+ long unsigned pulseWidth;
140
+ long unsigned lastPulse;
141
+ long unsigned startPulse;
142
+ long unsigned refreshTime;
143
+ int min;
144
+ int max;
145
+ };
146
+ STR
147
+ end
148
+
149
+ def self.add_debounce_struct
150
+ $plugin_structs[:debounce] = <<-STR
151
+ struct debounce {
152
+ int state;
153
+ int read;
154
+ int prev;
155
+ unsigned long time;
156
+ unsigned long adjust;
157
+ };
158
+ STR
159
+ end
160
+
161
+
162
+ def self.add_servo_struct
163
+ $plugin_structs[:servo] = <<-STR
164
+ struct servo {
165
+ int pin;
166
+ long unsigned pulseWidth;
167
+ long unsigned lastPulse;
168
+ long unsigned startPulse;
169
+ long unsigned refreshTime;
170
+ int min;
171
+ int max;
172
+ };
173
+ STR
174
+ end
175
+
176
+ def self.add_sensor_struct
177
+ $plugin_structs[:sensor] = <<-STR
178
+ struct hysteresis {
179
+ int pin;
180
+ int state;
181
+ };
182
+ STR
183
+ end
184
+
185
+ def self.add_spectra_struct
186
+ $plugin_structs[:spectra] = <<-STR
187
+ struct spectra {
188
+ int pin;
189
+ int state;
190
+ int r1;
191
+ int r2;
192
+ int r3;
193
+ };
194
+ STR
195
+ end
196
+
197
+
198
+ def self.check_for_plugin_use(sketch_string, plugin_string, file_name) # rename klass to filename
199
+ $plugin_structs = $plugin_structs || {}
200
+ $plugin_methods_hash = $plugin_methods_hash || {}
201
+ $plugins_to_load = $plugins_to_load || []
202
+ plugin_signatures = []
203
+ plugin_methods = []
204
+ ## need a test for this
205
+ ## fails on string interpolation, but since ruby_to_c also currently fails ...
206
+ sketch_string = sketch_string.gsub(/#(?!\{.*\}).*/, "")
207
+ plugin_signatures << plugin_string.scan(/^\s*(((#{PLUGIN_C_VAR_TYPES})\s*)+\w*\(.*\))/)
208
+ # gather just the method name and then add to #plugin_methods_hash
209
+ plugin_signatures[0].map {|sig| "#{sig[0]}"}.each {|m| plugin_methods << m.gsub!(/^.*\s(\w*)\(.*\)/, '\1')}
210
+ # we don't know the methods yet, so...
211
+ $plugin_methods_hash[file_name] = plugin_methods
212
+ $plugin_methods_hash.each do |k,meths|
213
+ meths.each do |meth|
214
+ if sketch_string.include?(meth)
215
+ # load this plugin...
216
+ $plugins_to_load << k unless $plugins_to_load.include?(k)
217
+ end
218
+ end
219
+ end
220
+
221
+ end
222
+
223
+
224
+ def self.process(plugin_string)
225
+ plugin_signatures = []
226
+ first_process = plugin_string
227
+ # todo: need to add plugin names to the methods, so we can add them as comments in the c code
228
+ # gather the c methods
229
+ $plugin_methods << first_process.scan(/^\s*(((#{PLUGIN_C_VAR_TYPES}).*\)).*(\n.*)*^\s*\})/)
230
+ plugin_signatures << first_process.scan(/^\s((#{PLUGIN_C_VAR_TYPES}).*\(.*\))/)
231
+ $plugin_signatures << plugin_signatures[0].map {|sig| "#{sig[0]};"}
232
+ ## strip out the methods and pass it back
233
+ result = plugin_string
234
+ # strip out the c methods so we have only ruby before eval
235
+ result.gsub(/^\s*(#{PLUGIN_C_VAR_TYPES}).*(\n.*)*^\s*\}/, "" )
236
+
237
+ end
238
+
239
+ private
240
+
241
+ def add_struct(struct)
242
+
243
+
244
+ end
245
+
246
+ end
@@ -0,0 +1,627 @@
1
+ # 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:
2
+ #
3
+ # class HelloWorld < ArduinoSketch
4
+ # output_pin 13, :as => :led
5
+ #
6
+ # def loop
7
+ # blink 13, 500
8
+ # end
9
+ # end
10
+ #
11
+ # 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.
12
+ #
13
+ # ==Arduino built-in methods
14
+ # 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.
15
+ #
16
+ # <b>Digital I/O</b>
17
+ #
18
+ # digital_write(pin, value)
19
+ #
20
+ # Arduino method: digitalWrite(pin, value)
21
+ #
22
+ # Description: "Ouputs either HIGH or LOW at a specified pin."
23
+ #
24
+ # Documentation: http://www.arduino.cc/en/Reference/DigitalWrite
25
+ #
26
+ # digital_read(pin)
27
+ #
28
+ # Arduino method: digitalRead(pin)
29
+ #
30
+ # Description: "Reads the value from a specified pin, it will be either HIGH or LOW."
31
+ #
32
+ # Documentation: http://www.arduino.cc/en/Reference/DigitalRead
33
+ #
34
+ # <b>Analog I/O</b>
35
+ #
36
+ # analog_read(pin)
37
+ #
38
+ # Arduino method: analogRead(pin)
39
+ #
40
+ # Description: "Reads the value from the specified analog pin. The Arduino board contains a 6 channel
41
+ # (8 channels on the Mini), 10-bit analog to digital converter. This means that it will map input
42
+ # voltages between 0 and 5 volts into integer values between 0 and 1023. This yields a resolution
43
+ # between readings of: 5 volts / 1024 units or, .0049 volts (4.9 mV) per unit. It takes about 100
44
+ # us (0.0001 s) to read an analog input, so the maximum reading rate is about 10,000 times a second."
45
+ #
46
+ # Documentation: http://www.arduino.cc/en/Reference/AnalogRead
47
+ #
48
+ # analog_write(pin, value)
49
+ #
50
+ # Arduino method: analogWrite(pin, value)
51
+ #
52
+ # Description: "Writes an analog value (PWM wave) to a pin. On newer Arduino boards (including the Mini
53
+ # and BT) with the ATmega168 chip, this function works on pins 3, 5, 6, 9, 10, and 11. Older USB and
54
+ # serial Arduino boards with an ATmega8 only support analogWrite() on pins 9, 10, and 11. Can be used
55
+ # to light a LED at varying brightnesses or drive a motor at various speeds. After a call to analogWrite,
56
+ # the pin will generate a steady wave until the next call to analogWrite (or a call to digitalRead or
57
+ # digitalWrite on the same pin)."
58
+ #
59
+ # Documentation: http://www.arduino.cc/en/Reference/AnalogWrite
60
+ #
61
+ # <b>Serial Communication</b>
62
+ #
63
+ # serial_available()
64
+ #
65
+ # Arduino method: Serial.available()
66
+ #
67
+ # Description: "Get the number of bytes (characters) available for reading over the serial port.
68
+ # Returns the number of bytes available to read in the serial buffer, or 0 if none are
69
+ # available. If any data has come in, Serial.available() will be greater than 0. The serial buffer
70
+ # can hold up to 128 bytes."
71
+ #
72
+ # Documentation: http://www.arduino.cc/en/Serial/Available
73
+ #
74
+ # serial_read()
75
+ #
76
+ # Arduino method: Serial.read()
77
+ #
78
+ # Description: "Reads incoming serial data and returns the first byte of incoming serial data
79
+ # available (or -1 if no data is available)"
80
+ #
81
+ # Documentation: http://www.arduino.cc/en/Serial/Read
82
+ #
83
+ # serial_print(data)
84
+ #
85
+ # Arduino method: Serial.print(data)
86
+ #
87
+ # Description: "Prints data to the serial port."
88
+ #
89
+ # Documentation: http://www.arduino.cc/en/Serial/Print
90
+ #
91
+ # serial_println(data)
92
+ #
93
+ # Arduino method: Serial.println(data)
94
+ #
95
+ # Description: "Prints a data to the serial port, followed by a carriage return character
96
+ # (ASCII 13, or '\r') and a newline character (ASCII 10, or '\n'). This command takes the
97
+ # same forms as Serial.print():"
98
+ #
99
+ # Documentation: http://www.arduino.cc/en/Serial/Println
100
+ #
101
+ # serial_flush()
102
+ #
103
+ # Arduino method: Serial.flush()
104
+ #
105
+ # Description: "Flushes the buffer of incoming serial data. That is, any call to Serial.read()
106
+ # or Serial.available() will return only data received after the most recent call
107
+ # to Serial.flush()."
108
+ #
109
+ # Documentation: http://www.arduino.cc/en/Serial/Flush
110
+ #
111
+ # June 25, 2008
112
+ # Added a new external variable method which keeps track
113
+ # external_vars :sensor_position => "int, 0", :feedback => "int", :pulseTime => "unsigned long, 0"
114
+ #
115
+ # added ability to write additional methods besides loop in the sketch
116
+ # since there is quite a bit of work to do with the c translation, it is easy to write a method that
117
+ # won't compile or even translate into c, but for basics, it works.
118
+ # Note: stay basic and mindful that c is picky about variables and must make a decision
119
+ # which will not always be what you want
120
+ # also: for now, don't leave empty methods (something like foo = 1 cures this)
121
+ #
122
+ # Example:
123
+ #
124
+ # class HelloMethods < ArduinoSketch
125
+ # output_pin 13, :as => :led
126
+ #
127
+ # def loop
128
+ # blink_it
129
+ # end
130
+
131
+ # def blink_it
132
+ # blink 13, 500
133
+ # end
134
+ #
135
+ # end
136
+ #
137
+ #
138
+ # added pin methods for servos and latching which generate an array of structs to contain setup and status
139
+ # input_pin 12, :as => :back_off_button, :latch => :off
140
+ # input_pin 8, :as => :red_button, :latch => :off # adjust is optional with default set to 200
141
+ #
142
+ # added add_to_setup method that takes a string of c code and adds it to setup
143
+ # colons are options and will be added if not present
144
+ # no translation from ruby for now
145
+ #
146
+ # example:
147
+ #
148
+ # add_to_setup "call_my_new_method();", "call_another();"
149
+ #
150
+ # added some checking to c translation that (hopefully) makes it a bit more predictable
151
+ # most notably, we keep track of all external variables and let the translator know they exist
152
+ #
153
+ #
154
+
155
+ class ArduinoSketch
156
+
157
+ include ExternalVariableProcessing
158
+
159
+ # find another way to do this
160
+ @@twowire_inc = FALSE
161
+ @@hwserial_inc = FALSE
162
+
163
+
164
+ def initialize #:nodoc:
165
+ @servo_settings = [] # need modular way to add this
166
+ @debounce_settings = [] # need modular way to add this
167
+ @hysteresis_settings = []
168
+ @spectra_settings = []
169
+ @servo_pins = []
170
+ @debounce_pins = []
171
+ @hysteresis_pins = []
172
+ @spectra_pins = []
173
+ $external_array_vars = []
174
+ $external_vars =[]
175
+ $external_var_identifiers = []
176
+ $sketch_methods = []
177
+ $load_libraries ||= []
178
+ $defines ||= []
179
+ $define_types = {}
180
+ $array_types = {}
181
+ $array_index_helpers = ('a'..'zz').to_a
182
+
183
+ @declarations = []
184
+ @pin_modes = {:output => [], :input => []}
185
+ @pullups = []
186
+ @other_setup = [] # specifically, Serial.begin
187
+ @assembler_declarations = []
188
+ @accessors = []
189
+ @signatures = ["int main();"]
190
+
191
+ helper_methods = []
192
+ @helper_methods = helper_methods.join( "\n" )
193
+
194
+ end
195
+
196
+
197
+
198
+ # array "char buffer[32]"
199
+ # result: char buffer[32];
200
+ # array "char buffer[32]"
201
+ # result: char buffer[32];
202
+ # todo
203
+ # 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)
204
+ def array(arg)
205
+ if arg
206
+ arg = arg.chomp.rstrip.lstrip
207
+ name = arg.scan(/\s*(\w*)\[\d*\]?/).first.first
208
+ # help rad_processor do a better job with array types
209
+ types = ["int", "long", "char*", "unsigned int", "unsigned long", "byte", "bool", "float" ]
210
+ types.each_with_index do |type, i|
211
+ @type = types[i] if /#{type}/ =~ arg
212
+ end
213
+ raise ArgumentError, "type not currently supported.. got: #{arg}. Currently supporting #{types.join(", ")}" unless @type
214
+
215
+ arg = "#{arg};" unless arg[-1,1] == ";"
216
+ $array_types[name] = @type
217
+ @type = nil
218
+ $external_var_identifiers << name unless $external_var_identifiers.include?(name)
219
+ # add array_name declaration
220
+ $external_array_vars << arg unless $external_array_vars.include?(arg)
221
+ end
222
+ end
223
+
224
+ # define "DS1307_SEC 0"
225
+ # result: #define DS1307_SEC 0
226
+ # note we send the constant identifiers and type to our rad_type_checker
227
+ # however, it only knows about long, float, str....
228
+ # so we don't send ints ...yet..
229
+ # need more testing
230
+ def define(arg)
231
+ if arg
232
+ arg = arg.chomp.rstrip.lstrip
233
+ name = arg.split(" ").first
234
+ value = arg.gsub!("#{name} ","")
235
+ # negative
236
+ if value =~ /^-(\d|x)*$/
237
+ type = "long"
238
+ # negative float
239
+ elsif value =~ /^-(\d|\.|x)*$/
240
+ type = "float"
241
+ elsif value =~ /[a-zA-Z]/
242
+ type = "str"
243
+ value = "\"#{value}\""
244
+ elsif value !~ /(\.|x)/
245
+ type = "long"
246
+ elsif value =~ /(\d*\.\d*)/ # and no
247
+ type = "float"
248
+ elsif value =~ /0x\d\d/
249
+ type = "byte"
250
+ else
251
+ raise ArgumentError, "opps, could not determine the define type, got #{value}"
252
+ end
253
+ $define_types[name] = type
254
+ arg = "#define #{name} #{value}"
255
+ $defines << arg
256
+ dummy_for_testing = arg, type
257
+ end
258
+ end
259
+
260
+ # Configure a single pin for output and setup a method to refer to that pin, i.e.:
261
+ #
262
+ # output_pin 7, :as => :led
263
+ #
264
+ # would configure pin 7 as an output and let you refer to it from the then on by calling
265
+ # the `led` method in your loop like so:
266
+ #
267
+ # def loop
268
+ # digital_write led, ON
269
+ # end
270
+ #
271
+ def output_pin(num, opts={})
272
+ raise ArgumentError, "can only define pin from Fixnum, got #{num.class}" unless num.is_a?(Fixnum)
273
+ @pin_modes[:output] << num
274
+ if opts[:as]
275
+ if opts[:device]
276
+ case opts[:device]
277
+ when :servo
278
+ servo_setup(num, opts)
279
+ return # don't use declarations, accessor, signatures below
280
+ when :pa_lcd || :pa_LCD
281
+ pa_lcd_setup(num, opts)
282
+ return
283
+ when :sf_lcd || :sf_LCD
284
+ sf_lcd_setup(num, opts)
285
+ return
286
+ when :freq_out || :freq_gen || :frequency_generator
287
+ frequency_timer(num, opts)
288
+ return
289
+ when :i2c
290
+ two_wire(num, opts) unless @@twowire_inc
291
+ return #
292
+ when :i2c_eeprom
293
+ two_wire(num, opts) unless @@twowire_inc
294
+ i2c_eeprom(num, opts)
295
+ return #
296
+ when :i2c_ds1307
297
+ two_wire(num, opts) unless @@twowire_inc
298
+ ds1307(num, opts)
299
+ return #
300
+ when :i2c_blinkm
301
+ two_wire(num, opts) unless @@twowire_inc
302
+ blinkm
303
+ return #
304
+ when :onewire
305
+ one_wire(num, opts)
306
+ return #
307
+ when :ethernet
308
+ ethernet(num, opts)
309
+ return #
310
+ else
311
+ 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]}"
312
+ end
313
+ end
314
+
315
+ # add state variables for outputs with :state => :on or :off -- useful for toggling a light with output_toggle -- need to make this more modular
316
+ if opts[:state]
317
+ # add debounce settings to dbce struct array
318
+ ArduinoPlugin.add_debounce_struct
319
+ @debounce_pins << num
320
+ state = opts[:latch] == :on ? 1 : 0
321
+ prev = opts[:latch] == :on ? 0 : 1
322
+ adjust = opts[:adjust] ? opts[:adjust] : 200
323
+ @debounce_settings << "dbce[#{num}].state = #{state}, dbce[#{num}].read = 0, dbce[#{num}].prev = #{prev}, dbce[#{num}].time = 0, dbce[#{num}].adjust = #{adjust}"
324
+ end
325
+
326
+ @declarations << "int _#{opts[ :as ]} = #{num};"
327
+
328
+ accessor = []
329
+ accessor << "int #{opts[ :as ]}() {"
330
+ accessor << "\treturn _#{opts[ :as ]};"
331
+ accessor << "}"
332
+ @accessors << accessor.join( "\n" )
333
+
334
+ @signatures << "int #{opts[ :as ]}();"
335
+ end
336
+ end
337
+
338
+
339
+ # Configure a single pin for input and setup a method to refer to that pin, i.e.:
340
+ #
341
+ # input_pin 3, :as => :button
342
+ #
343
+ # would configure pin 3 as an input and let you refer to it from the then on by calling
344
+ # the `button` method in your loop like so:
345
+ #
346
+ # def loop
347
+ # digital_write led if digital_read button
348
+ # end
349
+ #
350
+ def input_pin(num, opts={})
351
+ raise ArgumentError, "can only define pin from Fixnum, got #{num.class}" unless num.is_a?(Fixnum)
352
+ @pin_modes[:input] << num
353
+ if opts[:as]
354
+ # transitioning to :device => :button syntax
355
+ if opts[:latch] || opts[:device] == :button
356
+ if opts[:device] == :button
357
+ opts[:latch] ||= :off
358
+ end
359
+ # add debounce settings to dbce struct array
360
+ ArduinoPlugin.add_debounce_struct
361
+ @debounce_pins << num
362
+ state = opts[:latch] == :on ? 1 : 0
363
+ prev = opts[:latch] == :on ? 0 : 1
364
+ adjust = opts[:adjust] ? opts[:adjust] : 200
365
+ @debounce_settings << "dbce[#{num}].state = #{state}, dbce[#{num}].read = 0, dbce[#{num}].prev = #{prev}, dbce[#{num}].time = 0, dbce[#{num}].adjust = #{adjust}"
366
+ end
367
+ if opts[:device] == :sensor
368
+ ArduinoPlugin.add_sensor_struct
369
+ count = @hysteresis_pins.length
370
+ @hysteresis_pins << num
371
+ @hysteresis_settings << "hyst[#{count}].pin = #{num}, hyst[#{count}].state = 0"
372
+ end
373
+ if opts[:device] == :spectra
374
+ ArduinoPlugin.add_spectra_struct
375
+ count = @spectra_pins.length
376
+ @spectra_pins << num
377
+ @spectra_settings << "spec[#{count}].pin = #{num}, spec[#{count}].state = 10, spec[#{count}].r1 = 0, spec[#{count}].r2 = 0, spec[#{count}].r3 = 0"
378
+ end
379
+ @declarations << "int _#{opts[ :as ]} = #{num};"
380
+
381
+ accessor = []
382
+ accessor << "int #{opts[ :as ]}() {"
383
+ accessor << "\treturn _#{opts[ :as ]};"
384
+ accessor << "}"
385
+ @accessors << accessor.join( "\n" )
386
+
387
+ @signatures << "int #{opts[ :as ]}();"
388
+ end
389
+ @pullups << num if opts[:as]
390
+ end
391
+
392
+ # Like ArduinoSketch#input_pin but configure more than one input pin simultaneously. Takes an array of pin numbers.
393
+ def input_pins(nums)
394
+ ar = Array(nums)
395
+ ar.each {|n| input_pin(n)}
396
+ end
397
+
398
+ def add(st) #:nodoc:
399
+ @helper_methods << "\n#{st}\n"
400
+ end
401
+
402
+ # Configure Arduino for serial communication. Optionally, set the baud rate:
403
+ #
404
+ # serial_begin :rate => 2400
405
+ #
406
+ # default is 9600. See http://www.arduino.cc/en/Serial/Begin for more details.
407
+ #
408
+ def serial_begin(opts={})
409
+ rate = opts[:rate] ? opts[:rate] : 9600
410
+ @other_setup << "Serial.begin(#{rate});"
411
+ @@hwserial_inc = TRUE
412
+ end
413
+
414
+
415
+ def formatted_print(opts={})
416
+
417
+ buffer_size = opts[:buffer_size] ? opts[:buffer_size] : 64
418
+
419
+ if opts[:as]
420
+ @@sprintf_inc ||= FALSE
421
+ if @@sprintf_inc == FALSE
422
+ @@sprintf_inc = TRUE
423
+ accessor = []
424
+ accessor << "\n#undef int\n#include <stdio.h>"
425
+ accessor << "#define write_line(...) sprintf(#{opts[:as]},__VA_ARGS__);"
426
+ @accessors << accessor.join( "\n" )
427
+ array("char #{opts[:as]}[#{buffer_size}]")
428
+ end
429
+ end
430
+ end
431
+
432
+
433
+
434
+
435
+ def compose_setup #:nodoc: also composes headers and signatures
436
+
437
+ declarations = []
438
+ plugin_directives = []
439
+ signatures = []
440
+ external_vars = []
441
+ setup = []
442
+ additional_setup =[]
443
+ helpers = []
444
+ main = []
445
+ result = []
446
+
447
+ declarations << comment_box( "Auto-generated by RAD" )
448
+
449
+ declarations << "#include <WProgram.h>\n"
450
+ declarations << "#include <SoftwareSerial.h>\n"
451
+ $load_libraries.each { |lib| declarations << "#include <#{lib}.h>" } unless $load_libraries.nil?
452
+ $defines.each { |d| declarations << d }
453
+
454
+ plugin_directives << comment_box( 'plugin directives' )
455
+ $plugin_directives.each {|dir| plugin_directives << dir } unless $plugin_directives.nil? || $plugin_directives.empty?
456
+
457
+ signatures << comment_box( 'method signatures' )
458
+ signatures << "void loop();"
459
+ signatures << "void setup();"
460
+ signatures << "// sketch signatures"
461
+ @signatures.each {|sig| signatures << sig}
462
+ signatures << "// plugin signatures"
463
+ $plugin_signatures.each {|sig| signatures << sig } unless $plugin_signatures.nil? || $plugin_signatures.empty?
464
+ external_vars << "\n" + comment_box( "plugin external variables" )
465
+ $plugin_external_variables.each { |meth| external_vars << meth } unless $plugin_external_variables.nil? || $plugin_external_variables.empty?
466
+
467
+ signatures << "\n" + comment_box( "plugin structs" )
468
+ $plugin_structs.each { |k,v| signatures << v } unless $plugin_structs.nil? || $plugin_structs.empty?
469
+
470
+ external_vars << "\n" + comment_box( "sketch external variables" )
471
+
472
+ $external_vars.each {|v| external_vars << v }
473
+ external_vars << ""
474
+ external_vars << "// servo_settings array"
475
+
476
+ array_size = @servo_settings.empty? ? 1 : @servo_pins.max + 1 # conserve space if no variables needed
477
+ external_vars << "struct servo serv[#{array_size}] = { #{@servo_settings.join(", ")} };" if $plugin_structs[:servo]
478
+ external_vars << ""
479
+
480
+ external_vars << "// debounce array"
481
+ array_size = @debounce_settings.empty? ? 1 : @debounce_pins.max + 1 # conserve space if no variables needed
482
+ external_vars << "struct debounce dbce[#{array_size}] = { #{@debounce_settings.join(", ")} };" if $plugin_structs[:debounce]
483
+ external_vars << ""
484
+
485
+ external_vars << "// hysteresis array"
486
+ h_array_size = @hysteresis_settings.empty? ? 1 : @hysteresis_pins.length + 1 # conserve space if no variables needed
487
+ external_vars << "struct hysteresis hyst[#{h_array_size}] = { #{@hysteresis_settings.join(", ")} };" if $plugin_structs[:sensor]
488
+ external_vars << ""
489
+
490
+ external_vars << "// spectrasymbol soft pot array"
491
+ sp_array_size = @spectra_settings.empty? ? 1 : @spectra_pins.length + 1 # conserve space if no variables needed
492
+ external_vars << "struct spectra spec[#{sp_array_size}] = { #{@spectra_settings.join(", ")} };" if $plugin_structs[:spectra]
493
+ external_vars << ""
494
+
495
+ $external_array_vars.each { |var| external_vars << var } if $external_array_vars
496
+
497
+ external_vars << "\n" + comment_box( "variable and accessors" )
498
+ @declarations.each {|dec| external_vars << dec}
499
+ external_vars << ""
500
+ @accessors.each {|ac| external_vars << ac}
501
+
502
+ # fix naming
503
+ external_vars << "\n" + comment_box( "assembler declarations" )
504
+ unless @assembler_declarations.empty?
505
+ external_vars << <<-CODE
506
+ extern "C" {
507
+ #{@assembler_declarations.join("\n")}
508
+ }
509
+ CODE
510
+ end
511
+
512
+ external_vars << "\n" + comment_box( "setup" )
513
+ setup << "void setup() {"
514
+ setup << "\t// pin modes"
515
+
516
+ @pin_modes.each do |k,v|
517
+ v.each do |value|
518
+ setup << "\tpinMode(#{value}, #{k.to_s.upcase});"
519
+ end
520
+ end
521
+
522
+ @pullups.each do |pin|
523
+ setup << "\tdigitalWrite( #{pin}, HIGH ); // enable pull-up resistor for input"
524
+ end
525
+
526
+ unless $add_to_setup.nil? || $add_to_setup.empty?
527
+ setup << "\t// setup from plugins via add_to_setup method"
528
+ $add_to_setup.each {|item| setup << "\t#{item}"}
529
+ end
530
+
531
+ unless @other_setup.empty?
532
+ setup << "\t// other setup"
533
+ setup << @other_setup.join( "\n" )
534
+ end
535
+
536
+ additional_setup << "}\n"
537
+
538
+ helpers << comment_box( "helper methods" )
539
+ helpers << "\n// RAD built-in helpers"
540
+ helpers << @helper_methods.lstrip
541
+
542
+ helpers << "\n" + comment_box( "plugin methods" )
543
+ # need to add plugin name to this...
544
+ $plugin_methods.each { |meth| helpers << "#{meth[0][0]}\n" } unless $plugin_methods.nil? || $plugin_methods.empty?
545
+
546
+ if @@hwserial_inc == TRUE
547
+ helpers << "\n// serial helpers"
548
+ helpers << serial_boilerplate.lstrip
549
+ end
550
+
551
+ main << "\n" + comment_box( "main() function" )
552
+ main << "int main() {"
553
+ main << "\tinit();"
554
+ main << "\tsetup();"
555
+ main << "\tfor( ;; ) { loop(); }"
556
+ main << "\treturn 0;"
557
+ main << "}"
558
+
559
+ main << "\n" + comment_box( "loop! Autogenerated by RubyToC, sorry it's ugly." )
560
+
561
+ return [declarations, plugin_directives, signatures, external_vars, setup, additional_setup, helpers, main]
562
+
563
+ end
564
+
565
+
566
+ # 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
567
+ def assembler(name, signature, code)
568
+ @assembler_declarations << signature
569
+ assembler_code = <<-CODE
570
+ .file "#{name}.S"
571
+ .arch #{Makefile.hardware_params['mcu']}
572
+ .global __do_copy_data
573
+ .global __do_clear_bss
574
+ .text
575
+ .global #{name}
576
+ .type #{name}, @function
577
+ #{code}
578
+ CODE
579
+
580
+ File.open(File.expand_path("#{RAD_ROOT}") + "/#{PROJECT_DIR_NAME}/#{name}.S", "w"){|f| f << assembler_code}
581
+ end
582
+
583
+ def self.pre_process(sketch_string) #:nodoc:
584
+ result = sketch_string
585
+ # add external vars to each method (needed for better translation, will be removed in make:upload)
586
+ result.gsub!(/(^\s*def\s.\w*(\(.*\))?)/, '\1' + " \n #{$external_vars.join(" \n ")}" )
587
+ # gather method names
588
+ sketch_methods = result.scan(/^\s*def\s.\w*/)
589
+ sketch_methods.each {|m| $sketch_methods << m.gsub(/\s*def\s*/, "") }
590
+
591
+ result.gsub!("HIGH", "1")
592
+ result.gsub!("LOW", "0")
593
+ result.gsub!("ON", "1")
594
+ result.gsub!("OFF", "0")
595
+ result
596
+ end
597
+
598
+ def self.add_to_setup(meth)
599
+ meth = meth.gsub("setup", "additional_setup")
600
+ post_process_ruby_to_c_methods(meth)
601
+ end
602
+
603
+ def self.post_process_ruby_to_c_methods(e)
604
+ clean_c_methods = []
605
+ # need to take a look at the \(unsigned in the line below not sure if we are really trying to catch something like that
606
+ if e !~ /^\s*(#{C_VAR_TYPES})(\W{1,6}|\(unsigned\()(#{$external_var_identifiers.join("|")})/ || $external_var_identifiers.empty?
607
+ # use the list of identifers the external_vars method of the sketch and remove the parens the ruby2c sometime adds to variables
608
+ # keep an eye on the gsub!.. are we getting nil errors
609
+ # and more recently, the \b
610
+ e.gsub!(/\b((#{$external_var_identifiers.join("|")})\(\))/, '\2') unless $external_var_identifiers.empty?
611
+ clean_c_methods << e
612
+ end
613
+ return clean_c_methods.join( "\n" )
614
+ end
615
+
616
+
617
+ def comment_box( content ) #:nodoc:
618
+ out = []
619
+ out << "/" * 74
620
+ out << "// " + content
621
+ out << "/" * 74
622
+
623
+ return out.join( "\n" )
624
+ end
625
+
626
+
627
+ end