Skip to content

Commit f518ffa

Browse files
committed
Switch to raw sysfs
1 parent 8e3c553 commit f518ffa

File tree

8 files changed

+926
-113
lines changed

8 files changed

+926
-113
lines changed

deploy/Manifest.toml

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
julia_version = "1.12.4"
44
manifest_format = "2.0"
5-
project_hash = "1f4210cd068465307a9c95f53a8d8f3e44b6baa9"
5+
project_hash = "87738c60e6c51224ddbda83104ac0e922de89472"
66

77
[[deps.ArgTools]]
88
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
@@ -35,12 +35,6 @@ version = "1.7.0"
3535
uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"
3636
version = "1.11.0"
3737

38-
[[deps.JLLWrappers]]
39-
deps = ["Artifacts", "Preferences"]
40-
git-tree-sha1 = "0533e564aae234aff59ab625543145446d8b6ec2"
41-
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
42-
version = "1.7.1"
43-
4438
[[deps.JuliaSyntaxHighlighting]]
4539
deps = ["StyledStrings"]
4640
uuid = "ac6e5ff7-fb65-4e79-a425-ec3bc9c03011"
@@ -198,18 +192,6 @@ version = "1.11.0"
198192
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
199193
version = "1.11.0"
200194

201-
[[deps.WiringPi]]
202-
deps = ["WiringPi_jll"]
203-
git-tree-sha1 = "9c9733c7f8ca73698ce601fc2df625be5270f334"
204-
uuid = "56b06491-0088-44d9-858f-9bc194f2c904"
205-
version = "0.2.2"
206-
207-
[[deps.WiringPi_jll]]
208-
deps = ["Artifacts", "JLLWrappers", "Libdl"]
209-
git-tree-sha1 = "99a7679f9e8618aca73b022548c032eecdac42e1"
210-
uuid = "39e6258f-44e5-5edf-b49b-51a5e5bce6ab"
211-
version = "3.16.0+0"
212-
213195
[[deps.Zlib_jll]]
214196
deps = ["Libdl"]
215197
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"

deploy/Project.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,3 @@
22
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
33
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
44
Timers = "21f18d07-b854-4dab-86f0-c15a3821819a"
5-
WiringPi = "56b06491-0088-44d9-858f-9bc194f2c904"

deploy/src/encoder.jl

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,29 @@
1-
using WiringPi
1+
include(joinpath(@__DIR__, "gpio.jl"))
2+
using .GPIO
23

34
#=============================================================================
45
Encoder Struct and Basic Operations
56
=============================================================================#
67

78
mutable struct Encoder
8-
pin::Int
9+
line::GPIO.GPIOLine
910
count::Int
1011
state::Bool
1112
end
1213

13-
function Encoder(pin::Int)
14-
return Encoder(pin, 0, digitalRead(pin) == HIGH)
14+
function Encoder(chip::GPIO.GPIOChip, pin::Int)
15+
line = GPIO.get_line(chip, pin)
16+
GPIO.request_input(line, "encoder")
17+
initial_state = GPIO.get_value(line) == 1
18+
return Encoder(line, 0, initial_state)
1519
end
1620

1721
function step!(e::Encoder)
18-
new_state = digitalRead(e.pin)
19-
if e.state && new_state == LOW
22+
new_state = GPIO.get_value(e.line)
23+
if e.state && new_state == 0
2024
e.count += 1
2125
e.state = false
22-
elseif !e.state && new_state == HIGH
26+
elseif !e.state && new_state == 1
2327
e.state = true
2428
end
2529
end
@@ -28,6 +32,10 @@ function reset!(e::Encoder)
2832
e.count = 0
2933
end
3034

35+
function close!(e::Encoder)
36+
GPIO.release_line(e.line)
37+
end
38+
3139
#=============================================================================
3240
Threaded Encoder Wrapper
3341
=============================================================================#
@@ -42,7 +50,8 @@ Send commands via the command channel, receive count via the response channel.
4250
4351
# Example
4452
```julia
45-
enc = Encoder(pin)
53+
chip = GPIO.open_chip()
54+
enc = Encoder(chip, pin)
4655
tenc = ThreadedEncoder(enc, 1_000_000) # 1ms poll interval
4756
4857
# Read current count

deploy/src/gpio.jl

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
#=============================================================================
2+
GPIO Wrapper using sysfs
3+
4+
Provides Julia interface for GPIO control via /sys/class/gpio/
5+
No external library dependencies - pure file I/O.
6+
=============================================================================#
7+
8+
module GPIO
9+
10+
export GPIOPin, INPUT, OUTPUT
11+
export export_pin, unexport_pin, set_direction, set_value, get_value
12+
13+
const GPIO_SYSFS_PATH = "/sys/class/gpio"
14+
15+
# Line direction
16+
@enum LineDirection begin
17+
INPUT
18+
OUTPUT
19+
end
20+
21+
#=============================================================================
22+
GPIO Pin Handle
23+
=============================================================================#
24+
25+
mutable struct GPIOPin
26+
pin::Int
27+
path::String
28+
exported::Bool
29+
direction::LineDirection
30+
end
31+
32+
#=============================================================================
33+
Low-level sysfs Operations
34+
=============================================================================#
35+
36+
"""
37+
sysfs_write(path::String, value::String)
38+
39+
Write a value to a sysfs file.
40+
"""
41+
function sysfs_write(path::String, value::String)
42+
f = open(path, "w")
43+
try
44+
write(f, value)
45+
finally
46+
close(f)
47+
end
48+
end
49+
50+
"""
51+
sysfs_read(path::String) -> String
52+
53+
Read a value from a sysfs file.
54+
"""
55+
function sysfs_read(path::String)
56+
f = open(path, "r")
57+
try
58+
return strip(read(f, String))
59+
finally
60+
close(f)
61+
end
62+
end
63+
64+
#=============================================================================
65+
Pin Export/Unexport
66+
=============================================================================#
67+
68+
"""
69+
export_pin(pin::Int) -> GPIOPin
70+
71+
Export a GPIO pin for userspace control.
72+
"""
73+
function export_pin(pin::Int)
74+
pin_path = joinpath(GPIO_SYSFS_PATH, "gpio$pin")
75+
76+
# Export if not already exported
77+
if !isdir(pin_path)
78+
export_file = joinpath(GPIO_SYSFS_PATH, "export")
79+
sysfs_write(export_file, string(pin))
80+
# Wait for sysfs to create the directory
81+
sleep(0.05)
82+
end
83+
84+
if !isdir(pin_path)
85+
error("Failed to export GPIO pin $pin")
86+
end
87+
88+
return GPIOPin(pin, pin_path, true, INPUT)
89+
end
90+
91+
"""
92+
unexport_pin(gpio::GPIOPin)
93+
94+
Unexport a GPIO pin.
95+
"""
96+
function unexport_pin(gpio::GPIOPin)
97+
if gpio.exported
98+
unexport_file = joinpath(GPIO_SYSFS_PATH, "unexport")
99+
sysfs_write(unexport_file, string(gpio.pin))
100+
gpio.exported = false
101+
end
102+
end
103+
104+
#=============================================================================
105+
Direction Control
106+
=============================================================================#
107+
108+
"""
109+
set_direction(gpio::GPIOPin, direction::LineDirection)
110+
111+
Set the GPIO pin direction (INPUT or OUTPUT).
112+
"""
113+
function set_direction(gpio::GPIOPin, direction::LineDirection)
114+
direction_file = joinpath(gpio.path, "direction")
115+
dir_str = direction == OUTPUT ? "out" : "in"
116+
sysfs_write(direction_file, dir_str)
117+
gpio.direction = direction
118+
end
119+
120+
#=============================================================================
121+
Value Read/Write
122+
=============================================================================#
123+
124+
"""
125+
set_value(gpio::GPIOPin, value::Int)
126+
127+
Set the value of an output pin (0 or 1).
128+
"""
129+
function set_value(gpio::GPIOPin, value::Int)
130+
value_file = joinpath(gpio.path, "value")
131+
sysfs_write(value_file, value == 0 ? "0" : "1")
132+
end
133+
134+
"""
135+
get_value(gpio::GPIOPin) -> Int
136+
137+
Get the value of a pin (0 or 1).
138+
"""
139+
function get_value(gpio::GPIOPin)
140+
value_file = joinpath(gpio.path, "value")
141+
val_str = sysfs_read(value_file)
142+
return parse(Int, val_str)
143+
end
144+
145+
#=============================================================================
146+
Convenience Functions (compatible with previous API)
147+
=============================================================================#
148+
149+
# Compatibility types
150+
const GPIOChip = Nothing
151+
const GPIOLine = GPIOPin
152+
153+
"""
154+
open_chip(path::String="/dev/gpiochip0") -> Nothing
155+
156+
Dummy function for API compatibility. sysfs doesn't use chip handles.
157+
"""
158+
function open_chip(path::String="/dev/gpiochip0")
159+
return nothing
160+
end
161+
162+
"""
163+
close_chip(chip::Nothing)
164+
165+
Dummy function for API compatibility.
166+
"""
167+
function close_chip(chip::Nothing)
168+
return nothing
169+
end
170+
171+
"""
172+
get_line(chip::Nothing, pin::Int) -> GPIOPin
173+
174+
Export and return a GPIO pin. Chip argument ignored (sysfs doesn't use it).
175+
"""
176+
function get_line(chip::Nothing, pin::Int)
177+
return export_pin(pin)
178+
end
179+
180+
"""
181+
request_output(gpio::GPIOPin, consumer::String, default_value::Int=0)
182+
183+
Configure pin as output with initial value.
184+
"""
185+
function request_output(gpio::GPIOPin, consumer::String, default_value::Int=0)
186+
set_direction(gpio, OUTPUT)
187+
set_value(gpio, default_value)
188+
return 0
189+
end
190+
191+
"""
192+
request_input(gpio::GPIOPin, consumer::String)
193+
194+
Configure pin as input.
195+
"""
196+
function request_input(gpio::GPIOPin, consumer::String)
197+
set_direction(gpio, INPUT)
198+
return 0
199+
end
200+
201+
"""
202+
release_line(gpio::GPIOPin)
203+
204+
Unexport the GPIO pin.
205+
"""
206+
function release_line(gpio::GPIOPin)
207+
unexport_pin(gpio)
208+
end
209+
210+
"""
211+
digitalWrite(gpio::GPIOPin, value::Bool)
212+
213+
Set a GPIO output pin high (true) or low (false).
214+
"""
215+
function digitalWrite(gpio::GPIOPin, value::Bool)
216+
set_value(gpio, value ? 1 : 0)
217+
end
218+
219+
"""
220+
digitalRead(gpio::GPIOPin) -> Bool
221+
222+
Read a GPIO input pin state.
223+
"""
224+
function digitalRead(gpio::GPIOPin)
225+
return get_value(gpio) == 1
226+
end
227+
228+
end # module GPIO

0 commit comments

Comments
 (0)