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 +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: []
|