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