lgpio 0.1.10 → 0.1.11

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: 4da526bc3f239adf23035ca2c8923463667f979038b01fe0f8b63f0ad017a0e1
4
- data.tar.gz: 6beafa4839875a6aac25f78a0b4b3e4fa25a28569269254ec4dcea27bfc06572
3
+ metadata.gz: 3371c46b2f589524fba421f579bd0f779d5e006eb62ef6d7480e8ca39cdf7540
4
+ data.tar.gz: 704f472a31ca5d9711a300ce5ce05ce89f930dd2322192a7251ce8cdab8f5abe
5
5
  SHA512:
6
- metadata.gz: af9365d7c43fc0f7d5bab7c360e5a2e9325f2c3f7b7015ffff39d98ee3c4c2041123dfb81354d5d0113a06daab31910d18ed3fcee91dd75ded80c13b87543cba
7
- data.tar.gz: aef0e2f50840a3b601627283f15df63f1f6ab5d065288f05275c07d04e0ad32def28d055acedfbba807c16f16b041d2df3bd5444f093bbb55c604aac2026c4ac
6
+ metadata.gz: cf2c6d2fec7b57b371a69c11ba1e7fd66997c72581a19c09bc73dc224e59be6e7347450d2499d84af38b4b73465e97bcf6d3021975b9427fd7f52a729cad2b08
7
+ data.tar.gz: 8fe39d478e3453cf5d42452a59552660742b249b9f533fbec506dfde165c746fe2ab3dada38fbde8ea60e8567e57419a6393faa9236b97772954a9d96f619829
data/README.md CHANGED
@@ -38,7 +38,7 @@ These use the sysfs PWM interface, not lgpio C, but are a good fit for this gem.
38
38
  - Carrier generated by hardware PWM. Software modulated with monotonic clock timing.
39
39
  - Useful for sending infrared signals at 38kHz, for example.
40
40
 
41
- **Note:** Once hardware PWM is used on a pin, it stays PWM until reboot. The associated GPIO won't work.
41
+ **Note:** Once a pin is bound to hardware PWM in the device tree, it shouldn't be used as regular GPIO. Behavior is inconsistent across different hardware.
42
42
 
43
43
  ## Installation
44
44
  On Debian-based Linuxes (RaspberryPi OS, Armbian, DietPi etc.):
@@ -35,8 +35,8 @@ LGPIO.chip_close(scl_handle)
35
35
  LGPIO.chip_close(sda_handle) unless (scl_handle == sda_handle)
36
36
 
37
37
  fps = FRAME_COUNT / (finish - start)
38
- # Also calculate C calls per second, using roughly 23 calls per byte written.
39
- cps = (START_ARRAY.length + ((PATTERN_1.length + PATTERN_2.length) / 2) + 2) * 23 * fps
38
+ # Also calculate C calls per second, using roughly 24.5 GPIO calls per byte written.
39
+ cps = (START_ARRAY.length + ((PATTERN_1.length + PATTERN_2.length) / 2) + 2) * 24.5 * fps
40
40
  cps = (cps / 1000.0).round
41
41
 
42
42
  puts "SSD1306 benchmark result: #{fps.round(2)} fps | #{cps}k C calls/s"
@@ -25,8 +25,6 @@ pins.each_value do |hash|
25
25
  end
26
26
  end
27
27
 
28
- puts pins.inspect
29
-
30
28
  spi_bb = LGPIO::SPIBitBang.new(clock: pins[:clock], output: pins[:output])
31
29
  LGPIO.gpio_claim_output(pins[:reset][:handle], pins[:reset][:line], LGPIO::SET_PULL_NONE, LGPIO::LOW)
32
30
  LGPIO.gpio_claim_output(pins[:dc][:handle], pins[:dc][:line], LGPIO::SET_PULL_NONE, LGPIO::LOW)
@@ -12,7 +12,7 @@ puts "TX bytes: #{tx_bytes.inspect}"
12
12
 
13
13
  # rx_bytes == tx_bytes if MOSI looped back to MISO.
14
14
  # rx_byte all 255 when MOSI and MISO not connected.
15
- rx_bytes = LGPIO.spi_xfer(spi_handle, tx_bytes)
15
+ rx_bytes = LGPIO.spi_xfer(spi_handle, tx_bytes, tx_bytes.length)
16
16
  puts "RX bytes: #{rx_bytes.inspect}"
17
17
 
18
18
  LGPIO.spi_close(spi_handle)
data/ext/lgpio/lgpio.c CHANGED
@@ -42,6 +42,11 @@ static void microDelay(uint64_t micros) {
42
42
  nanoDelay(micros * 1000);
43
43
  }
44
44
 
45
+ static VALUE rbMicroDelay(VALUE self, VALUE micros) {
46
+ microDelay(NUM2ULL(micros));
47
+ return Qnil;
48
+ }
49
+
45
50
  /*****************************************************************************/
46
51
  /* CHIP & GPIO */
47
52
  /*****************************************************************************/
@@ -86,6 +91,7 @@ static VALUE gpio_write(VALUE self, VALUE handle, VALUE gpio, VALUE level) {
86
91
  }
87
92
 
88
93
  static VALUE group_claim_input(VALUE self, VALUE handle, VALUE gpios, VALUE flags) {
94
+ Check_Type(gpios, T_ARRAY);
89
95
  int count = rb_array_len(gpios);
90
96
  int lgGpios[count];
91
97
  int i;
@@ -97,6 +103,7 @@ static VALUE group_claim_input(VALUE self, VALUE handle, VALUE gpios, VALUE flag
97
103
  }
98
104
 
99
105
  static VALUE group_claim_output(VALUE self, VALUE handle, VALUE gpios, VALUE flags, VALUE levels) {
106
+ Check_Type(gpios, T_ARRAY);
100
107
  int count = rb_array_len(gpios);
101
108
  int lgGpios[count];
102
109
  int lgLevels[count];
@@ -190,7 +197,7 @@ static VALUE tx_pulse(VALUE self, VALUE handle, VALUE gpio, VALUE on, VALUE off,
190
197
  }
191
198
 
192
199
  static VALUE tx_pwm(VALUE self, VALUE handle, VALUE gpio, VALUE freq, VALUE duty, VALUE offset, VALUE cycles) {
193
- int result = lgTxPwm(NUM2INT(handle), NUM2INT(gpio), NUM2INT(freq), NUM2INT(duty), NUM2INT(offset), NUM2INT(cycles));
200
+ int result = lgTxPwm(NUM2INT(handle), NUM2INT(gpio), NUM2INT(freq), NUM2DBL(duty), NUM2INT(offset), NUM2INT(cycles));
194
201
  return INT2NUM(result);
195
202
  }
196
203
 
@@ -201,6 +208,7 @@ static VALUE tx_servo(VALUE self, VALUE handle, VALUE gpio, VALUE width, VALUE f
201
208
 
202
209
  static VALUE tx_wave(VALUE self, VALUE handle, VALUE lead_gpio, VALUE pulses) {
203
210
  // Copy Ruby array to array of lgPulse_t.
211
+ Check_Type(pulses, T_ARRAY);
204
212
  int pulseCount = rb_array_len(pulses);
205
213
  lgPulse_t pulsesOut[pulseCount];
206
214
  VALUE rbPulse;
@@ -225,9 +233,10 @@ static VALUE tx_wave_ook(VALUE self, VALUE dutyPath, VALUE dutyString, VALUE pul
225
233
  // The Ruby class LGPIO::HardwarePWM should have already set the PWM carrier frequency.
226
234
  //
227
235
  // Convert pulses from microseconds to nanoseconds.
236
+ Check_Type(pulses, T_ARRAY);
228
237
  uint32_t pulseCount = rb_array_len(pulses);
229
238
  uint64_t nanoPulses[pulseCount];
230
- for (int i=0; i<pulseCount; i++) {
239
+ for (uint32_t i=0; i<pulseCount; i++) {
231
240
  nanoPulses[i] = NUM2UINT(rb_ary_entry(pulses, i)) * 1000;
232
241
  }
233
242
 
@@ -242,7 +251,7 @@ static VALUE tx_wave_ook(VALUE self, VALUE dutyPath, VALUE dutyString, VALUE pul
242
251
  const char *cDuty = StringValueCStr(dutyString);
243
252
 
244
253
  // Toggle duty cycle between given value and 0, to modulate the PWM carrier.
245
- for (int i=0; i<pulseCount; i++) {
254
+ for (uint32_t i=0; i<pulseCount; i++) {
246
255
  if (i % 2 == 0) {
247
256
  dutyFile = fopen(filePath, "w");
248
257
  fputs(cDuty, dutyFile);
@@ -259,6 +268,7 @@ static VALUE tx_wave_ook(VALUE self, VALUE dutyPath, VALUE dutyString, VALUE pul
259
268
  dutyFile = fopen(filePath, "w");
260
269
  fputs("0", dutyFile);
261
270
  fclose(dutyFile);
271
+ return UINT2NUM(pulseCount);
262
272
  }
263
273
 
264
274
  /*****************************************************************************/
@@ -274,12 +284,13 @@ static VALUE i2c_close(VALUE self, VALUE handle){
274
284
  return INT2NUM(result);
275
285
  }
276
286
 
277
- static VALUE i2c_write_device(VALUE self, VALUE handle, VALUE byteArray){
278
- int count = RARRAY_LEN(byteArray);
287
+ static VALUE i2c_write_device(VALUE self, VALUE handle, VALUE txArray){
288
+ Check_Type(txArray, T_ARRAY);
289
+ int count = rb_array_len(txArray);
279
290
  uint8_t txBuf[count];
280
291
  VALUE currentByte;
281
292
  for(int i=0; i<count; i++){
282
- currentByte = rb_ary_entry(byteArray, i);
293
+ currentByte = rb_ary_entry(txArray, i);
283
294
  Check_Type(currentByte, T_FIXNUM);
284
295
  txBuf[i] = NUM2CHR(currentByte);
285
296
  }
@@ -303,7 +314,8 @@ static VALUE i2c_read_device(VALUE self, VALUE handle, VALUE count){
303
314
  }
304
315
 
305
316
  static VALUE i2c_zip(VALUE self, VALUE handle, VALUE txArray, VALUE rb_rxCount){
306
- int txCount = RARRAY_LEN(txArray);
317
+ Check_Type(txArray, T_ARRAY);
318
+ int txCount = rb_array_len(txArray);
307
319
  uint8_t txBuf[txCount];
308
320
  VALUE currentByte;
309
321
  for(int i=0; i<txCount; i++){
@@ -357,7 +369,8 @@ static VALUE spi_read(VALUE self, VALUE handle, VALUE rxCount){
357
369
  }
358
370
 
359
371
  static VALUE spi_write(VALUE self, VALUE handle, VALUE txArray){
360
- int count = RARRAY_LEN(txArray);
372
+ Check_Type(txArray, T_ARRAY);
373
+ int count = rb_array_len(txArray);
361
374
  uint8_t txBuf[count];
362
375
  VALUE currentByte;
363
376
  for(int i=0; i<count; i++){
@@ -370,31 +383,42 @@ static VALUE spi_write(VALUE self, VALUE handle, VALUE txArray){
370
383
  return INT2NUM(result);
371
384
  }
372
385
 
373
- static VALUE spi_xfer(VALUE self, VALUE handle, VALUE txArray){
374
- int count = RARRAY_LEN(txArray);
386
+ static VALUE spi_xfer(VALUE self, VALUE handle, VALUE txArray, VALUE rxLength){
387
+ Check_Type(txArray, T_ARRAY);
388
+ int txCount = rb_array_len(txArray);
389
+ int rxCount = NUM2INT(rxLength);
390
+ int count = txCount;
391
+ if (rxCount > txCount) count = rxCount;
392
+
375
393
  uint8_t txBuf[count];
394
+ // Not sure if this needs null termination like I2C. +1 won't hurt.
395
+ uint8_t rxBuf[count+1];
396
+
397
+ // Add given bytes to transmit.
376
398
  VALUE currentByte;
377
- for(int i=0; i<count; i++){
399
+ for(int i=0; i<txCount; i++){
378
400
  currentByte = rb_ary_entry(txArray, i);
379
401
  Check_Type(currentByte, T_FIXNUM);
380
402
  txBuf[i] = NUM2CHR(currentByte);
381
403
  }
382
-
383
- // Not sure if this needs null termination like I2C. +1 won't hurt.
384
- uint8_t rxBuf[count+1];
404
+ // Extend with zeroes if reading more than writing.
405
+ if (count > txCount) {
406
+ for(int i=txCount; i<count; i++) txBuf[i] = 0;
407
+ }
385
408
 
386
409
  int result = lgSpiXfer(NUM2INT(handle), txBuf, rxBuf, count);
387
410
  if(result < 0) return INT2NUM(result);
388
411
 
389
- VALUE retArray = rb_ary_new2(count);
390
- for(int i=0; i<count; i++){
412
+ VALUE retArray = rb_ary_new2(rxCount);
413
+ for(int i=0; i<rxCount; i++){
391
414
  rb_ary_store(retArray, i, UINT2NUM(rxBuf[i]));
392
415
  }
393
416
  return retArray;
394
417
  }
395
418
 
396
419
  static VALUE spi_ws2812_write(VALUE self, VALUE handle, VALUE pixelArray){
397
- int count = RARRAY_LEN(pixelArray);
420
+ Check_Type(pixelArray, T_ARRAY);
421
+ int count = rb_array_len(pixelArray);
398
422
 
399
423
  // Pull low for at least one byte at 2.4 Mhz before data, and 90 after.
400
424
  int zeroesBefore = 1;
@@ -522,7 +546,7 @@ static VALUE gpio_read_pulses_us(VALUE self, VALUE rbHandle, VALUE rbGPIO, VALUE
522
546
  // Return Ruby array of pulse as microseconds
523
547
  if (pulseIndex == 0) return Qnil;
524
548
  VALUE retArray = rb_ary_new2(pulseIndex);
525
- for(int i=0; i<pulseIndex; i++){
549
+ for(uint32_t i=0; i<pulseIndex; i++){
526
550
  uint32_t pulse_us = round(pulses_ns[i] / 1000.0);
527
551
  rb_ary_store(retArray, i, UINT2NUM(pulse_us));
528
552
  }
@@ -598,6 +622,83 @@ static VALUE one_wire_reset(VALUE self, VALUE rbHandle, VALUE rbGPIO) {
598
622
  return UINT2NUM(presence);
599
623
  }
600
624
 
625
+ /*****************************************************************************/
626
+ /* Bit-Bang I2C Helpers */
627
+ /*****************************************************************************/
628
+ static uint8_t bitReadU8(uint8_t* b, uint8_t i) {
629
+ return (*b >> i) & 0b1;
630
+ }
631
+
632
+ static void bitWriteU8(uint8_t* b, uint8_t i, uint8_t v) {
633
+ if (v == 0) {
634
+ *b &= ~(1 << i);
635
+ } else {
636
+ *b |= (1 << i);
637
+ }
638
+ }
639
+
640
+ static void i2c_bb_set_sda(int handle, int gpio, uint8_t* state, uint8_t level) {
641
+ if (level == *state) return;
642
+ lgGpioWrite(handle, gpio, level);
643
+ *state = level;
644
+ }
645
+
646
+ static VALUE i2c_bb_read_byte(VALUE self, VALUE rbSCL_H, VALUE rbSCL_L, VALUE rbSDA_H, VALUE rbSDA_L, VALUE rbACK) {
647
+ int scl_H = NUM2INT(rbSCL_H);
648
+ int scl_L = NUM2INT(rbSCL_L);
649
+ int sda_H = NUM2INT(rbSDA_H);
650
+ int sda_L = NUM2INT(rbSDA_L);
651
+ uint8_t ack = RTEST(rbACK);
652
+
653
+ // Prevent caching by setting opposite to first state SDA will take.
654
+ uint8_t sdaState = 0;
655
+ uint8_t b;
656
+ uint8_t bit;
657
+
658
+ // Receive MSB first.
659
+ for (int i=7; i>=0; i--) {
660
+ i2c_bb_set_sda(sda_H, sda_L, &sdaState, 1);
661
+ lgGpioWrite(scl_H, scl_L, 1);
662
+ bit = lgGpioRead(sda_H, sda_L);
663
+ lgGpioWrite(scl_H, scl_L, 0);
664
+
665
+ bitWriteU8(&b, i, bit);
666
+ }
667
+
668
+ // Send ACK or NACK.
669
+ i2c_bb_set_sda(sda_H, sda_L, &sdaState, ack ^ 0b1);
670
+ lgGpioWrite(scl_H, scl_L, 1);
671
+ lgGpioWrite(scl_H, scl_L, 0);
672
+
673
+ return UINT2NUM(b);
674
+ }
675
+
676
+ static VALUE i2c_bb_write_byte(VALUE self, VALUE rbSCL_H, VALUE rbSCL_L, VALUE rbSDA_H, VALUE rbSDA_L, VALUE rbByte) {
677
+ int scl_H = NUM2INT(rbSCL_H);
678
+ int scl_L = NUM2INT(rbSCL_L);
679
+ int sda_H = NUM2INT(rbSDA_H);
680
+ int sda_L = NUM2INT(rbSDA_L);
681
+ uint8_t b = NUM2UINT(rbByte);
682
+
683
+ // Prevent caching by setting opposite to first state SDA will take.
684
+ uint8_t sdaState = bitReadU8(&b, 7) ^ 0b1;
685
+ uint8_t ack;
686
+
687
+ // Write MSBFIRST.
688
+ for (int i=7; i>=0; i--) {
689
+ i2c_bb_set_sda(sda_H, sda_L, &sdaState, bitReadU8(&b, i));
690
+ lgGpioWrite(scl_H, scl_L, 1);
691
+ lgGpioWrite(scl_H, scl_L, 0);
692
+ }
693
+
694
+ // Read and return ACK.
695
+ i2c_bb_set_sda(sda_H, sda_L, &sdaState, 1);
696
+ lgGpioWrite(scl_H, scl_L, 1);
697
+ ack = lgGpioRead(sda_H, sda_L);
698
+ lgGpioWrite(scl_H, scl_L, 0);
699
+ return (ack == 0) ? Qtrue : Qfalse;
700
+ }
701
+
601
702
  /*****************************************************************************/
602
703
  /* EXTENSION INIT */
603
704
  /*****************************************************************************/
@@ -605,7 +706,7 @@ void Init_lgpio(void) {
605
706
  // Modules
606
707
  VALUE mLGPIO = rb_define_module("LGPIO");
607
708
 
608
- // Basics
709
+ // Constants
609
710
  rb_define_const(mLGPIO, "SET_ACTIVE_LOW", INT2NUM(LG_SET_ACTIVE_LOW));
610
711
  rb_define_const(mLGPIO, "SET_OPEN_DRAIN", INT2NUM(LG_SET_OPEN_DRAIN));
611
712
  rb_define_const(mLGPIO, "SET_OPEN_SOURCE", INT2NUM(LG_SET_OPEN_SOURCE));
@@ -615,6 +716,11 @@ void Init_lgpio(void) {
615
716
  rb_define_const(mLGPIO, "RISING_EDGE", INT2NUM(LG_RISING_EDGE));
616
717
  rb_define_const(mLGPIO, "FALLING_EDGE", INT2NUM(LG_FALLING_EDGE));
617
718
  rb_define_const(mLGPIO, "BOTH_EDGES", INT2NUM(LG_BOTH_EDGES));
719
+
720
+ // Generic Helpers
721
+ rb_define_singleton_method(mLGPIO, "micro_delay", rbMicroDelay, 1);
722
+
723
+ // Basic GPIO
618
724
  rb_define_singleton_method(mLGPIO, "chip_open", chip_open, 1);
619
725
  rb_define_singleton_method(mLGPIO, "chip_close", chip_close, 1);
620
726
  rb_define_singleton_method(mLGPIO, "gpio_get_mode", gpio_get_mode, 2);
@@ -648,23 +754,23 @@ void Init_lgpio(void) {
648
754
  // Don't use this. Servo will jitter.
649
755
  rb_define_singleton_method(mLGPIO, "tx_servo", tx_servo, 6);
650
756
 
651
- // Hardware PWM waves for on-off-keying.
757
+ // HW PWM waves, on-off-keying only.
652
758
  VALUE cHardwarePWM = rb_define_class_under(mLGPIO, "HardwarePWM", rb_cObject);
653
759
  rb_define_method(cHardwarePWM, "tx_wave_ook", tx_wave_ook, 3);
654
760
 
655
- // I2C
761
+ // HW I2C
656
762
  rb_define_singleton_method(mLGPIO, "i2c_open", i2c_open, 3);
657
763
  rb_define_singleton_method(mLGPIO, "i2c_close", i2c_close, 1);
658
764
  rb_define_singleton_method(mLGPIO, "i2c_write_device", i2c_write_device, 2);
659
765
  rb_define_singleton_method(mLGPIO, "i2c_read_device", i2c_read_device, 2);
660
766
  rb_define_singleton_method(mLGPIO, "i2c_zip", i2c_zip, 3);
661
767
 
662
- // SPI
768
+ // HW SPI
663
769
  rb_define_singleton_method(mLGPIO, "spi_open", spi_open, 4);
664
770
  rb_define_singleton_method(mLGPIO, "spi_close", spi_close, 1);
665
771
  rb_define_singleton_method(mLGPIO, "spi_read", spi_read, 2);
666
772
  rb_define_singleton_method(mLGPIO, "spi_write", spi_write, 2);
667
- rb_define_singleton_method(mLGPIO, "spi_xfer", spi_xfer, 2);
773
+ rb_define_singleton_method(mLGPIO, "spi_xfer", spi_xfer, 3);
668
774
  rb_define_singleton_method(mLGPIO, "spi_ws2812_write", spi_ws2812_write, 2);
669
775
 
670
776
  // Bit-Bang Pulse Input
@@ -675,4 +781,8 @@ void Init_lgpio(void) {
675
781
  rb_define_singleton_method(mLGPIO, "one_wire_bit_read", one_wire_bit_read, 2);
676
782
  rb_define_singleton_method(mLGPIO, "one_wire_bit_write", one_wire_bit_write, 3);
677
783
  rb_define_singleton_method(mLGPIO, "one_wire_reset", one_wire_reset, 2);
784
+
785
+ // Bit-bang I2C Helpers
786
+ rb_define_singleton_method(mLGPIO, "i2c_bb_write_byte", i2c_bb_write_byte, 5);
787
+ rb_define_singleton_method(mLGPIO, "i2c_bb_read_byte", i2c_bb_read_byte, 5);
678
788
  }
data/lgpio.gemspec CHANGED
@@ -4,7 +4,7 @@ Gem::Specification.new do |s|
4
4
  s.name = 'lgpio'
5
5
  s.version = LGPIO::VERSION
6
6
  s.licenses = ['MIT']
7
- s.summary = "Use Linux GPIO, I2C, SPI and PWM in Ruby"
7
+ s.summary = "Ruby C extension for Linux GPIO"
8
8
  s.description = "Use Linux GPIO, I2C, SPI and PWM in Ruby"
9
9
 
10
10
  s.authors = ["vickash"]
@@ -13,5 +13,6 @@ Gem::Specification.new do |s|
13
13
  s.homepage = 'https://github.com/denko-rb/lgpio'
14
14
  s.metadata = { "source_code_uri" => "https://github.com/denko-rb/lgpio" }
15
15
 
16
+ s.required_ruby_version = '>=3'
16
17
  s.extensions = %w[ext/lgpio/extconf.rb]
17
18
  end
@@ -4,7 +4,7 @@ module LGPIO
4
4
  NS_PER_US = 1_000
5
5
  SYS_FS_PWM_PATH = "/sys/class/pwm/"
6
6
 
7
- attr_reader :period, :duty, :enabled
7
+ attr_reader :polarity, :period, :duty, :enabled
8
8
 
9
9
  def initialize(chip, channel, frequency: nil, period: nil)
10
10
  @chip = chip
@@ -16,6 +16,11 @@ module LGPIO
16
16
  end
17
17
 
18
18
  period ? self.period = period : self.frequency = frequency
19
+
20
+ # Default to with 0 duty cycle and normal polarity.
21
+ self.duty = 0
22
+ self.polarity = :normal
23
+
19
24
  enable
20
25
  end
21
26
 
@@ -23,6 +28,10 @@ module LGPIO
23
28
  @path ||= "#{SYS_FS_PWM_PATH}pwmchip#{@chip}/pwm#{@channel}/"
24
29
  end
25
30
 
31
+ def polarity_path
32
+ @polarity_path ||= "#{path}polarity"
33
+ end
34
+
26
35
  def period_path
27
36
  @period_path ||= "#{path}period"
28
37
  end
@@ -35,8 +44,24 @@ module LGPIO
35
44
  @enable_path ||= "#{path}enable"
36
45
  end
37
46
 
47
+ def polarity=(p=:normal)
48
+ if p == :inversed
49
+ File.open(polarity_path, 'w') { |f| f.write("inversed") }
50
+ @polarity = :inversed
51
+ else
52
+ File.open(polarity_path, 'w') { |f| f.write("normal") }
53
+ @polarity = :normal
54
+ end
55
+ end
56
+
38
57
  def frequency=(freq)
39
58
  self.period = (NS_PER_S / freq.to_f).round
59
+ @frequency = freq
60
+ end
61
+
62
+ def frequency
63
+ # If not set explicitly, calculate from period, rounded to nearest Hz.
64
+ @frequency ||= (1_000_000_000.0 / period).round
40
65
  end
41
66
 
42
67
  def period=(p)
@@ -45,6 +70,7 @@ module LGPIO
45
70
  File.open(duty_path, 'w') { |f| f.write("0") }
46
71
  end
47
72
  File.open(period_path, 'w') { |f| f.write(p) }
73
+ @frequency = nil
48
74
  @period = p
49
75
  end
50
76
 
@@ -20,6 +20,10 @@ module LGPIO
20
20
  initialize_pins
21
21
  end
22
22
 
23
+ def config
24
+ @config ||= [scl_handle, scl_line, sda_handle, scl_line]
25
+ end
26
+
23
27
  def initialize_pins
24
28
  LGPIO.gpio_claim_output(scl_handle, scl_line, LGPIO::SET_PULL_NONE, LGPIO::HIGH)
25
29
  LGPIO.gpio_claim_output(sda_handle, sda_line, LGPIO::SET_OPEN_DRAIN | LGPIO::SET_PULL_UP, LGPIO::HIGH)
@@ -84,6 +88,14 @@ module LGPIO
84
88
  (read_bit == 0)
85
89
  end
86
90
 
91
+ def read_byte_c(ack)
92
+ LGPIO.i2c_bb_read_byte(@scl_handle, @scl_line, @sda_handle, @sda_line, ack)
93
+ end
94
+
95
+ def write_byte_c(byte)
96
+ LGPIO.i2c_bb_write_byte(@scl_handle, @scl_line, @sda_handle, @sda_line, byte)
97
+ end
98
+
87
99
  def read(address, length)
88
100
  raise ArgumentError, "invalid I2C address: #{address}. Range is 0x08..0x77" unless VALID_ADDRESSES.include?(address)
89
101
  raise ArgumentError, "invalid Integer for read length: #{length}" unless length.kind_of?(Integer)
@@ -94,10 +106,16 @@ module LGPIO
94
106
 
95
107
  # Read length bytes, and ACK for all but the last one.
96
108
  bytes = []
97
- (length-1).times { bytes << read_byte(true) }
98
- bytes << read_byte(false)
99
- stop
100
109
 
110
+ # Bit-bang per-byte in Ruby.
111
+ # (length-1).times { bytes << read_byte(true) }
112
+ # bytes << read_byte(false)
113
+
114
+ # Bit-bang per-byte in C.
115
+ (length-1).times { bytes << read_byte_c(true) }
116
+ bytes << read_byte_c(false)
117
+
118
+ stop
101
119
  bytes
102
120
  end
103
121
 
@@ -107,7 +125,13 @@ module LGPIO
107
125
 
108
126
  start
109
127
  write_byte(write_form(address))
110
- bytes.each { |byte| write_byte(byte) }
128
+
129
+ # Bit-bang per-byte in Ruby.
130
+ # bytes.each { |byte| write_byte(byte) }
131
+
132
+ # Bit-bang per-byte in C.
133
+ bytes.each { |byte| write_byte_c(byte) }
134
+
111
135
  stop
112
136
  end
113
137
 
@@ -19,7 +19,7 @@ module LGPIO
19
19
  @handle = handle
20
20
  @gpio = gpio
21
21
  @found_addresses = []
22
- LGPIO.gpio_claim_output(handle, LGPIO::SET_OPEN_DRAIN | LGPIO::SET_PULL_UP, gpio, LGPIO::HIGH)
22
+ LGPIO.gpio_claim_output(handle, gpio, LGPIO::SET_OPEN_DRAIN | LGPIO::SET_PULL_UP, LGPIO::HIGH)
23
23
  end
24
24
 
25
25
  def reset
@@ -25,7 +25,7 @@ module LGPIO
25
25
  end
26
26
 
27
27
  def config
28
- @config ||= { handle: handle, clock: clock, input: input, output: output }
28
+ @config ||= [clock_handle, clock_line, input_handle, input_line, output_handle, output_line]
29
29
  end
30
30
 
31
31
  def initialize_pins
data/lib/lgpio/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module LGPIO
2
- VERSION = "0.1.10"
2
+ VERSION = "0.1.11"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lgpio
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.1.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - vickash
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-28 00:00:00.000000000 Z
11
+ date: 2024-10-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Use Linux GPIO, I2C, SPI and PWM in Ruby
14
14
  email: mail@vickash.com
@@ -75,7 +75,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
75
75
  requirements:
76
76
  - - ">="
77
77
  - !ruby/object:Gem::Version
78
- version: '0'
78
+ version: '3'
79
79
  required_rubygems_version: !ruby/object:Gem::Requirement
80
80
  requirements:
81
81
  - - ">="
@@ -85,5 +85,5 @@ requirements: []
85
85
  rubygems_version: 3.5.20
86
86
  signing_key:
87
87
  specification_version: 4
88
- summary: Use Linux GPIO, I2C, SPI and PWM in Ruby
88
+ summary: Ruby C extension for Linux GPIO
89
89
  test_files: []