lgpio 0.1.6 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/examples/{i2c_bitbang_search.rb → i2c_bb_search.rb} +2 -3
  3. data/examples/pwm_hw_bench.rb +20 -0
  4. data/examples/{spi_bitbang_ssd1306_bench.rb → spi_bb_ssd1306_bench.rb} +1 -1
  5. data/ext/lgpio/lgpio.c +123 -290
  6. data/lgpio.gemspec +2 -2
  7. data/lib/lgpio/spi_bitbang.rb +4 -0
  8. data/lib/lgpio/version.rb +1 -1
  9. metadata +28 -29
  10. data/examples/i2c_bitbang_aht10.rb +0 -40
  11. data/examples/i2c_bitbang_ssd1306_bench.rb +0 -35
  12. /data/examples/{bench_in.rb → gpio_bench_in.rb} +0 -0
  13. /data/examples/{bench_out.rb → gpio_bench_out.rb} +0 -0
  14. /data/examples/{blink.rb → gpio_blink.rb} +0 -0
  15. /data/examples/{group_in.rb → gpio_group_in.rb} +0 -0
  16. /data/examples/{group_out.rb → gpio_group_out.rb} +0 -0
  17. /data/examples/{momentary.rb → gpio_momentary.rb} +0 -0
  18. /data/examples/{reports.rb → gpio_reports.rb} +0 -0
  19. /data/examples/{rotary_encoder.rb → gpio_rotary_encoder.rb} +0 -0
  20. /data/examples/{rotary_encoder_led.rb → gpio_rotary_encoder_led.rb} +0 -0
  21. /data/examples/{wave.rb → gpio_wave.rb} +0 -0
  22. /data/examples/{i2c_bitbang-rb_aht10.rb → i2c_bb_aht10.rb} +0 -0
  23. /data/examples/{i2c_bitbang-rb_ssd1306_bench.rb → i2c_bb_ssd1306_bench.rb} +0 -0
  24. /data/examples/{i2c_aht10.rb → i2c_hw_aht10.rb} +0 -0
  25. /data/examples/{i2c_aht10_zip.rb → i2c_hw_aht10_zip.rb} +0 -0
  26. /data/examples/{i2c_ssd1306_bench.rb → i2c_hw_ssd1306_bench.rb} +0 -0
  27. /data/examples/{servo.rb → pwm_hw_servo.rb} +0 -0
  28. /data/examples/{pwm.rb → pwm_sw.rb} +0 -0
  29. /data/examples/{spi_bitbang_loopback.rb → spi_bb_loopback.rb} +0 -0
  30. /data/examples/{spi_bitbang_ssd1306_sim_bench.rb → spi_bb_sim_bench.rb} +0 -0
  31. /data/examples/{spi_loopback.rb → spi_hw_loopback.rb} +0 -0
  32. /data/examples/{spi_ws2812.rb → spi_hw_ws2812.rb} +0 -0
  33. /data/examples/{spi_ws2812_bounce.rb → spi_hw_ws2812_bounce.rb} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ba4963055ec58ea685427a0c9395eedfbc20cf0159df764edbd3b735dd7ce40
4
- data.tar.gz: b4149669d2ac089120582d09db4ab6d0e9bb45f8c93e22a62164272f9150c758
3
+ metadata.gz: 3007d43d8623a895efdcfb2089ccc3c9105bde952af5095d904019d2df56eaaf
4
+ data.tar.gz: 8aa7f8ecf78eff10e04deb2bc5a5732b939cbbaa99f7b4f578dd8320a7634fb7
5
5
  SHA512:
6
- metadata.gz: 9e3397df71dadb44d9ebfb96d6732d9ba211f9dc5a530b96747e7ec2ee93e22b6412218f61938560864c10208fdc60609b93c18707ca67332c2a8800e880d21c
7
- data.tar.gz: 7ebd239afcd78e16ea893943f1e226b06e68c9b0b2cf4c3a98acebe3f23a33e044fa51c1309b1779ac5415877be8512b78cff651e48a87fc0fe860ef2405531f
6
+ metadata.gz: 93cc1be6fcafd45e98a11272f608241adc2c809f0ff6d71333a63f93453bb34fba4a75155cb973c06407b6cea281fbdd934664970077a1608718f0f218eb49cd
7
+ data.tar.gz: f94f8859d0b7c3999687263a54979472fd73df50c0a3e09319aeb908c3b4e7de1bac458d97478f0ddeba19e4fe10d061c57e9331fc6910f386101315f4d087d5
@@ -5,9 +5,8 @@ SCL_PIN = 228
5
5
  SDA_PIN = 270
6
6
 
7
7
  chip_handle = LGPIO.chip_open(GPIO_CHIP)
8
- LGPIO.i2c_bb_claim(chip_handle, SCL_PIN, SDA_PIN)
9
-
10
- devices = LGPIO.i2c_bb_search(chip_handle, SCL_PIN, SDA_PIN)
8
+ i2c_bb = LGPIO::I2CBitBang.new(chip_handle, SCL_PIN, SDA_PIN)
9
+ devices = i2c_bb.search
11
10
 
12
11
  if devices.empty?
13
12
  puts "No devices found on I2C bus"
@@ -0,0 +1,20 @@
1
+ require 'lgpio'
2
+ #
3
+ # Writing directly to a hardware PWM channel.
4
+ # Arguments in order are:
5
+ # pwmchip index (X in /sys/class/pwm/pwmchipX/)
6
+ # PWM channel on the chip (Y in /sys/class/pwm/pwmchipX/pwmY)
7
+ # period: given in nanoseconds
8
+ # OR frequency: given in Hz
9
+ #
10
+ pwm_out = LGPIO::HardwarePWM.new(0, 1, period: 20_000_000)
11
+
12
+ RUNS = 250_000
13
+ start = Time.now
14
+ RUNS.times do
15
+ pwm_out.duty_us = 1000
16
+ end
17
+ finish = Time.now
18
+
19
+ wps = RUNS / (finish - start)
20
+ puts "Hardware PWM writes per second: #{wps.round(2)}"
@@ -43,7 +43,7 @@ LGPIO.chip_close(chip_handle)
43
43
 
44
44
  fps = FRAME_COUNT / (finish - start)
45
45
  # Also calculate C calls per second, using roughly 20 calls per byte written.
46
- data_calls = START_ARRAY.length + ((PATTERN_1.length + PATTERN_2.length) / 2) * 20
46
+ data_calls = (START_ARRAY.length + (PATTERN_1.length + PATTERN_2.length) / 2) * 20
47
47
  # Add DC, SELECT and clock idle calls.
48
48
  total_calls = data_calls + 8
49
49
  cps = ((total_calls * fps) / 1000.0).round
data/ext/lgpio/lgpio.c CHANGED
@@ -3,13 +3,19 @@
3
3
  #include <stdio.h>
4
4
  #include <time.h>
5
5
 
6
- // Set up a queue for up to 2**16 GPIO reports.
6
+ /*****************************************************************************/
7
+ /* GPIO REPORT QUEUE */
8
+ /*****************************************************************************/
7
9
  static pthread_mutex_t queueLock;
10
+ // Set up a queue for up to 2**16 GPIO reports.
8
11
  #define QUEUE_LENGTH UINT16_MAX + 1
9
12
  static lgGpioReport_t reportQueue[QUEUE_LENGTH];
10
13
  static uint16_t qWritePos = 1;
11
14
  static uint16_t qReadPos = 0;
12
15
 
16
+ /*****************************************************************************/
17
+ /* TIMING HELPERS */
18
+ /*****************************************************************************/
13
19
  static uint64_t nanoDiff(const struct timespec *event2, const struct timespec *event1) {
14
20
  uint64_t event2_ns = (uint64_t)event2->tv_sec * 1000000000LL + event2->tv_nsec;
15
21
  uint64_t event1_ns = (uint64_t)event1->tv_sec * 1000000000LL + event1->tv_nsec;
@@ -36,6 +42,9 @@ static void microDelay(uint64_t micros) {
36
42
  nanoDelay(micros * 1000);
37
43
  }
38
44
 
45
+ /*****************************************************************************/
46
+ /* CHIP & GPIO */
47
+ /*****************************************************************************/
39
48
  static VALUE chip_open(VALUE self, VALUE gpio_dev) {
40
49
  int result = lgGpiochipOpen(NUM2INT(gpio_dev));
41
50
  return INT2NUM(result);
@@ -162,103 +171,9 @@ static VALUE gpio_get_report(VALUE self){
162
171
  return (popped) ? hash : Qnil;
163
172
  }
164
173
 
165
- static VALUE gpio_read_ultrasonic(VALUE self, VALUE rbHandle, VALUE rbTrigger, VALUE rbEcho, VALUE rbTriggerTime) {
166
- int handle = NUM2UINT(rbHandle);
167
- int trigger = NUM2UINT(rbTrigger);
168
- int echo = NUM2UINT(rbEcho);
169
- uint32_t triggerTime = NUM2UINT(rbTriggerTime);
170
- struct timespec start;
171
- struct timespec now;
172
- bool echoSeen = false;
173
-
174
- // Pull down avoids false readings if disconnected.
175
- lgGpioClaimInput(handle, LG_SET_PULL_DOWN, echo);
176
-
177
- // Initial pulse on the triger pin.
178
- lgGpioClaimOutput(handle, LG_SET_PULL_NONE, trigger, 0);
179
- microDelay(5);
180
- lgGpioWrite(handle, trigger, 1);
181
- microDelay(triggerTime);
182
- lgGpioWrite(handle, trigger, 0);
183
-
184
- clock_gettime(CLOCK_MONOTONIC, &start);
185
- now = start;
186
-
187
- // Wait for echo to go high, up to 25,000 us after trigger.
188
- while(nanoDiff(&now, &start) < 25000000){
189
- clock_gettime(CLOCK_MONOTONIC, &now);
190
- if (lgGpioRead(handle, echo) == 1) {
191
- echoSeen = true;
192
- start = now;
193
- break;
194
- }
195
- }
196
- if (!echoSeen) return Qnil;
197
-
198
- // Wait for echo to go low again, up to 25,000 us after echo start.
199
- while(nanoDiff(&now, &start) < 25000000){
200
- clock_gettime(CLOCK_MONOTONIC, &now);
201
- if (lgGpioRead(handle, echo) == 0) break;
202
- }
203
-
204
- // High pulse time in microseconds.
205
- return INT2NUM(round(nanoDiff(&now, &start) / 1000.0));
206
- }
207
-
208
- static VALUE gpio_read_pulses_us(VALUE self, VALUE rbHandle, VALUE rbGPIO, VALUE rbReset_us, VALUE rbResetLevel, VALUE rbLimit, VALUE rbTimeout_ms) {
209
- // C values
210
- int handle = NUM2INT(rbHandle);
211
- int gpio = NUM2INT(rbGPIO);
212
- uint32_t reset_us = NUM2UINT(rbReset_us);
213
- uint8_t resetLevel = NUM2UINT(rbResetLevel);
214
- uint32_t limit = NUM2UINT(rbLimit);
215
- uint64_t timeout_ns = NUM2UINT(rbTimeout_ms) * 1000000;
216
-
217
- // State setup
218
- uint64_t pulses_ns[limit];
219
- uint32_t pulseIndex = 0;
220
- int gpioState;
221
- struct timespec start;
222
- struct timespec lastPulse;
223
- struct timespec now;
224
-
225
- // Perform reset
226
- if (reset_us > 0) {
227
- int result = lgGpioClaimOutput(handle, LG_SET_PULL_NONE, gpio, resetLevel);
228
- if (result < 0) return NUM2INT(result);
229
- microDelay(reset_us);
230
- }
231
-
232
- // Initialize timing
233
- clock_gettime(CLOCK_MONOTONIC, &start);
234
- lastPulse = start;
235
- now = start;
236
-
237
- // Switch to input and read initial state
238
- lgGpioClaimInput(handle, LG_SET_PULL_NONE, gpio);
239
- gpioState = lgGpioRead(handle, gpio);
240
-
241
- // Read pulses in nanoseconds
242
- while ((nanoDiff(&now, &start) < timeout_ns) && (pulseIndex < limit)) {
243
- clock_gettime(CLOCK_MONOTONIC, &now);
244
- if (lgGpioRead(handle, gpio) != gpioState) {
245
- pulses_ns[pulseIndex] = nanoDiff(&now, &lastPulse);
246
- lastPulse = now;
247
- gpioState = gpioState ^ 0b1;
248
- pulseIndex++;
249
- }
250
- }
251
-
252
- // Return Ruby array of pulse as microseconds
253
- if (pulseIndex == 0) return Qnil;
254
- VALUE retArray = rb_ary_new2(pulseIndex);
255
- for(int i=0; i<pulseIndex; i++){
256
- uint32_t pulse_us = round(pulses_ns[i] / 1000.0);
257
- rb_ary_store(retArray, i, UINT2NUM(pulse_us));
258
- }
259
- return retArray;
260
- }
261
-
174
+ /*****************************************************************************/
175
+ /* SOFTWARE PWM & WAVE */
176
+ /*****************************************************************************/
262
177
  static VALUE tx_busy(VALUE self, VALUE handle, VALUE gpio, VALUE kind) {
263
178
  int result = lgTxBusy(NUM2INT(handle), NUM2INT(gpio), NUM2INT(kind));
264
179
  return INT2NUM(result);
@@ -302,6 +217,9 @@ static VALUE tx_wave(VALUE self, VALUE handle, VALUE lead_gpio, VALUE pulses) {
302
217
  return INT2NUM(result);
303
218
  }
304
219
 
220
+ /*****************************************************************************/
221
+ /* HARDWARE PWM OOK WAVE */
222
+ /*****************************************************************************/
305
223
  static VALUE tx_wave_ook(VALUE self, VALUE dutyPath, VALUE dutyString, VALUE pulses) {
306
224
  // NOTE: This uses hardware PWM, NOT the lgpio software PWM/wave interface.
307
225
  // The Ruby class LGPIO::HardwarePWM should have already set the PWM carrier frequency.
@@ -343,6 +261,9 @@ static VALUE tx_wave_ook(VALUE self, VALUE dutyPath, VALUE dutyString, VALUE pul
343
261
  fclose(dutyFile);
344
262
  }
345
263
 
264
+ /*****************************************************************************/
265
+ /* HARDWARE I2C */
266
+ /*****************************************************************************/
346
267
  static VALUE i2c_open(VALUE self, VALUE i2cDev, VALUE i2cAddr, VALUE i2cFlags){
347
268
  int handle = lgI2cOpen(NUM2INT(i2cDev), NUM2INT(i2cAddr), NUM2INT(i2cFlags));
348
269
  return INT2NUM(handle);
@@ -406,6 +327,9 @@ static VALUE i2c_zip(VALUE self, VALUE handle, VALUE txArray, VALUE rb_rxCount){
406
327
  return retArray;
407
328
  }
408
329
 
330
+ /*****************************************************************************/
331
+ /* HARDWARE SPI */
332
+ /*****************************************************************************/
409
333
  static VALUE spi_open(VALUE self, VALUE spiDev, VALUE spiChan, VALUE spiBaud, VALUE spiFlags){
410
334
  int handle = lgSpiOpen(NUM2INT(spiDev), NUM2INT(spiChan), NUM2INT(spiBaud), NUM2INT(spiFlags));
411
335
  return INT2NUM(handle);
@@ -506,32 +430,108 @@ static VALUE spi_ws2812_write(VALUE self, VALUE handle, VALUE pixelArray){
506
430
  }
507
431
 
508
432
  /*****************************************************************************/
509
- /* ONE WIRE */
433
+ /* BIT-BANG PULSE INPUT */
510
434
  /*****************************************************************************/
511
- static uint8_t bitReadU64(uint64_t* b, uint8_t i) {
512
- return ((*b >> i) & 0b1);
513
- }
435
+ static VALUE gpio_read_ultrasonic(VALUE self, VALUE rbHandle, VALUE rbTrigger, VALUE rbEcho, VALUE rbTriggerTime) {
436
+ int handle = NUM2UINT(rbHandle);
437
+ int trigger = NUM2UINT(rbTrigger);
438
+ int echo = NUM2UINT(rbEcho);
439
+ uint32_t triggerTime = NUM2UINT(rbTriggerTime);
440
+ struct timespec start;
441
+ struct timespec now;
442
+ bool echoSeen = false;
514
443
 
515
- static void bitWriteU64(uint64_t* b, uint8_t i, uint8_t v) {
516
- if (v == 0) {
517
- *b &= ~(1ULL << i);
518
- } else {
519
- *b |= (1ULL << i);
444
+ // Pull down avoids false readings if disconnected.
445
+ lgGpioClaimInput(handle, LG_SET_PULL_DOWN, echo);
446
+
447
+ // Initial pulse on the triger pin.
448
+ lgGpioClaimOutput(handle, LG_SET_PULL_NONE, trigger, 0);
449
+ microDelay(5);
450
+ lgGpioWrite(handle, trigger, 1);
451
+ microDelay(triggerTime);
452
+ lgGpioWrite(handle, trigger, 0);
453
+
454
+ clock_gettime(CLOCK_MONOTONIC, &start);
455
+ now = start;
456
+
457
+ // Wait for echo to go high, up to 25,000 us after trigger.
458
+ while(nanoDiff(&now, &start) < 25000000){
459
+ clock_gettime(CLOCK_MONOTONIC, &now);
460
+ if (lgGpioRead(handle, echo) == 1) {
461
+ echoSeen = true;
462
+ start = now;
463
+ break;
464
+ }
465
+ }
466
+ if (!echoSeen) return Qnil;
467
+
468
+ // Wait for echo to go low again, up to 25,000 us after echo start.
469
+ while(nanoDiff(&now, &start) < 25000000){
470
+ clock_gettime(CLOCK_MONOTONIC, &now);
471
+ if (lgGpioRead(handle, echo) == 0) break;
520
472
  }
521
- }
522
473
 
523
- static uint8_t bitReadU8(uint8_t* b, uint8_t i) {
524
- return (*b >> i) & 0b1;
474
+ // High pulse time in microseconds.
475
+ return INT2NUM(round(nanoDiff(&now, &start) / 1000.0));
525
476
  }
526
477
 
527
- static void bitWriteU8(uint8_t* b, uint8_t i, uint8_t v) {
528
- if (v == 0) {
529
- *b &= ~(1 << i);
530
- } else {
531
- *b |= (1 << i);
478
+ static VALUE gpio_read_pulses_us(VALUE self, VALUE rbHandle, VALUE rbGPIO, VALUE rbReset_us, VALUE rbResetLevel, VALUE rbLimit, VALUE rbTimeout_ms) {
479
+ // C values
480
+ int handle = NUM2INT(rbHandle);
481
+ int gpio = NUM2INT(rbGPIO);
482
+ uint32_t reset_us = NUM2UINT(rbReset_us);
483
+ uint8_t resetLevel = NUM2UINT(rbResetLevel);
484
+ uint32_t limit = NUM2UINT(rbLimit);
485
+ uint64_t timeout_ns = NUM2UINT(rbTimeout_ms) * 1000000;
486
+
487
+ // State setup
488
+ uint64_t pulses_ns[limit];
489
+ uint32_t pulseIndex = 0;
490
+ int gpioState;
491
+ struct timespec start;
492
+ struct timespec lastPulse;
493
+ struct timespec now;
494
+
495
+ // Perform reset
496
+ if (reset_us > 0) {
497
+ int result = lgGpioClaimOutput(handle, LG_SET_PULL_NONE, gpio, resetLevel);
498
+ if (result < 0) return NUM2INT(result);
499
+ microDelay(reset_us);
500
+ }
501
+
502
+ // Initialize timing
503
+ clock_gettime(CLOCK_MONOTONIC, &start);
504
+ lastPulse = start;
505
+ now = start;
506
+
507
+ // Switch to input and read initial state
508
+ lgGpioClaimInput(handle, LG_SET_PULL_NONE, gpio);
509
+ gpioState = lgGpioRead(handle, gpio);
510
+
511
+ // Read pulses in nanoseconds
512
+ while ((nanoDiff(&now, &start) < timeout_ns) && (pulseIndex < limit)) {
513
+ clock_gettime(CLOCK_MONOTONIC, &now);
514
+ if (lgGpioRead(handle, gpio) != gpioState) {
515
+ pulses_ns[pulseIndex] = nanoDiff(&now, &lastPulse);
516
+ lastPulse = now;
517
+ gpioState = gpioState ^ 0b1;
518
+ pulseIndex++;
519
+ }
532
520
  }
521
+
522
+ // Return Ruby array of pulse as microseconds
523
+ if (pulseIndex == 0) return Qnil;
524
+ VALUE retArray = rb_ary_new2(pulseIndex);
525
+ for(int i=0; i<pulseIndex; i++){
526
+ uint32_t pulse_us = round(pulses_ns[i] / 1000.0);
527
+ rb_ary_store(retArray, i, UINT2NUM(pulse_us));
528
+ }
529
+ return retArray;
533
530
  }
534
531
 
532
+ /*****************************************************************************/
533
+ /* BIT BANG 1-WIRE HEPERS */
534
+ /*****************************************************************************/
535
535
  static VALUE one_wire_bit_read(VALUE self, VALUE rbHandle, VALUE rbGPIO) {
536
536
  int handle = NUM2INT(rbHandle);
537
537
  int gpio = NUM2INT(rbGPIO);
@@ -598,167 +598,6 @@ static VALUE one_wire_reset(VALUE self, VALUE rbHandle, VALUE rbGPIO) {
598
598
  return UINT2NUM(presence);
599
599
  }
600
600
 
601
- /*****************************************************************************/
602
- /* BIT-BANG I2C */
603
- /*****************************************************************************/
604
- static uint8_t sdaState = 1;
605
-
606
- static void i2c_bb_set_sda(int handle, int sda, uint8_t level) {
607
- if (level == sdaState) return;
608
- lgGpioWrite(handle, sda, level);
609
- sdaState = level;
610
- }
611
-
612
- // Start condition is SDA then SCL going low, from both high.
613
- static void i2c_bb_start(int handle, int scl, int sda) {
614
- lgGpioWrite(handle, sda, 0);
615
- lgGpioWrite(handle, scl, 0);
616
- }
617
-
618
- // Stop condition is SDA going high, while SCL is also high.
619
- static void i2c_bb_stop(int handle, int scl, int sda) {
620
- lgGpioWrite(handle, sda, 0);
621
- lgGpioWrite(handle, scl, 1);
622
- lgGpioWrite(handle, sda, 1);
623
- }
624
-
625
- static uint8_t i2c_bb_read_bit(int handle, int scl, int sda) {
626
- uint8_t bit;
627
- // Ensure SDA high before we pull SCL high.
628
- i2c_bb_set_sda(handle, sda, 1);
629
- lgGpioWrite(handle, scl, 1);
630
- bit = lgGpioRead(handle, sda);
631
- lgGpioWrite(handle, scl, 0);
632
- return bit;
633
- }
634
-
635
- static void i2c_bb_write_bit(int handle, int scl, int sda, uint8_t bit) {
636
- // Set SDA while SCL is low.
637
- i2c_bb_set_sda(handle, sda, bit);
638
- lgGpioWrite(handle, scl, 1);
639
- lgGpioWrite(handle, scl, 0);
640
- }
641
-
642
- static uint8_t i2c_bb_read_byte(int handle, int scl, int sda, bool ack) {
643
- uint8_t b;
644
-
645
- // Receive MSB first.
646
- for (int i=7; i>=0; i--) bitWriteU8(&b, i, i2c_bb_read_bit(handle, scl, sda));
647
-
648
- // Send ACK or NACK and return byte.
649
- if (ack) {
650
- i2c_bb_write_bit(handle, scl, sda, 0);
651
- } else {
652
- i2c_bb_write_bit(handle, scl, sda, 1);
653
- }
654
- return b;
655
- }
656
-
657
- static int i2c_bb_write_byte(int handle, int scl, int sda, uint8_t b) {
658
- // Send MSB first.
659
- for (int i=7; i>=0; i--) i2c_bb_write_bit(handle, scl, sda, bitReadU8(&b, i));
660
-
661
- // Return -1 for NACK, 0 for ACK.
662
- return (i2c_bb_read_bit(handle, scl, sda) == 0) ? 0 : -1;
663
- }
664
-
665
- static VALUE i2c_bb_claim(VALUE self, VALUE rbHandle, VALUE rbSCL, VALUE rbSDA) {
666
- int handle = NUM2INT(rbHandle);
667
- int scl = NUM2INT(rbSCL);
668
- int sda = NUM2INT(rbSDA);
669
-
670
- // SCL is a driven output. SDA is open drain with pullup enabled.
671
- lgGpioClaimOutput(handle, LG_SET_PULL_NONE, scl, 1);
672
- lgGpioClaimOutput(handle, LG_SET_OPEN_DRAIN | LG_SET_PULL_UP, sda, 1);
673
- }
674
-
675
- static VALUE i2c_bb_search(VALUE self, VALUE rbHandle, VALUE rbSCL, VALUE rbSDA) {
676
- int handle = NUM2INT(rbHandle);
677
- int scl = NUM2INT(rbSCL);
678
- int sda = NUM2INT(rbSDA);
679
- int ack;
680
- uint8_t present[128];
681
- uint8_t presentCount = 0;
682
- sdaState = 1;
683
-
684
- // Only addresses from 0x08 to 0x77 are usable (8 to 127).
685
- for (uint8_t addr = 0x08; addr < 0x78; addr++) {
686
- i2c_bb_start(handle, scl, sda);
687
- ack = i2c_bb_write_byte(handle, scl, sda, ((addr << 1) & 0b11111110));
688
- i2c_bb_stop(handle, scl, sda);
689
- if (ack == 0){
690
- present[addr] = 1;
691
- presentCount++;
692
- } else {
693
- present[addr] = 0;
694
- }
695
- }
696
- if (presentCount == 0) return Qnil;
697
-
698
- VALUE retArray = rb_ary_new2(presentCount);
699
- uint8_t i = 0;
700
- for (uint8_t addr = 0x08; addr < 0x78; addr++) {
701
- if (present[addr] == 1) {
702
- rb_ary_store(retArray, i, UINT2NUM(addr));
703
- i++;
704
- }
705
- }
706
- return retArray;
707
- }
708
-
709
- static VALUE i2c_bb_write(VALUE self, VALUE rbHandle, VALUE rbSCL, VALUE rbSDA, VALUE rbAddress, VALUE txArray) {
710
- int handle = NUM2INT(rbHandle);
711
- int scl = NUM2INT(rbSCL);
712
- int sda = NUM2INT(rbSDA);
713
- uint8_t address = NUM2CHR(rbAddress);
714
- uint8_t writeAddress = (address << 1);
715
- sdaState = 1;
716
-
717
- int count = RARRAY_LEN(txArray);
718
- uint8_t txBuf[count];
719
- VALUE currentByte;
720
- for(int i=0; i<count; i++){
721
- currentByte = rb_ary_entry(txArray, i);
722
- Check_Type(currentByte, T_FIXNUM);
723
- txBuf[i] = NUM2CHR(currentByte);
724
- }
725
-
726
- i2c_bb_start(handle, scl, sda);
727
- i2c_bb_write_byte(handle, scl, sda, writeAddress);
728
- for (int i=0; i<count; i++) i2c_bb_write_byte(handle, scl, sda, txBuf[i]);
729
- i2c_bb_stop(handle, scl, sda);
730
- }
731
-
732
- static VALUE i2c_bb_read(VALUE self, VALUE rbHandle, VALUE rbSCL, VALUE rbSDA, VALUE rbAddress, VALUE rbCount) {
733
- int handle = NUM2INT(rbHandle);
734
- int scl = NUM2INT(rbSCL);
735
- int sda = NUM2INT(rbSDA);
736
- uint8_t address = NUM2CHR(rbAddress);
737
- uint8_t readAddress = (address << 1) | 0b00000001;
738
- sdaState = 1;
739
-
740
- int count = NUM2INT(rbCount);
741
- uint8_t rxBuf[count];
742
-
743
- i2c_bb_start(handle, scl, sda);
744
- int ack = i2c_bb_write_byte(handle, scl, sda, readAddress);
745
- // Device with this address not present on the bus.
746
- if (ack != 0) return Qnil;
747
-
748
- // Read and ACK for all but the last byte.
749
- int pos = 0;
750
- while(pos < count-1) {
751
- rxBuf[pos] = i2c_bb_read_byte(handle, scl, sda, true);
752
- pos++;
753
- }
754
- rxBuf[pos] = i2c_bb_read_byte(handle, scl, sda, false);
755
- i2c_bb_stop(handle, scl, sda);
756
-
757
- VALUE retArray = rb_ary_new2(count);
758
- for(int i=0; i<count; i++) rb_ary_store(retArray, i, UINT2NUM(rxBuf[i]));
759
- return retArray;
760
- }
761
-
762
601
  /*****************************************************************************/
763
602
  /* EXTENSION INIT */
764
603
  /*****************************************************************************/
@@ -798,10 +637,6 @@ void Init_lgpio(void) {
798
637
  rb_define_singleton_method(mLGPIO, "gpio_start_reporting", gpio_start_reporting, 0);
799
638
  rb_define_singleton_method(mLGPIO, "gpio_get_report", gpio_get_report, 0);
800
639
 
801
- // Pulse Input
802
- rb_define_singleton_method(mLGPIO, "gpio_read_ultrasonic", gpio_read_ultrasonic, 4);
803
- rb_define_singleton_method(mLGPIO, "gpio_read_pulses_us", gpio_read_pulses_us, 6);
804
-
805
640
  // Soft PWM / Wave
806
641
  rb_define_const(mLGPIO, "TX_PWM", INT2NUM(LG_TX_PWM));
807
642
  rb_define_const(mLGPIO, "TX_WAVE",INT2NUM(LG_TX_WAVE));
@@ -813,6 +648,10 @@ void Init_lgpio(void) {
813
648
  // Don't use this. Servo will jitter.
814
649
  rb_define_singleton_method(mLGPIO, "tx_servo", tx_servo, 6);
815
650
 
651
+ // Hardware PWM waves for on-off-keying.
652
+ VALUE cHardwarePWM = rb_define_class_under(mLGPIO, "HardwarePWM", rb_cObject);
653
+ rb_define_method(cHardwarePWM, "tx_wave_ook", tx_wave_ook, 3);
654
+
816
655
  // I2C
817
656
  rb_define_singleton_method(mLGPIO, "i2c_open", i2c_open, 3);
818
657
  rb_define_singleton_method(mLGPIO, "i2c_close", i2c_close, 1);
@@ -828,18 +667,12 @@ void Init_lgpio(void) {
828
667
  rb_define_singleton_method(mLGPIO, "spi_xfer", spi_xfer, 2);
829
668
  rb_define_singleton_method(mLGPIO, "spi_ws2812_write", spi_ws2812_write, 2);
830
669
 
831
- // Hardware PWM waves for on-off-keying.
832
- VALUE cHardwarePWM = rb_define_class_under(mLGPIO, "HardwarePWM", rb_cObject);
833
- rb_define_method(cHardwarePWM, "tx_wave_ook", tx_wave_ook, 3);
670
+ // Bit-Bang Pulse Input
671
+ rb_define_singleton_method(mLGPIO, "gpio_read_ultrasonic", gpio_read_ultrasonic, 4);
672
+ rb_define_singleton_method(mLGPIO, "gpio_read_pulses_us", gpio_read_pulses_us, 6);
834
673
 
835
- // Bit-banged 1-Wire
674
+ // Bit-bang 1-Wire Helpers
836
675
  rb_define_singleton_method(mLGPIO, "one_wire_bit_read", one_wire_bit_read, 2);
837
676
  rb_define_singleton_method(mLGPIO, "one_wire_bit_write", one_wire_bit_write, 3);
838
677
  rb_define_singleton_method(mLGPIO, "one_wire_reset", one_wire_reset, 2);
839
-
840
- // Bit-banged I2C
841
- rb_define_singleton_method(mLGPIO, "i2c_bb_claim", i2c_bb_claim, 3);
842
- rb_define_singleton_method(mLGPIO, "i2c_bb_search", i2c_bb_search, 3);
843
- rb_define_singleton_method(mLGPIO, "i2c_bb_write", i2c_bb_write, 5);
844
- rb_define_singleton_method(mLGPIO, "i2c_bb_read", i2c_bb_read, 5);
845
678
  }
data/lgpio.gemspec CHANGED
@@ -4,8 +4,8 @@ Gem::Specification.new do |s|
4
4
  s.name = 'lgpio'
5
5
  s.version = LGPIO::VERSION
6
6
  s.licenses = ['MIT']
7
- s.summary = "lgpio (lg) bindings for Ruby"
8
- s.description = "Use GPIO / PWM / I2C / SPI / UART on Linux SBCs in Ruby"
7
+ s.summary = "Use Linux GPIO, I2C, SPI and PWM in Ruby"
8
+ s.description = "Use Linux GPIO, I2C, SPI and PWM in Ruby"
9
9
 
10
10
  s.authors = ["vickash"]
11
11
  s.email = 'mail@vickash.com'
@@ -16,6 +16,10 @@ module LGPIO
16
16
  initialize_pins
17
17
  end
18
18
 
19
+ def config
20
+ @config ||= { handle: handle, clock: clock, input: input, output: output }
21
+ end
22
+
19
23
  def initialize_pins
20
24
  LGPIO.gpio_claim_output(handle, LGPIO::SET_PULL_NONE, clock, LGPIO::LOW)
21
25
  LGPIO.gpio_claim_input(handle, LGPIO::SET_PULL_NONE, input) if input
data/lib/lgpio/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module LGPIO
2
- VERSION = "0.1.6"
2
+ VERSION = "0.1.8"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lgpio
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - vickash
@@ -10,7 +10,7 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2024-09-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: Use GPIO / PWM / I2C / SPI / UART on Linux SBCs in Ruby
13
+ description: Use Linux GPIO, I2C, SPI and PWM in Ruby
14
14
  email: mail@vickash.com
15
15
  executables: []
16
16
  extensions:
@@ -21,37 +21,36 @@ files:
21
21
  - LICENSE
22
22
  - README.md
23
23
  - Rakefile
24
- - examples/bench_in.rb
25
- - examples/bench_out.rb
26
- - examples/blink.rb
27
24
  - examples/dht.rb
28
- - examples/group_in.rb
29
- - examples/group_out.rb
25
+ - examples/gpio_bench_in.rb
26
+ - examples/gpio_bench_out.rb
27
+ - examples/gpio_blink.rb
28
+ - examples/gpio_group_in.rb
29
+ - examples/gpio_group_out.rb
30
+ - examples/gpio_momentary.rb
31
+ - examples/gpio_reports.rb
32
+ - examples/gpio_rotary_encoder.rb
33
+ - examples/gpio_rotary_encoder_led.rb
34
+ - examples/gpio_wave.rb
30
35
  - examples/hcsr04.rb
31
- - examples/i2c_aht10.rb
32
- - examples/i2c_aht10_zip.rb
33
- - examples/i2c_bitbang-rb_aht10.rb
34
- - examples/i2c_bitbang-rb_ssd1306_bench.rb
35
- - examples/i2c_bitbang_aht10.rb
36
- - examples/i2c_bitbang_search.rb
37
- - examples/i2c_bitbang_ssd1306_bench.rb
38
- - examples/i2c_ssd1306_bench.rb
36
+ - examples/i2c_bb_aht10.rb
37
+ - examples/i2c_bb_search.rb
38
+ - examples/i2c_bb_ssd1306_bench.rb
39
+ - examples/i2c_hw_aht10.rb
40
+ - examples/i2c_hw_aht10_zip.rb
41
+ - examples/i2c_hw_ssd1306_bench.rb
39
42
  - examples/infrared.rb
40
- - examples/momentary.rb
41
43
  - examples/one_wire_ds18b20.rb
42
44
  - examples/one_wire_search.rb
43
- - examples/pwm.rb
44
- - examples/reports.rb
45
- - examples/rotary_encoder.rb
46
- - examples/rotary_encoder_led.rb
47
- - examples/servo.rb
48
- - examples/spi_bitbang_loopback.rb
49
- - examples/spi_bitbang_ssd1306_bench.rb
50
- - examples/spi_bitbang_ssd1306_sim_bench.rb
51
- - examples/spi_loopback.rb
52
- - examples/spi_ws2812.rb
53
- - examples/spi_ws2812_bounce.rb
54
- - examples/wave.rb
45
+ - examples/pwm_hw_bench.rb
46
+ - examples/pwm_hw_servo.rb
47
+ - examples/pwm_sw.rb
48
+ - examples/spi_bb_loopback.rb
49
+ - examples/spi_bb_sim_bench.rb
50
+ - examples/spi_bb_ssd1306_bench.rb
51
+ - examples/spi_hw_loopback.rb
52
+ - examples/spi_hw_ws2812.rb
53
+ - examples/spi_hw_ws2812_bounce.rb
55
54
  - ext/lgpio/extconf.rb
56
55
  - ext/lgpio/lgpio.c
57
56
  - lgpio.gemspec
@@ -86,5 +85,5 @@ requirements: []
86
85
  rubygems_version: 3.5.16
87
86
  signing_key:
88
87
  specification_version: 4
89
- summary: lgpio (lg) bindings for Ruby
88
+ summary: Use Linux GPIO, I2C, SPI and PWM in Ruby
90
89
  test_files: []
@@ -1,40 +0,0 @@
1
- require 'lgpio'
2
-
3
- POWER_ON_DELAY = 0.100
4
- RESET_DELAY = 0.020
5
- COMMAND_DELAY = 0.010
6
- MEASURE_DELAY = 0.080
7
- DATA_LENGTH = 6
8
- SOFT_RESET = [0xBA]
9
- INIT_AND_CALIBRATE = [0xE1, 0x08, 0x00]
10
- START_MEASUREMENT = [0xAC, 0x33, 0x00]
11
-
12
- GPIO_CHIP = 0
13
- SCL_PIN = 228
14
- SDA_PIN = 270
15
- ADDRESS = 0x38
16
-
17
- chip_handle = LGPIO.chip_open(GPIO_CHIP)
18
- LGPIO.i2c_bb_claim(chip_handle, SCL_PIN, SDA_PIN)
19
-
20
- # Startup sequence
21
- sleep(POWER_ON_DELAY)
22
- LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, SOFT_RESET)
23
- sleep(RESET_DELAY)
24
- LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, INIT_AND_CALIBRATE)
25
- sleep(COMMAND_DELAY)
26
-
27
- # Read and close
28
- LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, START_MEASUREMENT)
29
- sleep(MEASURE_DELAY)
30
- bytes = LGPIO.i2c_bb_read(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, DATA_LENGTH)
31
-
32
- # Humidity uses the upper 4 bits of the shared byte as its lowest 4 bits.
33
- h_raw = ((bytes[1] << 16) | (bytes[2] << 8) | (bytes[3])) >> 4
34
- humidity = (h_raw.to_f / 2**20) * 100
35
-
36
- # Temperature uses the lower 4 bits of the shared byte as its highest 4 bits.
37
- t_raw = ((bytes[3] & 0x0F) << 16) | (bytes[4] << 8) | bytes[5]
38
- temperature = (t_raw.to_f / 2**20) * 200 - 50
39
-
40
- puts "#{Time.now.strftime '%Y-%m-%d %H:%M:%S'} - Temperature: #{temperature.round(2)} \xC2\xB0C | Humidity: #{humidity.round(2)} %"
@@ -1,35 +0,0 @@
1
- require 'lgpio'
2
-
3
- INIT_ARRAY = [0, 168, 63, 211, 0, 64, 161, 200, 218, 18, 164, 166, 213, 128, 219, 32, 217, 241, 141, 20, 32, 0, 175]
4
- START_ARRAY = [0, 33, 0, 127, 34, 0, 7]
5
- PATTERN_1 = [64] + Array.new(1024) { 0b00110011 }
6
- PATTERN_2 = [64] + Array.new(1024) { 0b11001100 }
7
-
8
- GPIO_CHIP = 0
9
- SCL_PIN = 228
10
- SDA_PIN = 270
11
- ADDRESS = 0x3C
12
-
13
- chip_handle = LGPIO.chip_open(GPIO_CHIP)
14
- LGPIO.i2c_bb_claim(chip_handle, SCL_PIN, SDA_PIN)
15
-
16
- LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, INIT_ARRAY)
17
- FRAME_COUNT = 400
18
-
19
- start = Time.now
20
- (FRAME_COUNT / 2).times do
21
- LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, START_ARRAY)
22
- LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, PATTERN_1)
23
- LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, START_ARRAY)
24
- LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, PATTERN_2)
25
- end
26
- finish = Time.now
27
-
28
- LGPIO.chip_close(chip_handle)
29
-
30
- fps = FRAME_COUNT / (finish - start)
31
- # Also calculate C calls per second, using roughly 23 calls per byte written.
32
- cps = (START_ARRAY.length + ((PATTERN_1.length + PATTERN_2.length) / 2) + 2) * 23 * fps
33
- cps = (cps / 1000.0).round
34
-
35
- puts "SSD1306 benchmark result: #{fps.round(2)} fps | #{cps}k C calls/s"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes