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.
- data/History.txt +104 -0
- data/License.txt +282 -0
- data/Manifest.txt +142 -0
- data/README.rdoc +55 -0
- data/Rakefile +142 -0
- data/bin/hello_world_test/Makefile +436 -0
- data/bin/hello_world_test/hello_world.cpp +23 -0
- data/bin/rad +302 -0
- data/lib/examples/add_hysteresis.rb +13 -0
- data/lib/examples/basic_blink.rb +10 -0
- data/lib/examples/blink_m_address_assignment.rb +104 -0
- data/lib/examples/blink_m_hello.rb +14 -0
- data/lib/examples/blink_m_multi.rb +61 -0
- data/lib/examples/blink_with_serial.rb +16 -0
- data/lib/examples/configure_pa_lcd_boot.rb +91 -0
- data/lib/examples/debounce_methods.rb +49 -0
- data/lib/examples/external_variable_fu.rb +26 -0
- data/lib/examples/external_variables.rb +32 -0
- data/lib/examples/first_sound.rb +23 -0
- data/lib/examples/frequency_generator.rb +30 -0
- data/lib/examples/hello_array.rb +48 -0
- data/lib/examples/hello_array2.rb +79 -0
- data/lib/examples/hello_array_eeprom.rb +59 -0
- data/lib/examples/hello_clock.rb +84 -0
- data/lib/examples/hello_eeprom.rb +51 -0
- data/lib/examples/hello_eeprom_lcdpa.rb +81 -0
- data/lib/examples/hello_format_print.rb +94 -0
- data/lib/examples/hello_lcd_charset.rb +75 -0
- data/lib/examples/hello_pa_lcd.rb +59 -0
- data/lib/examples/hello_servos.rb +88 -0
- data/lib/examples/hello_spectra_sound.rb +38 -0
- data/lib/examples/hello_world.rb +11 -0
- data/lib/examples/hello_xbee.rb +12 -0
- data/lib/examples/hysteresis_duel.rb +39 -0
- data/lib/examples/i2c_with_clock_chip.rb +124 -0
- data/lib/examples/midi_beat_box.rb +86 -0
- data/lib/examples/midi_scales.rb +94 -0
- data/lib/examples/motor_knob.rb +30 -0
- data/lib/examples/servo_buttons.rb +23 -0
- data/lib/examples/servo_calibrate_continuous.rb +92 -0
- data/lib/examples/servo_throttle.rb +40 -0
- data/lib/examples/software_serial.rb +10 -0
- data/lib/examples/sparkfun_lcd.rb +48 -0
- data/lib/examples/spectra_soft_pot.rb +34 -0
- data/lib/examples/times_method.rb +8 -0
- data/lib/examples/toggle.rb +10 -0
- data/lib/examples/twitter.rb +57 -0
- data/lib/examples/two_wire.rb +14 -0
- data/lib/libraries/AFSoftSerial/AFSoftSerial.cpp +321 -0
- data/lib/libraries/AFSoftSerial/AFSoftSerial.h +61 -0
- data/lib/libraries/AFSoftSerial/keywords.txt +18 -0
- data/lib/libraries/AF_XPort/AF_XPort.cpp +166 -0
- data/lib/libraries/AF_XPort/AF_XPort.h +48 -0
- data/lib/libraries/DS1307/DS1307.cpp +162 -0
- data/lib/libraries/DS1307/DS1307.h +66 -0
- data/lib/libraries/DS1307/keywords.txt +18 -0
- data/lib/libraries/FrequencyTimer2/FrequencyTimer2.cpp +144 -0
- data/lib/libraries/FrequencyTimer2/FrequencyTimer2.h +42 -0
- data/lib/libraries/FrequencyTimer2/keywords.txt +22 -0
- data/lib/libraries/I2CEEPROM/I2CEEPROM.cpp +120 -0
- data/lib/libraries/I2CEEPROM/I2CEEPROM.h +70 -0
- data/lib/libraries/I2CEEPROM/keywords.txt +21 -0
- data/lib/libraries/LoopTimer/LoopTimer.cpp +35 -0
- data/lib/libraries/LoopTimer/LoopTimer.h +34 -0
- data/lib/libraries/LoopTimer/keywords.txt +27 -0
- data/lib/libraries/OneWire/OneWire.cpp +194 -0
- data/lib/libraries/OneWire/OneWire.h +63 -0
- data/lib/libraries/OneWire/keywords.txt +35 -0
- data/lib/libraries/OneWire/readme.txt +13 -0
- data/lib/libraries/SWSerLCDpa/SWSerLCDpa.cpp +296 -0
- data/lib/libraries/SWSerLCDpa/SWSerLCDpa.h +69 -0
- data/lib/libraries/SWSerLCDsf/SWSerLCDsf.cpp +311 -0
- data/lib/libraries/SWSerLCDsf/SWSerLCDsf.h +67 -0
- data/lib/libraries/Servo/Servo.cpp +192 -0
- data/lib/libraries/Servo/Servo.h +61 -0
- data/lib/libraries/Stepper/Stepper.cpp +220 -0
- data/lib/libraries/Stepper/Stepper.h +86 -0
- data/lib/libraries/Stepper/keywords.txt +28 -0
- data/lib/libraries/Wire/Wire.cpp +262 -0
- data/lib/libraries/Wire/Wire.h +67 -0
- data/lib/libraries/Wire/keywords.txt +31 -0
- data/lib/libraries/Wire/twi.h +57 -0
- data/lib/libraries/Wire/utility/twi.c +449 -0
- data/lib/libraries/Wire/utility/twi.h +57 -0
- data/lib/plugins/bitwise_ops.rb +54 -0
- data/lib/plugins/blink.rb +25 -0
- data/lib/plugins/blink_m.rb +356 -0
- data/lib/plugins/debounce.rb +138 -0
- data/lib/plugins/debug_output_to_lcd.rb +71 -0
- data/lib/plugins/hysteresis.rb +52 -0
- data/lib/plugins/input_output_state.rb +84 -0
- data/lib/plugins/lcd_padding.rb +58 -0
- data/lib/plugins/mem_test.rb +37 -0
- data/lib/plugins/midi.rb +60 -0
- data/lib/plugins/parallax_ping.rb +50 -0
- data/lib/plugins/servo_pulse.rb +31 -0
- data/lib/plugins/servo_setup.rb +86 -0
- data/lib/plugins/smoother.rb +54 -0
- data/lib/plugins/spark_fun_serial_lcd.rb +100 -0
- data/lib/plugins/spectra_symbol.rb +79 -0
- data/lib/plugins/twitter_connect.rb +145 -0
- data/lib/rad.rb +5 -0
- data/lib/rad/README.rdoc +5 -0
- data/lib/rad/arduino_plugin.rb +246 -0
- data/lib/rad/arduino_sketch.rb +627 -0
- data/lib/rad/generators/makefile/makefile.erb +243 -0
- data/lib/rad/generators/makefile/makefile.rb +38 -0
- data/lib/rad/hardware_library.rb +813 -0
- data/lib/rad/init.rb +14 -0
- data/lib/rad/progressbar.rb +236 -0
- data/lib/rad/rad_processor.rb +128 -0
- data/lib/rad/rad_rewriter.rb +94 -0
- data/lib/rad/rad_type_checker.rb +26 -0
- data/lib/rad/sim/arduino_sketch.rb +57 -0
- data/lib/rad/sketch_compiler.rb +47 -0
- data/lib/rad/tasks/build_and_make.rake +210 -0
- data/lib/rad/tasks/rad.rb +2 -0
- data/lib/rad/todo.txt +13 -0
- data/lib/rad/variable_processing.rb +153 -0
- data/lib/rad/version.rb +9 -0
- data/scripts/txt2html +67 -0
- data/setup.rb +1585 -0
- data/spec/examples/hello_world.rb +11 -0
- data/spec/examples/serial_motor.rb +12 -0
- data/spec/models/arduino_sketch_spec.rb +82 -0
- data/spec/models/sketch_compiler_spec.rb +96 -0
- data/spec/models/spec_helper.rb +2 -0
- data/spec/sim/hello_world_spec.rb +42 -0
- data/spec/spec.opts +1 -0
- data/test/test_array_processing.rb +179 -0
- data/test/test_plugin_loading.rb +151 -0
- data/test/test_translation_post_processing.rb +185 -0
- data/test/test_variable_processing.rb +238 -0
- data/website/examples/assembler_test.rb.html +73 -0
- data/website/examples/gps_reader.rb.html +39 -0
- data/website/examples/hello_world.rb.html +38 -0
- data/website/examples/serial_motor.rb.html +41 -0
- data/website/index.html +178 -0
- data/website/index.txt +64 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +169 -0
- data/website/template.rhtml +48 -0
- 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
data/lib/rad/README.rdoc
ADDED
|
@@ -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
|