TeleStern/libaltos/libaltos_posix.c

211 lines
4.5 KiB
C

/*
* Copyright © 2016 Keith Packard <keithp@keithp.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "libaltos_private.h"
#include "libaltos_posix.h"
void
altos_set_last_posix_error(void)
{
altos_set_last_error(errno, strerror(errno));
}
PUBLIC struct altos_file *
altos_open(struct altos_device *device)
{
struct altos_file_posix *file = calloc (sizeof (struct altos_file_posix), 1);
int ret;
struct termios term;
if (!file) {
altos_set_last_posix_error();
return NULL;
}
// altos_set_last_error(12, "yeah yeah, failed again");
// free(file);
// return NULL;
file->fd = open(device->path, O_RDWR | O_NOCTTY);
if (file->fd < 0) {
altos_set_last_posix_error();
free(file);
return NULL;
}
#ifdef USE_POLL
pipe(file->pipe);
#else
file->out_fd = open(device->path, O_RDWR | O_NOCTTY);
if (file->out_fd < 0) {
altos_set_last_posix_error();
close(file->fd);
free(file);
return NULL;
}
#endif
ret = tcgetattr(file->fd, &term);
if (ret < 0) {
altos_set_last_posix_error();
close(file->fd);
#ifndef USE_POLL
close(file->out_fd);
#endif
free(file);
return NULL;
}
cfmakeraw(&term);
cfsetospeed(&term, B9600);
cfsetispeed(&term, B9600);
#ifdef USE_POLL
term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 0;
#else
term.c_cc[VMIN] = 0;
term.c_cc[VTIME] = 1;
#endif
ret = tcsetattr(file->fd, TCSAFLUSH, &term);
if (ret < 0) {
altos_set_last_posix_error();
close(file->fd);
#ifndef USE_POLL
close(file->out_fd);
#endif
free(file);
return NULL;
}
return &file->file;
}
PUBLIC void
altos_close(struct altos_file *file_common)
{
struct altos_file_posix *file = (struct altos_file_posix *) file_common;
if (file->fd != -1) {
int fd = file->fd;
file->fd = -1;
#ifdef USE_POLL
write(file->pipe[1], "\r", 1);
#else
close(file->out_fd);
file->out_fd = -1;
#endif
close(fd);
}
}
PUBLIC int
altos_flush(struct altos_file *file_common)
{
struct altos_file_posix *file = (struct altos_file_posix *) file_common;
if (file->file.out_used && 0) {
printf ("flush \"");
fwrite(file->file.out_data, 1, file->file.out_used, stdout);
printf ("\"\n");
}
while (file->file.out_used) {
int ret;
if (file->fd < 0)
return -EBADF;
#ifdef USE_POLL
ret = write (file->fd, file->file.out_data, file->file.out_used);
#else
ret = write (file->out_fd, file->file.out_data, file->file.out_used);
#endif
if (ret < 0) {
altos_set_last_posix_error();
return -altos_last_error.code;
}
if (ret) {
memmove(file->file.out_data, file->file.out_data + ret,
file->file.out_used - ret);
file->file.out_used -= ret;
}
}
return 0;
}
#ifdef USE_POLL
#include <poll.h>
#endif
int
altos_fill(struct altos_file *file_common, int timeout)
{
struct altos_file_posix *file = (struct altos_file_posix *) file_common;
int ret;
#ifdef USE_POLL
struct pollfd fd[2];
#endif
if (timeout == 0)
timeout = -1;
while (file->file.in_read == file->file.in_used) {
if (file->fd < 0)
return LIBALTOS_ERROR;
#ifdef USE_POLL
fd[0].fd = file->fd;
fd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL;
fd[1].fd = file->pipe[0];
fd[1].events = POLLIN;
ret = poll(fd, 2, timeout);
if (ret < 0) {
altos_set_last_posix_error();
return LIBALTOS_ERROR;
}
if (ret == 0)
return LIBALTOS_TIMEOUT;
if (fd[0].revents & (POLLHUP|POLLERR|POLLNVAL))
return LIBALTOS_ERROR;
if (fd[0].revents & POLLIN)
#endif
{
ret = read(file->fd, file->file.in_data, USB_BUF_SIZE);
if (ret < 0) {
altos_set_last_posix_error();
return LIBALTOS_ERROR;
}
file->file.in_read = 0;
file->file.in_used = ret;
#ifndef USE_POLL
if (ret == 0 && timeout > 0)
return LIBALTOS_TIMEOUT;
#endif
}
}
if (file->file.in_used && 0) {
printf ("fill \"");
fwrite(file->file.in_data, 1, file->file.in_used, stdout);
printf ("\"\n");
}
return 0;
}
#include <time.h>
void
altos_pause_one_second(void)
{
struct timespec delay = { .tv_sec = 1, .tv_nsec = 0 };
nanosleep(&delay, NULL);
}