/**********************************************************************
 
	Copyright (C) 2003-2004
	Hirohisa MORI <joshua@nichibun.ac.jp>
	Tomoki SEKIYAMA <sekiyama@yahoo.co.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	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.

**********************************************************************/



#define STREAM_LIB
#define LIBRARY
#define S_FILE_LIBRARY

#undef __BEGIN_DECLS
#undef __END_DECLS
#define	__BEGIN_DECLS
#define	__END_DECLS

#include "machine/include.h"
#include <termios.h>

#include "stream.h"
#include "serial_port.h"

void sleep_ms(int ms);

STREAM *	s_open_file_descripter();
int s_close_file();
int s_flush_file();
int s_error();
STREAM * s_error_stream();

int s_write_serial_port();
int s_read_serial_port();


S_TABLE s_serial_port_table = {
	'p',
	STF_BUF_OUT,
	{0,0},
	0,
	s_open_file_descripter,
	s_close_file,
	s_write_serial_port,
	s_read_serial_port,
	s_flush_file,
	s_error,
	s_error_stream,
	s_error,
};


STREAM *
open_serial_port(SERIAL_PORT_INFO *info, int speed)
{
 struct termios ios;
int fid;
	
	fid = open(info->info, O_RDWR);
	if ( fid < 0 ) {
		perror("open");
		er_panic("open_serial_port");
	}
	tcgetattr(fid, &ios);
	cfsetispeed(&ios, speed);
	cfsetospeed(&ios, speed);
	ios.c_cflag |= CLOCAL;
	tcsetattr(fid, TCSAFLUSH, &ios);
	return s_open_file_descripter(fid, &s_serial_port_table);
}

int
s_write_serial_port(STREAM * s,void * data,int len)
{
int ret;
struct timeval tv;
fd_set fds;

retry:
	errno = 0; 
	
	FD_ZERO(&fds);
	FD_SET(s->file.fid,&fds);
	tv.tv_sec = 0;
	tv.tv_usec = 0;

	ret = select(s->file.fid+1,NULL,&fds,NULL,&tv);
	if ( ret < 0 ) {
		if ( errno == EINTR && s->h.tbl )
			goto retry;
		return ret;
	}
	if ( ret == 0 ) {
		sleep_ms(100);
		goto retry;
	}
	ret = write(s->file.fid,data,len);
	if ( ret < 0 && errno == EINTR && s->h.tbl )
		goto retry;
	s->h.last_size = len;
	s->h.last_err = errno;
	return ret;
}

int
s_read_serial_port(STREAM * s,void * data,int len)
{
int ret;
struct timeval tv;
fd_set fds;

retry:
	errno = 0;

	FD_ZERO(&fds);
	FD_SET(s->file.fid,&fds);
	tv.tv_sec = 0;
	tv.tv_usec = 0;

	ret = select(s->file.fid+1,&fds,NULL,NULL,&tv);
	if ( ret < 0 ) {
		if ( errno == EINTR && s->h.tbl )
			goto retry;
		return ret;
	}
	if ( ret == 0 ) {
		sleep_ms(100);
		goto retry;
	}
	ret = read(s->file.fid,data,len);
	if ( ret < 0 && errno == EINTR && s->h.tbl )
		goto retry;
	return ret;
}
