Permalink
Browse files

Merge pull request #1 from daha/serial_and_spi

Wrap serial and SPI libraries
  • Loading branch information...
2 parents 354a251 + b314a9b commit a8973c90dba5110c231e2e488586e8612fa2082a @klajo committed Sep 23, 2012
Showing with 278 additions and 14 deletions.
  1. +2 −0 README.md
  2. +171 −1 c_src/wpi.c
  3. +105 −13 src/wpi.erl
View
@@ -45,6 +45,8 @@ Functionality
* control and write to LCDs
* shift in/out bits (untested)
* soft PWM
+* read from and write to a serial console
+* write and read binary data from the SPI bus
Caveats
-------
View
@@ -23,6 +23,8 @@
#include <lcd.h>
#include <wiringShift.h>
#include <softPwm.h>
+#include <wiringSerial.h>
+#include <wiringPiSPI.h>
static ERL_NIF_TERM atom_ok;
static ERL_NIF_TERM atom_error;
@@ -266,6 +268,162 @@ soft_pwm_write_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return atom_ok;
}
+// serial
+static ERL_NIF_TERM
+serial_open_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int str_len, baud, handle;
+ if (!enif_get_int(env, argv[0], &baud) ||
+ !enif_get_int(env, argv[1], &str_len))
+ {
+ return enif_make_badarg(env);
+ }
+ char device[str_len+1];
+ if (!enif_get_string(env, argv[2], device, sizeof(device), ERL_NIF_LATIN1))
+ {
+ return enif_make_badarg(env);
+ }
+
+ handle = serialOpen(device, baud);
+ return enif_make_int(env, handle);
+}
+
+static ERL_NIF_TERM
+serial_close_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int handle;
+ if (!enif_get_int(env, argv[0], &handle))
+ {
+ return enif_make_badarg(env);
+ }
+ serialClose(handle);
+ return atom_ok;
+}
+
+static ERL_NIF_TERM
+serial_flush_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int handle;
+ if (!enif_get_int(env, argv[0], &handle))
+ {
+ return enif_make_badarg(env);
+ }
+ serialFlush(handle);
+ return atom_ok;
+}
+
+static ERL_NIF_TERM
+serial_put_char_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int handle, character;
+ if (!enif_get_int(env, argv[0], &handle) ||
+ !enif_get_int(env, argv[1], &character))
+ {
+ return enif_make_badarg(env);
+ }
+ serialPutchar(handle, (uint8_t)character);
+ return atom_ok;
+}
+
+static ERL_NIF_TERM
+serial_puts_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int handle, str_len;
+ if (!enif_get_int(env, argv[0], &handle) ||
+ !enif_get_int(env, argv[1], &str_len))
+ {
+ return enif_make_badarg(env);
+ }
+ char str[str_len+1];
+ if (!enif_get_string(env, argv[2], str, sizeof(str), ERL_NIF_LATIN1))
+ {
+ return enif_make_badarg(env);
+ }
+ serialPuts(handle, str);
+ return atom_ok;
+}
+
+static ERL_NIF_TERM
+serial_data_avail_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int handle;
+ if (!enif_get_int(env, argv[0], &handle))
+ {
+ return enif_make_badarg(env);
+ }
+ int data_avail = serialDataAvail(handle);
+ return enif_make_int(env, data_avail);
+}
+
+static ERL_NIF_TERM
+serial_get_char_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int handle;
+ if (!enif_get_int(env, argv[0], &handle))
+ {
+ return enif_make_badarg(env);
+ }
+ int c = serialGetchar(handle);
+ return enif_make_int(env, c);
+}
+
+// SPI
+static ERL_NIF_TERM
+spi_get_fd_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int channel;
+ if (!enif_get_int(env, argv[0], &channel))
+ {
+ return enif_make_badarg(env);
+ }
+ int fd = wiringPiSPIGetFd(channel);
+ return enif_make_int(env, fd);
+}
+
+static ERL_NIF_TERM
+spi_data_rw_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int channel, len;
+ ErlNifBinary buf;
+ ERL_NIF_TERM atom_fail, err_code;
+
+ if (!enif_get_int(env, argv[0], &channel) ||
+ !enif_inspect_binary(env, argv[1], &buf) ||
+ !enif_get_int(env, argv[2], &len))
+ {
+ return enif_make_badarg(env);
+ }
+
+ enif_realloc_binary(&buf, len);
+
+ int result = wiringPiSPIDataRW(channel, buf.data, len);
+ if (result >= 0) {
+ return enif_make_tuple2(env,
+ atom_ok,
+ enif_make_binary(env, &buf));
+ } else {
+ atom_fail = enif_make_atom(env, "failed_to_read_write_data");
+ err_code = enif_make_int(env, result);
+ enif_release_binary(&buf);
+ return enif_make_tuple2(env,
+ atom_error,
+ enif_make_tuple2(env, atom_fail, err_code));
+ }
+}
+
+static ERL_NIF_TERM
+spi_setup_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int channel, speed;
+ if (!enif_get_int(env, argv[0], &channel) ||
+ !enif_get_int(env, argv[1], &speed))
+ {
+ return enif_make_badarg(env);
+ }
+ int result = wiringPiSPISetup(channel, speed);
+ return enif_make_int(env, result);
+}
+
static ErlNifFunc nif_funcs[] =
{
// the basics: pins and stuff
@@ -286,7 +444,19 @@ static ErlNifFunc nif_funcs[] =
{"shift_out_nif", 4, shift_out_nif},
// soft pwm
{"soft_pwm_create_nif", 3, soft_pwm_create_nif},
- {"soft_pwm_write_nif", 2, soft_pwm_write_nif}
+ {"soft_pwm_write_nif", 2, soft_pwm_write_nif},
+ // serial
+ {"serial_open_nif", 3, serial_open_nif},
+ {"serial_close_nif", 1, serial_close_nif},
+ {"serial_flush_nif", 1, serial_flush_nif},
+ {"serial_put_char_nif", 2, serial_put_char_nif},
+ {"serial_puts_nif", 3, serial_puts_nif},
+ {"serial_data_avail_nif", 1, serial_data_avail_nif},
+ {"serial_get_char_nif", 1, serial_get_char_nif},
+ // SPI
+ {"spi_get_fd_nif", 1, spi_get_fd_nif},
+ {"spi_data_rw_nif", 3, spi_data_rw_nif},
+ {"spi_setup_nif", 2, spi_setup_nif}
};
ERL_NIF_INIT(wpi, nif_funcs, load, NULL, NULL, NULL)
View
@@ -45,22 +45,45 @@
-export([soft_pwm_create/3]).
-export([soft_pwm_write/2]).
+%% serial
+-export([serial_open/2]).
+-export([serial_close/1]).
+-export([serial_flush/1]).
+-export([serial_put_char/2]).
+-export([serial_puts/2]).
+-export([serial_printf/3]).
+-export([serial_format/3]).
+-export([serial_data_avail/1]).
+-export([serial_get_char/1]).
+
+%% SPI
+-export([spi_get_fd/1]).
+-export([spi_data_rw/2]).
+-export([spi_setup/2]).
+
-define(nif_stub,
erlang:nif_error({nif_not_loaded, module, ?MODULE, line, ?LINE})).
-on_load(on_load/0).
--type wpi_pin_mode() :: 0..2 % WPI_INPUT | WPI_OUTPUT | WPI_PWM_OUTPUT
- | input | output | pwm_output.
--type wpi_pin_number() :: integer().
--type wpi_digital_value() :: 0..1. % WPI_LOW | WPI_HIGH
--type wpi_pwm_value() :: 0..1023.
--type wpi_pud_mode() :: 0..2 % WPI_PUD_OFF | WPI_PUD_DOWN | WPI_PUD_UP
- | off | down | up.
--opaque wpi_lcd_handle() :: integer().
--type wpi_bit_order() :: 0..1 % WPI_LSB_FIRST | WPI_MSB_FIRST
- | lsb_first | msb_first.
--type wpi_uint8() :: 0..255.
+-type wpi_pin_mode() :: 0..2 % WPI_INPUT | WPI_OUTPUT | WPI_PWM_OUTPUT
+ | input | output | pwm_output.
+-type wpi_pin_number() :: integer().
+-type wpi_digital_value() :: 0..1. % WPI_LOW | WPI_HIGH
+-type wpi_pwm_value() :: 0..1023.
+-type wpi_pud_mode() :: 0..2 % WPI_PUD_OFF | WPI_PUD_DOWN | WPI_PUD_UP
+ | off | down | up.
+-opaque wpi_lcd_handle() :: integer().
+-type wpi_bit_order() :: 0..1 % WPI_LSB_FIRST | WPI_MSB_FIRST
+ | lsb_first | msb_first.
+-type wpi_uint8() :: 0..255.
+
+-opaque wpi_serial_handle() :: integer().
+
+-type wpi_baud() :: integer().
+
+-type wpi_spi_channel() :: 0..1.
+
on_load() ->
ok = erlang:load_nif(filename:join(code:priv_dir(wpi), "./wpi_drv"), 0).
@@ -119,7 +142,7 @@ pull_up_dn_control_nif(_Pin, _Mode) -> ?nif_stub.
-spec lcd_init(integer(), integer(),
wpi_pin_number(), wpi_pin_number(),
wpi_pin_number(), wpi_pin_number(),
- wpi_pin_number(), wpi_pin_number()) -> ok.
+ wpi_pin_number(), wpi_pin_number()) -> wpi_lcd_handle().
lcd_init(NumRows, NumCols, RsPin, EPin, D0Pin, D1Pin, D2Pin, D3Pin)
when is_integer(NumRows), NumRows > 0, is_integer(NumCols), NumCols > 0,
is_integer(RsPin), is_integer(EPin),
@@ -133,7 +156,7 @@ lcd_init(NumRows, NumCols, RsPin, EPin, D0Pin, D1Pin, D2Pin, D3Pin)
wpi_pin_number(), wpi_pin_number(),
wpi_pin_number(), wpi_pin_number(),
wpi_pin_number(), wpi_pin_number(),
- wpi_pin_number(), wpi_pin_number()) -> ok.
+ wpi_pin_number(), wpi_pin_number()) -> wpi_lcd_handle().
lcd_init(NumRows, NumCols, RsPin, EPin,
D0Pin, D1Pin, D2Pin, D3Pin, D4Pin, D5Pin, D6Pin, D7Pin)
when is_integer(NumRows), NumRows > 0, is_integer(NumCols), NumCols > 0,
@@ -222,3 +245,72 @@ soft_pwm_write(Pin, Value) when is_integer(Pin), is_integer(Value) ->
soft_pwm_create_nif(_Pin, _InitValue, _Range) -> ?nif_stub.
soft_pwm_write_nif(_Pin, _Value) -> ?nif_stub.
+
+%% serial
+-spec serial_open(string(), wpi_baud()) -> ok.
+serial_open(Device, Baud) when is_list(Device), is_integer(Baud) ->
+ serial_open_nif(Baud, length(Device), Device).
+
+-spec serial_close(wpi_serial_handle()) -> ok.
+serial_close(Handle) when is_integer(Handle) ->
+ serial_close_nif(Handle).
+
+-spec serial_flush(wpi_serial_handle()) -> ok.
+serial_flush(Handle) when is_integer(Handle) ->
+ serial_flush_nif(Handle).
+
+-spec serial_put_char(wpi_serial_handle(), 0..255) -> ok.
+serial_put_char(Handle, Char)
+ when is_integer(Handle), is_integer(Char), Char >= 0, Char =< 255 ->
+ serial_put_char_nif(Handle, Char).
+
+-spec serial_puts(wpi_serial_handle(), string()) -> ok.
+serial_puts(Handle, String)
+ when is_integer(Handle), is_list(String) ->
+ serial_puts_nif(Handle, length(String), String).
+
+-spec serial_printf(wpi_serial_handle(), string(), list(any())) -> ok.
+serial_printf(_Handle, _Format, _Args) ->
+ erlang:error(not_supported).
+
+-spec serial_format(wpi_serial_handle(), string(), list(any())) -> ok.
+serial_format(Handle, Format, Args)
+ when is_integer(Handle), is_list(Format), is_list(Args) ->
+ serial_puts(Handle, lists:flatten(io_lib:format(Format, Args))).
+
+-spec serial_data_avail(wpi_serial_handle()) -> integer().
+serial_data_avail(Handle) when is_integer(Handle) ->
+ serial_data_avail_nif(Handle).
+
+-spec serial_get_char(wpi_serial_handle()) -> 0..255.
+serial_get_char(Handle) when is_integer(Handle) ->
+ serial_get_char_nif(Handle).
+
+serial_open_nif(_Baud, _StringLen, _Device) -> ?nif_stub.
+serial_close_nif(_Handle) -> ?nif_stub.
+serial_flush_nif(_Handle) -> ?nif_stub.
+serial_put_char_nif(_Handle, _Char) -> ?nif_stub.
+serial_puts_nif(_Handle, _StringLen, _String) -> ?nif_stub.
+serial_data_avail_nif(_Handle) -> ?nif_stub.
+serial_get_char_nif(_Handle) -> ?nif_stub.
+
+%% SPI
+-spec spi_get_fd(wpi_spi_channel()) -> integer().
+spi_get_fd(Channel) when (Channel == 0 orelse Channel == 1) ->
+ spi_get_fd_nif(Channel).
+
+-spec spi_data_rw(wpi_spi_channel(), binary()) ->
+ {ok, binary()} |
+ {error, {failed_to_read_write_data, integer()}}.
+spi_data_rw(Channel, WriteData) when (Channel == 0 orelse Channel == 1),
+ is_binary(WriteData) ->
+ spi_data_rw_nif(Channel, WriteData, byte_size(WriteData)).
+
+-spec spi_setup(wpi_spi_channel(), integer()) -> integer().
+spi_setup(Channel, Speed) when (Channel == 0 orelse Channel == 1),
+ is_integer(Speed), Speed > 0 ->
+ spi_setup_nif(Channel, Speed).
+
+spi_get_fd_nif(_Channel) -> ?nif_stub.
+spi_data_rw_nif(_Channel, _WriteData, _Len) -> ?nif_stub.
+spi_setup_nif(_Channel, _Speed) -> ?nif_stub.

0 comments on commit a8973c9

Please sign in to comment.