lgpio 0.1.9 → 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: 968e706762503c9d172b41ff4df8a9c17021af5b4a4cb4372eeaaa166c30f5ff
4
- data.tar.gz: 82d8221f8e28293f542c4bd1913f85addb567c217d071fdbb1e47451c3be1da1
3
+ metadata.gz: 3371c46b2f589524fba421f579bd0f779d5e006eb62ef6d7480e8ca39cdf7540
4
+ data.tar.gz: 704f472a31ca5d9711a300ce5ce05ce89f930dd2322192a7251ce8cdab8f5abe
5
5
  SHA512:
6
- metadata.gz: 8749280110629032e20ac94c203c512a699e90b58266f78f7c26a9305b8e22ef0f97822247744403c2723b7417838b5972c2618a65ebcb0ee2ae483cd0d12e41
7
- data.tar.gz: a9bbac8e2f8c80de6adf86249bf559b10c590234597a15d3bf6dce37bc3b60ce27856f2343bdc1fe885a1a78105401419e221eb0ae5a10fa404ec7fc9c90a4fd
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.):
@@ -9,13 +9,19 @@ SOFT_RESET = [0xBA]
9
9
  INIT_AND_CALIBRATE = [0xE1, 0x08, 0x00]
10
10
  START_MEASUREMENT = [0xAC, 0x33, 0x00]
11
11
 
12
- GPIO_CHIP = 0
12
+ SCL_CHIP = 0
13
13
  SCL_PIN = 228
14
+ SDA_CHIP = 0
14
15
  SDA_PIN = 270
15
16
  ADDRESS = 0x38
16
17
 
17
- chip_handle = LGPIO.chip_open(GPIO_CHIP)
18
- i2c_bb = LGPIO::I2CBitBang.new(chip_handle, SCL_PIN, SDA_PIN)
18
+ scl_handle = LGPIO.chip_open(SCL_CHIP)
19
+ sda_handle = (SCL_CHIP == SDA_CHIP) ? scl_handle : LGPIO.chip_open(SDA_CHIP)
20
+ pin_hash = {
21
+ scl: { handle: scl_handle, line: SCL_PIN },
22
+ sda: { handle: sda_handle, line: SDA_PIN },
23
+ }
24
+ i2c_bb = LGPIO::I2CBitBang.new(pin_hash)
19
25
 
20
26
  # Startup sequence
21
27
  sleep(POWER_ON_DELAY)
@@ -24,11 +30,15 @@ sleep(RESET_DELAY)
24
30
  i2c_bb.write(ADDRESS, INIT_AND_CALIBRATE)
25
31
  sleep(COMMAND_DELAY)
26
32
 
27
- # Read and close
33
+ # Read
28
34
  i2c_bb.write(ADDRESS, START_MEASUREMENT)
29
35
  sleep(MEASURE_DELAY)
30
36
  bytes = i2c_bb.read(ADDRESS, DATA_LENGTH)
31
37
 
38
+ # Close
39
+ LGPIO.chip_close(scl_handle)
40
+ LGPIO.chip_close(sda_handle) unless (scl_handle == sda_handle)
41
+
32
42
  # Humidity uses the upper 4 bits of the shared byte as its lowest 4 bits.
33
43
  h_raw = ((bytes[1] << 16) | (bytes[2] << 8) | (bytes[3])) >> 4
34
44
  humidity = (h_raw.to_f / 2**20) * 100
@@ -1,13 +1,23 @@
1
1
  require 'lgpio'
2
2
 
3
- GPIO_CHIP = 0
3
+ SCL_CHIP = 0
4
4
  SCL_PIN = 228
5
+ SDA_CHIP = 0
5
6
  SDA_PIN = 270
6
7
 
7
- chip_handle = LGPIO.chip_open(GPIO_CHIP)
8
- i2c_bb = LGPIO::I2CBitBang.new(chip_handle, SCL_PIN, SDA_PIN)
8
+ scl_handle = LGPIO.chip_open(SCL_CHIP)
9
+ sda_handle = (SCL_CHIP == SDA_CHIP) ? scl_handle : LGPIO.chip_open(SDA_CHIP)
10
+ pin_hash = {
11
+ scl: { handle: scl_handle, line: SCL_PIN },
12
+ sda: { handle: sda_handle, line: SDA_PIN },
13
+ }
14
+ i2c_bb = LGPIO::I2CBitBang.new(pin_hash)
15
+
9
16
  devices = i2c_bb.search
10
17
 
18
+ LGPIO.chip_close(scl_handle)
19
+ LGPIO.chip_close(sda_handle) unless (scl_handle == sda_handle)
20
+
11
21
  if devices.empty?
12
22
  puts "No devices found on I2C bus"
13
23
  else
@@ -5,13 +5,19 @@ START_ARRAY = [0, 33, 0, 127, 34, 0, 7]
5
5
  PATTERN_1 = [64] + Array.new(1024) { 0b00110011 }
6
6
  PATTERN_2 = [64] + Array.new(1024) { 0b11001100 }
7
7
 
8
- GPIO_CHIP = 0
8
+ SCL_CHIP = 0
9
9
  SCL_PIN = 228
10
+ SDA_CHIP = 0
10
11
  SDA_PIN = 270
11
12
  ADDRESS = 0x3C
12
13
 
13
- chip_handle = LGPIO.chip_open(GPIO_CHIP)
14
- i2c_bb = LGPIO::I2CBitBang.new(chip_handle, SCL_PIN, SDA_PIN)
14
+ scl_handle = LGPIO.chip_open(SCL_CHIP)
15
+ sda_handle = (SCL_CHIP == SDA_CHIP) ? scl_handle : LGPIO.chip_open(SDA_CHIP)
16
+ pin_hash = {
17
+ scl: { handle: scl_handle, line: SCL_PIN },
18
+ sda: { handle: sda_handle, line: SDA_PIN },
19
+ }
20
+ i2c_bb = LGPIO::I2CBitBang.new(pin_hash)
15
21
 
16
22
  i2c_bb.write(ADDRESS, INIT_ARRAY)
17
23
  FRAME_COUNT = 400
@@ -25,11 +31,12 @@ start = Time.now
25
31
  end
26
32
  finish = Time.now
27
33
 
28
- LGPIO.chip_close(chip_handle)
34
+ LGPIO.chip_close(scl_handle)
35
+ LGPIO.chip_close(sda_handle) unless (scl_handle == sda_handle)
29
36
 
30
37
  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
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
33
40
  cps = (cps / 1000.0).round
34
41
 
35
42
  puts "SSD1306 benchmark result: #{fps.round(2)} fps | #{cps}k C calls/s"
@@ -10,7 +10,12 @@ ORDERS = [:msbfirst, :lsbfirst]
10
10
  TX_BYTES = [0, 1, 2, 3, 4, 5, 6, 7]
11
11
 
12
12
  chip_handle = LGPIO.chip_open(GPIO_CHIP)
13
- spi_bb = LGPIO::SPIBitBang.new(handle: chip_handle, clock: CLOCK_PIN, input: INPUT_PIN, output: OUTPUT_PIN)
13
+ pin_hash = {
14
+ clock: { handle: chip_handle, line: CLOCK_PIN },
15
+ input: { handle: chip_handle, line: INPUT_PIN },
16
+ output: { handle: chip_handle, line: OUTPUT_PIN },
17
+ }
18
+ spi_bb = LGPIO::SPIBitBang.new(pin_hash)
14
19
 
15
20
  puts "TX bytes => #{TX_BYTES.inspect}"
16
21
 
@@ -12,7 +12,12 @@ PATTERN_2 = [0x3C << 1] + [64] + Array.new(1179) { 0b11001100 }
12
12
  FRAME_COUNT = 400
13
13
 
14
14
  chip_handle = LGPIO.chip_open(GPIO_CHIP)
15
- spi_bb = LGPIO::SPIBitBang.new(handle: chip_handle, clock: CLOCK_PIN, input: INPUT_PIN, output: OUTPUT_PIN)
15
+ pin_hash = {
16
+ clock: { handle: chip_handle, line: CLOCK_PIN },
17
+ input: { handle: chip_handle, line: INPUT_PIN },
18
+ output: { handle: chip_handle, line: OUTPUT_PIN },
19
+ }
20
+ spi_bb = LGPIO::SPIBitBang.new(pin_hash)
16
21
 
17
22
  start = Time.now
18
23
  (FRAME_COUNT / 2).times do
@@ -5,41 +5,53 @@ START_ARRAY = [0, 33, 0, 127, 34, 0, 7]
5
5
  PATTERN_1 = Array.new(1024) { 0b00110011 }
6
6
  PATTERN_2 = Array.new(1024) { 0b11001100 }
7
7
 
8
- GPIO_CHIP = 0
9
- CLOCK_PIN = 17
10
- OUTPUT_PIN = 27
11
- SELECT_PIN = 22
12
- RESET_PIN = 5
13
- DC_PIN = 6
14
-
15
- # Initialize
16
- chip_handle = LGPIO.chip_open(GPIO_CHIP)
17
- spi_bb = LGPIO::SPIBitBang.new(handle: chip_handle, clock: CLOCK_PIN, output: OUTPUT_PIN)
18
- LGPIO.gpio_claim_output(chip_handle, SELECT_PIN, LGPIO::SET_PULL_NONE, LGPIO::HIGH)
19
- LGPIO.gpio_claim_output(chip_handle, RESET_PIN, LGPIO::SET_PULL_NONE, LGPIO::LOW)
20
- LGPIO.gpio_claim_output(chip_handle, DC_PIN, LGPIO::SET_PULL_NONE, LGPIO::LOW)
8
+ # Pins for Radxa Zero 3W
9
+ # Demonstration of how to use GPIOs across multiple /dev/gpiochip devices.
10
+ pins = {
11
+ clock: { chip: 1, line: 4 },
12
+ output: { chip: 3, line: 4 },
13
+ reset: { chip: 3, line: 5 },
14
+ dc: { chip: 3, line: 6 },
15
+ cs: { chip: 3, line: 7 },
16
+ }
17
+
18
+ # Open chip handles without duplicating.
19
+ open_handles = []
20
+ pins.each_value do |hash|
21
+ if hash[:handle] = open_handles[hash[:chip]]
22
+ else
23
+ hash[:handle] = LGPIO.chip_open(hash[:chip])
24
+ open_handles[hash[:chip]] = hash[:handle]
25
+ end
26
+ end
27
+
28
+ spi_bb = LGPIO::SPIBitBang.new(clock: pins[:clock], output: pins[:output])
29
+ LGPIO.gpio_claim_output(pins[:reset][:handle], pins[:reset][:line], LGPIO::SET_PULL_NONE, LGPIO::LOW)
30
+ LGPIO.gpio_claim_output(pins[:dc][:handle], pins[:dc][:line], LGPIO::SET_PULL_NONE, LGPIO::LOW)
31
+ LGPIO.gpio_claim_output(pins[:cs][:handle], pins[:cs][:line], LGPIO::SET_PULL_NONE, LGPIO::HIGH)
21
32
 
22
33
  # OLED STARTUP
23
- LGPIO.gpio_write(chip_handle, RESET_PIN, 1)
24
- LGPIO.gpio_write(chip_handle, DC_PIN, 0)
25
- spi_bb.transfer(write: INIT_ARRAY, select: SELECT_PIN)
34
+ LGPIO.gpio_write(pins[:reset][:handle], pins[:reset][:line], 1)
35
+ LGPIO.gpio_write(pins[:dc][:handle], pins[:dc][:line], 0)
36
+ spi_bb.transfer(write: INIT_ARRAY, select: pins[:cs])
26
37
 
27
38
  FRAME_COUNT = 400
28
39
 
29
40
  start = Time.now
30
41
  (FRAME_COUNT / 2).times do
31
- LGPIO.gpio_write(chip_handle, DC_PIN, 0)
32
- spi_bb.transfer(write: START_ARRAY, select: SELECT_PIN)
33
- LGPIO.gpio_write(chip_handle, DC_PIN, 1)
34
- spi_bb.transfer(write: PATTERN_1, select: SELECT_PIN)
35
- LGPIO.gpio_write(chip_handle, DC_PIN, 0)
36
- spi_bb.transfer(write: START_ARRAY, select: SELECT_PIN)
37
- LGPIO.gpio_write(chip_handle, DC_PIN, 1)
38
- spi_bb.transfer(write: PATTERN_2, select: SELECT_PIN)
42
+ LGPIO.gpio_write(pins[:dc][:handle], pins[:dc][:line], 0)
43
+ spi_bb.transfer(write: START_ARRAY, select: pins[:cs])
44
+ LGPIO.gpio_write(pins[:dc][:handle], pins[:dc][:line], 1)
45
+ spi_bb.transfer(write: PATTERN_1, select: pins[:cs])
46
+ LGPIO.gpio_write(pins[:dc][:handle], pins[:dc][:line], 0)
47
+ spi_bb.transfer(write: START_ARRAY, select: pins[:cs])
48
+ LGPIO.gpio_write(pins[:dc][:handle], pins[:dc][:line], 1)
49
+ spi_bb.transfer(write: PATTERN_2, select: pins[:cs])
39
50
  end
40
51
  finish = Time.now
41
52
 
42
- LGPIO.chip_close(chip_handle)
53
+ # Close all handles.
54
+ open_handles.compact.each { |h| LGPIO.chip_close(h) }
43
55
 
44
56
  fps = FRAME_COUNT / (finish - start)
45
57
  # Also calculate C calls per second, using roughly 20 calls per byte written.
@@ -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
 
@@ -2,24 +2,36 @@ module LGPIO
2
2
  class I2CBitBang
3
3
  VALID_ADDRESSES = (0x08..0x77).to_a
4
4
 
5
- attr_reader :handle, :scl, :sda
5
+ attr_reader :scl_handle, :scl_line, :sda_handle, :sda_line
6
6
 
7
- def initialize(handle, scl, sda)
8
- @handle = handle
9
- @scl = scl
10
- @sda = sda
11
- @sda_state = nil
7
+ def initialize(options={})
8
+ scl = options[:scl]
9
+ sda = options[:sda]
10
+
11
+ @scl_handle = scl[:handle] if scl
12
+ @scl_line = scl[:line] if scl
13
+ raise ArgumentError, ":scl pin required as Hash, with :handle and :line required" unless (@scl_handle && @scl_line)
14
+
15
+ @sda_handle = sda[:handle] if sda
16
+ @sda_line = sda[:line] if sda
17
+ raise ArgumentError, ":sda pin required as Hash, with :handle and :line required" unless (@sda_handle && @sda_line)
18
+
19
+ @sda_state = nil
12
20
  initialize_pins
13
21
  end
14
22
 
23
+ def config
24
+ @config ||= [scl_handle, scl_line, sda_handle, scl_line]
25
+ end
26
+
15
27
  def initialize_pins
16
- LGPIO.gpio_claim_output(handle, LGPIO::SET_PULL_NONE, scl, LGPIO::HIGH)
17
- LGPIO.gpio_claim_output(handle, LGPIO::SET_OPEN_DRAIN | LGPIO::SET_PULL_UP, sda, LGPIO::HIGH)
28
+ LGPIO.gpio_claim_output(scl_handle, scl_line, LGPIO::SET_PULL_NONE, LGPIO::HIGH)
29
+ LGPIO.gpio_claim_output(sda_handle, sda_line, LGPIO::SET_OPEN_DRAIN | LGPIO::SET_PULL_UP, LGPIO::HIGH)
18
30
  end
19
31
 
20
32
  def set_sda(value)
21
33
  return if (@sda_state == value)
22
- LGPIO.gpio_write(handle, sda, @sda_state = value)
34
+ LGPIO.gpio_write(sda_handle, sda_line, @sda_state = value)
23
35
  end
24
36
 
25
37
  def write_form(address)
@@ -31,28 +43,28 @@ module LGPIO
31
43
  end
32
44
 
33
45
  def start
34
- LGPIO.gpio_write(handle, sda, 0)
35
- LGPIO.gpio_write(handle, scl, 0)
46
+ LGPIO.gpio_write(sda_handle, sda_line, 0)
47
+ LGPIO.gpio_write(scl_handle, scl_line, 0)
36
48
  end
37
49
 
38
50
  def stop
39
- LGPIO.gpio_write(handle, sda, 0)
40
- LGPIO.gpio_write(handle, scl, 1)
41
- LGPIO.gpio_write(handle, sda, 1)
51
+ LGPIO.gpio_write(sda_handle, sda_line, 0)
52
+ LGPIO.gpio_write(scl_handle, scl_line, 1)
53
+ LGPIO.gpio_write(sda_handle, sda_line, 1)
42
54
  end
43
55
 
44
56
  def read_bit
45
57
  set_sda(1)
46
- LGPIO.gpio_write(handle, scl, 1)
47
- bit = LGPIO.gpio_read(handle, sda)
48
- LGPIO.gpio_write(handle, scl, 0)
58
+ LGPIO.gpio_write(scl_handle, scl_line, 1)
59
+ bit = LGPIO.gpio_read(sda_handle, sda_line)
60
+ LGPIO.gpio_write(scl_handle, scl_line, 0)
49
61
  bit
50
62
  end
51
63
 
52
64
  def write_bit(bit)
53
65
  set_sda(bit)
54
- LGPIO.gpio_write(handle, scl, 1)
55
- LGPIO.gpio_write(handle, scl, 0)
66
+ LGPIO.gpio_write(scl_handle, scl_line, 1)
67
+ LGPIO.gpio_write(scl_handle, scl_line, 0)
56
68
  end
57
69
 
58
70
  def read_byte(ack)
@@ -76,6 +88,14 @@ module LGPIO
76
88
  (read_bit == 0)
77
89
  end
78
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
+
79
99
  def read(address, length)
80
100
  raise ArgumentError, "invalid I2C address: #{address}. Range is 0x08..0x77" unless VALID_ADDRESSES.include?(address)
81
101
  raise ArgumentError, "invalid Integer for read length: #{length}" unless length.kind_of?(Integer)
@@ -86,10 +106,16 @@ module LGPIO
86
106
 
87
107
  # Read length bytes, and ACK for all but the last one.
88
108
  bytes = []
89
- (length-1).times { bytes << read_byte(true) }
90
- bytes << read_byte(false)
91
- stop
92
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
93
119
  bytes
94
120
  end
95
121
 
@@ -99,7 +125,13 @@ module LGPIO
99
125
 
100
126
  start
101
127
  write_byte(write_form(address))
102
- 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
+
103
135
  stop
104
136
  end
105
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
@@ -1,58 +1,66 @@
1
1
  module LGPIO
2
2
  class SPIBitBang
3
- attr_reader :handle, :clock, :input, :output
3
+ attr_reader :clock_handle, :input_handle, :output_handle
4
+ attr_reader :clock_line, :input_line, :output_line
4
5
 
5
6
  def initialize(options={})
6
- @handle = options[:handle]
7
- @clock = options[:clock] || options[:sck] || options[:clk]
8
- @input = options[:input] || options[:poci] || options[:miso]
9
- @output = options[:output] || options[:pico] || options[:mosi]
7
+ clock = options[:clock]
8
+ input = options[:input]
9
+ output = options[:output]
10
10
 
11
- raise ArgumentError, "a gpiochip :handle is required" unless @handle
12
- raise ArgumentError, "either input/:poci/:miso OR :output/:pico/:mosi pin required" unless (@input || @output)
13
- raise ArgumentError, ":clock/:sck/:clk pin required" unless @clock
11
+ @clock_handle = clock[:handle] if clock
12
+ @clock_line = clock[:line] if clock
13
+ raise ArgumentError, ":clock pin required as Hash, with :handle and :line required" unless (@clock_handle && @clock_line)
14
+
15
+ @input_handle = input[:handle] if input
16
+ @input_line = input[:line] if input
17
+ @output_handle = output[:handle] if output
18
+ @output_line = output[:line] if output
19
+ unless ((@input_handle && @input_line) || (@output_handle && @output_line))
20
+ raise ArgumentError, "either :input or :output pin required as Hash, with :handle and :line required"
21
+ end
14
22
 
15
23
  @output_state = nil
16
24
  initialize_pins
17
25
  end
18
26
 
19
27
  def config
20
- @config ||= { handle: handle, clock: clock, input: input, output: output }
28
+ @config ||= [clock_handle, clock_line, input_handle, input_line, output_handle, output_line]
21
29
  end
22
30
 
23
31
  def initialize_pins
24
- LGPIO.gpio_claim_output(handle, LGPIO::SET_PULL_NONE, clock, LGPIO::LOW)
25
- LGPIO.gpio_claim_input(handle, LGPIO::SET_PULL_NONE, input) if input
26
- LGPIO.gpio_claim_output(handle, LGPIO::SET_PULL_NONE, output, LGPIO::LOW) if output
32
+ LGPIO.gpio_claim_output(clock_handle, clock_line, LGPIO::SET_PULL_NONE, LGPIO::LOW)
33
+ LGPIO.gpio_claim_input(input_handle, input_line, LGPIO::SET_PULL_NONE) if input_line
34
+ LGPIO.gpio_claim_output(output_handle, output_line, LGPIO::SET_PULL_NONE, LGPIO::LOW) if output_line
27
35
  end
28
36
 
29
37
  def set_output(level)
30
38
  return if (level == @output_state)
31
- LGPIO.gpio_write(handle, output, @output_state = level)
39
+ LGPIO.gpio_write(output_handle, output_line, @output_state = level)
32
40
  end
33
41
 
34
42
  def transfer_bit(write_bit, reading: false, mode: 0)
35
43
  case mode
36
44
  when 0
37
45
  set_output(write_bit) if write_bit
38
- LGPIO.gpio_write(handle, clock, 1)
39
- read_bit = LGPIO.gpio_read(handle, input) if reading
40
- LGPIO.gpio_write(handle, clock, 0)
46
+ LGPIO.gpio_write(clock_handle, clock_line, 1)
47
+ read_bit = LGPIO.gpio_read(input_handle, input_line) if reading
48
+ LGPIO.gpio_write(clock_handle, clock_line, 0)
41
49
  when 1
42
- LGPIO.gpio_write(handle, clock, 1)
50
+ LGPIO.gpio_write(clock_handle, clock_line, 1)
43
51
  set_output(write_bit) if write_bit
44
- LGPIO.gpio_write(handle, clock, 0)
45
- read_bit = LGPIO.gpio_read(handle, input) if reading
52
+ LGPIO.gpio_write(clock_handle, clock_line, 0)
53
+ read_bit = LGPIO.gpio_read(input_handle, input_line) if reading
46
54
  when 2
47
55
  set_output(write_bit) if write_bit
48
- LGPIO.gpio_write(handle, clock, 0)
49
- read_bit = LGPIO.gpio_read(handle, input) if reading
50
- LGPIO.gpio_write(handle, clock, 1)
56
+ LGPIO.gpio_write(clock_handle, clock_line, 0)
57
+ read_bit = LGPIO.gpio_read(input_handle, input_line) if reading
58
+ LGPIO.gpio_write(clock_handle, clock_line, 1)
51
59
  when 3
52
- LGPIO.gpio_write(handle, clock, 0)
60
+ LGPIO.gpio_write(clock_handle, clock_line, 0)
53
61
  set_output(write_bit) if write_bit
54
- LGPIO.gpio_write(handle, clock, 1)
55
- read_bit = LGPIO.gpio_read(handle, input) if reading
62
+ LGPIO.gpio_write(clock_handle, clock_line, 1)
63
+ read_bit = LGPIO.gpio_read(input_handle, input_line) if reading
56
64
  else
57
65
  raise ArgumentError, "invalid SPI mode: #{mode} given"
58
66
  end
@@ -87,9 +95,9 @@ module LGPIO
87
95
  # Idle clock state depends on SPI mode.
88
96
  case mode
89
97
  when 0..1
90
- LGPIO.gpio_write(handle, clock, 0)
98
+ LGPIO.gpio_write(clock_handle, clock_line, 0)
91
99
  when 2..3
92
- LGPIO.gpio_write(handle, clock, 1)
100
+ LGPIO.gpio_write(clock_handle, clock_line, 1)
93
101
  else
94
102
  raise ArgumentError, "invalid SPI mode: #{mode} given"
95
103
  end
@@ -97,7 +105,7 @@ module LGPIO
97
105
  raise ArgumentError, "invalid Integer for read: #{read}" unless read.kind_of?(Integer)
98
106
 
99
107
  read_bytes = (read > 0) ? [] : nil
100
- LGPIO.gpio_write(handle, select, 0) if select
108
+ LGPIO.gpio_write(select[:handle], select[:line], 0) if select
101
109
 
102
110
  i = 0
103
111
  while (i < read) || (i < write.length)
@@ -106,7 +114,7 @@ module LGPIO
106
114
  i = i + 1
107
115
  end
108
116
 
109
- LGPIO.gpio_write(handle, select, 1) if select
117
+ LGPIO.gpio_write(select[:handle], select[:line], 1) if select
110
118
  read_bytes
111
119
  end
112
120
  end
data/lib/lgpio/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module LGPIO
2
- VERSION = "0.1.9"
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.9
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: []