/***************************************************************************
                          cserial.cpp  -  description
                             -------------------
    begin                : Mit Mai 28 2003
    copyright            : (C) 2003 by Markus Raab
    email                : markus.raab@aon.at
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "cserial.h"

CSerial::CSerial(){
   init();
}

CSerial::CSerial(const char * port){
   init();
   open(port);
}

void CSerial::init()
{
   cfmakeraw (&options);
   Cfd = -1;
	options.c_cflag &= ~CRTSCTS;	// disable Hardwareflow control
   setBaud (B9600);
   setBits (CS8);
   setPari (false);
   setStop (false);
   CDebug = false;
   CWait = 0;
}   

int CSerial::open (const char * port)
{ 
	
	Cfd = ::open (port, O_RDWR | O_SYNC);
	/*Öffne serielle Schnittstelle ttyS1 mit folgenden Eigenschaften:
	 * O_RDWR read and write
	 * O_SYNC warte bei jeden write aufruf, bis der Schreibvorgang
      physikalisch durchgeführt wurde.
      Diese Funktion ist aber bei einigen Systemen nicht implementiert.*/
	if (Cfd < 0) // negative Zahl bei fehler!
	{
		fprintf(stderr, "Open_port: unable to open %s\n", port);
		exit (1);	// irreparebel, verlasse Programm
	}   
	options.c_cflag |= (CLOCAL | CREAD);	// auch lesen möglich   
	tcsetattr (Cfd, TCSANOW, &options);
	return Cfd;
}

int CSerial::reopen()
{
	tcsetattr (Cfd, TCSANOW, &options);
   // sollte noch nicht offen sein, wird tcsetattr
   // beim öffnen nochmals aufgerufen
   return Cfd;
}

CSerial::~CSerial(){
   close();
}

int CSerial::close()
{
   ::close (Cfd);
   Cfd = -1;
   return Cfd;
}

int CSerial::setBaud (speed_t speed)
{
	cfsetispeed (&options, speed);	// ändere die Baud-rate
	cfsetospeed (&options, speed);	// ändere die Baud-rate
   reopen();
   return reopen();
}
int CSerial::setBits (tcflag_t bits)
{

	options.c_cflag &= ~CSIZE;
	// lösche Datenbitseinstellung, damit nächster Befehl gültig ist
   options.c_cflag |= bits;	// select Databits
   return reopen();
}

int CSerial::setStop (bool stop)
{
   if (stop)   options.c_cflag |=  CSTOPB;	   // 2 Stopbits
   else        options.c_cflag &= ~CSTOPB;	// nur ein Stop-bit
   return reopen();
}

int CSerial::setPari (bool pary)
{
   if (pary)   options.c_cflag |= PARENB;    // mit Parität
   else        options.c_cflag &= ~PARENB;	// keine Paritätbits
   return reopen();
}

int CSerial::setDebug (bool Debug)
{
   CDebug = Debug;
   return 1;
}

int CSerial::setWait (int Wait)
{
   CWait = Wait;
   return CWait;
}

/*für DEBUG zum Ausgeben was gesendet wird*/
void CSerial::ausgeben (const unsigned char * str,
   const int length,const char modus)
{
   unsigned char buffer;
	if (CDebug)
   {
      for (int i=0; i<length; i++)
      {
         buffer = str[i];
         //wird gesendet oder empfangen?
         if (modus == 'r') {
         	fprintf (stderr, "read\t");
         } else if (modus == 'w') {
         	fprintf (stderr, "write\t");
         } else if (modus == 'x') {
         	fprintf (stderr, "FEHLER\t");
         } else if (modus == 'i') {
            	fprintf (stderr, "INFO\t");
         }

         //Unabhängigen Teil ausgeben
         fprintf (stderr,"%d\t:%d\t0%o\th:0x%x\tc:'",
         	buffer,buffer,buffer,buffer);

         //Spezialzeichen ausgeben
         if (buffer == 255)
         	fprintf (stderr,"EOF");
         else if (buffer == 10)
         	fprintf (stderr,"\\n");
         else if (buffer == 11)
         	fprintf (stderr,"\\n");
         else if (buffer == 12)
         	fprintf (stderr, "\\r");
         else if (buffer == 13)
         	fprintf (stderr,"\\r");
         else if (buffer == 17)
         	fprintf (stderr,"\\?");
         else if (buffer == 9)
         	fprintf (stderr,"\\t");
         else {
         	fprintf (stderr,"%c",buffer);
         }
         fprintf (stderr, "'\n");
         fflush(stderr);
      }
   }
}

int CSerial::send_char (unsigned char wert)
{
	ausgeben (&wert,1,'w');
	write (Cfd, &wert, 1);
	warte_kurz();
	return 0;
}

void CSerial::send (void * buffer, int length)
{
   if (CWait)  // Zwischenwartezeiten gefordert!
   {
      for (int i=0; i<length; i++)
      {
         send_char (((unsigned char *) buffer)[i]);
      }
   } else {
      ausgeben ((unsigned char *)buffer, length, 'w');
      write (Cfd, &buffer, length);
   }     
}

unsigned char CSerial::empfange_char ()
{
	unsigned char buffer[1];
	read (Cfd, buffer,1); 
	ausgeben (buffer,1,'r');
	return buffer[0];
}

void CSerial::empfange (void * buffer, int length)
{
   if (CWait)  // Zwischenwartezeiten gefordert!
   {
      for (int i=0; i<length; i++)
      {
         ((unsigned char *)buffer)[i] = empfange_char ();
      }
   } else {
      ausgeben ((unsigned char *)buffer, length, 'r');
      read (Cfd, &buffer, length);
   }
}

int CSerial::empfange_string (string str)
{
   char c;
   do  {
      c = empfange_char ();
      str += c;
      if (c == EOF)
         return 0;
   } while (c != '\n');
   return 1;
}  

void CSerial::warte_kurz ()

{
	if (CWait)
      usleep (CWait);
}

/*
   CSerial & CSerial::operator << (const char val)
   CSerial & CSerial::operator << (const int val)
   CSerial & CSerial::operator << (const long int val)
#if defined __GNUC__
   CSerial & CSerial::operator << (const long long val)
#endif
   CSerial & CSerial::operator << (const float val)
   CSerial & CSerial::operator << (const double val)
#if _G_HAVE_BOOL
   CSerial & CSerial::operator << (const bool val)
#endif
   CSerial & CSerial::operator << (const char * val)

   CSerial & CSerial::operator >> (char val)
   CSerial & CSerial::operator >> (int val)
   CSerial & CSerial::operator >> (long int val)
#if defined __GNUC__
   CSerial & CSerial::operator >> (long long val)
#endif
   CSerial & CSerial::operator >> (float val)
   CSerial & CSerial::operator >> (double val)
#if _G_HAVE_BOOL
   CSerial & CSerial::operator >> (bool val)
#endif
   CSerial & CSerial::operator >> (char * val)  
*/

