Skip to content

Commit

Permalink
Merge pull request #14 from rdeits/lcm-core
Browse files Browse the repository at this point in the history
Use LCMCore to provide the LCM interface
  • Loading branch information
rdeits authored Jan 29, 2017
2 parents e9aa77b + adc1b5e commit 44addb9
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 171 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ os:
- linux
- osx
julia:
- 0.4
- 0.5
- nightly
notifications:
Expand Down
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
[![Build Status](https://travis-ci.org/rdeits/PyLCM.jl.svg?branch=master)](https://travis-ci.org/rdeits/PyLCM.jl)
[![codecov.io](https://codecov.io/github/rdeits/PyLCM.jl/coverage.svg?branch=master)](https://codecov.io/github/rdeits/PyLCM.jl?branch=master)

PyLCM provides an interface to the [Lightweight Communications and Marshalling (LCM) library](https://lcm-proj.github.io/) in Julia. It wraps the LCM Python interface using [PyCall](https://github.com/stevengj/PyCall.jl), so it will be slower than calling the LCM C-API directly.
PyLCM provides an interface to the [Lightweight Communications and Marshalling (LCM) library](https://lcm-proj.github.io/) in Julia. Most of the functionality is provided by [LCMCore.jl](https://github.com/rdeits/LCMCore.jl), which interacts with LCM through its C API. PyLCM builds on LCMCore by allowing you to send and receive Python LCM types from Julia.

# Installation

If you have a systemwide installation of LCM, PyLCM will try to use it. If you don't, then running `Pkg.build("PyLCM")` will download and install a private copy of LCM and the python bindings for you.
If you have a systemwide installation of LCM, PyLCM will try to use it. If you don't, then running `Pkg.build("LCMCore")` will download and install a private copy of LCM and the python bindings for you.

# Usage

Expand Down Expand Up @@ -65,3 +65,13 @@ while true
handle(lc)
end
```

### Asynchronously handling messages

Creating an asynchronous handler just requires the `@async` macro:

```julia
@async while true
handle(lc)
end
```
6 changes: 2 additions & 4 deletions REQUIRE
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
julia 0.4
julia 0.5
PyCall 1.4.0
BinDeps 0.4.0
Compat 0.8.0
@osx Homebrew 0.3.0
LCMCore 0.0.1
34 changes: 0 additions & 34 deletions appveyor.yml

This file was deleted.

85 changes: 0 additions & 85 deletions deps/build.jl

This file was deleted.

66 changes: 21 additions & 45 deletions src/PyLCM.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,35 @@ __precompile__()

module PyLCM

using Base.Dates: Period, Millisecond
using PyCall
using Base.Dates: Period, Millisecond
using LCMCore
import LCMCore: encode, subscribe, decode

export LCM, publish, subscribe, handle, @pyimport

const pylcm = PyNULL()

immutable LCM
lcm_obj::PyObject

LCM() = new(pylcm[:LCM]())
end

function publish(lc::LCM, channel::AbstractString, msg)
pycall(lc.lcm_obj[:publish], PyAny, channel, pycall(msg[:encode], PyObject))
end

function subscribe(lc::LCM, channel::AbstractString, handler::Function)
lc.lcm_obj[:subscribe](channel, pyeval("lambda chan, data, handler=h: handler(chan, bytearray(data))", h=handler))
end

function subscribe(lc::LCM, channel::AbstractString, handler::Function, msg_type::PyObject)
lc.lcm_obj[:subscribe](channel, pyeval("lambda chan, data, handler=h, msg_type=t: handler(chan, msg_type.decode(data))", h=handler, t=msg_type))
end

"Wait for and dispatch the next incoming message"
function handle(lc::LCM)
pycall(lc.lcm_obj[:handle], PyObject)
true
end

"""
handle(lc, timeout)
Wait for and dispatch the next incoming message, with a timeout expressed
as any Base.Dates.Period type. For example:
handle(lc, Millisecond(10))
or
handle(lc, Second(1))
Returns true if a message was handled, false if the function timed out.
"""
function handle(lc::LCM, timeout::Period)
timeout_ms = convert(Int, convert(Millisecond, timeout))
convert(Bool, pycall(lc.lcm_obj[:handle_timeout], PyObject, timeout_ms))
# This is the only method required to enable publishing python
# LCM messages
encode(msg::PyObject) = pycall(msg[:encode], Vector{UInt8})

# We override the subscribe() method that takes in a user-supplied
# message type. That's because the method in LCMCore assumes that
# the Julia type of the message is enough to determine how to
# decode the message. That's not the case for PyLCM because all
# python LCM types are just PyObjects.
function subscribe(lcm::LCM, channel::String, handler, msgtype::PyObject)
function inner_handler(channel, data)
pymsg = pycall(msgtype[:decode], PyObject, data)
handler(channel, pymsg)
end
subscribe(lcm, channel, inner_handler)
end

function __init__()
depsjl = joinpath(dirname(@__FILE__), "..", "deps", "deps.jl")
isfile(depsjl) ? include(depsjl) : error("PyLCM not properly ",
"installed. Please run\nPkg.build(\"PyLCM\")")
sys = pyimport("sys")
unshift!(PyVector(sys["path"]), joinpath(LCMCore.lcm_prefix, "lib", "python" * string(sys[:version_info][1]) * "." * string(sys[:version_info][2]), "site-packages"))
copy!(pylcm, pyimport("lcm"))
end

Expand Down

0 comments on commit 44addb9

Please sign in to comment.