denko-piboard 0.13.2 → 0.15.0

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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -0
  3. data/LICENSE +1 -1
  4. data/README.md +181 -132
  5. data/Rakefile +0 -5
  6. data/board_maps/README.md +59 -0
  7. data/board_maps/le_potato.yml +89 -0
  8. data/board_maps/orange_pi_zero_2w.yml +85 -0
  9. data/board_maps/radxa_zero3.yml +88 -0
  10. data/board_maps/raspberry_pi.yml +95 -0
  11. data/board_maps/raspberry_pi5.yml +95 -0
  12. data/denko_piboard.gemspec +6 -7
  13. data/examples/digital_io/bench_out.rb +22 -0
  14. data/examples/digital_io/rotary_encoder.rb +31 -0
  15. data/examples/display/ssd1306.rb +53 -0
  16. data/examples/i2c/bitbang_aht10.rb +18 -0
  17. data/examples/i2c/bitbang_search.rb +24 -0
  18. data/examples/i2c/bitbang_ssd1306_bench.rb +29 -0
  19. data/examples/i2c/search.rb +24 -0
  20. data/examples/led/blink.rb +10 -0
  21. data/examples/led/fade.rb +22 -0
  22. data/examples/led/ws2812_bounce.rb +36 -0
  23. data/examples/motor/servo.rb +16 -0
  24. data/examples/pi_system_monitor.rb +10 -8
  25. data/examples/pulse_io/buzzer.rb +34 -0
  26. data/examples/pulse_io/infrared.rb +25 -0
  27. data/examples/sensor/aht10.rb +17 -0
  28. data/examples/sensor/dht.rb +24 -0
  29. data/examples/sensor/ds18b20.rb +59 -0
  30. data/examples/sensor/hcsr04.rb +16 -0
  31. data/examples/sensor/neat_tph_readings.rb +32 -0
  32. data/examples/spi/bb_loopback.rb +31 -0
  33. data/examples/spi/loopback.rb +37 -0
  34. data/examples/spi/output_register.rb +38 -0
  35. data/lib/denko/piboard.rb +10 -2
  36. data/lib/denko/piboard_base.rb +21 -63
  37. data/lib/denko/piboard_core.rb +150 -130
  38. data/lib/denko/piboard_core_optimize_lookup.rb +31 -0
  39. data/lib/denko/piboard_hardware_pwm.rb +32 -0
  40. data/lib/denko/piboard_i2c.rb +59 -82
  41. data/lib/denko/piboard_i2c_bb.rb +48 -0
  42. data/lib/denko/piboard_infrared.rb +7 -44
  43. data/lib/denko/piboard_led_array.rb +9 -0
  44. data/lib/denko/piboard_map.rb +125 -38
  45. data/lib/denko/piboard_one_wire.rb +42 -0
  46. data/lib/denko/piboard_pulse.rb +11 -68
  47. data/lib/denko/piboard_spi.rb +47 -73
  48. data/lib/denko/piboard_spi_bb.rb +41 -0
  49. data/lib/denko/piboard_tone.rb +15 -26
  50. data/lib/denko/piboard_version.rb +1 -1
  51. data/scripts/99-denko.rules +9 -0
  52. data/scripts/set_permissions.rb +131 -0
  53. metadata +48 -21
  54. data/ext/gpiod/extconf.rb +0 -9
  55. data/ext/gpiod/gpiod.c +0 -179
  56. data/lib/denko/piboard_servo.rb +0 -18
  57. data/lib/gpiod.rb +0 -6
@@ -0,0 +1,131 @@
1
+ require 'yaml'
2
+
3
+ # `whoami` returns the name of the user running this script.
4
+ #
5
+ # If you automate this to run on startup (as root), you must put
6
+ # your literal Linux username here instead. If not, it will attempt
7
+ # to load a map from root's home, and root will get permissions, not you.
8
+ #
9
+ USERNAME = `whoami`.strip
10
+
11
+ GPIO_GROUP_NAME = "gpio"
12
+ I2C_GROUP_NAME = "i2c"
13
+ SPI_GROUP_NAME = "spi"
14
+ PWM_GROUP_NAME = "pwm"
15
+
16
+ MAP_FILENAME = ".denko_piboard_map.yml"
17
+ $added_to_group = false
18
+
19
+ # Create groups and add the user to them as needed.
20
+ def group_setup(group_name)
21
+ group_line = `egrep -i "^#{group_name}" /etc/group`
22
+
23
+ if group_line.empty?
24
+ `sudo groupadd #{group_name}`
25
+ end
26
+
27
+ unless group_line.match(/#{USERNAME}/)
28
+ `sudo usermod -aG #{group_name} #{USERNAME}`
29
+ puts "Added user #{USERNAME} to group #{group_name}. "
30
+ $added_to_group = true
31
+ else
32
+ puts "User #{USERNAME} already in group #{group_name}. "
33
+ end
34
+ end
35
+
36
+ # Change gpiochip ownership and permissions.
37
+ def setup_gpio
38
+ gpiochips = $map["pins"].each_value.map { |pin_def| pin_def["chip"] }.uniq
39
+ group_setup(GPIO_GROUP_NAME) unless gpiochips.empty?
40
+ gpiochips.each do |chip_index|
41
+ `sudo chgrp #{GPIO_GROUP_NAME} /dev/gpiochip#{chip_index}*`
42
+ `sudo chmod g+rw /dev/gpiochip#{chip_index}*`
43
+ puts "Set permissions for /dev/gpiochip#{chip_index}"
44
+ end
45
+ end
46
+
47
+ # Change I2C ownership and permissions
48
+ def setup_i2c
49
+ i2cs = $map["i2cs"].keys
50
+ group_setup(I2C_GROUP_NAME) unless i2cs.empty?
51
+ i2cs.each do |i2c_index|
52
+ dev = "/dev/i2c-#{i2c_index}"
53
+ `sudo chgrp #{I2C_GROUP_NAME} #{dev}`
54
+ `sudo chmod g+rw #{dev}`
55
+ puts "Set permissions for #{dev}"
56
+ end
57
+ end
58
+
59
+ # Change SPI ownership and permissions
60
+ def setup_spi
61
+ spis = $map["spis"].keys
62
+ group_setup(SPI_GROUP_NAME) unless spis.empty?
63
+ spis.each do |spi_index|
64
+ dev = "/dev/spidev#{spi_index}"
65
+ `sudo chgrp #{SPI_GROUP_NAME} #{dev}*`
66
+ `sudo chmod g+rw #{dev}*`
67
+ puts "Set permissions for #{dev}.*"
68
+ end
69
+ end
70
+
71
+ def setup_pwm
72
+ # Change PWM ownership and permissions
73
+ pwms = $map["pwms"]
74
+ unless pwms.empty?
75
+ group_setup(PWM_GROUP_NAME)
76
+ print "Exported and set permissions for: /sys/class/pwm/{"
77
+ end
78
+
79
+ i = 0
80
+ pwms.each_value do |hash|
81
+ i += 1
82
+ chip = hash["pwmchip"]
83
+ chan = hash["channel"]
84
+ chip_dir = "/sys/class/pwm/pwmchip#{chip}"
85
+ channel_dir = "/sys/class/pwm/pwmchip#{chip}/pwm#{chan}"
86
+
87
+ # Chip dir permissions
88
+ `sudo chgrp -RH #{PWM_GROUP_NAME} #{chip_dir}`
89
+ `sudo chmod -R g+rw #{chip_dir}`
90
+
91
+ # Export
92
+ `sudo echo #{chan} > #{chip_dir}/export` unless Dir.exist?(channel_dir)
93
+
94
+ # Channel dir permissions
95
+ `sudo chgrp -RH #{PWM_GROUP_NAME} #{channel_dir}`
96
+ `sudo chmod -R g+rw #{channel_dir}`
97
+
98
+ print channel_dir.gsub("/sys/class/pwm/", "")
99
+ print ", " unless i == pwms.length
100
+ end
101
+ puts "}"
102
+ end
103
+
104
+ # Load map
105
+ home = Dir.home(USERNAME)
106
+ yaml_path = home +"/#{MAP_FILENAME}"
107
+ $map = YAML.load_file(yaml_path)
108
+ puts
109
+
110
+ case ARGV[0]
111
+ when "gpio"
112
+ setup_gpio
113
+ when "i2c"
114
+ setup_i2c
115
+ when "spi"
116
+ setup_spi
117
+ when "pwm"
118
+ setup_pwm
119
+ else
120
+ setup_gpio
121
+ setup_i2c
122
+ setup_spi
123
+ setup_pwm
124
+ end
125
+
126
+ # Notify user
127
+ if $added_to_group
128
+ puts
129
+ puts "User #{USERNAME} has been added to new group(s). Log out, then log back in for this to take effect."
130
+ end
131
+ puts
metadata CHANGED
@@ -1,76 +1,104 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: denko-piboard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.2
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - vickash
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-09-27 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
- name: pigpio
13
+ name: lgpio
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: 0.1.12
18
+ version: '0.1'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: 0.1.12
25
+ version: '0.1'
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: denko
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - "~>"
32
31
  - !ruby/object:Gem::Version
33
- version: '0.13'
32
+ version: '0.15'
34
33
  type: :runtime
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
37
  - - "~>"
39
38
  - !ruby/object:Gem::Version
40
- version: '0.13'
41
- description: Denko::PiBoard is a drop-in replacement for Denko::Board. Use denko features
42
- and component classes to be used directly on a Raspberry Pi.
39
+ version: '0.15'
40
+ description: Use Linux single-board-computer GPIO, I2C, SPI and PWM in Ruby
43
41
  email: mail@vickash.com
44
42
  executables: []
45
- extensions:
46
- - ext/gpiod/extconf.rb
43
+ extensions: []
47
44
  extra_rdoc_files: []
48
45
  files:
46
+ - Gemfile
49
47
  - LICENSE
50
48
  - README.md
51
49
  - Rakefile
50
+ - board_maps/README.md
51
+ - board_maps/le_potato.yml
52
+ - board_maps/orange_pi_zero_2w.yml
53
+ - board_maps/radxa_zero3.yml
54
+ - board_maps/raspberry_pi.yml
55
+ - board_maps/raspberry_pi5.yml
52
56
  - denko_piboard.gemspec
57
+ - examples/digital_io/bench_out.rb
58
+ - examples/digital_io/rotary_encoder.rb
59
+ - examples/display/ssd1306.rb
60
+ - examples/i2c/bitbang_aht10.rb
61
+ - examples/i2c/bitbang_search.rb
62
+ - examples/i2c/bitbang_ssd1306_bench.rb
63
+ - examples/i2c/search.rb
64
+ - examples/led/blink.rb
65
+ - examples/led/fade.rb
66
+ - examples/led/ws2812_bounce.rb
67
+ - examples/motor/servo.rb
53
68
  - examples/pi_system_monitor.rb
54
- - ext/gpiod/extconf.rb
55
- - ext/gpiod/gpiod.c
69
+ - examples/pulse_io/buzzer.rb
70
+ - examples/pulse_io/infrared.rb
71
+ - examples/sensor/aht10.rb
72
+ - examples/sensor/dht.rb
73
+ - examples/sensor/ds18b20.rb
74
+ - examples/sensor/hcsr04.rb
75
+ - examples/sensor/neat_tph_readings.rb
76
+ - examples/spi/bb_loopback.rb
77
+ - examples/spi/loopback.rb
78
+ - examples/spi/output_register.rb
56
79
  - lib/denko/piboard.rb
57
80
  - lib/denko/piboard_base.rb
58
81
  - lib/denko/piboard_core.rb
82
+ - lib/denko/piboard_core_optimize_lookup.rb
83
+ - lib/denko/piboard_hardware_pwm.rb
59
84
  - lib/denko/piboard_i2c.rb
85
+ - lib/denko/piboard_i2c_bb.rb
60
86
  - lib/denko/piboard_infrared.rb
87
+ - lib/denko/piboard_led_array.rb
61
88
  - lib/denko/piboard_map.rb
89
+ - lib/denko/piboard_one_wire.rb
62
90
  - lib/denko/piboard_pulse.rb
63
- - lib/denko/piboard_servo.rb
64
91
  - lib/denko/piboard_spi.rb
92
+ - lib/denko/piboard_spi_bb.rb
65
93
  - lib/denko/piboard_tone.rb
66
94
  - lib/denko/piboard_version.rb
67
- - lib/gpiod.rb
95
+ - scripts/99-denko.rules
96
+ - scripts/set_permissions.rb
68
97
  homepage: https://github.com/denko-rb/denko-piboard
69
98
  licenses:
70
99
  - MIT
71
100
  metadata:
72
101
  source_code_uri: https://github.com/denko-rb/denko-piboard
73
- post_install_message:
74
102
  rdoc_options: []
75
103
  require_paths:
76
104
  - lib
@@ -78,15 +106,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
78
106
  requirements:
79
107
  - - ">="
80
108
  - !ruby/object:Gem::Version
81
- version: '0'
109
+ version: '3'
82
110
  required_rubygems_version: !ruby/object:Gem::Requirement
83
111
  requirements:
84
112
  - - ">="
85
113
  - !ruby/object:Gem::Version
86
114
  version: '0'
87
115
  requirements: []
88
- rubygems_version: 3.4.13
89
- signing_key:
116
+ rubygems_version: 3.6.7
90
117
  specification_version: 4
91
- summary: Use Raspberry Pi built-in GPIO as a Board class with the denko gem
118
+ summary: Linux SBC GPIO in Ruby
92
119
  test_files: []
data/ext/gpiod/extconf.rb DELETED
@@ -1,9 +0,0 @@
1
- require 'mkmf'
2
-
3
- #
4
- # Need libgpiod-dev installed.
5
- # sudo apt install libgpiod-dev
6
- #
7
- $libs += " -lgpiod"
8
-
9
- create_makefile('gpiod/gpiod')
data/ext/gpiod/gpiod.c DELETED
@@ -1,179 +0,0 @@
1
- #include <ruby.h>
2
- #include <gpiod.h>
3
-
4
- #define GPIO_CHIP_NAME "gpiochip0"
5
-
6
- static struct gpiod_chip *chip;
7
-
8
- // Save mapping of lowest 32 GPIOs to gpiod_line structs.
9
- static struct gpiod_line *lines[32] = { NULL };
10
-
11
- // Input and output values.
12
- static int gpio_number;
13
- static int gpio_value;
14
- static int return_value;
15
-
16
- static VALUE open_chip(VALUE self) {
17
- chip = gpiod_chip_open_by_name(GPIO_CHIP_NAME);
18
- if (!chip) {
19
- rb_raise(rb_eRuntimeError, "libgpiod error: Could not open GPIO chip");
20
- return Qnil;
21
- }
22
- return Qnil;
23
- }
24
-
25
- static VALUE close_chip(VALUE self) {
26
- gpiod_chip_close(chip);
27
- return Qnil;
28
- }
29
-
30
- static void validate_gpio_number(int gpio_number) {
31
- if ((gpio_number < 0) || (gpio_number > 31)) {
32
- VALUE error_message = rb_sprintf("libgpiod error: GPIO line (%d) out of range. Valid range is 0..31", gpio_number);
33
- rb_raise(rb_eRuntimeError, "%s", StringValueCStr(error_message));
34
- }
35
- }
36
-
37
- static void validate_gpio_value(int value) {
38
- if (!((value == 0) || (value == 1))) {
39
- VALUE error_message = rb_sprintf("libgpiod error: GPIO value (%d) out of range. Valid values are 0 or 1", value);
40
- rb_raise(rb_eRuntimeError, "%s", StringValueCStr(error_message));
41
- }
42
- }
43
-
44
- static VALUE open_line_output(VALUE self, VALUE gpio) {
45
- gpio_number = NUM2INT(gpio);
46
- validate_gpio_number(gpio_number);
47
-
48
- lines[gpio_number] = gpiod_chip_get_line(chip, gpio_number);
49
- if (!lines[gpio_number]) {
50
- gpiod_chip_close(chip);
51
- VALUE error_message = rb_sprintf("libgpiod error: Could not get GPIO line %d", gpio_number);
52
- rb_raise(rb_eRuntimeError, "%s", StringValueCStr(error_message));
53
- return Qnil;
54
- }
55
-
56
- return_value = gpiod_line_request_output(lines[gpio_number], "GPIOD_RB", 0);
57
- if (return_value < 0) {
58
- gpiod_chip_close(chip);
59
- VALUE error_message = rb_sprintf("libgpiod error: Could not request output for GPIO line %d", gpio_number);
60
- rb_raise(rb_eRuntimeError, "%s", StringValueCStr(error_message));
61
- return Qnil;
62
- }
63
-
64
- return Qnil;
65
- }
66
-
67
- static VALUE set_value(VALUE self, VALUE gpio, VALUE value) {
68
- gpio_number = NUM2INT(gpio);
69
- validate_gpio_number(gpio_number);
70
- gpio_value = NUM2INT(value);
71
- validate_gpio_value(gpio_value);
72
-
73
- return_value = gpiod_line_set_value(lines[gpio_number], gpio_value);
74
-
75
- if (return_value < 0) {
76
- gpiod_chip_close(chip);
77
- VALUE error_message = rb_sprintf("libgpiod error: Could not set value %d on GPIO line %d", gpio_value, gpio_number);
78
- rb_raise(rb_eRuntimeError, "%s", StringValueCStr(error_message));
79
- return Qnil;
80
- }
81
-
82
- return value;
83
- }
84
-
85
- static VALUE open_line_input(VALUE self, VALUE gpio) {
86
- gpio_number = NUM2INT(gpio);
87
- validate_gpio_number(gpio_number);
88
-
89
- lines[gpio_number] = gpiod_chip_get_line(chip, gpio_number);
90
- if (!lines[gpio_number]) {
91
- gpiod_chip_close(chip);
92
- VALUE error_message = rb_sprintf("libgpiod error: Could not get GPIO line %d", gpio_number);
93
- rb_raise(rb_eRuntimeError, "%s", StringValueCStr(error_message));
94
- return Qnil;
95
- }
96
-
97
- return_value = gpiod_line_request_input(lines[gpio_number], "GPIOD_RB");
98
- if (return_value < 0) {
99
- gpiod_chip_close(chip);
100
- VALUE error_message = rb_sprintf("libgpiod error: Could not request input for GPIO line %d", gpio_number);
101
- rb_raise(rb_eRuntimeError, "%s", StringValueCStr(error_message));
102
- return Qnil;
103
- }
104
-
105
- return Qnil;
106
- }
107
-
108
- static VALUE get_value(VALUE self, VALUE gpio) {
109
- gpio_number = NUM2INT(gpio);
110
- validate_gpio_number(gpio_number);
111
-
112
- return_value = gpiod_line_get_value(lines[gpio_number]);
113
-
114
- if (return_value < 0) {
115
- gpiod_chip_close(chip);
116
- VALUE error_message = rb_sprintf("libgpiod error: Could not get value from GPIO line %d", gpio_number);
117
- rb_raise(rb_eRuntimeError, "%s", StringValueCStr(error_message));
118
- return Qnil;
119
- }
120
-
121
- return INT2NUM(return_value);
122
- }
123
-
124
- static VALUE close_line(VALUE self, VALUE gpio) {
125
- gpio_number = NUM2INT(gpio);
126
- validate_gpio_number(gpio_number);
127
-
128
- // Only try to close the line if it was opened before.
129
- if (lines[gpio_number] == NULL) return Qnil;
130
-
131
- gpiod_line_release(lines[gpio_number]);
132
- lines[gpio_number] = NULL;
133
- return Qnil;
134
- }
135
-
136
- static VALUE set_value_raw(VALUE self, VALUE gpio, VALUE value) {
137
- gpio_number = NUM2INT(gpio);
138
- gpio_value = NUM2INT(value);
139
-
140
- return_value = gpiod_line_set_value(lines[gpio_number], gpio_value);
141
-
142
- if (return_value < 0) {
143
- gpiod_chip_close(chip);
144
- VALUE error_message = rb_sprintf("libgpiod error: Could not set value %d on GPIO line %d", gpio_value, gpio_number);
145
- rb_raise(rb_eRuntimeError, "%s", StringValueCStr(error_message));
146
- return Qnil;
147
- }
148
- return value;
149
- }
150
-
151
- static VALUE get_value_raw(VALUE self, VALUE gpio) {
152
- gpio_number = NUM2INT(gpio);
153
-
154
- return_value = gpiod_line_get_value(lines[gpio_number]);
155
-
156
- if (return_value < 0) {
157
- gpiod_chip_close(chip);
158
- VALUE error_message = rb_sprintf("libgpiod error: Could not get value from GPIO line %d", gpio_number);
159
- rb_raise(rb_eRuntimeError, "%s", StringValueCStr(error_message));
160
- return Qnil;
161
- }
162
- return INT2NUM(return_value);
163
- }
164
-
165
- void Init_gpiod(void) {
166
- VALUE mDenko = rb_define_module("Denko");
167
- VALUE mGPIOD = rb_define_module_under(mDenko, "GPIOD");
168
- rb_define_singleton_method(mGPIOD, "open_chip", open_chip, 0);
169
- rb_define_singleton_method(mGPIOD, "close_chip", close_chip, 0);
170
- rb_define_singleton_method(mGPIOD, "open_line_output", open_line_output, 1);
171
- rb_define_singleton_method(mGPIOD, "set_value", set_value, 2);
172
- rb_define_singleton_method(mGPIOD, "open_line_input", open_line_input, 1);
173
- rb_define_singleton_method(mGPIOD, "get_value", get_value, 1);
174
- rb_define_singleton_method(mGPIOD, "close_line", close_line, 1);
175
-
176
- // These do no validation.
177
- rb_define_singleton_method(mGPIOD, "set_value_raw", set_value_raw, 2);
178
- rb_define_singleton_method(mGPIOD, "get_value_raw", get_value_raw, 1);
179
- }
@@ -1,18 +0,0 @@
1
- module Denko
2
- class PiBoard
3
- # CMD = 10
4
- def servo_toggle(pin, value=:off, options={})
5
- if value == :off
6
- pwm_clear(pin)
7
- digital_write(pin, 0)
8
- else
9
- @pwms[pin] = :servo
10
- end
11
- end
12
-
13
- # CMD = 11
14
- def servo_write(pin, value=0)
15
- Pigpio::IF.set_servo_pulsewidth(pi_handle, pin, value)
16
- end
17
- end
18
- end
data/lib/gpiod.rb DELETED
@@ -1,6 +0,0 @@
1
- require_relative 'gpiod/gpiod'
2
-
3
- module Denko
4
- module GPIOD
5
- end
6
- end