rubyduino 0.1.2 → 0.1.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 06e43dd1d4e9f5f4d9dbfda78f6954733999175a658f50b5d76186e6c51fc544
4
- data.tar.gz: 62a7ba189c79f9741001a6724af58026c7870aaa9da5775dcf54c824afcf53d3
3
+ metadata.gz: 1ec4285a969c2afed1449f750c1674b63f1ba5cb5b454994cfdb9356173595cb
4
+ data.tar.gz: 8e1dba9b348672d0aa96f4eb7645242da1e111fa36595c1f601ab9a1fa45acdf
5
5
  SHA512:
6
- metadata.gz: 9a83433f8069a0e13757f47666c6913307185d66f388eb014fa68bc54a9afd0117e4c7155bf2f8199ffa5a73c4e7de415096f8cdce2a0965f4679cd567cbf7a1
7
- data.tar.gz: deb4d7cc643e4d93c172a525677fb7944fbc6fb2bab93fe2b48f7893ca2e0886153879fedd42ee7bf06605e4dc0ac5413cb16c767bd59a0ede37cde188dbf0c4
6
+ metadata.gz: 736ec9d0f9c5665ba2f88f647c36d0dcd1010a3e4d405d1a49a6032d1eaefaa60aecbd64a2d9e103796f9bf7443a8163370dc5951fdcd14bb589938452cc5ca7
7
+ data.tar.gz: 203d97b5aed491505f46e681d04aa4128dce2349ac93513d8cf307f1b8e96ddeaaa31478788c5f9aa919a028fe276cbab1b10a6c54466b69cf7ee17f2a1abc35
data/CHANGELOG.md CHANGED
@@ -1,13 +1,19 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2026-05-08
3
+ ## [0.1.3] - 2026-05-08
4
4
 
5
- - Initial release
5
+ - Add the built-in `ArduinoUNO` prelude with FFI-backed GPIO, analog read, and millisecond delay bindings
6
+ - Replace the legacy `system("pin13:*")` sketch API with top-level helpers like `pin_mode`, `digital_write`, and `delay_ms`
7
+ - Update the default hello example to use the new ArduinoUNO API
8
+
9
+ ## [0.1.2] - 2026-05-08
10
+
11
+ - Update vendored Spinel revision
6
12
 
7
13
  ## [0.1.1] - 2026-05-08
8
14
 
9
15
  - Fix avrdude discovery for installed command
10
16
 
11
- ## [0.1.2] - 2026-05-08
17
+ ## [0.1.0] - 2026-05-08
12
18
 
13
- - Update vendored Spinel revision
19
+ - Initial release
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  <div align="center">
2
2
 
3
- # Rubyduino
3
+ # Rubyduino
4
+ [Experimental]
4
5
 
5
6
  <img width="250" height="250" alt="image copy" src="https://github.com/user-attachments/assets/156c7d41-ed42-43f3-a720-ed2e9c12b52c" />
6
7
 
@@ -15,14 +16,13 @@ Under the hood it uses [Spinel](https://github.com/matz/spinel), a Ruby AOT comp
15
16
  <img width="500" height="281" alt="IMG_0197" src="https://github.com/user-attachments/assets/d2b1cc69-647a-4f63-b090-31b13a21e5a8" />
16
17
 
17
18
  ```ruby
18
- system("pin13:output")
19
+ pin_mode(ArduinoUNO::LED_BUILTIN, ArduinoUNO::OUTPUT)
19
20
 
20
21
  loop do
21
- duration = 0.1
22
- system("pin13:high")
23
- sleep duration
24
- system("pin13:low")
25
- sleep duration
22
+ digital_write(ArduinoUNO::LED_BUILTIN, ArduinoUNO::HIGH)
23
+ delay_ms(100)
24
+ digital_write(ArduinoUNO::LED_BUILTIN, ArduinoUNO::LOW)
25
+ delay_ms(100)
26
26
  end
27
27
  ```
28
28
 
data/bin/rubyduino CHANGED
@@ -98,6 +98,7 @@ rubyduino_dir = File.join(root_dir, "lib/rubyduino")
98
98
  parse_bin = File.join(spinel_dir, "spinel_parse")
99
99
  codegen_rb = File.join(rubyduino_dir, "spinel_arduino_codegen.rb")
100
100
  entry_c = File.join(rubyduino_dir, "arduino_entry.c")
101
+ arduino_uno_rb = File.join(rubyduino_dir, "arduino_uno.rb")
101
102
 
102
103
  mcu = "atmega328p"
103
104
  f_cpu = "16000000UL"
@@ -137,6 +138,7 @@ abort "rubyduino: #{source}: No such file" unless File.file?(source)
137
138
  abort "rubyduino: missing Spinel checkout at #{spinel_dir}" unless Dir.exist?(spinel_dir)
138
139
  abort "rubyduino: missing #{codegen_rb}" unless File.file?(codegen_rb)
139
140
  abort "rubyduino: missing #{entry_c}" unless File.file?(entry_c)
141
+ abort "rubyduino: missing #{arduino_uno_rb}" unless File.file?(arduino_uno_rb)
140
142
  abort "rubyduino: avr-gcc not found" unless command?("avr-gcc")
141
143
  abort "rubyduino: avr-objcopy not found" unless command?("avr-objcopy")
142
144
 
@@ -164,9 +166,11 @@ avrdude = find_avrdude
164
166
  abort "rubyduino: avrdude not found" unless avrdude
165
167
 
166
168
  ast_tmp = File.join(Dir.tmpdir, "spinel_arduino_ast.#{$PROCESS_ID}.#{rand(1_000_000)}")
169
+ source_tmp = File.join(Dir.tmpdir, "rubyduino_source.#{$PROCESS_ID}.#{rand(1_000_000)}.rb")
167
170
  begin
168
171
  warn "Spinel: #{source} -> #{c_file}"
169
- run!(parse_bin, source, ast_tmp)
172
+ File.write(source_tmp, "#{File.read(arduino_uno_rb)}\n#{File.read(source)}")
173
+ run!(parse_bin, source_tmp, ast_tmp)
170
174
  run!(RbConfig.ruby, codegen_rb, ast_tmp, c_file)
171
175
 
172
176
  warn "AVR: #{c_file} -> #{hex_file}"
@@ -183,4 +187,5 @@ begin
183
187
  run!(avrdude, *conf_args, "-p#{mcu}", "-carduino", "-P#{port}", "-b#{baud}", "-D", "-Uflash:w:#{hex_file}:i")
184
188
  ensure
185
189
  FileUtils.rm_f(ast_tmp)
190
+ FileUtils.rm_f(source_tmp)
186
191
  end
data/examples/hello.rb CHANGED
@@ -1,9 +1,8 @@
1
- system("pin13:output")
1
+ pin_mode(ArduinoUNO::LED_BUILTIN, ArduinoUNO::OUTPUT)
2
2
 
3
3
  loop do
4
- duration = 0.1
5
- system("pin13:high")
6
- sleep duration
7
- system("pin13:low")
8
- sleep duration
4
+ digital_write(ArduinoUNO::LED_BUILTIN, ArduinoUNO::HIGH)
5
+ delay_ms(100)
6
+ digital_write(ArduinoUNO::LED_BUILTIN, ArduinoUNO::LOW)
7
+ delay_ms(100)
9
8
  end
@@ -0,0 +1,43 @@
1
+ module ArduinoUNO
2
+ LOW = 0
3
+ HIGH = 1
4
+
5
+ INPUT = 0
6
+ OUTPUT = 1
7
+ INPUT_PULLUP = 2
8
+
9
+ A0 = 14
10
+ A1 = 15
11
+ A2 = 16
12
+ A3 = 17
13
+ A4 = 18
14
+ A5 = 19
15
+
16
+ LED_BUILTIN = 13
17
+
18
+ ffi_func :pin_mode, [:uint8, :uint8], :int
19
+ ffi_func :digital_write, [:uint8, :uint8], :int
20
+ ffi_func :digital_read, [:uint8], :int
21
+ ffi_func :analog_read, [:uint8], :int
22
+ ffi_func :delay_ms, [:uint32], :void
23
+ end
24
+
25
+ def pin_mode(pin, mode)
26
+ ArduinoUNO.pin_mode(pin, mode)
27
+ end
28
+
29
+ def digital_write(pin, value)
30
+ ArduinoUNO.digital_write(pin, value)
31
+ end
32
+
33
+ def digital_read(pin)
34
+ ArduinoUNO.digital_read(pin)
35
+ end
36
+
37
+ def analog_read(pin)
38
+ ArduinoUNO.analog_read(pin)
39
+ end
40
+
41
+ def delay_ms(ms)
42
+ ArduinoUNO.delay_ms(ms)
43
+ end
@@ -3,6 +3,7 @@
3
3
 
4
4
  #include <stdint.h>
5
5
  #include <stdlib.h>
6
+ #include <string.h>
6
7
  #include <avr/io.h>
7
8
  #include <util/delay.h>
8
9
  #include <util/delay_basic.h>
@@ -46,6 +47,7 @@ static void sp_gc_mark(void *ptr) {
46
47
 
47
48
  typedef struct {
48
49
  mrb_int *data;
50
+ mrb_int start;
49
51
  mrb_int len;
50
52
  mrb_int cap;
51
53
  } sp_IntArray;
@@ -69,6 +71,7 @@ static sp_Range sp_range_new(mrb_int first, mrb_int last) {
69
71
 
70
72
  static sp_IntArray *sp_IntArray_new(void) {
71
73
  sp_IntArray *array = (sp_IntArray *)malloc(sizeof(sp_IntArray));
74
+ array->start = 0;
72
75
  array->len = 0;
73
76
  array->cap = 4;
74
77
  array->data = (mrb_int *)malloc(sizeof(mrb_int) * array->cap);
@@ -80,7 +83,7 @@ static void sp_IntArray_push(sp_IntArray *array, mrb_int value) {
80
83
  array->cap *= 2;
81
84
  array->data = (mrb_int *)realloc(array->data, sizeof(mrb_int) * array->cap);
82
85
  }
83
- array->data[array->len] = value;
86
+ array->data[array->start + array->len] = value;
84
87
  array->len++;
85
88
  }
86
89
 
@@ -89,7 +92,7 @@ static mrb_int sp_IntArray_length(sp_IntArray *array) {
89
92
  }
90
93
 
91
94
  static mrb_int sp_IntArray_get(sp_IntArray *array, mrb_int index) {
92
- return array->data[index];
95
+ return array->data[array->start + index];
93
96
  }
94
97
 
95
98
  static sp_FloatArray *sp_FloatArray_new(void) {
@@ -117,30 +120,140 @@ static mrb_float sp_FloatArray_get(sp_FloatArray *array, mrb_int index) {
117
120
  return array->data[index];
118
121
  }
119
122
 
120
- static int sp_streq(const char *a, const char *b) {
121
- while (*a && *b && *a == *b) {
122
- a++;
123
- b++;
123
+ static int rd_uno_valid_pin(uint8_t pin) {
124
+ return pin <= 19;
125
+ }
126
+
127
+ static volatile uint8_t *rd_uno_ddr(uint8_t pin) {
128
+ if (pin <= 7) {
129
+ return &DDRD;
124
130
  }
125
- return *a == *b;
131
+ if (pin <= 13) {
132
+ return &DDRB;
133
+ }
134
+ if (pin <= 19) {
135
+ return &DDRC;
136
+ }
137
+ return NULL;
126
138
  }
127
139
 
128
- static int sp_arduino_system(const char *cmd) {
129
- if (sp_streq(cmd, "pin13:output")) {
130
- DDRB |= _BV(DDB5);
140
+ static volatile uint8_t *rd_uno_port(uint8_t pin) {
141
+ if (pin <= 7) {
142
+ return &PORTD;
143
+ }
144
+ if (pin <= 13) {
145
+ return &PORTB;
146
+ }
147
+ if (pin <= 19) {
148
+ return &PORTC;
149
+ }
150
+ return NULL;
151
+ }
152
+
153
+ static volatile uint8_t *rd_uno_pin_reg(uint8_t pin) {
154
+ if (pin <= 7) {
155
+ return &PIND;
156
+ }
157
+ if (pin <= 13) {
158
+ return &PINB;
159
+ }
160
+ if (pin <= 19) {
161
+ return &PINC;
162
+ }
163
+ return NULL;
164
+ }
165
+
166
+ static uint8_t rd_uno_bit(uint8_t pin) {
167
+ if (pin <= 7) {
168
+ return pin;
169
+ }
170
+ if (pin <= 13) {
171
+ return pin - 8;
172
+ }
173
+ return pin - 14;
174
+ }
175
+
176
+ int pin_mode(uint8_t pin, uint8_t mode) {
177
+ volatile uint8_t *ddr = rd_uno_ddr(pin);
178
+ volatile uint8_t *port = rd_uno_port(pin);
179
+ uint8_t mask;
180
+
181
+ if (!ddr || !port) {
182
+ return 1;
183
+ }
184
+
185
+ mask = (uint8_t)(1 << rd_uno_bit(pin));
186
+
187
+ if (mode == 1) {
188
+ *ddr |= mask;
131
189
  return 0;
132
190
  }
133
- if (sp_streq(cmd, "pin13:high")) {
134
- PORTB |= _BV(PORTB5);
191
+
192
+ if (mode == 0) {
193
+ *ddr &= (uint8_t)~mask;
194
+ *port &= (uint8_t)~mask;
135
195
  return 0;
136
196
  }
137
- if (sp_streq(cmd, "pin13:low")) {
138
- PORTB &= (uint8_t)~_BV(PORTB5);
197
+
198
+ if (mode == 2) {
199
+ *ddr &= (uint8_t)~mask;
200
+ *port |= mask;
139
201
  return 0;
140
202
  }
203
+
141
204
  return 1;
142
205
  }
143
206
 
207
+ int digital_write(uint8_t pin, uint8_t value) {
208
+ volatile uint8_t *port = rd_uno_port(pin);
209
+ uint8_t mask;
210
+
211
+ if (!port) {
212
+ return 1;
213
+ }
214
+
215
+ mask = (uint8_t)(1 << rd_uno_bit(pin));
216
+
217
+ if (value) {
218
+ *port |= mask;
219
+ } else {
220
+ *port &= (uint8_t)~mask;
221
+ }
222
+
223
+ return 0;
224
+ }
225
+
226
+ int digital_read(uint8_t pin) {
227
+ volatile uint8_t *reg = rd_uno_pin_reg(pin);
228
+
229
+ if (!reg) {
230
+ return -1;
231
+ }
232
+
233
+ return ((*reg & (uint8_t)(1 << rd_uno_bit(pin))) != 0) ? 1 : 0;
234
+ }
235
+
236
+ int analog_read(uint8_t pin) {
237
+ uint8_t channel = pin;
238
+
239
+ if (pin >= 14 && pin <= 19) {
240
+ channel = pin - 14;
241
+ }
242
+
243
+ if (channel > 5 || !rd_uno_valid_pin(pin)) {
244
+ return -1;
245
+ }
246
+
247
+ ADMUX = (uint8_t)((1 << REFS0) | channel);
248
+ ADCSRA = (uint8_t)((1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0));
249
+ ADCSRA |= (uint8_t)(1 << ADSC);
250
+
251
+ while (ADCSRA & (uint8_t)(1 << ADSC)) {
252
+ }
253
+
254
+ return ADC;
255
+ }
256
+
144
257
  static void sp_arduino_delay_ms(unsigned long ms) {
145
258
  while (ms > 0) {
146
259
  _delay_loop_2((uint16_t)(F_CPU / 4000UL));
@@ -148,12 +261,10 @@ static void sp_arduino_delay_ms(unsigned long ms) {
148
261
  }
149
262
  }
150
263
 
151
- static void sp_arduino_sleep_seconds(double seconds) {
152
- sp_arduino_delay_ms((unsigned long)(seconds * 1000.0 + 0.5));
264
+ void delay_ms(uint32_t ms) {
265
+ sp_arduino_delay_ms(ms);
153
266
  }
154
267
 
155
- #define system(cmd) sp_arduino_system(cmd)
156
- #define sleep(seconds) sp_arduino_delay_ms((unsigned long)((seconds) * 1000.0 + 0.5))
157
268
  #define fflush(stream) ((void)0)
158
269
 
159
270
  #endif
@@ -26,9 +26,6 @@ load_spinel_compiler
26
26
  module SpinelArduinoCodegen
27
27
  def compile_no_recv_call_expr(nid, mname)
28
28
  case mname
29
- when "sleep"
30
- compile_arduino_sleep(nid)
31
- "0"
32
29
  when "rand"
33
30
  arduino_rand = compile_arduino_rand(nid)
34
31
  return arduino_rand if arduino_rand
@@ -41,21 +38,6 @@ module SpinelArduinoCodegen
41
38
 
42
39
  private
43
40
 
44
- def compile_arduino_sleep(nid)
45
- args_id = @nd_arguments[nid]
46
- return if args_id < 0
47
-
48
- arg_ids = get_args(args_id)
49
- return if arg_ids.empty?
50
-
51
- arg = arg_ids.first
52
- if numeric_literal_node?(arg)
53
- emit_arduino_delay_literal(numeric_literal_value(arg))
54
- else
55
- emit(" sp_arduino_sleep_seconds(" + compile_expr(arg) + ");")
56
- end
57
- end
58
-
59
41
  def compile_arduino_rand(nid)
60
42
  args_id = @nd_arguments[nid]
61
43
  return nil if args_id < 0
@@ -79,32 +61,9 @@ module SpinelArduinoCodegen
79
61
  "((mrb_int)(#{first} + (rand() % #{span})))"
80
62
  end
81
63
 
82
- def emit_arduino_delay_literal(seconds)
83
- ms = (seconds * 1000.0).round
84
- parts = []
85
- while ms >= 250
86
- parts << "_delay_ms(250.0)"
87
- ms -= 250
88
- end
89
- parts << "_delay_ms(#{ms}.0)" if ms > 0
90
- emit(" " + parts.join("; ") + ";") unless parts.empty?
91
- end
92
-
93
64
  def integer_literal_node?(nid)
94
65
  nid && nid >= 0 && @nd_type[nid] == "IntegerNode"
95
66
  end
96
-
97
- def numeric_literal_node?(nid)
98
- nid && nid >= 0 && %w[IntegerNode FloatNode].include?(@nd_type[nid])
99
- end
100
-
101
- def numeric_literal_value(nid)
102
- if @nd_type[nid] == "IntegerNode"
103
- @nd_value[nid].to_f
104
- else
105
- @nd_content[nid].to_f
106
- end
107
- end
108
67
  end
109
68
 
110
69
  Compiler.prepend(SpinelArduinoCodegen)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubyduino
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.3"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyduino
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joseph Schito
@@ -27,6 +27,7 @@ files:
27
27
  - examples/hello.rb
28
28
  - lib/rubyduino.rb
29
29
  - lib/rubyduino/arduino_entry.c
30
+ - lib/rubyduino/arduino_uno.rb
30
31
  - lib/rubyduino/sp_runtime.h
31
32
  - lib/rubyduino/spinel.rb
32
33
  - lib/rubyduino/spinel_arduino_codegen.rb