Commit 769ee42b authored by Mattias Fält's avatar Mattias Fält

Fixed buffer and comedi

parent 12129528
......@@ -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
# Devices should define a type `T` with methods:
# AbstractDevice should define a type `T` with methods:
# write!(::T, identifier, val)
# read(::T, identifier)
......
......@@ -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
......
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
export initialize, getstream, setstream!, send!, set!, getsetvalue
export initialize, getstream, setstream!, send, set!
###### Defaults for Device
###### Defaults for AbstractDevice
#What to do when connecting
initialize(::Device) = nothing
initialize(::AbstractDevice) = 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
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::Device, val)
function safe_getwritecommand(dev::AbstractDevice, val)
stream = try getstream(dev) catch
error("Device $dev not connected to a stream")
end
......@@ -20,7 +20,7 @@ function safe_getwritecommand(dev::Device, val)
end
return cmd, stream
end
function safe_getreadcommand(dev::Device)
function safe_getreadcommand(dev::AbstractDevice)
stream = try getstream(dev) catch
error("Device $dev not connected to a stream")
end
......@@ -30,21 +30,24 @@ function safe_getreadcommand(dev::Device)
return cmd, stream
end
#Maybe rethink a bit to support IObox
function send!(dev::Device, val)
function send(dev::AbstractDevice, 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)
send(stream, cmd)
return
end
function read(dev::Device)
function read(dev::AbstractDevice)
cmd, stream = safe_getreadcommand(dev)
allcmds = (false, Int32(1), cmd)
println("Sending single command: $allcmds")
serialize(stream, allcmds)
return read(stream, cmd)
end
function set!(dev::AbstractDevice, val)
cmd, stream = safe_getwritecommand(dev, val)
push!(stream.sendbuffer,cmd)
return
end
#TODO get, wait for and return response
function get(dev::AbstractDevice, val)
cmd, stream = safe_getreadcommand(dev, val)
push!(stream.readbuffer,cmd)
return
end
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
......
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
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
......
abstract type LabStream end
function close(stream::LabStream)
for dev in stream.devices
close(dev)
end
close(stream.stream)
return
end
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)
......
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
/* 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);
}
__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
......
......@@ -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"
......
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