Commit 35085f69 authored by Mattias Fält's avatar Mattias Fält

Merge branch 'bufferandcomedi' into 'master'

Bufferandcomedi

See merge request !1
parents 12129528 c0f03998
*.jl.cov
*.jl.*.cov
*.jl.mem
*.sh~
\ No newline at end of file
*.sh~
*.jl~
......@@ -27,9 +27,9 @@ git:
## uncomment the following lines to override the default test script
#script:
# - julia -e 'Pkg.clone(pwd()); Pkg.build("LabConnection"); Pkg.test("LabConnection"; coverage=true)'
# - julia -e 'Pkg.clone(pwd()); Pkg.build("LabConnections"); Pkg.test("LabConnections"; coverage=true)'
after_success:
# push coverage results to Coveralls
- julia -e 'cd(Pkg.dir("LabConnection")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'
- julia -e 'cd(Pkg.dir("LabConnections")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'
# push coverage results to Codecov
- julia -e 'cd(Pkg.dir("LabConnection")); Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())'
- julia -e 'cd(Pkg.dir("LabConnections")); Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())'
#On beaglebone, run:
# include("LabConnection/src/LabConnection.jl")
# using LabConnection.BeagleBone
# include("LabConnections/src/LabConnections.jl")
# using LabConnections.BeagleBone
# run_server()
using LabConnection.Computer
using LabConnections.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
The LabConnection.jl package is licensed under the MIT "Expat" License:
The LabConnections.jl package is licensed under the MIT "Expat" License:
> Copyright (c) 2017: Mattias Fält.
>
......
# LabConnection
# LabConnections
[![Build Status](https://travis-ci.org/mfalt/LabConnection.jl.svg?branch=master)](https://travis-ci.org/mfalt/LabConnection.jl)
[![Build Status](https://travis-ci.org/mfalt/LabConnections.jl.svg?branch=master)](https://travis-ci.org/mfalt/LabConnections.jl)
[![Coverage Status](https://coveralls.io/repos/mfalt/LabConnection.jl/badge.svg?branch=master&service=github)](https://coveralls.io/github/mfalt/LabConnection.jl?branch=master)
[![Coverage Status](https://coveralls.io/repos/mfalt/LabConnections.jl/badge.svg?branch=master&service=github)](https://coveralls.io/github/mfalt/LabConnections.jl?branch=master)
[![codecov.io](http://codecov.io/github/mfalt/LabConnection.jl/coverage.svg?branch=master)](http://codecov.io/github/mfalt/LabConnection.jl?branch=master)
[![codecov.io](http://codecov.io/github/mfalt/LabConnections.jl/coverage.svg?branch=master)](http://codecov.io/github/mfalt/LabConnections.jl?branch=master)
......@@ -41,7 +41,7 @@ build_script:
# Need to convert from shallow to complete for Pkg.clone to work
- IF EXIST .git\shallow (git fetch --unshallow)
- C:\projects\julia\bin\julia -e "versioninfo();
Pkg.clone(pwd(), \"LabConnection\"); Pkg.build(\"LabConnection\")"
Pkg.clone(pwd(), \"LabConnections\"); Pkg.build(\"LabConnections\")"
test_script:
- C:\projects\julia\bin\julia -e "Pkg.test(\"LabConnection\")"
- C:\projects\julia\bin\julia -e "Pkg.test(\"LabConnections\")"
# 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, AnalogOutput10V
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), Int32(0), Int32(1), input.i)
getwritecommand(stream::LabStream, input::AnalogInput10V, 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 (Int32(0),Int32(1),input.i,val)
end
function getreadcommand(stream::ComediStream, input::AnalogInput10V)
return (Int32(0),Int32(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,68 @@ 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, Int32(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, Int32(ncmds), bbstream.readbuffer...))
#TODO wait for answer
vals = nothing
empty!(bbstream.readbuffer)
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(bbstream.stream, allcmds)
return
end
function read(bbstream::BeagleBoneStream, cmd)
allcmds = (false, Int32(1), cmd)
println("Sending single command: $allcmds")
serialize(bbstream.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!(comedistream::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)
return ccall((:comedi_read, comedipath), Float64, (Int32,Int32,Int32), cmd[1], cmd[2], cmd[3])
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
include("SysLED.jl")
include("10V.jl")
export LabStream
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)
SysLED(i::Int32) = new(i)
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);
}
module LabConnection
__precompile__()
module LabConnections
module BeagleBone
export run_server
......@@ -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
......
include("../../src/LabConnection.jl")
using LabConnection.BeagleBone
import LabConnection.BeagleBone: getdev, write!, channels
include("../../src/LabConnections.jl")
using LabConnections.BeagleBone
import LabConnections.BeagleBone: getdev, write!, channels
using Base.Test
......
include("../../src/LabConnection.jl")
using LabConnection.BeagleBone
import LabConnection.BeagleBone: getdev, write!, setup, teardown
include("../../src/LabConnections.jl")
using LabConnections.BeagleBone
import LabConnections.BeagleBone: getdev, write!, setup, teardown
pins = Dict(
"P9.22" => ("PWM0A", "pwmchip0", "0"),
......
include("../../src/LabConnection.jl")
using LabConnection.BeagleBone
import LabConnection.BeagleBone: getdev, write!, setup, teardown
pins = Dict(
"P9.22" => ("PWM0A", "pwmchip0", "0"),
"P9.21" => ("PWM0B", "pwmchip0", "1"),
"P9.14" => ("PWM1A", "pwmchip0", "0"),
"P9.16" => ("PWM1B", "pwmchip0", "1"),
"P8.19" => ("PWM2A", "pwmchip0", "0"),
"P8.13" => ("PWM2B", "pwmchip0", "1"),
)
dev = getdev("pwm")
println("Running first experiment on selected pins...")
for pin in keys(pins)
println("Testing pin $(pin)")
setup(dev, pin)
write!(dev, pin, 2, "100000000")
write!(dev, pin, 3, "50000000")
write!(dev, pin, 1, "1")
sleep(1)
write!(dev, pin, 1, "0")
teardown(dev, pin)
end
println("Running second experiment on pin $(pin)...")
pin = "P9.22"
setup(dev, pin)
write!(dev, pin, 2, "1000000000")
write!(dev, pin, 3, "250000000")
write!(dev, pin, 1, "1")
sleep(5.0)
write!(dev, pin, 3, "500000000")
sleep(5.0)
write!(dev, pin, 3, "750000000")
write!(dev, pin, 1, "0")
teardown(dev, pin)
include("../../src/LabConnection.jl")
using LabConnection.BeagleBone
import LabConnection.BeagleBone: getdev, write!
include("../../src/LabConnections.jl")
using LabConnections.BeagleBone
import LabConnections.BeagleBone: getdev, write!
using Base.Test
......