Commit d98af659 authored by Marcus Greiff's avatar Marcus Greiff

Created tests for the SysLed item and refactor code

parent 55f09f2d
"""
Lowest form of communication with the GPIO pins. The available pins are
listed in the "channel" parameter, and appear as directories in /sys/class/gpio.
Any of these GPIOs can be run in various ways, with any operation specified by an
Int32 value.
listed in the "channel" parameter, and appear as directories in /sys/class/gpio
after being exported.
For instance, to setup a GPIO on "gpio112", configure it as an output pin and set
it to high, the following code would be used.
gpio = GPIO(1)
write!(gpio, (2,"out"))
write!(gpio, (1, "1"))
gpio = GPIO(1)
write!(gpio, (2,"out"))
write!(gpio, (1, "1"))
The operation of reading the current output value of the GPIO is done by
read(gpio, 1)
read(gpio, 1)
See the test/BeagleBone/GPIO_test.jl for more examples.
"""
type GPIO <: IO_Object
i::Int32
basedir::String
filestreams::Array{IOStream,1}
function GPIO(i::Int32)
(i <= 0 || i > length(channels)) && error("Invalid GPIO index: $i")
(i <= 0 || i > length(gpio_channels)) && error("Invalid GPIO index: $i")
# If the tests re being run, a dummy filesystem is created
if isdefined(:RUNNING_TESTS)
# Export a dummy file system for testing
basedir = "$(pwd())/testfilesystem/gpio"
try
println("$(basedir)/$(channels[i])")
mkpath("$(basedir)/$(channels[i])")
catch
error("Could not export the GPIO device for channel $(channels[i]) for testing as the directory $(basedir)/$(channels[i]) already exists.")
end
try
f = open("$(basedir)/$(channels[i])/value", "w"); write(f,"0"); close(f);
f = open("$(basedir)/$(channels[i])/direction", "w"); write(f,"0"); close(f);
f = open("$(basedir)/$(channels[i])/edge", "w"); write(f,"0"); close(f);
catch
error("Could not open the requested GPIO testfiles for channel $(channels[i]).")
end
else
basedir = "/sys/class/gpio"
# TODO Export for real-time use
end
basedir = export_gpio(i)
# setup IOstreams
value_filestream = open("$(basedir)/$(channels[i])/value","r+")
direction_filestream = open("$(basedir)/$(channels[i])/direction","r+")
edge_filestream = open("$(basedir)/$(channels[i])/edge","r")
value_filestream = open("$(basedir)/$(gpio_channels[i])/value","r+")
direction_filestream = open("$(basedir)/$(gpio_channels[i])/direction","r+")
edge_filestream = open("$(basedir)/$(gpio_channels[i])/edge","r")
# Initialize object
return new(i, basedir, [value_filestream, direction_filestream, edge_filestream])
end
end
writeOperations = [["1", "0"],["in", "out"],["none","rising","falling","both"]]
channels =[
"gpio112"
"gpio114"
"gpio115"
"gpio116"
"gpio14"
"gpio15"
"gpio2"
"gpio20"
"gpio22"
"gpio23"
"gpio26"
"gpio27"
"gpio3"
"gpio30"
"gpio31"
"gpio4"
"gpio44"
"gpio45"
"gpio46"
"gpio47"
"gpio48"
"gpio49"
"gpio5"
"gpio50"
"gpio51"
"gpio60"
"gpio61"
"gpio65"
"gpio66"
"gpio67"
"gpio68"
"gpio69"
"gpio7"
]
"""
write!(gpio::GPIO, args::Tuple{Int32,String}, debug::Bool=false)
Writes an entry to an operation on a GPIO, of the form args = (operation, entry).
......@@ -101,10 +44,12 @@ Writes an entry to an operation on a GPIO, of the form args = (operation, entry)
function write!(gpio::GPIO, args::Tuple{Int32,String}, debug::Bool=false)
debug && return
operation, entry = args[1], args[2]
(operation < 1 || operation > length(gpio.filestreams)) && error("Invalid GPIO operation: $operation")
if entry in writeOperations[operation]
write(gpio.filestreams[operation], entry)
# Only filestreams 1 and 2 are writable
operation [1,2] && error("Invalid GPIO operation $operation for writing")
if entry in gpio_operations[operation]
seekstart(gpio.filestreams[operation])
write(gpio.filestreams[operation], "$entry\n")
flush(gpio.filestreams[operation])
else
error("Invalid entry for GPIO operation $(operation): $(entry)")
end
......@@ -116,9 +61,10 @@ Reads the current value from an operation on a GPIO.
"""
function read(gpio::GPIO, operation::Int32, debug::Bool=false)
debug && return
(operation < 1 || operation > length(gpio.filestreams)) && error("Invalid GPIO operation: $operation")
l = readline(gpio.filestreams[operation])
# Filestreams 1, 2 and 3 are readable
operation [1,2,3] && error("Invalid GPIO operation: $operation for reading")
seekstart(gpio.filestreams[operation])
l = readline(gpio.filestreams[operation])
return l
end
......@@ -139,16 +85,44 @@ function teardown(gpio::GPIO, debug::Bool=false)
# Remove the dummy file system for testing
basedir = "$(pwd())/testfilesystem/gpio"
try
rm("$(gpio.basedir)/$(channels[gpio.i])"; recursive=true)
rm("$(gpio.basedir)/$(gpio_channels[gpio.i])"; recursive=true)
catch
error("Could not remove the requested GPIO testfiles for channel $(channels[i]).")
error("Could not remove the requested GPIO testfiles for channel $(gpio_channels[i]).")
end
else
# Remove the file system
filename = "/sys/class/gpio/unexport"
#TODO Verify if this is the correct command to send to unexport...
write(filename, channels[gpio.i])
#TODO Verify if this is the correct command to send to unexport
write(filename, gpio_channels[gpio.i])
end
end
"""
export_gpio(i::Int32, debug::Bool=false)
Export the GPIO file system, either for real-time or testing usecases.
"""
function export_gpio(i::Int32)
if isdefined(:RUNNING_TESTS)
# Export a dummy file system for testing
basedir = "$(pwd())/testfilesystem/gpio"
try
#println("$(basedir)/$(gpio_channels[i])")
mkpath("$(basedir)/$(gpio_channels[i])")
catch
error("Could not export the GPIO device for channel $(gpio_channels[i]) for testing as the directory $(basedir)/$(gpio_channels[i]) already exists.")
end
try
f = open("$(basedir)/$(gpio_channels[i])/value", "w"); write(f,"0"); close(f);
f = open("$(basedir)/$(gpio_channels[i])/direction", "w"); write(f,"0"); close(f);
f = open("$(basedir)/$(gpio_channels[i])/edge", "w"); write(f,"0"); close(f);
catch
error("Could not open the requested GPIO testfiles for channel $(gpio_channels[i]).")
end
else
basedir = "/sys/class/gpio"
# TODO Export for real-time use
end
return basedir
end
"""
......
"""Define abstract type for pins/LEDS on the BeagleBone"""
"""
Define abstract type for pins/LEDS on the BeagleBone
"""
abstract type IO_Object end
"""
GPIO interfaces
"""
const gpio_operations = [
["1", "0"],
["in", "out"],
["none","rising","falling","both"]
]
const gpio_channels =[
"gpio112"
"gpio114"
"gpio115"
"gpio116"
"gpio14"
"gpio15"
"gpio2"
"gpio20"
"gpio22"
"gpio23"
"gpio26"
"gpio27"
"gpio3"
"gpio30"
"gpio31"
"gpio4"
"gpio44"
"gpio45"
"gpio46"
"gpio47"
"gpio48"
"gpio49"
"gpio5"
"gpio50"
"gpio51"
"gpio60"
"gpio61"
"gpio65"
"gpio66"
"gpio67"
"gpio68"
"gpio69"
"gpio7"
]
......@@ -5,12 +5,17 @@ i ∈ [1,2,3,4].
"""
type SysLED <: IO_Object
i::Int32
basedir::String
filestream::IOStream
function SysLED(i::Int32)
i [1,2,3,4] && error("Invalid SysLED index: $i")
#Note, in the future we should interface to config and retrieve IOStream from there
brightness_filestream = open("/sys/class/leds/beaglebone:green:usr$(i-1)/brightness","r+")
return new(i, brightness_filestream)
# Export system for testing
basedir = export_led(i)
# open filestream
brightness_filestream = open("$(basedir)/beaglebone:green:usr$(i-1)/brightness","r+")
return new(i, basedir, brightness_filestream)
end
end
......@@ -20,9 +25,10 @@ Turns the LED 'SysLed' on/off for val = true/false respectively.
"""
function write!(led::SysLED, entry::String, debug::Bool=false)
debug && return
entry ["0", "1"] && error("Invalid SysLED entry $(entry), valid options are 0 and 1 (string)")
write(led.filestream, entry)
entry ["0", "1"] && error("Invalid SysLED entry $(entry), valid options are 0 and 1 ::String")
seekstart(led.filestream)
write(led.filestream, "$entry\n")
flush(led.filestream)
end
"""
......@@ -31,10 +37,8 @@ Reads the current brightness value from the LED 'SysLED'.
"""
function read(led::SysLED, debug::Bool=false)
debug && return
l = read(filestream, Char)
(l != '1' && l != '0') && error("Invalid value \"$l\" read from SysLed")
seekstart(led.filestream)
return l
return readline(led.filestream)
end
"""
......@@ -44,4 +48,35 @@ Closes all open filestreams for the SysLED 'led'.
function teardown(led::SysLED, debug::Bool=false)
debug && return
close(led.filestream)
if isdefined(:RUNNING_TESTS)
# Remove the dummy file system for testing
try
#println("$(led.basedir)/beaglebone:green:usr$(led.i-1)")
rm("$(led.basedir)/beaglebone:green:usr$(led.i-1)"; recursive=true)
catch
error("Could not remove the requested LED testfiles for channel beaglebone:green:usr$(led.i-1).")
end
end
end
function export_led(i::Int32)
if isdefined(:RUNNING_TESTS)
# Export a dummy file system for testing
basedir = "$(pwd())/testfilesystem/leds"
try
#println("$(basedir)/beaglebone:green:usr$(i-1)")
mkpath("$(basedir)/beaglebone:green:usr$(i-1)")
catch
error("Could not export the LED device for beaglebone:green:usr$(i-1)) for testing as the directory $(basedir)/beaglebone:green:usr$(i-1) already exists.")
end
try
f = open("$(basedir)/beaglebone:green:usr$(i-1)/brightness", "w"); write(f,"0"); close(f);
catch
error("Could not open the requested LED testfiles for beaglebone:green:usr$(i-1)/brightness.")
end
else
basedir = "/sys/class/leds"
end
return basedir
end
using LabConnections.BeagleBone
import LabConnections.BeagleBone: initdev, listdev, closedev, printdev, write!, read!
import LabConnections.BeagleBone: initdev, listdev, closedev, printdev, write!, read, gpio_channels
using Base.Test
@testset "GPIO Inialization and termination" begin
@testset "GPIO tests" begin
@testset "Inialization/Termination" begin
# Initialize three devices
initdev("gpio", 1)
@test sum(listdev()) == 1
......@@ -41,9 +43,9 @@ using Base.Test
closedev("gpio", 5)
@test sum(listdev()) == 0
end
end
@testset "GPIO Read and write" begin
@testset "Read/Write" begin
# Fixture
device = initdev("gpio", 1)
......@@ -59,57 +61,61 @@ end
@test_throws ErrorException write!(device, (3, "bad_entry"))
# Test operation 1
sleep(0.001);write!(device, (1, "1"))
sleep(0.001);@test read(device, 1) == "1"
sleep(0.001);write!(device, (1, "0"))
sleep(0.001);@test read(device, 1) == "0"
sleep(0.001);write!(device, (1, "1"))
sleep(0.001);@test read(device, 1) == "1"
sleep(0.001);write!(device, (1, "0"))
sleep(0.001);@test read(device, 1) == "0"
if false
# TODO fix write function to clear files before writing otherwise writing "xy" when a file containt "abcd" results in "xycd" and a system failure
# Test operation 2
sleep(0.001);write!(device, (2, "in"))
sleep(0.001);@test read(device, 2) == "in"
sleep(0.001);write!(device, (2, "out"))
sleep(0.001);@test read(device, 2) == "out"
sleep(0.001);write!(device, (2, "in"))
sleep(0.001);@test read(device, 2) == "in"
sleep(0.001);write!(device, (2, "out"))
sleep(0.001);@test read(device, 2) == "out"
write!(device, (1, "1"))
@test read(device, 1) == "1"
write!(device, (1, "0"))
@test read(device, 1) == "0"
write!(device, (1, "1"))
@test read(device, 1) == "1"
write!(device, (1, "0"))
@test read(device, 1) == "0"
write!(device, (2, "in"))
@test read(device, 2) == "in"
write!(device, (2, "out"))
@test read(device, 2) == "out"
write!(device, (2, "in"))
@test read(device, 2) == "in"
write!(device, (2, "out"))
@test read(device, 2) == "out"
# Test operation 3
sleep(0.001);write!(device, (3, "none"))
sleep(0.001);@test read(device, 3) == "none"
sleep(0.001);write!(device, (3, "rising"))
sleep(0.001);@test read(device, 3) == "rising"
sleep(0.001);write!(device, (3, "falling"))
sleep(0.001);@test read(device, 3) == "falling"
sleep(0.001);write!(device, (3, "both"))
sleep(0.001);@test read(device, 3) == "both"
end
@test_throws ErrorException write!(device, (3, "none"))
@test_throws ErrorException write!(device, (3, "rising"))
@test_throws ErrorException write!(device, (3, "falling"))
@test_throws ErrorException write!(device, (3, "both"))
# Close Gpio
closedev("gpio", 1)
end
@testset "IO Communication" begin
@testset "All channels" begin
# Instanciate all possible leds and perform 10 read/write commands
# with the set high/low operation ("value")
# Configure the GPIO for output usage
device = initdev("gpio", 1)
devices = []
for ii = 1:length(gpio_channels)
device = initdev("gpio", ii)
# Operation 2 -> in/out, set out
write!(device, (2, "out"))
# Append to list
append!(devices, [device])
end
# Configure the GPIO for output usage
# Sets all available GPIO pins high/low in an alternating pattern
for i = 1:10
for ii = 1:length(gpio_channels)
state = "$(i%2)"
sleep(0.10);write!(device, (1, state))
sleep(0.001);@test read(device, 1) == state
write!(devices[ii], (1, state))
@test read(devices[ii], 1) == state
end
sleep(0.10)
end
# Closes all devices
for ii = 1:length(gpio_channels)
closedev("gpio", ii)
end
end
closedev("gpio", 1)
end
using Base.Test
# TODO write tests for PWM
@testset "PWM Inialization and termination" begin
@testset "PWM tests" begin
@testset "Inialization and termination" begin
@test 1 == 1
end
end
@testset "PWM Read and write" begin
@testset "Read and write" begin
@test 1 == 1
end
end
using LabConnections.BeagleBone
import LabConnections.BeagleBone: getdev, write!, closedev, read, initdev
import LabConnections.BeagleBone: getdev, write!, closedev, read, initdev, printdev, listdev
using Base.Test
@testset "SYS LED Tests" begin
@testset "Inialization/Termination" begin
# Initialize three devices
initdev("sysled", 1)
@test sum(listdev()) == 1
initdev("sysled", 3)
@test sum(listdev()) == 2
# Attempt to initialize a device which has already been initialized
@test_throws ErrorException initdev("sysled", 1)
@test_throws ErrorException initdev("sysled", 3)
# Attempt to initialize a device with a very high index (no matching channel)
@test_throws ErrorException initdev("sysled", 1000)
# Attempt to remove devices which have not been initialized
@test_throws ErrorException closedev("sysled", 2)
@test_throws ErrorException closedev("sysled", 4)
# Remove devices from TOC
closedev("sysled", 1)
@test sum(listdev()) == 1
closedev("sysled", 3)
@test sum(listdev()) == 0
end
@testset "Error Handling" begin
device = initdev("sysled", 1)
......@@ -17,20 +45,27 @@ using Base.Test
@testset "IO Communication" begin
# Instanciate all possible leds and perform 10 read/write commands
println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
device1 = initdev("sysled", 1)
device2 = initdev("sysled", 2)
device3 = initdev("sysled", 3)
device4 = initdev("sysled", 4)
for i = 1:10
state =
write!(device1, "$(i%2)")
write!(device2, "$((i+1)%2)")
write!(device3, "$(i%2)")
write!(device4, "$((i+1)%2)")
stateA = "$(i%2)"
stateB = "$((i+1)%2)"
write!(device1, stateA)
@test read(device1) == stateA
write!(device2, stateB)
@test read(device2) == stateB
write!(device3, stateA)
@test read(device3) == stateA
write!(device4, stateB)
@test read(device4) == stateB
sleep(0.1)
end
println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
closedev("sysled", 1)
closedev("sysled", 2)
closedev("sysled", 3)
......
......@@ -2,7 +2,8 @@ using Base.Test
# This flag is enabled if a dummy filesystem should be used for testing (for online testing)
# disabling the flag allows the BBB to be run in the loop, in this case blinking LEDS
RUNNING_TESTS = true
#RUNNING_TESTS = true
include("BeagleBone/SYS_LED_test.jl")
include("BeagleBone/GPIO_test.jl")
include("BeagleBone/PWM_test.jl")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment