diff --git a/Examples/testLED.jl b/Examples/testLED.jl index ef131791d714a3140ce60a924186ec34b97600df..6a9740acffa0a3bb7b6a10f9528ee8a90adb2cbc 100644 --- a/Examples/testLED.jl +++ b/Examples/testLED.jl @@ -6,30 +6,39 @@ using LabConnection.Computer stream = BeagleBoneStream(ip"192.168.7.2") +led1 = SysLED(1) led2 = SysLED(2) led3 = SysLED(3) +led4 = SysLED(4) # 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) +init_devices!(stream, led1, led2, led3, led4) 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 +for i = 1:50 + set!(led1, ledon) + set!(led2, !ledon) + set!(led3, ledon) + set!(led4, !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) + sleep(0.1) ledon = !ledon 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) +for i = 1:40 + send(led1, ledon) + sleep(0.03) + send(led2, ledon) + sleep(0.03) + send(led3, ledon) + sleep(0.03) + send(led4, ledon) + sleep(0.03) ledon = !ledon end +set!(led1, false) set!(led2, false) set!(led3, false) -send!(stream) +set!(led4, false) +send(stream) close(stream) #Tells BeagleBone to stop listening and close outputs diff --git a/src/BeagleBone/BeagleBone.jl b/src/BeagleBone/BeagleBone.jl index 0799a05c3695129fe9e01382dfaf70cc5de04967..e7d2e6e419215234404f056ab0449623f674c61e 100644 --- a/src/BeagleBone/BeagleBone.jl +++ b/src/BeagleBone/BeagleBone.jl @@ -1,4 +1,4 @@ -# Devices should define a type `T` with methods: +# AbstractDevice should define a type `T` with methods: # write!(::T, identifier, val) # read(::T, identifier) diff --git a/src/BeagleBone/precompile.jl b/src/BeagleBone/precompile.jl index eb9b76eebe1cd98a81e6c01dc3045b7120f45c5e..bf714ec3fbede44bfe021ca0d9ebda58de76e3af 100644 --- a/src/BeagleBone/precompile.jl +++ b/src/BeagleBone/precompile.jl @@ -28,6 +28,8 @@ function precompile_bb() write!(gpio, Int32(1), ("value", "1"), debug) #read(gpio, ind, args, debug) +#TODO write/read + try getdev("nonexistent") catch end try bbparse("Invalid input") catch end try bbparse(("Invalid input")) catch end diff --git a/src/Computer/10V.jl b/src/Computer/10V.jl new file mode 100644 index 0000000000000000000000000000000000000000..3da2a8b23a71b62585f1a739ec1097c65cdd8d18 --- /dev/null +++ b/src/Computer/10V.jl @@ -0,0 +1,39 @@ +export AnalogInput10V + +mutable struct AnalogInput10V <: AbstractDevice + i::Int32 + stream::LabStream + AnalogInput10V(i::Int32) = new(i) +end +mutable struct AnalogOutput10V <: AbstractDevice + i::Int32 + stream::LabStream + AnalogOutput10V(i::Int32) = new(i) +end +AnalogInput10V(i::Int64) = AnalogInput10V(convert(Int32, i)) +AnalogOutput10V(i::Int64) = AnalogOutput10V(convert(Int32, i)) + +initialize(::AnalogInput10V) = nothing +initialize(::AnalogOutput10V) = nothing + +close(::AnalogInput10V) = nothing +close(input::AnalogOutput10V) = ccall(:comedi_write_zero, comedipath, Void, (Int32, Int32, Int32), 0, 1, input.i) + +getwritecommand(stream::LabStream, input::AnalogIntput10V, val) = error("Can't write to device $input") +getreadcommand(stream::LabStream, output::AnalogOutput10V, val) = error("Can't read from device $output") + +function getwritecommand(stream::BeagleBoneStream, input::AnalogOutput10V, val::Float64) + abs(val) < 10 || error("Volatage $val not in range [-10,10]") + return ("analogin10", input.i, val) +end +function getreadcommand(stream::BeagleBoneStream, input::AnalogInput10V) + return ("analogin10", input.i, val) +end + +function getwritecommand(stream::ComediStream, input::AnalogOutput10V, val::Float64) + abs(val) < 10 || error("Volatage $val not in range [-10,10]") + return (0,1,input.i,val) +end +function getreadcommand(stream::ComediStream, input::AnalogInput10V) + return (0,0,input.i) +end diff --git a/src/Computer/AbstractDevice.jl b/src/Computer/AbstractDevice.jl new file mode 100644 index 0000000000000000000000000000000000000000..f4d65c3907517a26fd2ebd5387d0203a67193bf0 --- /dev/null +++ b/src/Computer/AbstractDevice.jl @@ -0,0 +1,53 @@ +export initialize, getstream, setstream!, send, set! + +###### Defaults for AbstractDevice +#What to do when connecting +initialize(::AbstractDevice) = nothing +#What to do when disconnecting +close(::AbstractDevice) = nothing +#Which stream is the AbstractDevice connected to +getstream(dev::AbstractDevice) = dev.stream +#Set the stream the AbstractDevice is connected to +setstream!(dev::AbstractDevice, stream::LabStream) = dev.stream = stream + + +function safe_getwritecommand(dev::AbstractDevice, 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::AbstractDevice) + 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 + +function send(dev::AbstractDevice, val) + cmd, stream = safe_getwritecommand(dev, val) + send(stream, cmd) + return +end +function read(dev::AbstractDevice) + cmd, stream = safe_getreadcommand(dev) + return read(stream, cmd) +end + +function set!(dev::AbstractDevice, val) + cmd, stream = safe_getwritecommand(dev, val) + push!(stream.sendbuffer,cmd) + return +end + +function get(dev::AbstractDevice, val) + cmd, stream = safe_getreadcommand(dev, val) + push!(stream.readbuffer,cmd) + return +end diff --git a/src/Computer/BeagleBoneStream.jl b/src/Computer/BeagleBoneStream.jl index 557da8f5feedf00fcd8c48ad1d844c573bc01205..24bd09f726307459a84be8c2c68bd0224fe47977 100644 --- a/src/Computer/BeagleBoneStream.jl +++ b/src/Computer/BeagleBoneStream.jl @@ -1,19 +1,21 @@ -export BeagleBoneStream, init_devices!, send! +export BeagleBoneStream, init_devices! struct BeagleBoneStream <: LabStream - devices::Array{Device,1} + devices::Array{AbstractDevice,1} + sendbuffer::Array{Tuple,1} + readbuffer::Array{Tuple,1} stream::TCPSocket end function BeagleBoneStream(addr::IPAddr, port::Int64=2001) clientside = connect(addr, port) - BeagleBoneStream(Device[], clientside) + BeagleBoneStream(AbstractDevice[], Tuple[], Tuple[], 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...) +function init_devices!(bbstream::BeagleBoneStream, devs::AbstractDevice...) for dev in devs if dev ∉ bbstream.devices setstream!(dev, bbstream) @@ -26,37 +28,69 @@ function init_devices!(bbstream::BeagleBoneStream, devs::Device...) return end -function send!(stream::BeagleBoneStream) - cmds = Tuple[] - for dev in stream.devices - val = getsetvalue(dev) - cmd, devstream = safe_getwritecommand(dev, val) - devstream == stream || error("Device $dev is connected to other stream $devstream") - push!(cmds, cmd) - end - ncmds = Int32(length(cmds)) - if ncmds > 0 - allcmds = (true, ncmds, cmds...) - println("Sending command: $allcmds") - serialize(stream, allcmds) - end +function send(bbstream::BeagleBoneStream) + ncmds = length(bbstream.sendbuffer) + serialize(bbstream.stream, (true, ncmds, bbstream.sendbuffer)) + empty!(bbstream.sendbuffer) return end -function read(stream::BeagleBoneStream) - cmds = Tuple[] - for dev in stream.devices - cmd, devstream = safe_getreadcommand(dev) - devstream == stream || error("Device $dev is connected to other stream $devstream") - push!(cmds, cmd) - end - ncmds = Int32(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 +function read(comedistream::BeagleBoneStream) + ncmds = length(bbstream.readbuffer) + serialize(bbstream.stream, (false, ncmds, bbstream.sendbuffer)) + #TODO wait for answer + vals = nothing + empty!(bbstream.sendbuffer) + return vals +end +# +# function send(stream::BeagleBoneStream) +# cmds = Tuple[] +# for dev in stream.devices +# val = getsetvalue(dev) +# cmd, devstream = safe_getwritecommand(dev, val) +# devstream == stream || error("Device $dev is connected to other stream $devstream") +# push!(cmds, cmd) +# end +# ncmds = Int32(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 +# cmd, devstream = safe_getreadcommand(dev) +# devstream == stream || error("Device $dev is connected to other stream $devstream") +# push!(cmds, cmd) +# end +# ncmds = Int32(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 + + +#Maybe rethink a bit to support IObox +function send(bbstream::BeagleBoneStream, cmd) + allcmds = (true, Int32(1), cmd) + println("Sending single command: $allcmds") + serialize(stream, allcmds) + return +end +function read(bbstream::BeagleBoneStream, cmd) + cmd, stream = safe_getreadcommand(dev) + allcmds = (false, Int32(1), cmd) + println("Sending single command: $allcmds") + serialize(stream, allcmds) + #TODO get, wait for and return response return end diff --git a/src/Computer/ComediStream.jl b/src/Computer/ComediStream.jl new file mode 100644 index 0000000000000000000000000000000000000000..a89fab3fdeb4822ddc8feba568977c39909bc8ab --- /dev/null +++ b/src/Computer/ComediStream.jl @@ -0,0 +1,56 @@ +export ComediStream, init_devices! + +const comedipath = joinpath(@__DIR__,"comedi","comedi_bridge.so") +const comediname = "/dev/comedi0" +const SendTuple = Tuple{Int32,Int32,Int32,Float64} +const ReadTuple = Tuple{Int32,Int32,Int32} + +struct ComediStream <: LabStream + devices::Array{AbstractDevice,1} + sendbuffer::Array{SendTuple,1} + readbuffer::Array{ReadTuple,1} +end + +function ComediStream() + ccall((:comedi_start, comedipath),Int32,(Ptr{UInt8},), comediname) + ComediStream(AbstractDevice[], SendTuple[], ReadTuple[]) +end + +function init_devices!(stream::ComediStream, devs::AbstractDevice...) + for dev in devs + if dev ∉ comedistream.devices + setstream!(dev, comedistream) + push!(comedistream.devices, dev) + initialize(dev) + else + warn("Device $dev already added to the stream") + end + end + return +end + +function send(comedistream::ComediStream, cmd::SendTuple) + ccall((:comedi_write, comedipath),Int32,(Int32,Int32,Int32,Float64), cmd[1], cmd[2], cmd[3], cmd[4]) + return +end +function read(comedistream::ComediStream, cmd::ReadTuple) + ccall((:comedi_read, comedipath),Int32,(Int32,Int32,Int32), cmd[1], cmd[2], cmd[3]) + return +end + +function send(comedistream::ComediStream) + map(cmd -> send(comedistream, cmd), comedistream.sendbuffer) + empty!(comedistream.readbuffer) + return +end +function read(comedistream::ComediStream) + vals = map(cmd -> read(comedistream, cmd), comedistream.sendbuffer) + empty!(comedistream.readbuffer) + return vals +end + +function close(stream::ComediStream) + foreach(close, stream.devices) + ccall((:comedi_stop, comedipath),Int32,(Int32,), 0) + return +end diff --git a/src/Computer/Computer.jl b/src/Computer/Computer.jl index eeb58a6de8fb4fca8ce29ea6a4ec11747ccec238..c494e99b016eaac2603041b99fc5bb80a86f7c3e 100644 --- a/src/Computer/Computer.jl +++ b/src/Computer/Computer.jl @@ -1,35 +1,35 @@ -abstract type LabStream end -abstract type Device end +abstract type AbstractDevice end -include("Device.jl") +include("LabStream.jl") +include("AbstractDevice.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 +# init_devices!(::T, devs::AbstractDevice...) # Initialize devices and connect them to stream +# send(::T) # Send set! commands for all devices to stream, using getwritecommand(stream::LabStream, dev::AbstractDevice, getsetvalue(dev::AbstractDevice)) +# read(::T) # Send read commands for all devices to stream, sing get(dev::AbstractDevice) +# init_devices! # Initialize all connected devises, using initialize(::AbstractDevice) +# close # Close connection, call close(::AbstractDevice) on all connected devices #Include the stream definitions +include("ComediStream.jl") include("BeagleBoneStream.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 +## A device to type T<:AbstractDevice should define the methods +# set!(dev::T, val) # Remember val for next send(::LabStream) command # 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 +# initialize(::AbstractDevice) = nothing #What to do when initializing +# close(::AbstractDevice) = nothing #What to do when disconnecting +# getstream(dev::AbstractDevice) = dev.stream #Which stream is the Device connected to +# setstream!(dev::AbstractDevice, stream::LabStream) = dev.stream = stream #Set the stream the Device is connected to ##### END General interface for devices #Include the device definitions diff --git a/src/Computer/Device.jl b/src/Computer/Device.jl deleted file mode 100644 index 96c299cfa731493411680d4db041b90eed1ee4bc..0000000000000000000000000000000000000000 --- a/src/Computer/Device.jl +++ /dev/null @@ -1,50 +0,0 @@ -export initialize, getstream, setstream!, send!, set!, getsetvalue - -###### 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) - #TODO This is not very general - allcmds = (true, Int32(1), cmd) - println("Sending single command: $allcmds") - serialize(stream, allcmds) - return -end -function read(dev::Device) - cmd, stream = safe_getreadcommand(dev) - allcmds = (false, Int32(1), cmd) - println("Sending single command: $allcmds") - serialize(stream, allcmds) - - #TODO get, wait for and return response - return -end diff --git a/src/Computer/LabStream.jl b/src/Computer/LabStream.jl new file mode 100644 index 0000000000000000000000000000000000000000..3856de744ef78ce63717393f7936d4f4fdf108ad --- /dev/null +++ b/src/Computer/LabStream.jl @@ -0,0 +1,9 @@ +abstract type LabStream end + +function close(stream::LabStream) + for dev in stream.devices + close(dev) + end + close(stream.stream) + return +end diff --git a/src/Computer/SysLED.jl b/src/Computer/SysLED.jl index 94a6962cdd4c0cb6b0d6cd7ed94eb22e99b69d5d..2d0837a492fdf0dee4c238d96d7035801f9d7970 100644 --- a/src/Computer/SysLED.jl +++ b/src/Computer/SysLED.jl @@ -1,21 +1,12 @@ export SysLED -mutable struct SysLED <: Device +mutable struct SysLED <: AbstractDevice i::Int32 - nextout::Bool - latestread::Bool stream::LabStream SysLED(i::Int32) = new(i, false, false) end SysLED(i::Int64) = SysLED(convert(Int32, i)) -#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) diff --git a/src/Computer/comedi/Makefile b/src/Computer/comedi/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2983d113d7fac4c5b0ebea540ebf3948ca263af9 --- /dev/null +++ b/src/Computer/comedi/Makefile @@ -0,0 +1,15 @@ +CC=gcc + +CFLAGS=-c -Wall -fPIC + +SOURCES=comedi_bridge.c +OBJECTS=$(SOURCES:.c=.o) + +.c.o: + $(CC) $(CFLAGS) $< -o $@ + +lib: $(OBJECTS) + $(CC) -shared -fPIC -lcomedi -lm -o comedi_bridge.so $(OBJECTS) + +clean: + rm *.o *.so diff --git a/src/Computer/comedi/comedi.c b/src/Computer/comedi/comedi.c new file mode 100644 index 0000000000000000000000000000000000000000..27cc729e874d1b82114888010f7bb5b394f445b5 --- /dev/null +++ b/src/Computer/comedi/comedi.c @@ -0,0 +1,57 @@ +/* This is a bridge between Julia and Comedi, written by Martin Karlsson + * and Jacob Mejvik at Dept. Automatic Control, Lund University.*/ + +#include <stdio.h> /* for printf() */ +#include <comedilib.h> + + +int range = 0; +int aref = AREF_GROUND; +comedi_t *device; +comedi_range * range_info; +lsampl_t maxdata; + +int comedi_write(int comediNbr, int subdev, int chan, double physical_value) { + static int comedi_value; + static int retval; + range_info = comedi_get_range(device, subdev, chan, range); + maxdata = comedi_get_maxdata(device, subdev, chan); + comedi_value = comedi_from_phys(physical_value, range_info, maxdata); + retval = comedi_data_write(device, subdev, chan, range, aref, comedi_value); + return retval; +} + +double comedi_read(int comediNbr, int subdev, int chan) { + static double physical_value; + lsampl_t comedi_value; + comedi_data_read(device, subdev, chan, range, aref, &comedi_value); + range_info = comedi_get_range(device, subdev, chan, range); + maxdata = comedi_get_maxdata(device, subdev, chan); + physical_value = comedi_to_phys(comedi_value, range_info, maxdata); + return physical_value; +} + +// comedi_path example: "/dev/comedi0" +int comedi_start(char* comedi_name) { + device = comedi_open(comedi_name); + if(device == NULL) + { + comedi_perror("comedi_open_error"); + return -1; + } + comedi_set_global_oor_behavior(COMEDI_OOR_NUMBER); + return 0; +} + +void comedi_write_zero(int comediNbr, int subdev, int chan) { + static double physical_value_zero = 0.0; + static lsampl_t comedi_value; + range_info = comedi_get_range(device, subdev, chan, range); + maxdata = comedi_get_maxdata(device, subdev, chan); + comedi_value = comedi_from_phys(physical_value_zero, range_info, maxdata); + comedi_data_write(device, subdev, chan, range, aref, comedi_value); +} + +void comedi_stop(int comediNbr) { + comedi_close(device); +} diff --git a/src/Computer/comedi/comedi_bridge.o b/src/Computer/comedi/comedi_bridge.o new file mode 100644 index 0000000000000000000000000000000000000000..91d8dd79812bcd5cc4888231b243e8f5ab44ab9e Binary files /dev/null and b/src/Computer/comedi/comedi_bridge.o differ diff --git a/src/Computer/comedi/comedi_bridge.so b/src/Computer/comedi/comedi_bridge.so new file mode 100755 index 0000000000000000000000000000000000000000..0526f55afaf161f8fb3d8f6c7d73eaddfae02472 Binary files /dev/null and b/src/Computer/comedi/comedi_bridge.so differ diff --git a/src/LabConnection.jl b/src/LabConnection.jl index f2319055e922856ea0d4c8dba85dd93af68a9227..18cd8788391aff96d762163ad04e4ebbc2e317d0 100644 --- a/src/LabConnection.jl +++ b/src/LabConnection.jl @@ -1,3 +1,4 @@ +__precompile__() module LabConnection module BeagleBone @@ -12,7 +13,7 @@ module LabConnection end module Computer - import Base: read, close, get, serialize + import Base: read, send, close, get, serialize println("Initializing Computer") include(joinpath("Computer","Computer.jl")) end diff --git a/util/copyfoldertobb.sh b/util/copyfoldertobb.sh index a38f4cca2af96f90121912ab7c6a45adfd94f02d..1bf613891e797a71bc3fdd5b228fc9757b4dd2b9 100755 --- a/util/copyfoldertobb.sh +++ b/util/copyfoldertobb.sh @@ -8,7 +8,7 @@ printf "${BLUE}Updating project${NC}\n..." codeHost=gitlab.control.lth.se codeUser=labdev -projects=(LabConnection) +projects=LabConnection flag=false printf "${BLUE}Initializing Transferring files to BBB${NC}\n"