Skip to content
Permalink
master
Go to file
 
 
Cannot retrieve contributors at this time
244 lines (188 sloc) 5.17 KB
/**
* Copyright (c) 2010 William Light <wrl@illest.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* for asprintf */
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/select.h>
#include <termios.h>
#include <errno.h>
#include <monome.h>
#include "internal.h"
#include "platform.h"
#define MONOME_BAUD_RATE B115200
#define READ_TIMEOUT 25
#if !defined(EMBED_PROTOS)
/* stops gcc from complaining when compiled with -pedantic */
typedef union {
void *vptr;
monome_t *(*func)();
} func_vptr_t;
monome_t *monome_platform_load_protocol(const char *proto) {
void *dl_handle;
func_vptr_t protocol_new;
monome_t *monome;
char *buf;
if( asprintf(&buf, LIBDIR "/monome/protocol_%s" LIBSUFFIX, proto) < 0 )
return NULL;
dl_handle = dlopen(buf, RTLD_LAZY);
free(buf);
if( !dl_handle ) {
fprintf(stderr, "couldn't load monome protocol module. "
"dlopen said: \n\t%s\n\n"
"please make sure that libmonome is installed correctly!\n",
dlerror());
return NULL;
}
protocol_new.vptr = dlsym(dl_handle, "monome_protocol_new");
if( !protocol_new.func ) {
fprintf(stderr, "couldn't initialize monome protocol module. "
"dlopen said:\n\t%s\n\n"
"please make sure you're using a valid protocol library!\n"
"if this is a protocol library you wrote, make sure you're"
"providing a \033[1mmonome_protocol_new\033[0m function.\n",
dlerror());
goto err;
}
monome = (*protocol_new.func)();
if( !monome )
goto err;
monome->dl_handle = dl_handle;
return monome;
err:
dlclose(dl_handle);
return NULL;
}
void monome_platform_free(monome_t *monome) {
void *dl_handle = monome->dl_handle;
monome->free(monome);
dlclose(dl_handle);
}
#endif
int monome_platform_open(monome_t *monome, const monome_devmap_t *m,
const char *dev) {
struct termios nt, ot;
int fd;
if( (fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0 ) {
perror("libmonome: could not open monome device");
return 1;
}
tcgetattr(fd, &ot);
nt = ot;
/* baud rate */
if( m->quirks & QUIRK_57600_BAUD ) {
cfsetispeed(&nt, B57600);
cfsetospeed(&nt, B57600);
} else {
cfsetispeed(&nt, MONOME_BAUD_RATE);
cfsetospeed(&nt, MONOME_BAUD_RATE);
}
/* parity (8N1) */
nt.c_cflag &= ~(PARENB | CSTOPB | CSIZE);
nt.c_cflag |= (CS8 | CLOCAL | CREAD);
/* no line processing */
nt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN);
/* raw input */
nt.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | PARMRK |
INPCK | ISTRIP | IXON);
/* raw output */
nt.c_oflag &= ~(OCRNL | ONLCR | ONLRET | ONOCR |
OFILL | OPOST);
nt.c_cc[VMIN] = 1;
nt.c_cc[VTIME] = 0;
if( tcsetattr(fd, TCSANOW, &nt) < 0 )
goto err_tcsetattr;
tcflush(fd, TCIOFLUSH);
monome->fd = fd;
return 0;
err_tcsetattr:
perror("libmonome: could not set terminal attributes");
close(fd);
return 1;
}
int monome_platform_close(monome_t *monome) {
return close(monome->fd);
}
ssize_t monome_platform_write(monome_t *monome, const uint8_t *buf, size_t nbyte) {
ssize_t ret = write(monome->fd, buf, nbyte);
if( ret < nbyte )
perror("libmonome: write is missing bytes");
if( ret < 0 )
perror("libmonome: error in write");
return ret;
}
ssize_t monome_platform_read(monome_t *monome, uint8_t *buf, size_t nbyte) {
ssize_t bytes, ret = 0;
int err;
goto start;
for( ; nbyte; nbyte -= bytes ) {
err = monome_platform_wait_for_input(monome, READ_TIMEOUT);
if( err > 0 )
return ret;
if( err < 0 )
return -1;
start:
if ((bytes = read(monome->fd, buf, nbyte)) < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
return 0;
if (errno == EINTR)
goto start;
return bytes;
}
ret += bytes;
buf += bytes;
}
return ret;
}
void monome_event_loop(monome_t *monome) {
monome_callback_t *handler;
monome_event_t e;
fd_set fds;
e.monome = monome;
do {
FD_ZERO(&fds);
FD_SET(monome->fd, &fds);
if( select(monome->fd + 1, &fds, NULL, NULL, NULL) < 0 ) {
perror("libmonome: error in select()");
break;
}
if( monome->next_event(monome, &e) < 1 )
continue;
handler = &monome->handlers[e.event_type];
if( !handler->cb )
continue;
handler->cb(&e, handler->data);
} while( 1 );
}
void *m_malloc(size_t size) {
return malloc(size);
}
void *m_calloc(size_t nmemb, size_t size) {
return calloc(nmemb, size);
}
void *m_strdup(const char *s) {
return strdup(s);
}
void m_free(void *ptr) {
free(ptr);
}
void m_sleep(uint_t msec) {
usleep(msec * 1000);
}