README.md

# Cure

A small library that interfaces Elixir-code with C/C++ programs using Erlang/Elixir Ports. Provides Mix tasks to kickstart the development process.

## Example

The following example loads a program called "program" which is located in the ./c_src/ directory of your project.

```elixir
# Open the Port to the C/C++ program:
{:ok, server} = Cure.load "./c_src/program" 

# Depending on the kind of communication you need, there are several modes for 
# sending and receiving messages:

# Option 1 (once, asynchronous):
# Useful for messages that generate a single response

# without callback function
server |> Cure.send_data "any binary can be transmitted to the C/C++ side!", :once
receive do
  {:cure_data, response} -> 
    # Process response here..
end

# with callback function
server |> Cure.send_data <<1, 2, 3>>, :once, fn(response) ->
  # Process response here..
end


# Option 2 (noreply, asynchronous):
# Useful if you don't need a response from the C/C++ side or if you are already subscribed to the Cure process.
server |> Cure.send_data "more data..", :noreply


# Option 3 (permanent, asynchronous)
# Useful when you want to keep processing responses after you send an initial message
# (NOTE: After this function is used once, you can use :noreply and still keep getting responses)

# without callback function
server |> Cure.send_data "abcdef", :permanent
receive do
  {:cure_data, msg} -> 
    # Process response here...
end

# with callback function
server |> Cure.send_data "...", :permanent, fn(response) ->
  # Process response here..
end


# Option 4 (synchronous):
result1 = server |> Cure.send_data "testdata", :sync # a timeout can also be added as last argument
server |> Cure.send_data <<1,2,3>>, :sync, fn(response) ->
    IO.inspect response
end


# Close the program:
server |> Cure.stop # stops the supervised server
```

By default, Cure starts a supervisor which supervises all of its children (a child in this case is a GenServer that communicates with a C/C++ program). A child is added to the supervision tree with Cure.load(program_name). If you don't want this behaviour, you can also directly start a server with one of the following lines of code:

```elixir
# Option 1:
{:ok, server} = Cure.Server.start_link "program_name"

# Option 2:
{:ok, server} = Cure.Server.start "program_name"

# Stopping the server:
:ok = Cure.Server.stop(server)
```

A process can also (un)subscribe to responses coming from the C/C++ side using the following functions:

```elixir
# Option 1: receives responses as {:cure_data, ...}
server |> Cure.subscribe
server |> Cure.unsubscribe

# Option 2: passes every response to a function that processes it
fun = fn(response) -> IO.inspect response end
server |> Cure.subscribe fun
server |> Cure.unsubscribe fun
```

Examples that use Cure can be found at the following links:

- [Subtitlex](https://github.com/Primordus/Subtitlex)

## Getting started

### Add the Cure dependency to your mix.exs file:
```elixir
def deps do
	[{:cure, "~> 0.4.0"}]
end
```
### Fetch & compile dependencies
```
mix deps.get
mix deps.compile
```

### Start developing in C/C++

- Generate the necessary base files to communicate between C/C++ and Elixir:
```
mix cure.bootstrap
```

- Compile your C/C++ code (needed after each modification of your code)
```
mix compile.cure
```

- If you have dependencies that also use Cure:
```
mix compile.cure.deps
```

Another option is to add the last 2 tasks to your mix.exs to compile all code
automatically when you type mix.compile:

```elixir
def project do
  [...,
    compilers: Mix.compilers ++ [:cure, :"cure.deps"],
    ...]
end
```

## C/C++ code

C/C++ code is currently placed in the c_src directory of your application.
It can interface with Elixir-code based on 2 important functions:

1. read_msg to read data coming from Elixir;
2. send_msg to send data to Elixir.

- These helper-functions interface with Elixir by sending/receiving data via stdin or stdout. (Right now it's only possible to send messages up to 64KiB.)
- To be able to use the send and receive functions, you need to add the following include:
```C
#include <elixir_comm.h>
```

- The code for these functions is mostly based on the following [link](http://www.erlang.org/doc/tutorial/c_port.html#id57564).

## Makefile

The command "mix cure.bootstrap" generates a basic Makefile (in ./c_src/) that handles the compilation of all your C-code. This file is only generated if it doesn't exist yet so it's safe to add modifications for when your C-files need extra includes to compile properly.

The command "mix cure.make" uses the Makefile to compile all your C/C++ code.

## More information regarding Ports

- [Erlang documentation](http://www.erlang.org/doc/tutorial/c_port.html)
- [Elixir](http://elixir-lang.org/docs/stable/elixir/Port.html)