lgpio 0.1.3 → 0.1.4
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/.gitignore +1 -0
- data/README.md +21 -15
- data/examples/spi_ws2812.rb +4 -34
- data/examples/spi_ws2812_bounce.rb +44 -0
- data/ext/lgpio/lgpio.c +37 -0
- data/lib/lgpio/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 84493ab6ca425d960887480b8f186a610fd9e41f0885657c79b5a4038a8a2035
|
4
|
+
data.tar.gz: 705d88399e518bdbc167eca65cd795dea2d33936b919aaaf22a34c8be032a1a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 77f3c42ed9a94f8ea0c59acc2cb276efd400990099ac4272f06619645953f6014dbc4a9330d04ed154eee86fabba4791290fcd7201b326f2d6f4b2437a5d5812
|
7
|
+
data.tar.gz: 7fd2aa6715e36f3e95d35248b1b13ffb141dca3c50b1ab7a5fbe2e420b67a3873d3de50a24b5eda460a50bd69133492043356715522b27cbe509e280c3174699
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,18 +1,24 @@
|
|
1
1
|
# lgpio
|
2
2
|
|
3
|
-
Ruby bindings for the [lgpio (lg)](https://github.com/joan2937/lg)
|
4
|
-
|
5
|
-
##
|
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
|
3
|
+
Ruby bindings for the [lgpio (lg)](https://github.com/joan2937/lg) Linux library, running on single board computers (SBCs), like Raspberry Pi.
|
4
|
+
|
5
|
+
## Standard LGPIO Functions
|
6
|
+
- [x] GPIO Read/Write
|
7
|
+
- [x] GPIO Group Read/Write
|
8
|
+
- [x] 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
|
+
- [x] PWM Output
|
11
11
|
- Software timed on any pin. No interface for hardware PWM yet.
|
12
|
-
- Wave
|
12
|
+
- [x] Wave
|
13
13
|
- Software timed on any pin, as with PWM.
|
14
|
-
- I2C
|
15
|
-
- SPI
|
14
|
+
- [x] I2C
|
15
|
+
- [x] SPI
|
16
|
+
|
17
|
+
## Extras
|
18
|
+
- [x] WS2812 over SPI
|
19
|
+
- Only outputs on a SPI MOSI pin. Must be able to set SPI clock frequency to 2.4 MHz.
|
20
|
+
- [ ] Bit Bang SPI
|
21
|
+
- [ ] Bit Bang I2C
|
16
22
|
|
17
23
|
## Installation
|
18
24
|
On Debian-based Linuxes (RaspberryPi OS, Armbian, DietPi etc.):
|
@@ -33,9 +39,9 @@ gem install lgpio
|
|
33
39
|
```
|
34
40
|
|
35
41
|
## Enabling Hardware & Permissions
|
36
|
-
Depending on your SBC and Linux distro/version, you may need to manually enable I2C and SPI hardware. You
|
42
|
+
Depending on your SBC and Linux distro/version, you may need to manually enable I2C and SPI hardware. You should use the setup or config tool that came with your distro for that.
|
37
43
|
|
38
|
-
You may also not have permission to access
|
44
|
+
You may also not have permission to access the GPIO and peripherals. To run without `sudo`, you need read+write permission to some or all of the following devices:
|
39
45
|
```
|
40
46
|
/dev/gpiochip* (For GPIO, example: /dev/gpiochip0)
|
41
47
|
/dev/i2c-* (For I2C, example: /dev/i2c-1)
|
@@ -44,11 +50,11 @@ You may also not have permission to access some or all of the GPIO and periphera
|
|
44
50
|
|
45
51
|
## Documentation
|
46
52
|
- See examples folder for demos of every implemented interface.
|
47
|
-
- Development was done on an Orange Pi Zero 2W. Your GPIO numbers
|
53
|
+
- Development was done on an Orange Pi Zero 2W. Your GPIO numbers may be different, so change them.
|
48
54
|
- For more info, see the [lgpio C API docs.](https://abyz.me.uk/lg/lgpio.html)
|
49
55
|
- As much as possible, the Ruby methods closely follow the C API functions, except:
|
50
56
|
- Snake case instead of camel case names for methods.
|
51
57
|
- Method names have the leading `lg` removed, since inside the `LGPIO` class.
|
52
58
|
- Constants have leading `LG_` removed, as above.
|
53
59
|
- "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
|
60
|
+
- Check the return values of your method calls. On failure, they return negative values, matching the `LG_` error codes at the bottom of the C API doc page.
|
data/examples/spi_ws2812.rb
CHANGED
@@ -1,42 +1,15 @@
|
|
1
1
|
#
|
2
|
-
# 2.4 MHz SPI method for writing WS2812 addressable LEDs
|
3
|
-
# Based on:https://learn.adafruit.com/dma-driven-neopixels/overview
|
2
|
+
# 2.4 MHz SPI method for writing WS2812 addressable LEDs.
|
3
|
+
# Based on: https://learn.adafruit.com/dma-driven-neopixels/overview
|
4
4
|
#
|
5
5
|
require 'lgpio'
|
6
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
7
|
# SPI Config
|
15
8
|
SPI_DEV = 1
|
16
9
|
SPI_CHAN = 0
|
17
10
|
SPI_MODE = 0
|
18
11
|
SPI_BAUD = 2_400_000
|
19
12
|
|
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
13
|
# 4 pixels: RGBW. Data order per pixel is GRB.
|
41
14
|
pixels_on = [
|
42
15
|
0, 255, 0,
|
@@ -44,17 +17,14 @@ pixels_on = [
|
|
44
17
|
0, 0, 255,
|
45
18
|
255, 255, 255,
|
46
19
|
]
|
47
|
-
data_on = NP_START + pixel_to_raw_spi_bytes(pixels_on) + NP_END
|
48
|
-
|
49
20
|
# 4 pixels, all off.
|
50
21
|
pixels_off = Array.new(12) { 0 }
|
51
|
-
data_off = NP_START + pixel_to_raw_spi_bytes(pixels_off) + NP_END
|
52
22
|
|
53
23
|
spi_handle = LGPIO.spi_open(SPI_DEV, SPI_CHAN, SPI_BAUD, SPI_MODE)
|
54
24
|
|
55
25
|
loop do
|
56
|
-
LGPIO.
|
26
|
+
LGPIO.spi_ws2812_write(spi_handle, pixels_on)
|
57
27
|
sleep 0.5
|
58
|
-
LGPIO.
|
28
|
+
LGPIO.spi_ws2812_write(spi_handle, pixels_off)
|
59
29
|
sleep 0.5
|
60
30
|
end
|
@@ -0,0 +1,44 @@
|
|
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
|
+
# SPI config
|
8
|
+
SPI_DEV = 1
|
9
|
+
SPI_CHAN = 0
|
10
|
+
SPI_MODE = 0
|
11
|
+
SPI_BAUD = 2_400_000
|
12
|
+
|
13
|
+
PIXEL_COUNT = 8
|
14
|
+
COLORS = [
|
15
|
+
[255, 255, 255],
|
16
|
+
[0, 255, 0],
|
17
|
+
[255, 0, 0],
|
18
|
+
[0, 0, 255],
|
19
|
+
[255, 255, 0],
|
20
|
+
[255, 0, 255],
|
21
|
+
[0, 255, 255]
|
22
|
+
]
|
23
|
+
|
24
|
+
# Move along the strip and back, one pixel at a time.
|
25
|
+
POSITIONS = (0..PIXEL_COUNT-1).to_a + (1..PIXEL_COUNT-2).to_a.reverse
|
26
|
+
|
27
|
+
pixels = Array.new(PIXEL_COUNT) { [0, 0, 0] }
|
28
|
+
spi_handle = LGPIO.spi_open(SPI_DEV, SPI_CHAN, SPI_BAUD, SPI_MODE)
|
29
|
+
|
30
|
+
loop do
|
31
|
+
COLORS.each do |color|
|
32
|
+
POSITIONS.each do |index|
|
33
|
+
# Clear and write.
|
34
|
+
(0..PIXEL_COUNT-1).each { |i| pixels[i] = [0, 0, 0] }
|
35
|
+
LGPIO.spi_ws2812_write(spi_handle, pixels.flatten)
|
36
|
+
|
37
|
+
# Set one pixel and write.
|
38
|
+
pixels[index] = color
|
39
|
+
LGPIO.spi_ws2812_write(spi_handle, pixels.flatten)
|
40
|
+
|
41
|
+
sleep 0.05
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/ext/lgpio/lgpio.c
CHANGED
@@ -302,6 +302,42 @@ static VALUE spi_xfer(VALUE self, VALUE handle, VALUE txArray){
|
|
302
302
|
return retArray;
|
303
303
|
}
|
304
304
|
|
305
|
+
static VALUE spi_ws2812_write(VALUE self, VALUE handle, VALUE pixelArray){
|
306
|
+
int count = RARRAY_LEN(pixelArray);
|
307
|
+
|
308
|
+
// Pull low for at least one byte at 2.4 Mhz before data, and 90 after.
|
309
|
+
int zeroesBefore = 1;
|
310
|
+
int zeroesAfter = 90;
|
311
|
+
int txBufLength = zeroesBefore + (count*3) + zeroesAfter;
|
312
|
+
uint8_t txBuf[txBufLength];
|
313
|
+
for (int i=0; i<txBufLength; i++) { txBuf[i] = 0; }
|
314
|
+
|
315
|
+
VALUE currentByte_rb;
|
316
|
+
uint8_t currentByte;
|
317
|
+
uint8_t currentBit;
|
318
|
+
uint32_t temp;
|
319
|
+
|
320
|
+
for (int i=0; i<count; i++){
|
321
|
+
temp = 0;
|
322
|
+
currentByte_rb = rb_ary_entry(pixelArray, i);
|
323
|
+
Check_Type(currentByte_rb, T_FIXNUM);
|
324
|
+
currentByte = NUM2CHR(currentByte_rb);
|
325
|
+
|
326
|
+
for (int i=7; i>=0; i--) {
|
327
|
+
currentBit = (currentByte & (1 << i));
|
328
|
+
temp = temp << 3;
|
329
|
+
temp = (currentBit == 0) ? (temp | 0b100) : (temp | 0b110);
|
330
|
+
}
|
331
|
+
|
332
|
+
txBuf[zeroesBefore+(i*3)] = (temp >> 16) & 0xFF;
|
333
|
+
txBuf[zeroesBefore+(i*3)+1] = (temp >> 8) & 0xFF;
|
334
|
+
txBuf[zeroesBefore+(i*3)+2] = temp & 0xFF;
|
335
|
+
}
|
336
|
+
|
337
|
+
int result = lgSpiWrite(NUM2INT(handle), txBuf, txBufLength);
|
338
|
+
return INT2NUM(result);
|
339
|
+
}
|
340
|
+
|
305
341
|
void Init_lgpio(void) {
|
306
342
|
// Modules
|
307
343
|
VALUE mLGPIO = rb_define_module("LGPIO");
|
@@ -360,4 +396,5 @@ void Init_lgpio(void) {
|
|
360
396
|
rb_define_singleton_method(mLGPIO, "spi_read", spi_read, 2);
|
361
397
|
rb_define_singleton_method(mLGPIO, "spi_write", spi_write, 2);
|
362
398
|
rb_define_singleton_method(mLGPIO, "spi_xfer", spi_xfer, 2);
|
399
|
+
rb_define_singleton_method(mLGPIO, "spi_ws2812_write", spi_ws2812_write, 2);
|
363
400
|
}
|
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.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- vickash
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-05 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
|
@@ -37,6 +37,7 @@ files:
|
|
37
37
|
- examples/spi_loopback.rb
|
38
38
|
- examples/spi_read.rb
|
39
39
|
- examples/spi_ws2812.rb
|
40
|
+
- examples/spi_ws2812_bounce.rb
|
40
41
|
- examples/wave.rb
|
41
42
|
- ext/lgpio/extconf.rb
|
42
43
|
- ext/lgpio/lgpio.c
|