Home | History | Annotate | Line # | Download | only in gpio
      1 /*	$NetBSD: gpio.c,v 1.9 2014/07/19 18:38:34 lneto Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2011 Marc Balmer <marc (at) msys.ch>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 /* GPIO interface for Lua */
     29 
     30 #include <errno.h>
     31 #include <fcntl.h>
     32 #include <stdarg.h>
     33 #include <stdio.h>
     34 #include <string.h>
     35 #include <ctype.h>
     36 #include <stdlib.h>
     37 #include <unistd.h>
     38 
     39 #include <lua.h>
     40 #include <lauxlib.h>
     41 #include <lualib.h>
     42 
     43 #include <sys/gpio.h>
     44 #include <sys/ioctl.h>
     45 
     46 #define GPIO_METATABLE "GPIO object methods"
     47 
     48 static __printflike(2, 3) void
     49 gpio_error(lua_State *L, const char *fmt, ...)
     50 {
     51 	va_list ap;
     52 	int len;
     53 	char *msg;
     54 
     55 	va_start(ap, fmt);
     56 	len = vasprintf(&msg, fmt, ap);
     57 	va_end(ap);
     58 
     59 	if (len != -1) {
     60 		lua_pushstring(L, msg);
     61 		free(msg);
     62 	} else
     63 		lua_pushstring(L, "vasprintf failed");
     64 	lua_error(L);
     65 }
     66 
     67 static int
     68 gpio_open(lua_State *L)
     69 {
     70 	int *fd;
     71 
     72 	fd = lua_newuserdata(L, sizeof(int));
     73 	*fd = open(luaL_checkstring(L, -2), O_RDWR);
     74 	if (*fd == -1) {
     75 		gpio_error(L, "%s", strerror(errno));
     76 		/* NOTREACHED */
     77 		return 0;
     78 	}
     79 	luaL_getmetatable(L, GPIO_METATABLE);
     80 	lua_setmetatable(L, -2);
     81 	return 1;
     82 }
     83 
     84 static int
     85 gpio_close(lua_State *L)
     86 {
     87 	int *fd;
     88 
     89 	fd = luaL_checkudata(L, 1, GPIO_METATABLE);
     90 	if (*fd != -1) {
     91 		close(*fd);
     92 		*fd = -1;
     93 	}
     94 	return 0;
     95 }
     96 
     97 static int
     98 gpio_info(lua_State *L)
     99 {
    100 	struct gpio_info info;
    101 	int *fd;
    102 
    103 	fd = luaL_checkudata(L, 1, GPIO_METATABLE);
    104 	if (ioctl(*fd, GPIOINFO, &info) == -1)
    105 		gpio_error(L, "GPIOINFO");
    106 	lua_pushinteger(L, info.gpio_npins);
    107 	return 1;
    108 }
    109 
    110 static void
    111 gpio_get_pin(lua_State *L, int n, struct gpio_req *req)
    112 {
    113 	switch (lua_type(L, n)) {
    114 	case LUA_TNUMBER:
    115 		req->gp_pin = (int)lua_tointeger(L, n);	/* not 1 based! */
    116 		break;
    117 	case LUA_TSTRING:
    118 		strlcpy(req->gp_name, lua_tostring(L, n), sizeof(req->gp_name));
    119 		break;
    120 	default:
    121 		luaL_argerror(L, n, "expected string or integer");
    122 		/* NOTREACHED */
    123 	}
    124 }
    125 
    126 static int
    127 gpio_set(lua_State *L)
    128 {
    129 	struct gpio_set set;
    130 	int *fd;
    131 
    132 	fd = luaL_checkudata(L, 1, GPIO_METATABLE);
    133 	memset(&set, 0, sizeof(set));
    134 	gpio_get_pin(L, 2, (void *)&set);
    135 	set.gp_flags = (int)luaL_checkinteger(L, 3);
    136 	if (ioctl(*fd, GPIOSET, &set) == -1)
    137 		gpio_error(L, "GPIOSET");
    138 	return 0;
    139 }
    140 
    141 static int
    142 gpio_unset(lua_State *L)
    143 {
    144 	struct gpio_set set;
    145 	int *fd;
    146 
    147 	fd = luaL_checkudata(L, 1, GPIO_METATABLE);
    148 	memset(&set, 0, sizeof(set));
    149 	gpio_get_pin(L, 2, (void *)&set);
    150 	if (ioctl(*fd, GPIOUNSET, &set) == -1)
    151 		gpio_error(L, "GPIOUNSET");
    152 	return 0;
    153 }
    154 
    155 static int
    156 gpio_read(lua_State *L)
    157 {
    158 	struct gpio_req req;
    159 	int *fd;
    160 
    161 	fd = luaL_checkudata(L, 1, GPIO_METATABLE);
    162 	memset(&req, 0, sizeof(req));
    163 	gpio_get_pin(L, 2, &req);
    164 	if (ioctl(*fd, GPIOREAD, &req) == -1)
    165 		gpio_error(L, "GPIOREAD");
    166 	lua_pushinteger(L, req.gp_value);
    167 	return 1;
    168 }
    169 
    170 
    171 static int
    172 gpio_write(lua_State *L)
    173 {
    174 	struct gpio_req req;
    175 	int *fd, val;
    176 
    177 	fd = luaL_checkudata(L, 1, GPIO_METATABLE);
    178 	val = (int)luaL_checkinteger(L, 3);
    179 	if (val != GPIO_PIN_HIGH && val != GPIO_PIN_LOW)
    180 		gpio_error(L, "%d: invalid value", val);
    181 	memset(&req, 0, sizeof(req));
    182 	gpio_get_pin(L, 2, &req);
    183 	req.gp_value = val;
    184 	if (ioctl(*fd, GPIOWRITE, &req) == -1)
    185 		gpio_error(L, "GPIOWRITE");
    186 	lua_pushinteger(L, req.gp_value);
    187 	return 1;
    188 }
    189 
    190 static int
    191 gpio_toggle(lua_State *L)
    192 {
    193 	struct gpio_req req;
    194 	int *fd;
    195 
    196 	fd = luaL_checkudata(L, 1, GPIO_METATABLE);
    197 	memset(&req, 0, sizeof(req));
    198 	gpio_get_pin(L, 2, &req);
    199 	if (ioctl(*fd, GPIOTOGGLE, &req) == -1)
    200 		gpio_error(L, "GPIOTOGGLE");
    201 	lua_pushinteger(L, req.gp_value);
    202 	return 1;
    203 }
    204 
    205 static int
    206 gpio_attach(lua_State *L)
    207 {
    208 	struct gpio_attach attach;
    209 	int *fd;
    210 
    211 	fd = luaL_checkudata(L, 1, GPIO_METATABLE);
    212 	memset(&attach, 0, sizeof(attach));
    213 	strlcpy(attach.ga_dvname, luaL_checkstring(L, 2),
    214 	    sizeof(attach.ga_dvname));
    215 	attach.ga_offset = (int)luaL_checkinteger(L, 3);
    216 	attach.ga_mask = (int)luaL_checkinteger(L, 4);
    217 	if (lua_gettop(L) > 4)
    218 		attach.ga_flags = (int)luaL_checkinteger(L, 5);
    219 	else
    220 		attach.ga_flags = 0;
    221 
    222 	if (ioctl(*fd, GPIOATTACH, &attach) == -1)
    223 		gpio_error(L, "GPIOATTACH");
    224 	return 0;
    225 }
    226 
    227 struct constant {
    228 	const char *name;
    229 	int value;
    230 };
    231 
    232 static const struct constant gpio_constant[] = {
    233 	/* GPIO pin states */
    234 	{ "PIN_LOW",		GPIO_PIN_LOW },
    235 	{ "PIN_HIGH",		GPIO_PIN_HIGH },
    236 
    237 	/* GPIO pin configuration flags */
    238 	{ "PIN_INPUT",		GPIO_PIN_INPUT },
    239 	{ "PIN_OUTPUT",		GPIO_PIN_OUTPUT },
    240 	{ "PIN_INOUT",		GPIO_PIN_INOUT },
    241 	{ "PIN_OPENDRAIN",	GPIO_PIN_OPENDRAIN },
    242 	{ "PIN_PUSHPULL",	GPIO_PIN_PUSHPULL },
    243 	{ "PIN_TRISTATE",	GPIO_PIN_TRISTATE },
    244 	{ "PIN_PULLUP",		GPIO_PIN_PULLUP },
    245 	{ "PIN_PULLDOWN",	GPIO_PIN_PULLDOWN },
    246 	{ "PIN_INVIN",		GPIO_PIN_INVIN },
    247 	{ "PIN_INVOUT",		GPIO_PIN_INVOUT },
    248 	{ "PIN_USER",		GPIO_PIN_USER },
    249 	{ "PIN_PULSATE",	GPIO_PIN_PULSATE },
    250 	{ "PIN_SET",		GPIO_PIN_SET },
    251 	{ NULL,			0 }
    252 };
    253 
    254 static void
    255 gpio_set_info(lua_State *L)
    256 {
    257 	lua_pushliteral(L, "_COPYRIGHT");
    258 	lua_pushliteral(L, "Copyright (C) 2011, 2013 Marc Balmer "
    259 	    "<marc (at) msys.ch>");
    260 	lua_settable(L, -3);
    261 	lua_pushliteral(L, "_DESCRIPTION");
    262 	lua_pushliteral(L, "GPIO interface for Lua");
    263 	lua_settable(L, -3);
    264 	lua_pushliteral(L, "_VERSION");
    265 	lua_pushliteral(L, "gpio 1.0.2");
    266 	lua_settable(L, -3);
    267 }
    268 
    269 int luaopen_gpio(lua_State*);
    270 
    271 int
    272 luaopen_gpio(lua_State* L)
    273 {
    274 	static const struct luaL_Reg methods[] = {
    275 		{ "open",	gpio_open },
    276 		{ NULL,		NULL }
    277 	};
    278 	static const struct luaL_Reg gpio_methods[] = {
    279 		{ "info",	gpio_info },
    280 		{ "close",	gpio_close },
    281 		{ "set",	gpio_set },
    282 		{ "unset",	gpio_unset },
    283 		{ "read",	gpio_read },
    284 		{ "write",	gpio_write },
    285 		{ "toggle",	gpio_toggle },
    286 		{ "attach",	gpio_attach },
    287 		{ NULL,		NULL }
    288 	};
    289 	int n;
    290 
    291 	luaL_newlib(L, methods);
    292 	luaL_setfuncs(L, gpio_methods, 0);
    293 	gpio_set_info(L);
    294 
    295 	/* The gpio metatable */
    296 	if (luaL_newmetatable(L, GPIO_METATABLE)) {
    297 		luaL_setfuncs(L, gpio_methods, 0);
    298 
    299 		lua_pushliteral(L, "__gc");
    300 		lua_pushcfunction(L, gpio_close);
    301 		lua_settable(L, -3);
    302 
    303 		lua_pushliteral(L, "__index");
    304 		lua_pushvalue(L, -2);
    305 		lua_settable(L, -3);
    306 
    307 		lua_pushliteral(L, "__metatable");
    308 		lua_pushliteral(L, "must not access this metatable");
    309 		lua_settable(L, -3);
    310 	}
    311 	lua_pop(L, 1);
    312 
    313 	for (n = 0; gpio_constant[n].name != NULL; n++) {
    314 		lua_pushinteger(L, gpio_constant[n].value);
    315 		lua_setfield(L, -2, gpio_constant[n].name);
    316 	};
    317 	return 1;
    318 }
    319