rubyduino 0.1.3 → 0.2.0

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: 1ec4285a969c2afed1449f750c1674b63f1ba5cb5b454994cfdb9356173595cb
4
- data.tar.gz: 8e1dba9b348672d0aa96f4eb7645242da1e111fa36595c1f601ab9a1fa45acdf
3
+ metadata.gz: bac10de4fac724a35791684086ec7ac0ab440f2e3272e75d665f58a1b0d94f8d
4
+ data.tar.gz: f0c542257835047dda8edcfdd6d1c1480c27b1f2dd596f3e9e0f32303df06c81
5
5
  SHA512:
6
- metadata.gz: 736ec9d0f9c5665ba2f88f647c36d0dcd1010a3e4d405d1a49a6032d1eaefaa60aecbd64a2d9e103796f9bf7443a8163370dc5951fdcd14bb589938452cc5ca7
7
- data.tar.gz: 203d97b5aed491505f46e681d04aa4128dce2349ac93513d8cf307f1b8e96ddeaaa31478788c5f9aa919a028fe276cbab1b10a6c54466b69cf7ee17f2a1abc35
6
+ metadata.gz: c544a3120274e0a8dc7cd53d24438c17fe4a72e6abab2c35d6130b0d1568e4f0d95d40490415fbd0a60303a89a25d9334b4f3e5f8e510b07f1046cce0193a3ac
7
+ data.tar.gz: 5ffcf8876947fa43e4d7cc9a15b6329df635230b9f397ed807cf58466e0d142e5c2ab2aa1fa1490914e848f5fc5db2e0f9d1cec54f72bd3b2468cf3b6bd636f6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.2.0] - 2026-05-08
4
+
5
+ - Expand the ArduinoUNO API with PWM, microsecond delays, millis/micros timing, pulse measurement, serial I/O, shift helpers, and interrupt control
6
+ - Add special code generation for `serial_print` and `serial_println` so string and integer values map to the correct runtime functions
7
+ - Add an HC-SR04 ultrasonic distance sensor example
8
+
3
9
  ## [0.1.3] - 2026-05-08
4
10
 
5
11
  - Add the built-in `ArduinoUNO` prelude with FFI-backed GPIO, analog read, and millisecond delay bindings
@@ -0,0 +1,39 @@
1
+ trig_pin = 9
2
+ echo_pin = 10
3
+ led_pin = 13
4
+
5
+ pin_mode(trig_pin, ArduinoUNO::OUTPUT)
6
+ pin_mode(echo_pin, ArduinoUNO::INPUT)
7
+ pin_mode(led_pin, ArduinoUNO::OUTPUT)
8
+
9
+ serial_begin(9600)
10
+
11
+ loop do
12
+ digital_write(trig_pin, ArduinoUNO::LOW)
13
+ delay_us(2)
14
+
15
+ digital_write(trig_pin, ArduinoUNO::HIGH)
16
+ delay_us(10)
17
+ digital_write(trig_pin, ArduinoUNO::LOW)
18
+
19
+ duration = pulse_in(echo_pin, ArduinoUNO::HIGH)
20
+ distance = duration * 34 / 2000
21
+
22
+ serial_print("Distance: ")
23
+ serial_print(distance)
24
+ serial_println(" cm")
25
+
26
+ blink_delay = 700
27
+
28
+ if distance < 10
29
+ blink_delay = 100
30
+ elsif distance < 30
31
+ blink_delay = 300
32
+ end
33
+
34
+ digital_write(led_pin, ArduinoUNO::HIGH)
35
+ delay_ms(blink_delay)
36
+
37
+ digital_write(led_pin, ArduinoUNO::LOW)
38
+ delay_ms(blink_delay)
39
+ end
@@ -14,12 +14,32 @@ module ArduinoUNO
14
14
  A5 = 19
15
15
 
16
16
  LED_BUILTIN = 13
17
+ LSBFIRST = 0
18
+ MSBFIRST = 1
17
19
 
18
20
  ffi_func :pin_mode, [:uint8, :uint8], :int
19
21
  ffi_func :digital_write, [:uint8, :uint8], :int
20
22
  ffi_func :digital_read, [:uint8], :int
21
23
  ffi_func :analog_read, [:uint8], :int
24
+ ffi_func :analog_write, [:uint8, :uint8], :int
22
25
  ffi_func :delay_ms, [:uint32], :void
26
+ ffi_func :delay_us, [:uint32], :void
27
+ ffi_func :millis, [], :uint32
28
+ ffi_func :micros, [], :uint32
29
+ ffi_func :pulse_in, [:uint8, :uint8], :uint32
30
+ ffi_func :pulse_in_timeout, [:uint8, :uint8, :uint32], :uint32
31
+ ffi_func :serial_begin, [:uint32], :void
32
+ ffi_func :serial_available, [], :int
33
+ ffi_func :serial_read, [], :int
34
+ ffi_func :serial_write, [:uint8], :void
35
+ ffi_func :serial_print_str, [:str], :void
36
+ ffi_func :serial_print_int, [:int], :void
37
+ ffi_func :serial_println_str, [:str], :void
38
+ ffi_func :serial_println_int, [:int], :void
39
+ ffi_func :shift_in, [:uint8, :uint8, :uint8], :uint8
40
+ ffi_func :shift_out, [:uint8, :uint8, :uint8, :uint8], :void
41
+ ffi_func :interrupts, [], :void
42
+ ffi_func :no_interrupts, [], :void
23
43
  end
24
44
 
25
45
  def pin_mode(pin, mode)
@@ -38,6 +58,62 @@ def analog_read(pin)
38
58
  ArduinoUNO.analog_read(pin)
39
59
  end
40
60
 
61
+ def analog_write(pin, value)
62
+ ArduinoUNO.analog_write(pin, value)
63
+ end
64
+
41
65
  def delay_ms(ms)
42
66
  ArduinoUNO.delay_ms(ms)
43
67
  end
68
+
69
+ def delay_us(us)
70
+ ArduinoUNO.delay_us(us)
71
+ end
72
+
73
+ def millis
74
+ ArduinoUNO.millis
75
+ end
76
+
77
+ def micros
78
+ ArduinoUNO.micros
79
+ end
80
+
81
+ def pulse_in(pin, value)
82
+ ArduinoUNO.pulse_in(pin, value)
83
+ end
84
+
85
+ def pulse_in_timeout(pin, value, timeout_us)
86
+ ArduinoUNO.pulse_in_timeout(pin, value, timeout_us)
87
+ end
88
+
89
+ def serial_begin(baud)
90
+ ArduinoUNO.serial_begin(baud)
91
+ end
92
+
93
+ def serial_available
94
+ ArduinoUNO.serial_available
95
+ end
96
+
97
+ def serial_read
98
+ ArduinoUNO.serial_read
99
+ end
100
+
101
+ def serial_write(value)
102
+ ArduinoUNO.serial_write(value)
103
+ end
104
+
105
+ def shift_in(data_pin, clock_pin, bit_order)
106
+ ArduinoUNO.shift_in(data_pin, clock_pin, bit_order)
107
+ end
108
+
109
+ def shift_out(data_pin, clock_pin, bit_order, value)
110
+ ArduinoUNO.shift_out(data_pin, clock_pin, bit_order, value)
111
+ end
112
+
113
+ def interrupts
114
+ ArduinoUNO.interrupts
115
+ end
116
+
117
+ def no_interrupts
118
+ ArduinoUNO.no_interrupts
119
+ end
@@ -4,6 +4,7 @@
4
4
  #include <stdint.h>
5
5
  #include <stdlib.h>
6
6
  #include <string.h>
7
+ #include <avr/interrupt.h>
7
8
  #include <avr/io.h>
8
9
  #include <util/delay.h>
9
10
  #include <util/delay_basic.h>
@@ -45,6 +46,23 @@ static void sp_gc_mark(void *ptr) {
45
46
  (void)ptr;
46
47
  }
47
48
 
49
+ static inline mrb_int sp_idiv(mrb_int a, mrb_int b) {
50
+ mrb_int q;
51
+ mrb_int r;
52
+
53
+ if (b == 0) {
54
+ return 0;
55
+ }
56
+
57
+ q = a / b;
58
+ r = a % b;
59
+ if ((r != 0) && ((r ^ b) < 0)) {
60
+ q--;
61
+ }
62
+
63
+ return q;
64
+ }
65
+
48
66
  typedef struct {
49
67
  mrb_int *data;
50
68
  mrb_int start;
@@ -120,6 +138,25 @@ static mrb_float sp_FloatArray_get(sp_FloatArray *array, mrb_int index) {
120
138
  return array->data[index];
121
139
  }
122
140
 
141
+ static volatile uint32_t rd_uno_timer0_overflows = 0;
142
+ static uint8_t rd_uno_timer0_ready = 0;
143
+
144
+ ISR(TIMER0_OVF_vect) {
145
+ rd_uno_timer0_overflows++;
146
+ }
147
+
148
+ static void rd_uno_timer0_init(void) {
149
+ if (rd_uno_timer0_ready) {
150
+ return;
151
+ }
152
+
153
+ TCCR0A |= (uint8_t)((1 << WGM00) | (1 << WGM01));
154
+ TCCR0B = (uint8_t)((TCCR0B & (uint8_t)~((1 << CS02) | (1 << CS01) | (1 << CS00))) | (1 << CS01) | (1 << CS00));
155
+ TIMSK0 |= (uint8_t)(1 << TOIE0);
156
+ rd_uno_timer0_ready = 1;
157
+ sei();
158
+ }
159
+
123
160
  static int rd_uno_valid_pin(uint8_t pin) {
124
161
  return pin <= 19;
125
162
  }
@@ -254,6 +291,60 @@ int analog_read(uint8_t pin) {
254
291
  return ADC;
255
292
  }
256
293
 
294
+ int analog_write(uint8_t pin, uint8_t value) {
295
+ if (!rd_uno_valid_pin(pin)) {
296
+ return 1;
297
+ }
298
+
299
+ pin_mode(pin, 1);
300
+
301
+ if (value == 0) {
302
+ return digital_write(pin, 0);
303
+ }
304
+ if (value == 255) {
305
+ return digital_write(pin, 1);
306
+ }
307
+
308
+ if (pin == 5) {
309
+ rd_uno_timer0_init();
310
+ TCCR0A |= (uint8_t)(1 << COM0B1);
311
+ OCR0B = value;
312
+ return 0;
313
+ }
314
+ if (pin == 6) {
315
+ rd_uno_timer0_init();
316
+ TCCR0A |= (uint8_t)(1 << COM0A1);
317
+ OCR0A = value;
318
+ return 0;
319
+ }
320
+ if (pin == 9) {
321
+ TCCR1A |= (uint8_t)((1 << WGM10) | (1 << COM1A1));
322
+ TCCR1B = (uint8_t)((TCCR1B & (uint8_t)~((1 << CS12) | (1 << CS11) | (1 << CS10) | (1 << WGM13))) | (1 << WGM12) | (1 << CS11) | (1 << CS10));
323
+ OCR1A = value;
324
+ return 0;
325
+ }
326
+ if (pin == 10) {
327
+ TCCR1A |= (uint8_t)((1 << WGM10) | (1 << COM1B1));
328
+ TCCR1B = (uint8_t)((TCCR1B & (uint8_t)~((1 << CS12) | (1 << CS11) | (1 << CS10) | (1 << WGM13))) | (1 << WGM12) | (1 << CS11) | (1 << CS10));
329
+ OCR1B = value;
330
+ return 0;
331
+ }
332
+ if (pin == 3) {
333
+ TCCR2A |= (uint8_t)((1 << WGM20) | (1 << WGM21) | (1 << COM2B1));
334
+ TCCR2B = (uint8_t)((TCCR2B & (uint8_t)~((1 << CS22) | (1 << CS21) | (1 << CS20))) | (1 << CS22));
335
+ OCR2B = value;
336
+ return 0;
337
+ }
338
+ if (pin == 11) {
339
+ TCCR2A |= (uint8_t)((1 << WGM20) | (1 << WGM21) | (1 << COM2A1));
340
+ TCCR2B = (uint8_t)((TCCR2B & (uint8_t)~((1 << CS22) | (1 << CS21) | (1 << CS20))) | (1 << CS22));
341
+ OCR2A = value;
342
+ return 0;
343
+ }
344
+
345
+ return digital_write(pin, value < 128 ? 0 : 1);
346
+ }
347
+
257
348
  static void sp_arduino_delay_ms(unsigned long ms) {
258
349
  while (ms > 0) {
259
350
  _delay_loop_2((uint16_t)(F_CPU / 4000UL));
@@ -265,6 +356,193 @@ void delay_ms(uint32_t ms) {
265
356
  sp_arduino_delay_ms(ms);
266
357
  }
267
358
 
359
+ void delay_us(uint32_t us) {
360
+ while (us > 0) {
361
+ _delay_us(1.0);
362
+ us--;
363
+ }
364
+ }
365
+
366
+ uint32_t micros(void) {
367
+ uint32_t overflows;
368
+ uint8_t counter;
369
+ uint8_t flags;
370
+ uint8_t sreg;
371
+
372
+ rd_uno_timer0_init();
373
+
374
+ sreg = SREG;
375
+ cli();
376
+ overflows = rd_uno_timer0_overflows;
377
+ counter = TCNT0;
378
+ flags = TIFR0;
379
+ if ((flags & (uint8_t)(1 << TOV0)) && counter < 255) {
380
+ overflows++;
381
+ }
382
+ SREG = sreg;
383
+
384
+ return ((overflows << 8) + counter) * (uint32_t)(64UL / (F_CPU / 1000000UL));
385
+ }
386
+
387
+ uint32_t millis(void) {
388
+ return micros() / 1000UL;
389
+ }
390
+
391
+ uint32_t pulse_in_timeout(uint8_t pin, uint8_t value, uint32_t timeout_us) {
392
+ uint32_t start;
393
+ uint32_t pulse_start;
394
+ uint32_t width;
395
+
396
+ if (!rd_uno_valid_pin(pin)) {
397
+ return 0;
398
+ }
399
+
400
+ value = value ? 1 : 0;
401
+ start = micros();
402
+
403
+ while (digital_read(pin) == value) {
404
+ if ((micros() - start) >= timeout_us) {
405
+ return 0;
406
+ }
407
+ }
408
+
409
+ while (digital_read(pin) != value) {
410
+ if ((micros() - start) >= timeout_us) {
411
+ return 0;
412
+ }
413
+ }
414
+
415
+ pulse_start = micros();
416
+
417
+ while (digital_read(pin) == value) {
418
+ width = micros() - pulse_start;
419
+ if ((micros() - start) >= timeout_us) {
420
+ return 0;
421
+ }
422
+ }
423
+
424
+ return micros() - pulse_start;
425
+ }
426
+
427
+ uint32_t pulse_in(uint8_t pin, uint8_t value) {
428
+ return pulse_in_timeout(pin, value, 1000000UL);
429
+ }
430
+
431
+ void serial_begin(uint32_t baud) {
432
+ uint16_t ubrr;
433
+
434
+ if (baud == 0) {
435
+ return;
436
+ }
437
+
438
+ ubrr = (uint16_t)((F_CPU / 16UL / baud) - 1UL);
439
+ UBRR0H = (uint8_t)(ubrr >> 8);
440
+ UBRR0L = (uint8_t)ubrr;
441
+ UCSR0A = 0;
442
+ UCSR0B = (uint8_t)((1 << RXEN0) | (1 << TXEN0));
443
+ UCSR0C = (uint8_t)((1 << UCSZ01) | (1 << UCSZ00));
444
+ }
445
+
446
+ int serial_available(void) {
447
+ return (UCSR0A & (uint8_t)(1 << RXC0)) ? 1 : 0;
448
+ }
449
+
450
+ int serial_read(void) {
451
+ if (!serial_available()) {
452
+ return -1;
453
+ }
454
+ return UDR0;
455
+ }
456
+
457
+ void serial_write(uint8_t value) {
458
+ while (!(UCSR0A & (uint8_t)(1 << UDRE0))) {
459
+ }
460
+ UDR0 = value;
461
+ }
462
+
463
+ void serial_print_str(const char *value) {
464
+ while (*value) {
465
+ serial_write((uint8_t)*value);
466
+ value++;
467
+ }
468
+ }
469
+
470
+ void serial_print_int(int value) {
471
+ char buf[12];
472
+ char *p = &buf[11];
473
+ unsigned int n;
474
+
475
+ *p = '\0';
476
+ if (value < 0) {
477
+ serial_write((uint8_t)'-');
478
+ n = (unsigned int)(-value);
479
+ } else {
480
+ n = (unsigned int)value;
481
+ }
482
+
483
+ do {
484
+ p--;
485
+ *p = (char)('0' + (n % 10));
486
+ n /= 10;
487
+ } while (n > 0);
488
+
489
+ serial_print_str(p);
490
+ }
491
+
492
+ void serial_println_str(const char *value) {
493
+ serial_print_str(value);
494
+ serial_write((uint8_t)'\r');
495
+ serial_write((uint8_t)'\n');
496
+ }
497
+
498
+ void serial_println_int(int value) {
499
+ serial_print_int(value);
500
+ serial_write((uint8_t)'\r');
501
+ serial_write((uint8_t)'\n');
502
+ }
503
+
504
+ uint8_t shift_in(uint8_t data_pin, uint8_t clock_pin, uint8_t bit_order) {
505
+ uint8_t value = 0;
506
+ uint8_t i;
507
+
508
+ for (i = 0; i < 8; i++) {
509
+ digital_write(clock_pin, 1);
510
+ if (bit_order == 0) {
511
+ value |= (uint8_t)(digital_read(data_pin) << i);
512
+ } else {
513
+ value |= (uint8_t)(digital_read(data_pin) << (7 - i));
514
+ }
515
+ digital_write(clock_pin, 0);
516
+ }
517
+
518
+ return value;
519
+ }
520
+
521
+ void shift_out(uint8_t data_pin, uint8_t clock_pin, uint8_t bit_order, uint8_t value) {
522
+ uint8_t i;
523
+ uint8_t bit;
524
+
525
+ for (i = 0; i < 8; i++) {
526
+ if (bit_order == 0) {
527
+ bit = (uint8_t)((value >> i) & 1);
528
+ } else {
529
+ bit = (uint8_t)((value >> (7 - i)) & 1);
530
+ }
531
+
532
+ digital_write(data_pin, bit);
533
+ digital_write(clock_pin, 1);
534
+ digital_write(clock_pin, 0);
535
+ }
536
+ }
537
+
538
+ void interrupts(void) {
539
+ sei();
540
+ }
541
+
542
+ void no_interrupts(void) {
543
+ cli();
544
+ }
545
+
268
546
  #define fflush(stream) ((void)0)
269
547
 
270
548
  #endif
@@ -30,6 +30,16 @@ module SpinelArduinoCodegen
30
30
  arduino_rand = compile_arduino_rand(nid)
31
31
  return arduino_rand if arduino_rand
32
32
 
33
+ super
34
+ when "serial_print"
35
+ arduino_serial_print = compile_arduino_serial_print(nid, false)
36
+ return arduino_serial_print if arduino_serial_print
37
+
38
+ super
39
+ when "serial_println"
40
+ arduino_serial_print = compile_arduino_serial_print(nid, true)
41
+ return arduino_serial_print if arduino_serial_print
42
+
33
43
  super
34
44
  else
35
45
  super
@@ -38,6 +48,26 @@ module SpinelArduinoCodegen
38
48
 
39
49
  private
40
50
 
51
+ def compile_arduino_serial_print(nid, newline)
52
+ args_id = @nd_arguments[nid]
53
+ return nil if args_id < 0
54
+
55
+ arg_ids = get_args(args_id)
56
+ return nil unless arg_ids.length == 1
57
+
58
+ arg = arg_ids.first
59
+ fn = arduino_serial_print_func(arg, newline)
60
+ "(" + fn + "(" + compile_expr(arg) + "), (mrb_int)0)"
61
+ end
62
+
63
+ def arduino_serial_print_func(arg, newline)
64
+ if infer_type(arg) == "string"
65
+ return newline ? "serial_println_str" : "serial_print_str"
66
+ end
67
+
68
+ newline ? "serial_println_int" : "serial_print_int"
69
+ end
70
+
41
71
  def compile_arduino_rand(nid)
42
72
  args_id = @nd_arguments[nid]
43
73
  return nil if args_id < 0
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubyduino
4
- VERSION = "0.1.3"
4
+ VERSION = "0.2.0"
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.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joseph Schito
@@ -24,6 +24,7 @@ files:
24
24
  - README.md
25
25
  - Rakefile
26
26
  - bin/rubyduino
27
+ - examples/hc_sr04.rb
27
28
  - examples/hello.rb
28
29
  - lib/rubyduino.rb
29
30
  - lib/rubyduino/arduino_entry.c