diff --git a/src/BeagleBone/BeagleBone.jl b/src/BeagleBone/BeagleBone.jl new file mode 100644 index 0000000000000000000000000000000000000000..099d5e0302b4fdee987fa8e6217c669d5cb1dc99 --- /dev/null +++ b/src/BeagleBone/BeagleBone.jl @@ -0,0 +1,67 @@ +# Devices should define a type `T` with methods: +# write!(::T, identifier, val) +# read(::T, identifier) + +include("SysLED.jl") + +#List of available devices and their constructors +const DEVICES = Dict("sysled" => SysLED()] + +""" + dev = getdev(devname) + Gets the device corresponding to the name `devname` +""" +function getdev(devname) + dev = try + DEVICES[devname] + catch + error("Device $devname does not exist") + end + return dev +end + +""" + bbparse(cmd) +Parse and execute the command `cmd` +""" +bbparse(any) = error("Unexpected input: $any") + +""" + bbparse(l::Tuple) +Parse input on the form `l=(iswrite, ndev, cmd1, cmd2, ..., cmdn)`` +where if `iswrite` + `cmdi = (devname, id, val)` + and if not `iswrite` + `cmdi = (devname, id)` +""" +function bbparse(l::Tuple) + iswrite = l[1]::Bool #True if write command, false if read + ndev = l[2]::Int32 #Number of devices/commands + for i = 1:ndev + command = l[2+i]::Tuple + dev = getdev(devname) + if iswrite + write!(dev, command[2], command[3]) + else + val = read(dev, command[2]) + println("val") + #TODO return somewhere + end + end +end + +""" + run_server(port=2001) +Run a server on `port` that listens for commands from computer +""" +function run_server(port=2001) + server = listen(port) + @async while isopen(server) + sock = accept(server) + @async while isopen(sock) + l = deserialize(sock); println("deserialize: $l") + bbparse(l) + end + end + return server +end diff --git a/src/BeagleBone/SysLED.jl b/src/BeagleBone/SysLED.jl new file mode 100644 index 0000000000000000000000000000000000000000..8625b20f5972dc47976367e0718351a21afad362 --- /dev/null +++ b/src/BeagleBone/SysLED.jl @@ -0,0 +1,23 @@ +""" +The on-board leds with id ∈ [1,2,3,4] +""" +struct SysLED +end + +function write!(::SysLED, ind::Int32, val::Bool) + ind ∉ [1,2,3,4] && error("Invalid SysLEND ind: $ind") + filename = "/sys/class/leds/beaglebone:green:usr$(ind-1)" + file = open(filename, "w+") + write(file, val ? "1" : "0") + close(file) + return +end +function read(::SysLED, ind::Int32) + ind ∉ [1,2,3,4] && error("Invalid SysLEND ind: $ind") + filename = "/sys/class/leds/beaglebone:green:usr$(ind-1)" + file = open(filename, "r") + l = readline(file, val) + (l != "1" && l != "0") && error("Invalid value \"$l\" read from SysLed") + close(file) + return l == "1" +end diff --git a/src/Computer/BeagleBoneStream.jl b/src/Computer/BeagleBoneStream.jl new file mode 100644 index 0000000000000000000000000000000000000000..985aeb06e1371316e518971225553824a76b27d9 --- /dev/null +++ b/src/Computer/BeagleBoneStream.jl @@ -0,0 +1,80 @@ +struct BeagleBoneStream <: LabStream + devices::Device + stream::TCPSocket +end + +function BeagleBoneStream(addr::IPAddr, port::Int64=2001) + clientside = connect(addr, port) + BeagleBoneStream(Device[], clientside) +end + +#For BeagleBoneStream we can directly serialize the data, other streams might want to send binary data +serialize(bbstream::BeagleBoneStream, cmd) = serialize(bbstream.stream, cmd) + +function init_devices!(bbstream::BeagleBoneStream, devs::Device...) + for dev in devs + if dev ∉ bbstream.devices + setstream!(dev, bbstream) + append!(bbstream.devices, dev) + initialize(dev) + else + warn("Device $dev already added to a stream") + end + end + return +end + +function send!(stream::BeagleBoneStream) + cmds = Tuple[] + for dev in stream.devices + val = getsetvalue(dev) + devstream, cmd = safe_getwritecommand(dev, val) + devstream == stream || error("Device $dev is connected to other stream $devstream") + push!(cmds, cmd) + end + ncmds = length(cmds) + if ncmds > 0 + allcmds = (true, ncmds, cmds...) + println("Sending command: $allcmds") + serialize(stream, allcmds) + end + return +end +function read(stream::BeagleBoneStream) + cmds = Tuple[] + for dev in stream.devices + devstream, cmd = safe_getreadcommand(dev) + devstream == stream || error("Device $dev is connected to other stream $devstream") + push!(cmds, cmd) + end + ncmds = length(cmds) + if ncmds > 0 + allcmds = (false, ncmds, cmds...) + println("Sending command: $allcmds") + serialize(stream, allcmds) + #TODO save values in dev + # update_read_vale!(dev, val) + end + return +end +function init_devices!(bbstream::BeagleBoneStream, devs::Device...) + for dev in devs + if dev ∉ bbstream.devices + setstream!(dev, bbstream) + append!(bbstream.devices, dev) + initialize(dev) + else + warn("Device $dev already added to a stream") + end + end + return +end + +function close!(bbstream::BeagleBoneStream) + cmds = Tuple[] + for dev in stream.devices + close!(dev) + end + close!(bbstream.stream) + return +end diff --git a/src/Computer/Device.jl b/src/Computer/Device.jl new file mode 100644 index 0000000000000000000000000000000000000000..419d88eaff8d90b44f427e829699dbd30bdf6918 --- /dev/null +++ b/src/Computer/Device.jl @@ -0,0 +1,42 @@ +###### Defaults for Device +#What to do when connecting +initialize(::Device) = nothing +#What to do when disconnecting +close!(::Device) = nothing +#Which stream is the Device connected to +getstream(dev::Device) = dev.stream +#Set the stream the Device is connected to +setstream!(dev::Device, stream::LabStream) = dev.stream = stream + + +function safe_getwritecommand(dev::Device, val) + stream = try getstream(dev) catch + error("Device $dev not connected to a stream") + end + cmd = try getwritecommand(stream, dev, val) catch + error("Device $dev with output val $val not supported on stream $stream") + end + return cmd, stream +end +function safe_getreadcommand(dev::Device) + stream = try getstream(dev) catch + error("Device $dev not connected to a stream") + end + cmd = try getreadcommand(stream, dev) catch + error("Device $dev not supported to read from on stream $stream") + end + return cmd, stream +end + +#Maybe rethink a bit to support IObox +function send!(dev::Device, val) + cmd, stream = safe_getwritecommand(dev, val) + serialize(stream, (true, 1, cmd)) + return +end +function read(dev::Device) + cmd, stream = safe_getreadcommand(dev) + serialize(stream, (false, 1, cmd)) + #TODO get, wait for and return response + return +end diff --git a/src/Computer/SysLED.jl b/src/Computer/SysLED.jl new file mode 100644 index 0000000000000000000000000000000000000000..7d3ae9ede182fbe6d5075d0a7da1911bba55f862 --- /dev/null +++ b/src/Computer/SysLED.jl @@ -0,0 +1,26 @@ +mutable struct SysLED <: Device + i::Int32 + nextout::Bool + latestread::Bool + stream::LabStream + SysLED(i::Int32) = new(i) +end +SysLED(i::Int64) = SysLED(convert(Int32, i), false, false) + +#Save value to send later +set!(led::SysLED, val::Bool) = led.nextout = val +#Get the value from set! back for use +getsetvalue(led::SysLED) = led.nextout +#Get value that was read erlier +get(led::SysLED) = led.latestread + +#No definition for IOBox since there are no LEDs +#Stream specific methods +function getwritecommand(stream::BeagleBoneStream, led::SysLED, val::Bool) + led.i ∉ [1,2,3,4] && error("SysLED $i not defined on BeagleBoneStream") + return ("sysled", led.i, val) +end +function getreadcommand(stream::BeagleBoneStream, led::SysLED) + led.i ∉ [1,2,3,4] && error("SysLED $i not defined on BeagleBoneStream") + return ("sysled", led.i) +end diff --git a/src/Computer/example.jl b/src/Computer/example.jl new file mode 100644 index 0000000000000000000000000000000000000000..a3f08635058ab15f9b3ee0ca76572ec945a57f06 --- /dev/null +++ b/src/Computer/example.jl @@ -0,0 +1,30 @@ +include("server.jl") + +stream = BeagleBoneStream(ip"127.0.0.1") +led2 = SysLED(2) +led3 = SysLED(3) + +# Send info to steam about which inputs/otputs to initialize +# and adds a ref in motor and led to stream +init_devices!(stream, led2, led3) +ledon = true +for i = 1:10 + set!(led2, ledon) + set!(led3, !ledon) + send!(stream) #Sends all the outputs to the stream in one atomic call + #read(stream) #Sends request to read, reads all inputs + sleep(1) + led_on = !led_on +end +for i = 1:10 + send!(led2, ledon) + sleep(0.5) + send!(led3, !ledon) + #read(stream) #Sends request to read, reads all inputs + sleep(0.5) + led_on = !led_on +end +set!(led2, false) +set!(led3, false) +send!(stream) +close!(stream) #Tells BeagleBone to stop listening and close outputs diff --git a/src/Computer/server.jl b/src/Computer/server.jl new file mode 100644 index 0000000000000000000000000000000000000000..7ceb84b06e0b22ae547636320e8115873920df4f --- /dev/null +++ b/src/Computer/server.jl @@ -0,0 +1,35 @@ +abstract type LabStream end +abstract type Device end + +include("Device.jl") + +##### General interface for devices +## A device to type T<:Device should define the methods +# set!(dev::T, val) # Remember val for next send!(::LabStream) command +# getsetvalue(dev::T) # Get the value that was saved to send +# get(dev::T) # Get val from last next read(::LabStream) command + +# getwritecommand(stream::LabStream, dev::T, val) #Get canonlical representation of send command +# getreadcommand(stream::LabStream, dev::T) #Get canonlical representation of read command + +## Default methods: +# initialize(::Device) = nothing #What to do when initializing +# close!(::Device) = nothing #What to do when disconnecting +# getstream(dev::Device) = dev.stream #Which stream is the Device connected to +# setstream!(dev::Device, stream::LabStream) = dev.stream = stream #Set the stream the Device is connected to +##### END General interface for devices + +#Include the device definitions +include("SysLED.jl") + +##### General interface for LabStream +## A stream of type T <: LabStream should define the methods +# serialize(::T, cmd) # Send data `cmd` +# init_devices!(::T, devs::Device...) # Initialize devices and connect them to stream +# send!(::T) # Send set! commands for all devices to stream, using getwritecommand(stream::LabStream, dev::Device, getsetvalue(dev::Device)) +# read(::T) # Send read commands for all devices to stream, sing get(dev::Device) +# init_devices! # Initialize all connected devises, using initialize(::Device) +# close! # Close connection, call close!(::Device) on all connected devices + +#Include the stream definitions +include("BeagleBoneStream.jl")