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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4bb351b8041dc3f5e78ed92128c3c971cf3f9e35d247a71e8d4ce56acec87f32
4
- data.tar.gz: a4df4836decc51de97ad16093bbd19e649cd02b675d6511c601feddde0cded66
3
+ metadata.gz: e24e221cb39d27714d3fdd9486c47dd01e33115980d29e5104a455e14fd40890
4
+ data.tar.gz: 4ffd6e35644bc8dcde49486cd43d8e7ca73ebbfe9b46955a8de89a4ecff49d33
5
5
  SHA512:
6
- metadata.gz: f94daeeaba65d22c4ee2e0205a9399f18f886cc5f42e15f53a4991381756b7a33d97d29113918b809b6ff96d7900a327ee26d441d9249e86020cee7c21c34765
7
- data.tar.gz: 367559fcd9750f88e728b80836c3dfa7d9273dcb2c734bc67faed29b23e177fc03e9e18df9678533907f3ddbe85be5d4d443a5d45404a03322ac09e586827e11
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, which provides GPIO, PWM, I2C, SPI and Serial features on single-board-computers (SBCs) running Linux.
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
- - [lg homepage](https://abyz.me.uk/lg/index.html)
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
- ### Progress:
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
- - [x] GPIO Read/Write
10
- - [x] GPIO Group Read/Write
11
- - [x] GPIO Alerts / Callbacks (read from a queue)
12
- - [x] PWM (software-timed)
13
- - [x] Wave (software-timed)
14
- - [ ] I2C
15
- - [ ] SPI
16
- - [ ] Serial
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
@@ -6,6 +6,7 @@ PIN = 76
6
6
  chip_handle = LGPIO.chip_open(GPIO_CHIP)
7
7
 
8
8
  LGPIO.gpio_claim_input(chip_handle, LGPIO::SET_PULL_NONE, PIN)
9
+ LGPIO.gpio_set_debounce(chip_handle, PIN, 1)
9
10
  LGPIO.gpio_claim_alert(chip_handle, 0, LGPIO::BOTH_EDGES, PIN)
10
11
  LGPIO.gpio_start_reporting
11
12
 
@@ -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
@@ -1,3 +1,3 @@
1
1
  module LGPIO
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
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.2
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-07-31 00:00:00.000000000 Z
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