lgpio 0.1.2 → 0.1.3
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 +49 -11
- data/examples/i2c_aht10.rb +36 -0
- data/examples/i2c_aht10_zip.rb +36 -0
- data/examples/i2c_ssd1306_bench.rb +25 -0
- data/examples/reports.rb +1 -0
- data/examples/rotary_encoder.rb +3 -0
- data/examples/rotary_encoder_led.rb +56 -0
- data/examples/spi_loopback.rb +18 -0
- data/examples/spi_read.rb +14 -0
- data/examples/spi_ws2812.rb +60 -0
- data/ext/lgpio/lgpio.c +150 -3
- data/lib/lgpio/version.rb +1 -1
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e24e221cb39d27714d3fdd9486c47dd01e33115980d29e5104a455e14fd40890
|
4
|
+
data.tar.gz: 4ffd6e35644bc8dcde49486cd43d8e7ca73ebbfe9b46955a8de89a4ecff49d33
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5060a2fd7a5ef20a1de29f01a87aa2ff2639c9d0e9005594de672d7fa011df48e7a65b893ad4310d07d780f9677c1544ccc80018a5bb4794e014513f4864fae4
|
7
|
+
data.tar.gz: 16e6a32af1a358ffcf18c7864d2748527f635a83f42734fc3191ecb6eed7fb50cef3ffe4370651b063fde6e4a28bd2075a12b6adb8d04b3e4646353d973515c3
|
data/README.md
CHANGED
@@ -1,16 +1,54 @@
|
|
1
1
|
# lgpio
|
2
2
|
|
3
|
-
Ruby bindings for the [lgpio (lg)](https://github.com/joan2937/lg) C library,
|
3
|
+
Ruby bindings for the [lgpio (lg)](https://github.com/joan2937/lg) C library, for Linux on single board computers (SBCs), like the Raspberry Pi and its competitors.
|
4
4
|
|
5
|
-
|
5
|
+
## Features
|
6
|
+
- GPIO Read/Write
|
7
|
+
- GPIO Group Read/Write
|
8
|
+
- GPIO Alerts / Callbacks
|
9
|
+
- lg generates alerts at high speed, in a separate thread. In Ruby they can be read from a queue as part of your application loop.
|
10
|
+
- PWM Output
|
11
|
+
- Software timed on any pin. No interface for hardware PWM yet.
|
12
|
+
- Wave
|
13
|
+
- Software timed on any pin, as with PWM.
|
14
|
+
- I2C
|
15
|
+
- SPI
|
6
16
|
|
7
|
-
|
17
|
+
## Installation
|
18
|
+
On Debian-based Linuxes (RaspberryPi OS, Armbian, DietPi etc.):
|
19
|
+
```bash
|
20
|
+
sudo apt install swig python3-dev python3-setuptools
|
8
21
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
-
|
16
|
-
|
22
|
+
# NOTE: There's a bug with GPIO numbers > 255.
|
23
|
+
# If you need to use those, wget the second URL instead, until that fix is merged.
|
24
|
+
wget https://github.com/joan2937/lg/archive/master.zip
|
25
|
+
# wget https://github.com/vickash/lg/archive/refs/heads/master.zip
|
26
|
+
|
27
|
+
unzip master.zip
|
28
|
+
cd lg-master
|
29
|
+
make
|
30
|
+
sudo make install
|
31
|
+
|
32
|
+
gem install lgpio
|
33
|
+
```
|
34
|
+
|
35
|
+
## Enabling Hardware & Permissions
|
36
|
+
Depending on your SBC and Linux distro/version, you may need to manually enable I2C and SPI hardware. You may use the setup or config tool that came with your distro for that.
|
37
|
+
|
38
|
+
You may also not have permission to access some or all of the GPIO and peripherals. To run without `sudo`, you will need read+write permission to some or all of the following devices:
|
39
|
+
```
|
40
|
+
/dev/gpiochip* (For GPIO, example: /dev/gpiochip0)
|
41
|
+
/dev/i2c-* (For I2C, example: /dev/i2c-1)
|
42
|
+
/dev/spidev* (For SPI, example: /dev/spidev-0.1)
|
43
|
+
```
|
44
|
+
|
45
|
+
## Documentation
|
46
|
+
- See examples folder for demos of every implemented interface.
|
47
|
+
- Development was done on an Orange Pi Zero 2W. Your GPIO numbers will be different, so change them.
|
48
|
+
- For more info, see the [lgpio C API docs.](https://abyz.me.uk/lg/lgpio.html)
|
49
|
+
- As much as possible, the Ruby methods closely follow the C API functions, except:
|
50
|
+
- Snake case instead of camel case names for methods.
|
51
|
+
- Method names have the leading `lg` removed, since inside the `LGPIO` class.
|
52
|
+
- Constants have leading `LG_` removed, as above.
|
53
|
+
- "count" or "length" arguments associated with array args are not needed.
|
54
|
+
- Check the return values of your method calls. On failure, they return negative values values, matching the `LG_` error codes at the bottom of the C API doc page.
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
|
3
|
+
I2C_DEV = 2
|
4
|
+
POWER_ON_DELAY = 0.100
|
5
|
+
RESET_DELAY = 0.020
|
6
|
+
COMMAND_DELAY = 0.010
|
7
|
+
MEASURE_DELAY = 0.080
|
8
|
+
DATA_LENGTH = 6
|
9
|
+
SOFT_RESET = [0xBA]
|
10
|
+
INIT_AND_CALIBRATE = [0xE1, 0x08, 0x00]
|
11
|
+
START_MEASUREMENT = [0xAC, 0x33, 0x00]
|
12
|
+
|
13
|
+
aht10_handle = LGPIO.i2c_open(I2C_DEV, 0x38, 0)
|
14
|
+
|
15
|
+
# Startup sequence
|
16
|
+
sleep(POWER_ON_DELAY)
|
17
|
+
LGPIO.i2c_write_device(aht10_handle, SOFT_RESET)
|
18
|
+
sleep(RESET_DELAY)
|
19
|
+
LGPIO.i2c_write_device(aht10_handle, INIT_AND_CALIBRATE)
|
20
|
+
sleep(COMMAND_DELAY)
|
21
|
+
|
22
|
+
# Read and close
|
23
|
+
LGPIO.i2c_write_device(aht10_handle, START_MEASUREMENT)
|
24
|
+
sleep(MEASURE_DELAY)
|
25
|
+
bytes = LGPIO.i2c_read_device(aht10_handle, DATA_LENGTH)
|
26
|
+
LGPIO.i2c_close(aht10_handle)
|
27
|
+
|
28
|
+
# Humidity uses the upper 4 bits of the shared byte as its lowest 4 bits.
|
29
|
+
h_raw = ((bytes[1] << 16) | (bytes[2] << 8) | (bytes[3])) >> 4
|
30
|
+
humidity = (h_raw.to_f / 2**20) * 100
|
31
|
+
|
32
|
+
# Temperature uses the lower 4 bits of the shared byte as its highest 4 bits.
|
33
|
+
t_raw = ((bytes[3] & 0x0F) << 16) | (bytes[4] << 8) | bytes[5]
|
34
|
+
temperature = (t_raw.to_f / 2**20) * 200 - 50
|
35
|
+
|
36
|
+
puts "#{Time.now.strftime '%Y-%m-%d %H:%M:%S'} - Temperature: #{temperature.round(2)} \xC2\xB0C | Humidity: #{humidity.round(2)} %"
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
|
3
|
+
I2C_DEV = 2
|
4
|
+
POWER_ON_DELAY = 0.100
|
5
|
+
RESET_DELAY = 0.020
|
6
|
+
COMMAND_DELAY = 0.010
|
7
|
+
MEASURE_DELAY = 0.080
|
8
|
+
SOFT_RESET = [5, 1, 0xBA, 0]
|
9
|
+
INIT_AND_CALIBRATE = [5, 3, 0xE1, 0x08, 0x00, 0]
|
10
|
+
START_MEASUREMENT = [5, 3, 0xAC, 0x33, 0x00, 0]
|
11
|
+
READ_SIX = [4, 6, 0]
|
12
|
+
|
13
|
+
aht10_handle = LGPIO.i2c_open(I2C_DEV, 0x38, 0)
|
14
|
+
|
15
|
+
# Startup sequence
|
16
|
+
sleep(POWER_ON_DELAY)
|
17
|
+
LGPIO.i2c_zip(aht10_handle, SOFT_RESET, 0)
|
18
|
+
sleep(RESET_DELAY)
|
19
|
+
LGPIO.i2c_zip(aht10_handle, INIT_AND_CALIBRATE, 0)
|
20
|
+
sleep(COMMAND_DELAY)
|
21
|
+
|
22
|
+
# Read and close
|
23
|
+
LGPIO.i2c_zip(aht10_handle, START_MEASUREMENT, 0)
|
24
|
+
sleep(MEASURE_DELAY)
|
25
|
+
bytes = LGPIO.i2c_zip(aht10_handle, READ_SIX, 6)
|
26
|
+
LGPIO.i2c_close(aht10_handle)
|
27
|
+
|
28
|
+
# Humidity uses the upper 4 bits of the shared byte as its lowest 4 bits.
|
29
|
+
h_raw = ((bytes[1] << 16) | (bytes[2] << 8) | (bytes[3])) >> 4
|
30
|
+
humidity = (h_raw.to_f / 2**20) * 100
|
31
|
+
|
32
|
+
# Temperature uses the lower 4 bits of the shared byte as its highest 4 bits.
|
33
|
+
t_raw = ((bytes[3] & 0x0F) << 16) | (bytes[4] << 8) | bytes[5]
|
34
|
+
temperature = (t_raw.to_f / 2**20) * 200 - 50
|
35
|
+
|
36
|
+
puts "#{Time.now.strftime '%Y-%m-%d %H:%M:%S'} - Temperature: #{temperature.round(2)} \xC2\xB0C | Humidity: #{humidity.round(2)} %"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
|
3
|
+
I2C_DEV = 2
|
4
|
+
INIT_ARRAY = [0, 168, 63, 211, 0, 64, 161, 200, 218, 18, 164, 166, 213, 128, 219, 32, 217, 241, 141, 20, 32, 0, 175]
|
5
|
+
START_ARRAY = [0, 33, 0, 127, 34, 0, 7]
|
6
|
+
BLANK_ARRAY = [64] + Array.new(1024) { 0 }
|
7
|
+
FILL_ARRAY = [64] + Array.new(1024) { 255 }
|
8
|
+
|
9
|
+
ssd1306_handle = LGPIO.i2c_open(I2C_DEV, 0x3C, 0)
|
10
|
+
LGPIO.i2c_write_device(ssd1306_handle, INIT_ARRAY)
|
11
|
+
FRAME_COUNT = 100
|
12
|
+
|
13
|
+
start = Time.now
|
14
|
+
(FRAME_COUNT / 2).times do
|
15
|
+
LGPIO.i2c_write_device(ssd1306_handle, START_ARRAY)
|
16
|
+
LGPIO.i2c_write_device(ssd1306_handle, FILL_ARRAY)
|
17
|
+
LGPIO.i2c_write_device(ssd1306_handle, START_ARRAY)
|
18
|
+
LGPIO.i2c_write_device(ssd1306_handle, BLANK_ARRAY)
|
19
|
+
end
|
20
|
+
finish = Time.now
|
21
|
+
|
22
|
+
LGPIO.i2c_close(ssd1306_handle)
|
23
|
+
|
24
|
+
fps = FRAME_COUNT / (finish - start)
|
25
|
+
puts "SSD1306 benchmark result: #{fps.round(2)} fps"
|
data/examples/reports.rb
CHANGED
data/examples/rotary_encoder.rb
CHANGED
@@ -18,12 +18,15 @@ chip_handle = LGPIO.chip_open(GPIO_CHIP)
|
|
18
18
|
|
19
19
|
# Encoder pin setup
|
20
20
|
LGPIO.gpio_claim_input(chip_handle, LGPIO::SET_PULL_NONE, PIN_A)
|
21
|
+
LGPIO.gpio_set_debounce(chip_handle, PIN_A, 1)
|
21
22
|
LGPIO.gpio_claim_alert(chip_handle, 0, LGPIO::BOTH_EDGES, PIN_A)
|
22
23
|
LGPIO.gpio_claim_input(chip_handle, LGPIO::SET_PULL_NONE, PIN_B)
|
24
|
+
LGPIO.gpio_set_debounce(chip_handle, PIN_B, 1)
|
23
25
|
LGPIO.gpio_claim_alert(chip_handle, 0, LGPIO::BOTH_EDGES, PIN_B)
|
24
26
|
|
25
27
|
# Switch pin setup
|
26
28
|
LGPIO.gpio_claim_input(chip_handle, LGPIO::SET_PULL_UP, PIN_SW)
|
29
|
+
LGPIO.gpio_set_debounce(chip_handle, PIN_SW, 1)
|
27
30
|
LGPIO.gpio_claim_alert(chip_handle, 0, LGPIO::FALLING_EDGE, PIN_SW)
|
28
31
|
|
29
32
|
# Start generating reports for GPIO level changes.
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#
|
2
|
+
# Demo of a simple 30-detent rotary encoder.
|
3
|
+
# PIN_A = CLK/CLOCK, PIN_B = DT/DATA, PIN_SW = SWITCH
|
4
|
+
#
|
5
|
+
require 'lgpio'
|
6
|
+
|
7
|
+
GPIO_CHIP = 0
|
8
|
+
PIN_A = 76
|
9
|
+
PIN_B = 228
|
10
|
+
|
11
|
+
PIN_LED = 260
|
12
|
+
PWM_FREQ = 500
|
13
|
+
PWM_OFFSET = 0
|
14
|
+
PWM_CYCLES = 0 # 0 = infinite
|
15
|
+
|
16
|
+
# Encoder state
|
17
|
+
state_a = 0
|
18
|
+
state_b = 0
|
19
|
+
led_duty = 0
|
20
|
+
|
21
|
+
chip_handle = LGPIO.chip_open(GPIO_CHIP)
|
22
|
+
|
23
|
+
# LED pin setup
|
24
|
+
LGPIO.gpio_claim_output(chip_handle, LGPIO::SET_PULL_NONE, PIN_LED, LGPIO::LOW)
|
25
|
+
|
26
|
+
# Encoder pin setup
|
27
|
+
LGPIO.gpio_claim_input(chip_handle, LGPIO::SET_PULL_NONE, PIN_A)
|
28
|
+
LGPIO.gpio_set_debounce(chip_handle, PIN_A, 1)
|
29
|
+
LGPIO.gpio_claim_alert(chip_handle, 0, LGPIO::BOTH_EDGES, PIN_A)
|
30
|
+
LGPIO.gpio_claim_input(chip_handle, LGPIO::SET_PULL_NONE, PIN_B)
|
31
|
+
LGPIO.gpio_set_debounce(chip_handle, PIN_B, 1)
|
32
|
+
LGPIO.gpio_claim_alert(chip_handle, 0, LGPIO::BOTH_EDGES, PIN_B)
|
33
|
+
|
34
|
+
# Start generating reports for GPIO level changes.
|
35
|
+
LGPIO.gpio_start_reporting
|
36
|
+
|
37
|
+
# Get and reports to update state.
|
38
|
+
loop do
|
39
|
+
report = LGPIO.gpio_get_report
|
40
|
+
if report
|
41
|
+
if report[:gpio] == PIN_A
|
42
|
+
# Half quadrature, so we count every detent.
|
43
|
+
state_a = report[:level]
|
44
|
+
elsif report[:gpio] == PIN_B
|
45
|
+
delta = (report[:level] == state_a) ? -1 : 1
|
46
|
+
state_b = report[:level]
|
47
|
+
|
48
|
+
led_duty += delta
|
49
|
+
led_duty = 0 if led_duty < 0
|
50
|
+
led_duty = 100 if led_duty > 100
|
51
|
+
LGPIO.tx_pwm(chip_handle, PIN_LED, PWM_FREQ, led_duty, PWM_OFFSET, PWM_CYCLES)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
sleep(0.001)
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
|
3
|
+
SPI_DEV = 1
|
4
|
+
SPI_CHAN = 0
|
5
|
+
SPI_MODE = 0
|
6
|
+
SPI_BAUD = 1_000_000
|
7
|
+
|
8
|
+
spi_handle = LGPIO.spi_open(SPI_DEV, SPI_CHAN, SPI_BAUD, SPI_MODE)
|
9
|
+
|
10
|
+
tx_bytes = [0, 1, 2, 3, 4, 5, 6, 7]
|
11
|
+
puts "TX bytes: #{tx_bytes.inspect}"
|
12
|
+
|
13
|
+
# rx_bytes == tx_bytes if MOSI looped back to MISO.
|
14
|
+
# rx_byte all 255 when MOSI and MISO not connected.
|
15
|
+
rx_bytes = LGPIO.spi_xfer(spi_handle, tx_bytes)
|
16
|
+
puts "RX bytes: #{rx_bytes.inspect}"
|
17
|
+
|
18
|
+
LGPIO.spi_close(spi_handle)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
|
3
|
+
SPI_DEV = 1
|
4
|
+
SPI_CHAN = 0
|
5
|
+
SPI_MODE = 0
|
6
|
+
SPI_BAUD = 1_000_000
|
7
|
+
|
8
|
+
spi_handle = LGPIO.spi_open(SPI_DEV, SPI_CHAN, SPI_BAUD, SPI_MODE)
|
9
|
+
|
10
|
+
# Pull MISO high or low. High gives array of 255, low array of 0.
|
11
|
+
rx_bytes = LGPIO.spi_read(spi_handle, 8)
|
12
|
+
puts "RX bytes: #{rx_bytes.inspect}"
|
13
|
+
|
14
|
+
LGPIO.spi_close(spi_handle)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#
|
2
|
+
# 2.4 MHz SPI method for writing WS2812 addressable LEDs
|
3
|
+
# Based on:https://learn.adafruit.com/dma-driven-neopixels/overview
|
4
|
+
#
|
5
|
+
require 'lgpio'
|
6
|
+
|
7
|
+
# WS2812 Constants
|
8
|
+
NP_ONE = 0b110
|
9
|
+
NP_ZERO = 0b100
|
10
|
+
NP_START = [0]
|
11
|
+
NP_END = Array.new(90) { 0 }
|
12
|
+
BITS = (0..7).to_a.reverse
|
13
|
+
|
14
|
+
# SPI Config
|
15
|
+
SPI_DEV = 1
|
16
|
+
SPI_CHAN = 0
|
17
|
+
SPI_MODE = 0
|
18
|
+
SPI_BAUD = 2_400_000
|
19
|
+
|
20
|
+
# Map array of pixel values (3 bytes each) to raw SPI bytes (1bit -> 3 bits).
|
21
|
+
def pixel_to_raw_spi_bytes(pixel_arr)
|
22
|
+
raw_spi_bytes = []
|
23
|
+
pixel_arr.flatten.each do |byte|
|
24
|
+
long = 0b0
|
25
|
+
for i in BITS do
|
26
|
+
long = long << 3
|
27
|
+
if byte[i] == 0
|
28
|
+
long |= NP_ZERO
|
29
|
+
else
|
30
|
+
long |= NP_ONE
|
31
|
+
end
|
32
|
+
end
|
33
|
+
# Pack as big-endian uint32, then unpack to bytes, taking lowest 24 bits only.
|
34
|
+
long = [long].pack('L>')
|
35
|
+
raw_spi_bytes << long.unpack('C*')[1..3]
|
36
|
+
end
|
37
|
+
return raw_spi_bytes.flatten
|
38
|
+
end
|
39
|
+
|
40
|
+
# 4 pixels: RGBW. Data order per pixel is GRB.
|
41
|
+
pixels_on = [
|
42
|
+
0, 255, 0,
|
43
|
+
255, 0, 0,
|
44
|
+
0, 0, 255,
|
45
|
+
255, 255, 255,
|
46
|
+
]
|
47
|
+
data_on = NP_START + pixel_to_raw_spi_bytes(pixels_on) + NP_END
|
48
|
+
|
49
|
+
# 4 pixels, all off.
|
50
|
+
pixels_off = Array.new(12) { 0 }
|
51
|
+
data_off = NP_START + pixel_to_raw_spi_bytes(pixels_off) + NP_END
|
52
|
+
|
53
|
+
spi_handle = LGPIO.spi_open(SPI_DEV, SPI_CHAN, SPI_BAUD, SPI_MODE)
|
54
|
+
|
55
|
+
loop do
|
56
|
+
LGPIO.spi_write(spi_handle, data_on)
|
57
|
+
sleep 0.5
|
58
|
+
LGPIO.spi_write(spi_handle, data_off)
|
59
|
+
sleep 0.5
|
60
|
+
end
|
data/ext/lgpio/lgpio.c
CHANGED
@@ -83,6 +83,11 @@ static VALUE group_write(VALUE self, VALUE handle, VALUE gpio, VALUE bits, VALUE
|
|
83
83
|
return INT2NUM(result);
|
84
84
|
}
|
85
85
|
|
86
|
+
static VALUE gpio_set_debounce(VALUE self, VALUE handle, VALUE gpio, VALUE debounce) {
|
87
|
+
int result = lgGpioSetDebounce(NUM2INT(handle), NUM2INT(gpio), NUM2INT(debounce));
|
88
|
+
return INT2NUM(result);
|
89
|
+
}
|
90
|
+
|
86
91
|
static VALUE gpio_claim_alert(VALUE self, VALUE handle, VALUE flags, VALUE eFlags, VALUE gpio) {
|
87
92
|
int result = lgGpioClaimAlert(NUM2INT(handle), NUM2INT(flags), NUM2INT(eFlags), NUM2INT(gpio), -1);
|
88
93
|
return INT2NUM(result);
|
@@ -101,12 +106,13 @@ void queue_gpio_reports(int count, lgGpioAlert_p events, void *data){
|
|
101
106
|
|
102
107
|
static VALUE gpio_start_reporting(VALUE self) {
|
103
108
|
lgGpioSetSamplesFunc(queue_gpio_reports, NULL);
|
109
|
+
return Qnil;
|
104
110
|
}
|
105
111
|
|
106
|
-
static VALUE gpio_get_report(VALUE self){
|
112
|
+
static VALUE gpio_get_report(VALUE self){
|
107
113
|
VALUE hash = rb_hash_new();
|
108
114
|
bool popped = false;
|
109
|
-
|
115
|
+
|
110
116
|
pthread_mutex_lock(&queueLock);
|
111
117
|
// qWritePos is where the NEXT report will go. Always trail it by 1.
|
112
118
|
if (qWritePos - qReadPos != 1){
|
@@ -170,6 +176,132 @@ static VALUE tx_wave(VALUE self, VALUE handle, VALUE lead_gpio, VALUE pulses) {
|
|
170
176
|
return INT2NUM(result);
|
171
177
|
}
|
172
178
|
|
179
|
+
static VALUE i2c_open(VALUE self, VALUE i2cDev, VALUE i2cAddr, VALUE i2cFlags){
|
180
|
+
int handle = lgI2cOpen(NUM2INT(i2cDev), NUM2INT(i2cAddr), NUM2INT(i2cFlags));
|
181
|
+
return INT2NUM(handle);
|
182
|
+
}
|
183
|
+
|
184
|
+
static VALUE i2c_close(VALUE self, VALUE handle){
|
185
|
+
int result = lgI2cClose(NUM2INT(handle));
|
186
|
+
return INT2NUM(result);
|
187
|
+
}
|
188
|
+
|
189
|
+
static VALUE i2c_write_device(VALUE self, VALUE handle, VALUE byteArray){
|
190
|
+
int count = RARRAY_LEN(byteArray);
|
191
|
+
uint8_t txBuf[count];
|
192
|
+
VALUE currentByte;
|
193
|
+
for(int i=0; i<count; i++){
|
194
|
+
currentByte = rb_ary_entry(byteArray, i);
|
195
|
+
Check_Type(currentByte, T_FIXNUM);
|
196
|
+
txBuf[i] = NUM2CHR(currentByte);
|
197
|
+
}
|
198
|
+
|
199
|
+
int result = lgI2cWriteDevice(NUM2INT(handle), txBuf, count);
|
200
|
+
return INT2NUM(result);
|
201
|
+
}
|
202
|
+
|
203
|
+
static VALUE i2c_read_device(VALUE self, VALUE handle, VALUE count){
|
204
|
+
int rxCount = NUM2INT(count);
|
205
|
+
uint8_t rxBuf[rxCount];
|
206
|
+
|
207
|
+
int result = lgI2cReadDevice(NUM2INT(handle), rxBuf, rxCount);
|
208
|
+
if(result < 0) return INT2NUM(result);
|
209
|
+
|
210
|
+
VALUE retArray = rb_ary_new2(rxCount);
|
211
|
+
for(int i=0; i<rxCount; i++){
|
212
|
+
rb_ary_store(retArray, i, UINT2NUM(rxBuf[i]));
|
213
|
+
}
|
214
|
+
return retArray;
|
215
|
+
}
|
216
|
+
|
217
|
+
static VALUE i2c_zip(VALUE self, VALUE handle, VALUE txArray, VALUE rb_rxCount){
|
218
|
+
int txCount = RARRAY_LEN(txArray);
|
219
|
+
uint8_t txBuf[txCount];
|
220
|
+
VALUE currentByte;
|
221
|
+
for(int i=0; i<txCount; i++){
|
222
|
+
currentByte = rb_ary_entry(txArray, i);
|
223
|
+
Check_Type(currentByte, T_FIXNUM);
|
224
|
+
txBuf[i] = NUM2CHR(currentByte);
|
225
|
+
}
|
226
|
+
|
227
|
+
int rxCount = NUM2INT(rb_rxCount);
|
228
|
+
uint8_t rxBuf[rxCount+1];
|
229
|
+
|
230
|
+
// Buffer size must be rxCount+1 or result is LG_BAD_I2C_RLEN
|
231
|
+
int result = lgI2cZip(NUM2INT(handle), txBuf, txCount, rxBuf, rxCount+1);
|
232
|
+
if(result < 0) return INT2NUM(result);
|
233
|
+
|
234
|
+
if (rxCount == 0) return Qnil;
|
235
|
+
VALUE retArray = rb_ary_new2(rxCount);
|
236
|
+
for(int i=0; i<rxCount; i++){
|
237
|
+
rb_ary_store(retArray, i, UINT2NUM(rxBuf[i]));
|
238
|
+
}
|
239
|
+
return retArray;
|
240
|
+
}
|
241
|
+
|
242
|
+
static VALUE spi_open(VALUE self, VALUE spiDev, VALUE spiChan, VALUE spiBaud, VALUE spiFlags){
|
243
|
+
int handle = lgSpiOpen(NUM2INT(spiDev), NUM2INT(spiChan), NUM2INT(spiBaud), NUM2INT(spiFlags));
|
244
|
+
return INT2NUM(handle);
|
245
|
+
}
|
246
|
+
|
247
|
+
static VALUE spi_close(VALUE self, VALUE handle){
|
248
|
+
int result = lgSpiClose(NUM2INT(handle));
|
249
|
+
return INT2NUM(result);
|
250
|
+
}
|
251
|
+
|
252
|
+
static VALUE spi_read(VALUE self, VALUE handle, VALUE rxCount){
|
253
|
+
int count = NUM2INT(rxCount);
|
254
|
+
|
255
|
+
// Not sure if this needs null termination like I2C. +1 won't hurt.
|
256
|
+
uint8_t rxBuf[count+1];
|
257
|
+
|
258
|
+
int result = lgSpiRead(NUM2INT(handle), rxBuf, count);
|
259
|
+
if(result < 0) return INT2NUM(result);
|
260
|
+
|
261
|
+
VALUE retArray = rb_ary_new2(count);
|
262
|
+
for(int i=0; i<count; i++){
|
263
|
+
rb_ary_store(retArray, i, UINT2NUM(rxBuf[i]));
|
264
|
+
}
|
265
|
+
return retArray;
|
266
|
+
}
|
267
|
+
|
268
|
+
static VALUE spi_write(VALUE self, VALUE handle, VALUE txArray){
|
269
|
+
int count = RARRAY_LEN(txArray);
|
270
|
+
uint8_t txBuf[count];
|
271
|
+
VALUE currentByte;
|
272
|
+
for(int i=0; i<count; i++){
|
273
|
+
currentByte = rb_ary_entry(txArray, i);
|
274
|
+
Check_Type(currentByte, T_FIXNUM);
|
275
|
+
txBuf[i] = NUM2CHR(currentByte);
|
276
|
+
}
|
277
|
+
|
278
|
+
int result = lgSpiWrite(NUM2INT(handle), txBuf, count);
|
279
|
+
return INT2NUM(result);
|
280
|
+
}
|
281
|
+
|
282
|
+
static VALUE spi_xfer(VALUE self, VALUE handle, VALUE txArray){
|
283
|
+
int count = RARRAY_LEN(txArray);
|
284
|
+
uint8_t txBuf[count];
|
285
|
+
VALUE currentByte;
|
286
|
+
for(int i=0; i<count; i++){
|
287
|
+
currentByte = rb_ary_entry(txArray, i);
|
288
|
+
Check_Type(currentByte, T_FIXNUM);
|
289
|
+
txBuf[i] = NUM2CHR(currentByte);
|
290
|
+
}
|
291
|
+
|
292
|
+
// Not sure if this needs null termination like I2C. +1 won't hurt.
|
293
|
+
uint8_t rxBuf[count+1];
|
294
|
+
|
295
|
+
int result = lgSpiXfer(NUM2INT(handle), txBuf, rxBuf, count);
|
296
|
+
if(result < 0) return INT2NUM(result);
|
297
|
+
|
298
|
+
VALUE retArray = rb_ary_new2(count);
|
299
|
+
for(int i=0; i<count; i++){
|
300
|
+
rb_ary_store(retArray, i, UINT2NUM(rxBuf[i]));
|
301
|
+
}
|
302
|
+
return retArray;
|
303
|
+
}
|
304
|
+
|
173
305
|
void Init_lgpio(void) {
|
174
306
|
// Modules
|
175
307
|
VALUE mLGPIO = rb_define_module("LGPIO");
|
@@ -198,8 +330,9 @@ void Init_lgpio(void) {
|
|
198
330
|
rb_define_singleton_method(mLGPIO, "group_free", group_free, 2);
|
199
331
|
rb_define_singleton_method(mLGPIO, "group_read", group_read, 2);
|
200
332
|
rb_define_singleton_method(mLGPIO, "group_write", group_write, 4);
|
201
|
-
|
333
|
+
|
202
334
|
// Alerts / Reports
|
335
|
+
rb_define_singleton_method(mLGPIO, "gpio_set_debounce", gpio_set_debounce, 3);
|
203
336
|
rb_define_singleton_method(mLGPIO, "gpio_claim_alert", gpio_claim_alert, 4);
|
204
337
|
rb_define_singleton_method(mLGPIO, "gpio_start_reporting", gpio_start_reporting, 0);
|
205
338
|
rb_define_singleton_method(mLGPIO, "gpio_get_report", gpio_get_report, 0);
|
@@ -213,4 +346,18 @@ void Init_lgpio(void) {
|
|
213
346
|
rb_define_singleton_method(mLGPIO, "tx_pwm", tx_pwm, 6);
|
214
347
|
rb_define_singleton_method(mLGPIO, "tx_servo", tx_servo, 6);
|
215
348
|
rb_define_singleton_method(mLGPIO, "tx_wave", tx_wave, 3);
|
349
|
+
|
350
|
+
// I2C
|
351
|
+
rb_define_singleton_method(mLGPIO, "i2c_open", i2c_open, 3);
|
352
|
+
rb_define_singleton_method(mLGPIO, "i2c_close", i2c_close, 1);
|
353
|
+
rb_define_singleton_method(mLGPIO, "i2c_write_device", i2c_write_device, 2);
|
354
|
+
rb_define_singleton_method(mLGPIO, "i2c_read_device", i2c_read_device, 2);
|
355
|
+
rb_define_singleton_method(mLGPIO, "i2c_zip", i2c_zip, 3);
|
356
|
+
|
357
|
+
// SPI
|
358
|
+
rb_define_singleton_method(mLGPIO, "spi_open", spi_open, 4);
|
359
|
+
rb_define_singleton_method(mLGPIO, "spi_close", spi_close, 1);
|
360
|
+
rb_define_singleton_method(mLGPIO, "spi_read", spi_read, 2);
|
361
|
+
rb_define_singleton_method(mLGPIO, "spi_write", spi_write, 2);
|
362
|
+
rb_define_singleton_method(mLGPIO, "spi_xfer", spi_xfer, 2);
|
216
363
|
}
|
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.3
|
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-08-03 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Use GPIO / PWM / I2C / SPI / UART on Linux SBCs in Ruby
|
14
14
|
email: mail@vickash.com
|
@@ -26,10 +26,17 @@ files:
|
|
26
26
|
- examples/blink.rb
|
27
27
|
- examples/group_in.rb
|
28
28
|
- examples/group_out.rb
|
29
|
+
- examples/i2c_aht10.rb
|
30
|
+
- examples/i2c_aht10_zip.rb
|
31
|
+
- examples/i2c_ssd1306_bench.rb
|
29
32
|
- examples/momentary.rb
|
30
33
|
- examples/pwm.rb
|
31
34
|
- examples/reports.rb
|
32
35
|
- examples/rotary_encoder.rb
|
36
|
+
- examples/rotary_encoder_led.rb
|
37
|
+
- examples/spi_loopback.rb
|
38
|
+
- examples/spi_read.rb
|
39
|
+
- examples/spi_ws2812.rb
|
33
40
|
- examples/wave.rb
|
34
41
|
- ext/lgpio/extconf.rb
|
35
42
|
- ext/lgpio/lgpio.c
|