Home | History | Annotate | Line # | Download | only in gpio
gpio.c revision 1.2
      1 /*	$NetBSD: gpio.c,v 1.2 2011/10/08 08:46:40 mbalmer 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 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 = lua_tointeger(L, n) - 1;	/* 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, (struct gpio_req *)&set);
    135 	set.gp_flags = 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, (struct gpio_req *)&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 = 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, val;
    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 = 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 static int
    228 gpio_pulse(lua_State *L)
    229 {
    230 	struct gpio_pulse pulse;
    231 	suseconds_t period, on, off;
    232 	double freq, dc;
    233 	int *fd;
    234 
    235 	fd = luaL_checkudata(L, 1, GPIO_METATABLE);
    236 	freq = luaL_checknumber(L, 3);
    237 	dc = luaL_checknumber(L, 4);
    238 
    239 	if (freq < 0.0 || (dc < 0.0 || dc >= 100.0))
    240 		gpio_error(L, "%.f Hz, %.f%% duty cycle: invalid value",
    241 		    freq, dc);
    242 
    243 	memset(&pulse, 0, sizeof(pulse));
    244 	gpio_get_pin(L, 2, (struct gpio_req *)&pulse);
    245 
    246 	if (freq > 0.0 && dc > 0.0) {
    247 		period = 1000000 / freq;
    248 		on = period * dc / 100;
    249 		off = period - on;
    250 
    251 		if (on >= 1000000) {
    252 			pulse.gp_pulse_on.tv_sec = on / 1000000;
    253 			on -= pulse.gp_pulse_on.tv_sec * 1000000;
    254 			pulse.gp_pulse_on.tv_usec = on;
    255 		} else {
    256 			pulse.gp_pulse_on.tv_sec = 0;
    257 			pulse.gp_pulse_on.tv_usec = on;
    258 		}
    259 		if (off >= 1000000) {
    260 			pulse.gp_pulse_off.tv_sec = off / 1000000;
    261 			off -= pulse.gp_pulse_off.tv_sec * 1000000;
    262 			pulse.gp_pulse_off.tv_usec = off;
    263 		} else {
    264 			pulse.gp_pulse_off.tv_sec = 0;
    265 			pulse.gp_pulse_off.tv_usec = off;
    266 		}
    267 	} else {	/* gpio(4) defaults */
    268 		freq = 1.0;
    269 		dc = 50.0;
    270 	}
    271 
    272 	if (ioctl(*fd, GPIOPULSE, &pulse) == -1)
    273 		gpio_error(L, "GPIOPULSE");
    274 }
    275 
    276 struct constant {
    277 	char *name;
    278 	int value;
    279 };
    280 
    281 static struct constant gpio_constant[] = {
    282 	/* GPIO pin states */
    283 	{ "PIN_LOW",		GPIO_PIN_LOW },
    284 	{ "PIN_HIGH",		GPIO_PIN_HIGH },
    285 	{ "PIN_PULSE",		GPIO_PIN_PULSE },
    286 
    287 	/* GPIO pin configuration flags */
    288 	{ "PIN_INPUT",		GPIO_PIN_INPUT },
    289 	{ "PIN_OUTPUT",		GPIO_PIN_OUTPUT },
    290 	{ "PIN_INOUT",		GPIO_PIN_INOUT },
    291 	{ "PIN_OPENDRAIN",	GPIO_PIN_OPENDRAIN },
    292 	{ "PIN_PUSHPULL",	GPIO_PIN_PUSHPULL },
    293 	{ "PIN_TRISTATE",	GPIO_PIN_TRISTATE },
    294 	{ "PIN_PULLUP",		GPIO_PIN_PULLUP },
    295 	{ "PIN_PULLDOWN",	GPIO_PIN_PULLDOWN },
    296 	{ "PIN_INVIN",		GPIO_PIN_INVIN },
    297 	{ "PIN_INVOUT",		GPIO_PIN_INVOUT },
    298 	{ "PIN_USER",		GPIO_PIN_USER },
    299 	{ "PIN_PULSATE",	GPIO_PIN_PULSATE },
    300 	{ "PIN_INTR",		GPIO_PIN_INTR },
    301 	{ "PIN_INTR_HIGH",	GPIO_PIN_INTR_HIGH },
    302 	{ "PIN_SET",		GPIO_PIN_SET },
    303 	{ NULL,			0 }
    304 };
    305 
    306 static void
    307 gpio_set_info(lua_State *L)
    308 {
    309 	lua_pushliteral(L, "_COPYRIGHT");
    310 	lua_pushliteral(L, "Copyright (C) 2011 Marc Balmer <marc (at) msys.ch>");
    311 	lua_settable(L, -3);
    312 	lua_pushliteral(L, "_DESCRIPTION");
    313 	lua_pushliteral(L, "GPIO interface for Lua");
    314 	lua_settable(L, -3);
    315 	lua_pushliteral(L, "_VERSION");
    316 	lua_pushliteral(L, "gpio 1.0.0");
    317 	lua_settable(L, -3);
    318 }
    319 
    320 int
    321 luaopen_gpio(lua_State* L)
    322 {
    323 	static const struct luaL_Reg methods[] = {
    324 		{ "open",	gpio_open },
    325 		{ NULL,		NULL }
    326 	};
    327 	static const struct luaL_Reg gpio_methods[] = {
    328 		{ "info",	gpio_info },
    329 		{ "close",	gpio_close },
    330 		{ "set",	gpio_set },
    331 		{ "unset",	gpio_unset },
    332 		{ "read",	gpio_read },
    333 		{ "write",	gpio_write },
    334 		{ "toggle",	gpio_toggle },
    335 		{ "attach",	gpio_attach },
    336 		{ "pulse",	gpio_pulse },
    337 		{ NULL,		NULL }
    338 	};
    339 	int n;
    340 
    341 	luaL_register(L, "gpio", methods);
    342 	gpio_set_info(L);
    343 
    344 	/* The gpio metatable */
    345 	if (luaL_newmetatable(L, GPIO_METATABLE)) {
    346 		luaL_register(L, NULL, gpio_methods);
    347 
    348 		lua_pushliteral(L, "__gc");
    349 		lua_pushcfunction(L, gpio_close);
    350 		lua_settable(L, -3);
    351 
    352 		lua_pushliteral(L, "__index");
    353 		lua_pushvalue(L, -2);
    354 		lua_settable(L, -3);
    355 
    356 		lua_pushliteral(L, "__metatable");
    357 		lua_pushliteral(L, "must not access this metatable");
    358 		lua_settable(L, -3);
    359 	}
    360 	lua_pop(L, 1);
    361 
    362 	for (n = 0; gpio_constant[n].name != NULL; n++) {
    363 		lua_pushinteger(L, gpio_constant[n].value);
    364 		lua_setfield(L, -2, gpio_constant[n].name);
    365 	};
    366 	return 1;
    367 }
    368