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 +4 -4
- data/README.md +1 -1
- data/examples/i2c_bb_ssd1306_bench.rb +2 -2
- data/examples/spi_bb_ssd1306_bench.rb +0 -2
- data/examples/spi_hw_loopback.rb +1 -1
- data/ext/lgpio/lgpio.c +133 -23
- data/lgpio.gemspec +2 -1
- data/lib/lgpio/hardware_pwm.rb +27 -1
- data/lib/lgpio/i2c_bitbang.rb +28 -4
- data/lib/lgpio/one_wire.rb +1 -1
- data/lib/lgpio/spi_bitbang.rb +1 -1
- data/lib/lgpio/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3371c46b2f589524fba421f579bd0f779d5e006eb62ef6d7480e8ca39cdf7540
|
4
|
+
data.tar.gz: 704f472a31ca5d9711a300ce5ce05ce89f930dd2322192a7251ce8cdab8f5abe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
39
|
-
cps = (START_ARRAY.length + ((PATTERN_1.length + PATTERN_2.length) / 2) + 2) *
|
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)
|
data/examples/spi_hw_loopback.rb
CHANGED
@@ -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),
|
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 (
|
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 (
|
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
|
278
|
-
|
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(
|
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
|
-
|
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
|
-
|
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
|
-
|
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<
|
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
|
-
|
384
|
-
|
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(
|
390
|
-
for(int i=0; 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
|
-
|
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(
|
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
|
-
//
|
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
|
-
//
|
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,
|
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 = "
|
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
|
data/lib/lgpio/hardware_pwm.rb
CHANGED
@@ -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
|
|
data/lib/lgpio/i2c_bitbang.rb
CHANGED
@@ -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
|
-
|
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
|
|
data/lib/lgpio/one_wire.rb
CHANGED
@@ -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,
|
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
|
data/lib/lgpio/spi_bitbang.rb
CHANGED
data/lib/lgpio/version.rb
CHANGED
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.
|
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-
|
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: '
|
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:
|
88
|
+
summary: Ruby C extension for Linux GPIO
|
89
89
|
test_files: []
|