/*
 *
 *
 *    termios.cc
 *
 *    C++ source code for class my::termios member functions and/or static
 *    member data.
 *
 *    =========================================================================
 *
 *    Copyright (C) 1999-2013 by Matt Roberts, KK5JY.
 *
 *    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; either
 *    version 2.1 of the License, or (at your option) any later version.
 *
 *    This library 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *    =========================================================================
 *
 *
 */


#include <my++/termios.h>
#include <iostream>
#include <string.h>

using namespace std;


/*
 *
 *    void my::termios::copy_to (...)
 *
 */

const my::termios & my::termios::copy_to (::termios &t) const {
	memcpy ((void*)&t, (void*)&t_ios, sizeof(t));
	return (*this);
}


/*
 *
 *    void my::termios::init ()
 *
 */

void my::termios::init (void) {
	clearInputFlags();
	clearOutputFlags();
	clearLocalFlags();
	clearCommFlags();
	setInterbyteTimeout(0);
	setMinimumByteCount(1);

	optionCommReceiver(true);
	optionCommCharSize(8);
}


namespace my {
	/*
 	 *
 	 * operator << (ostream&, my::termios&)
 	 *
 	 */

	ostream &operator << (ostream &out, my::termios &obj) {
		out << "Dumping termios structure at " << ((unsigned long)(&obj)) << endl
			<< "   char size = ";
		switch (obj.t_ios.c_cflag & CSIZE) {
			case CS8: out << 8 << endl; break;
			case CS7: out << 7 << endl; break;
			case CS6: out << 6 << endl; break;
			case CS5: out << 5 << endl; break;
			default: break;
		}
		out << "   parity    = ";
		if (obj.t_ios.c_cflag & PARENB) {
			out << "(enabled)";
			if (obj.t_ios.c_cflag & PARODD) out << " ODD";
			else out << " EVEN";
		} else {
			out << "(disabled)";
		}
		out << endl;

		out << "c_iflag flags: ";
		if (obj.t_ios.c_iflag & IGNPAR) out << "IGNPAR ";
		if (obj.t_ios.c_iflag & PARMRK) out << "PARMRK ";
		if (obj.t_ios.c_iflag & ICRNL) out << "ICRNL ";
		if (obj.t_ios.c_iflag & BRKINT) out << "BRKINT ";
		if (obj.t_ios.c_iflag & IGNBRK) out << "IGNBRK ";
		if (obj.t_ios.c_iflag & INPCK) out << "INPCK ";
		if (obj.t_ios.c_iflag & ISTRIP) out << "ISTRIP ";
		if (obj.t_ios.c_iflag & INLCR) out << "INLCR ";
		if (obj.t_ios.c_iflag & IGNCR) out << "IGNCR ";
		if (obj.t_ios.c_iflag & ICRNL) out << "ICRNL ";
		if (obj.t_ios.c_iflag & IUCLC) out << "IUCLC ";
		if (obj.t_ios.c_iflag & IXOFF) out << "IXOFF ";
		if (obj.t_ios.c_iflag & IXON) out << "IXON ";
		if (obj.t_ios.c_iflag & IXANY) out << "IXANY ";
		if (obj.t_ios.c_iflag & IMAXBEL) out << "IMAXBEL ";
		out << endl;

		out << "c_oflag flags: ";
		if (obj.t_ios.c_oflag & OPOST) out << "OPOST ";
		if (obj.t_ios.c_oflag & OLCUC) out << "OLCUC ";
		if (obj.t_ios.c_oflag & ONLCR) out << "ONLCR ";
		if (obj.t_ios.c_oflag & OCRNL) out << "OCRNL ";
		if (obj.t_ios.c_oflag & ONOCR) out << "ONOCR ";
		if (obj.t_ios.c_oflag & ONLRET) out << "ONLRET ";
		if (obj.t_ios.c_oflag & OFILL) out << "OFILL ";
		if (obj.t_ios.c_oflag & OFDEL) out << "OFDEL ";
		out << endl;

		out << "c_lflag flags: ";
		if (obj.t_ios.c_lflag & ISIG) out << "ISIG ";
		if (obj.t_ios.c_lflag & ICANON) out << "ICANON ";
		if (obj.t_ios.c_lflag & XCASE) out << "XCASE ";
		if (obj.t_ios.c_lflag & ECHO) out << "ECHO ";
		if (obj.t_ios.c_lflag & ECHOE) out << "ECHOE ";
		if (obj.t_ios.c_lflag & ECHOK) out << "ECHOK ";
		if (obj.t_ios.c_lflag & ECHONL) out << "ECHONL ";
		if (obj.t_ios.c_lflag & ECHOCTL) out << "ECHOCTL ";
		if (obj.t_ios.c_lflag & ECHOPRT) out << "ECHOPRT ";
		if (obj.t_ios.c_lflag & ECHOKE) out << "ECHOKE ";
		if (obj.t_ios.c_lflag & FLUSHO) out << "FLUSHO ";
		if (obj.t_ios.c_lflag & NOFLSH) out << "NOFLSH ";
		if (obj.t_ios.c_lflag & TOSTOP) out << "TOSTOP ";
		if (obj.t_ios.c_lflag & PENDIN) out << "PENDIN ";
		if (obj.t_ios.c_lflag & IEXTEN) out << "IEXTEN ";
		out << endl;

		out << "c_cflag flags: ";
		if (obj.t_ios.c_cflag & CREAD) out << "CREAD ";
		if (obj.t_ios.c_cflag & PARENB) out << "PARENB ";
		if (obj.t_ios.c_cflag & PARODD) out << "PARODD ";
		if (obj.t_ios.c_cflag & HUPCL) out << "HUPCL ";
		if (obj.t_ios.c_cflag & CLOCAL) out << "CLOCAL ";
		if (obj.t_ios.c_cflag & CRTSCTS) out << "CRTSCTS ";
		out << endl;
		return out;
	}
}


void my::termios::optionCommSpeed (int arg) {
	speed_t calling_arg = B0;

	switch (arg) {
		case 0:
			calling_arg = B0;
			break;
		case 50:
			calling_arg = B50;
			break;
		case 75:
			calling_arg = B75;
			break;
		case 110:
			calling_arg = B110;
			break;
		case 134:
			calling_arg = B134;
			break;
		case 150:
			calling_arg = B150;
			break;
		case 200:
			calling_arg = B200;
			break;
		case 300:
			calling_arg = B300;
			break;
		case 600:
			calling_arg = B600;
			break;
		case 1200:
			calling_arg = B1200;
			break;
		case 1800:
			calling_arg = B1800;
			break;
		case 2400:
			calling_arg = B2400;
			break;
		case 4800:
			calling_arg = B4800;
			break;
		case 9600:
			calling_arg = B9600;
			break;
		case 19200:
			calling_arg = B19200;
			break;
		case 38400:
			calling_arg = B38400;
			break;
		case 57600:
			calling_arg = B57600;
			break;
		case 115200:
			calling_arg = B115200;
			break;
		case 230400:
			calling_arg = B230400;
			break;
		default:
			return;
	}

	cfsetispeed (&t_ios, calling_arg);
	cfsetospeed (&t_ios, calling_arg);
}


int my::termios::optionCommSpeed (void) {
	int rtn = 0;
	speed_t speed1 = cfgetispeed (&t_ios);
	speed_t speed2 = cfgetospeed (&t_ios);

	if (speed1 != speed2)
		return 0;

	switch (speed1) {
		case B0:
			rtn = 0;
			break;
		case B50:
			rtn = 50;
			break;
		case B75:
			rtn = 75;
			break;
		case B110:
			rtn = 110;
			break;
		case B134:
			rtn = 134;
			break;
		case B150:
			rtn = 150;
			break;
		case B200:
			rtn = 200;
			break;
		case B300:
			rtn = 300;
			break;
		case B600:
			rtn = 600;
			break;
		case B1200:
			rtn = 1200;
			break;
		case B1800:
			rtn = 1800;
			break;
		case B2400:
			rtn = 2400;
			break;
		case B4800:
			rtn = 4800;
			break;
		case B9600:
			rtn = 9600;
			break;
		case B19200:
			rtn = 19200;
			break;
		case B38400:
			rtn = 38400;
			break;
		case B57600:
			rtn = 57600;
			break;
		case B115200:
			rtn = 115200;
			break;
		case B230400:
			rtn = 230400;
			break;
		default:
			return 0;
	}

	return rtn;
}


void my::termios::optionCommCharSize (int arg) {
	switch (arg) {
		case 8: arg = CS8; break;
		case 7: arg = CS7; break;
		case 6: arg = CS6; break;
		case 5: arg = CS5; break;
	}

	__c_cflag_option_mask_word (CSIZE, arg);
}


int my::termios::optionCommCharSize (void) {
	switch (__c_cflag_option_get_word (CSIZE)) {
		case CS5: return 5; break;
		case CS6: return 6; break;
		case CS7: return 7; break;
		case CS8: return 8; break;
	}
	
	return 0;
}


void my::termios::optionCommStopBits (int arg) {
	if (arg == 2) __c_cflag_option_mask_bit (CSTOPB, true);
	else  __c_cflag_option_mask_bit (CSTOPB, false);
}


int my::termios::optionCommStopBits (void) {
	if (__c_cflag_option_get_bit (CSTOPB)) return 2;
	else return 1;
}
