lgpio 0.1.10 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
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: []