gpiod 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: aa08910a821f653b7a8e24bb23d4179b1bc830ad476b07483c7b07ad8932348e
4
+ data.tar.gz: 335c870b62e4a83ae059d40ea161ab213d9af5ebff25803005c29b3259e59bd9
5
+ SHA512:
6
+ metadata.gz: 27996555e451e2cd7c4bb1d79f5cd5a69979d2db1ef66a6bd1613d8862075d22d71da8c0969ace049db5ff30b42f4399ba18a911396ad31e9d72fcee32c9615c
7
+ data.tar.gz: d54d80244f65bf29ae4fa928c0d065f3dfc19f87f7095a4eb6c1afb0f1ea27e99627c31ee84a5cdaf455d7f797bbd8124fbbab85aac2f7b6c158a4dc04710d17
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 denko-rb
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # gpiod
2
+
3
+ # Experimental (DO NOT USE!)
4
+
5
+ If you need to use Linux GPIO in Ruby, please see [denko-piboard](https://github.com/denko-rb/denko-piboard) or [lgpio](https://github.com/denko-rb/lgpio) instead.
6
+
7
+ This gem only contains some (probably bad) code, extracted from an old version of `denko-piboard`. I started building that on top of `libgpiod` directly, but eventually settled on [lgpio](https://github.com/joan2937/lg) which has more features and was simpler to implement.
8
+
9
+ At some point, I will probably finish the `libgpiod` implementation, and substitute it where applicable in `denko-piboard`, in place of `lgpio`. It performs ~15-20% better, but `lgpio` + YJIT is already pretty fast, so this isn't a priority.
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "rake/extensiontask"
2
+
3
+ Rake::ExtensionTask.new "gpiod" do |ext|
4
+ ext.lib_dir = "lib/gpiod"
5
+ end
@@ -0,0 +1,21 @@
1
+ require 'gpiod'
2
+
3
+ GPIO_CHIP = 0
4
+ PIN = 17
5
+ COUNT = 1000000
6
+
7
+ # Always opens gpiochip0 for now.
8
+ GPIOD.open_chip
9
+ GPIOD.open_line_output(PIN)
10
+
11
+ t1 = Time.now
12
+ COUNT.times do
13
+ GPIOD.set_value(PIN, 1)
14
+ GPIOD.set_value(PIN, 0)
15
+ end
16
+ t2 = Time.now
17
+
18
+ puts "Toggles per second: #{COUNT.to_f / (t2 - t1).to_f}"
19
+
20
+ GPIOD.close_line(PIN)
21
+ GPIOD.close_chip
@@ -0,0 +1,9 @@
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 ADDED
@@ -0,0 +1,178 @@
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 mGPIOD = rb_define_module("GPIOD");
167
+ rb_define_singleton_method(mGPIOD, "open_chip", open_chip, 0);
168
+ rb_define_singleton_method(mGPIOD, "close_chip", close_chip, 0);
169
+ rb_define_singleton_method(mGPIOD, "open_line_output", open_line_output, 1);
170
+ rb_define_singleton_method(mGPIOD, "set_value", set_value, 2);
171
+ rb_define_singleton_method(mGPIOD, "open_line_input", open_line_input, 1);
172
+ rb_define_singleton_method(mGPIOD, "get_value", get_value, 1);
173
+ rb_define_singleton_method(mGPIOD, "close_line", close_line, 1);
174
+
175
+ // These do no validation.
176
+ rb_define_singleton_method(mGPIOD, "set_value_raw", set_value_raw, 2);
177
+ rb_define_singleton_method(mGPIOD, "get_value_raw", get_value_raw, 1);
178
+ }
data/gpiod.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ require_relative 'lib/gpiod/version'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'gpiod'
5
+ s.version = GPIOD::VERSION
6
+ s.licenses = ['MIT']
7
+ s.summary = "Use Linux SBC GPIO in Ruby"
8
+ s.description = "This gem provides Ruby bindings to the Linux gpiod C library"
9
+
10
+ s.authors = ["vickash"]
11
+ s.email = 'mail@vickash.com'
12
+ s.files = Dir['**/*'].reject { |f| f.match /.gem\z/}
13
+ s.homepage = "https://github.com/denko-rb/gpiod"
14
+ s.metadata = { "source_code_uri" => "https://github.com/denko-rb/gpiod" }
15
+
16
+ # libgpio C extension
17
+ s.extensions = %w[ext/gpiod/extconf.rb]
18
+ end
@@ -0,0 +1,3 @@
1
+ module GPIOD
2
+ VERSION = "0.1.0"
3
+ end
data/lib/gpiod.rb ADDED
@@ -0,0 +1,2 @@
1
+ require_relative 'gpiod/gpiod'
2
+ require_relative 'gpiod/version'
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gpiod
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - vickash
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-10-02 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: This gem provides Ruby bindings to the Linux gpiod C library
14
+ email: mail@vickash.com
15
+ executables: []
16
+ extensions:
17
+ - ext/gpiod/extconf.rb
18
+ extra_rdoc_files: []
19
+ files:
20
+ - LICENSE
21
+ - README.md
22
+ - Rakefile
23
+ - examples/bench_out.rb
24
+ - ext/gpiod/extconf.rb
25
+ - ext/gpiod/gpiod.c
26
+ - gpiod.gemspec
27
+ - lib/gpiod.rb
28
+ - lib/gpiod/version.rb
29
+ homepage: https://github.com/denko-rb/gpiod
30
+ licenses:
31
+ - MIT
32
+ metadata:
33
+ source_code_uri: https://github.com/denko-rb/gpiod
34
+ post_install_message:
35
+ rdoc_options: []
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubygems_version: 3.5.16
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: Use Linux SBC GPIO in Ruby
53
+ test_files: []