/* * The Rin Library – gpio module * * Copyright (C) 2016 Gediminas Jakutis * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; version 2.1 * of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "rin/gpio.h" #include "gpio_private.h" unsigned int rin_gpio_open(const unsigned int num, const enum rin_gpiotype type) { struct stat st; struct timespec grace = { 0, 1 * 1000 * 1000 }; /* 1 ms */ char buf[48] = { 0 }; int fd; unsigned int timeout; init(); if (type == rin_gpio_closed || !rin_gpio_num_exists(num) || gpio[num].type != rin_gpio_closed) { return 1; } fd = open("/sys/class/gpio/export", O_WRONLY | O_DSYNC); sprintf(buf, "%u", num); write(fd, buf, strlen(buf)); close(fd); sprintf(buf, "/sys/class/gpio/gpio%u/direction", num); timeout = 500; /* 500 ms, if it takes longer, something ain't right. */ while (stat(buf, &st)) { nanosleep(&grace, NULL); if (!(--timeout)) { return 1; } } fd = open(buf, O_WRONLY | O_DSYNC); if (type == rin_gpio_in) { write(fd, "in", 2); } else { write(fd, "out", 3); } close(fd); gpio[num].type = type; sprintf(buf, "/sys/class/gpio/gpio%u/value", num); if (type == rin_gpio_in) { gpio[num].fd = open(buf, O_RDONLY); } else { gpio[num].fd = open(buf, O_WRONLY); } return 0; } unsigned int rin_gpio_close(const unsigned int num) { char buf[32] = { 0 }; struct stat st; int fd; init(); sprintf(buf, "/sys/class/gpio/gpio%u", num); if (stat(buf, &st)) { return 0; } close(gpio[num].fd); gpio[num].fd = -1; fd = open("/sys/class/gpio/unexport", O_WRONLY); sprintf(buf, "%u", num); write(fd, buf, strlen(buf)); close(fd); gpio[num].type = rin_gpio_closed; return 0; } unsigned int rin_gpio_setval(const unsigned int num, const unsigned int val) { char buf[8] = { 0 }; init(); if (!rin_gpio_num_exists(num) || gpio[num].type != rin_gpio_out) { return 1; } sprintf(buf, "%u", val); lseek(gpio[num].fd, 0, SEEK_SET); write(gpio[num].fd, buf, strlen(buf)); return 0; } unsigned int rin_gpio_readval(const unsigned int num, unsigned int * const val) { init(); if (!rin_gpio_num_exists(num) || gpio[num].type != rin_gpio_in) { exit(EXIT_FAILURE); } lseek(gpio[num].fd, 0, SEEK_SET); read(gpio[num].fd, val, 1); if (*val >= '0') { *val -= '0'; } return 0; } unsigned int rin_gpio_writesequence(const struct rin_gpio_dataset * const dataset) { unsigned char *data; size_t i; if (!dataset || !dataset->data) { return 1; } data = dataset->data; for (i = 0; i < dataset->len; ++i) { unsigned char a; unsigned char bit; a = data[i / CHAR_BIT]; bit = !(!(a & (1 << (i % CHAR_BIT)))); rin_gpio_setval(dataset->signalnum, bit); rin_gpio_pulse(dataset->clocknum, dataset->pulseduration); if (dataset->delay) { nanosleep(dataset->delay, NULL); } } return 0; } unsigned int rin_gpio_on(const unsigned int num) { return rin_gpio_setval(1, num); } unsigned int rin_gpio_off(const unsigned int num) { return rin_gpio_setval(0, num); } unsigned int rin_gpio_pulse(const unsigned int num, const struct timespec * const pulselen) { unsigned int ret; ret = rin_gpio_on(num); if (ret) { return ret; } if (pulselen) { nanosleep(pulselen, NULL); } ret = rin_gpio_off(num); return ret; } /* * right now is rpi V1 specific, should be rewritten when/if we support * other platforms. */ unsigned int rin_gpio_num_exists(const unsigned int num) { switch (num) { case 2: case 3: case 4: case 7: case 8: case 9: case 10: case 11: case 14: case 15: case 17: case 18: case 22: case 23: case 24: case 25: return 1; default: return 0; } } /* * in case we ever support hardware other than the V1 Raspberry, * we need this to get the pin usable pin count */ unsigned int rin_gpio_get_numcount(void) { return 16; } unsigned int rin_gpio_get_pincount(void) { return 26; } unsigned int rin_gpio_pin_to_num(const unsigned int pin) { static const unsigned int pinmap[] = { 0, /* nonexistent zeroth index */ 0, 0, 2, 0, 3, 0, 4, 14, 0, 15, 17, 18, 27, 0, 22, 23, 0, 24, 10, 0, 9, 25, 11, 8, 7}; if (pin <= rin_gpio_get_pincount()) { return pinmap[pin]; } else { return 0; } } unsigned int rin_gpio_num_to_pin(const unsigned int num) { static const unsigned int nummap[] = { 0, /* zeroth */ 0, 3, 5, 7, 0, 0, 26, 24, 21, 19, 23, 0, 0, 8, 10, 0, 11, 12, 0, 0, 0, 15, 16, 18, 22}; if (num <= 26) { return nummap[num]; } else { return 0; } } static void init(void) { size_t i; static unsigned int firstrun = 1; if (firstrun) { firstrun = 0; for (i = 0; i < gpio_count; ++i) { gpio[i].num = i; gpio[i].type = rin_gpio_closed; gpio[i].fd = -1; } } }