lgpio 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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