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 +4 -4
- data/README.md +1 -1
- data/examples/i2c_bb_aht10.rb +14 -4
- data/examples/i2c_bb_search.rb +13 -3
- data/examples/i2c_bb_ssd1306_bench.rb +13 -6
- data/examples/spi_bb_loopback.rb +6 -1
- data/examples/spi_bb_sim_bench.rb +6 -1
- data/examples/spi_bb_ssd1306_bench.rb +37 -25
- 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 +55 -23
- data/lib/lgpio/one_wire.rb +1 -1
- data/lib/lgpio/spi_bitbang.rb +37 -29
- 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.):
|
data/examples/i2c_bb_aht10.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
18
|
-
|
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
|
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
|
data/examples/i2c_bb_search.rb
CHANGED
@@ -1,13 +1,23 @@
|
|
1
1
|
require 'lgpio'
|
2
2
|
|
3
|
-
|
3
|
+
SCL_CHIP = 0
|
4
4
|
SCL_PIN = 228
|
5
|
+
SDA_CHIP = 0
|
5
6
|
SDA_PIN = 270
|
6
7
|
|
7
|
-
|
8
|
-
|
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
|
-
|
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
|
-
|
14
|
-
|
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(
|
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
|
32
|
-
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
|
33
40
|
cps = (cps / 1000.0).round
|
34
41
|
|
35
42
|
puts "SSD1306 benchmark result: #{fps.round(2)} fps | #{cps}k C calls/s"
|
data/examples/spi_bb_loopback.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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(
|
24
|
-
LGPIO.gpio_write(
|
25
|
-
spi_bb.transfer(write: INIT_ARRAY, select:
|
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(
|
32
|
-
spi_bb.transfer(write: START_ARRAY, select:
|
33
|
-
LGPIO.gpio_write(
|
34
|
-
spi_bb.transfer(write: PATTERN_1, select:
|
35
|
-
LGPIO.gpio_write(
|
36
|
-
spi_bb.transfer(write: START_ARRAY, select:
|
37
|
-
LGPIO.gpio_write(
|
38
|
-
spi_bb.transfer(write: PATTERN_2, select:
|
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
|
-
|
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.
|
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
@@ -2,24 +2,36 @@ module LGPIO
|
|
2
2
|
class I2CBitBang
|
3
3
|
VALID_ADDRESSES = (0x08..0x77).to_a
|
4
4
|
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :scl_handle, :scl_line, :sda_handle, :sda_line
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
@
|
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(
|
17
|
-
LGPIO.gpio_claim_output(
|
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(
|
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(
|
35
|
-
LGPIO.gpio_write(
|
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(
|
40
|
-
LGPIO.gpio_write(
|
41
|
-
LGPIO.gpio_write(
|
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(
|
47
|
-
bit = LGPIO.gpio_read(
|
48
|
-
LGPIO.gpio_write(
|
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(
|
55
|
-
LGPIO.gpio_write(
|
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
|
-
|
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
|
|
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
@@ -1,58 +1,66 @@
|
|
1
1
|
module LGPIO
|
2
2
|
class SPIBitBang
|
3
|
-
attr_reader :
|
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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
@output = options[:output] || options[:pico] || options[:mosi]
|
7
|
+
clock = options[:clock]
|
8
|
+
input = options[:input]
|
9
|
+
output = options[:output]
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
raise ArgumentError, ":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 ||=
|
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(
|
25
|
-
LGPIO.gpio_claim_input(
|
26
|
-
LGPIO.gpio_claim_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(
|
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(
|
39
|
-
read_bit = LGPIO.gpio_read(
|
40
|
-
LGPIO.gpio_write(
|
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(
|
50
|
+
LGPIO.gpio_write(clock_handle, clock_line, 1)
|
43
51
|
set_output(write_bit) if write_bit
|
44
|
-
LGPIO.gpio_write(
|
45
|
-
read_bit = LGPIO.gpio_read(
|
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(
|
49
|
-
read_bit = LGPIO.gpio_read(
|
50
|
-
LGPIO.gpio_write(
|
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(
|
60
|
+
LGPIO.gpio_write(clock_handle, clock_line, 0)
|
53
61
|
set_output(write_bit) if write_bit
|
54
|
-
LGPIO.gpio_write(
|
55
|
-
read_bit = LGPIO.gpio_read(
|
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(
|
98
|
+
LGPIO.gpio_write(clock_handle, clock_line, 0)
|
91
99
|
when 2..3
|
92
|
-
LGPIO.gpio_write(
|
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
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: []
|