/** \file tfd128.c 
\brief Source
 */

/***************************************************************************
 *   Copyright (C) 2003 by Michael Schuster                                *
 *                 schuster@enertex.de                                     *
 *                                                                         *
 *              Last update 15.06.04                                       *
 *                                                                         *
 *   This programm comes without any warranty !!!                          *
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 *   Parts of the code I found somewhere in newsgroups                     *
 *                                                                         *
 *   Other were inspired by an discussion at                               *
 *   ftdi-usb-sio-devel@lists.sourceforge.net with                         *
 *    Ned Konz <ned@bike-nomad.com> and Ian Abbott <abbotti@mev.co.uk>     *
 *                                                                         *
 ***************************************************************************/


/***************************************************************************
 *    This programm shows an simple way of comunication with the ftdi-chip *
 *    connected to an usb port in the C Language.                          *
 *                                                                         *
 *    It is intended to show how a single byte transfer can be implemented *
 *    You need to verify:                                                  *
 *      + a kernel with the ftdi_sio (look as root with lsmod) running     *
 *      + a rs232-subsystem connected (asynchr.) to the ftdi FT232 BM chip *
 ***************************************************************************/


// load driver with modprobe ftdi_sio vendor=0x0403 product=0xe0ec 

#include <stdio.h>
#include <string.h> 
#include <fcntl.h>
#include <unistd.h>
#include <termios.h> 
#include <time.h>

#include "prakt.h"
#include "tfd128.h"


int fd;
U8 dat[500] ;
struct termios tio,backup;




int main(int argc, char** arg)
{
    struct AllData sAllData;
    U8 mode = 3;
    U8 interval = 5;
    if ( init()!= 0 )
    {
        return -1;
    }
    char c;
    while( (c = getch()) != 'q')
    {
        switch(c)
        {
            case 'V':
                if( busy() == 0 )
                    printf("\nVersion: %d\n", getVersionNumb());
                else
                    printf("\nBusy");
                break;
            case 'A':
                if( busy() == 0 )
                    printf("\nDatapoints: %d\n", getDataPointsCount());
                else
                    printf("\nBusy");
                break;
            case 'S':
                if( busy() == 0 )
                    printf("Start Logging %d\n", startLogging(mode, interval));
                else
                    printf("\nBusy");
                break;
            case 'm':
                do
                {
                    printf("\nNew Mode 2-3\n 2: Temp only\t3: Temp +Hum\n");
                    scanf("%d",&mode);
                }while( mode < 2 && mode > 3);
                    
                break;
            case 'i':
                do
                {
                    printf("\nNew Inteval 1-5\n");
                    scanf("%d",&interval);
                }while( interval < 1 && interval > 5);
                
                break;
            case 'E':
                printf("Stop Logging %d\n", stopLogging());
                break;
                
            case 'R':
            case 'N':
                if( busy() == 0 )
                    showLog();
                else
                    printf("\nBusy");
                break;
                
            case 'Z':
                if( busy() == 0 )
                {
                    sAllData = getAllData();
                    printf("\nStart time\n");
                    showTime(sAllData.sStartDate);
                    printf("Mode %d, interval %d\n", sAllData.mode, sAllData.interval);
                    U8 interval;
                    printf("Stop time\n");
                    showTime(sAllData.sStopDate);
                    
                }
                else
                    printf("\nBusy");
                break;
                
            case 'h':
                
            default:
                printf("V - Display version\nA - Available datapoints\nS - Start logging\nE - Stop logging\nR - Show log\nZ - Show settings\ni - Set interval\nm - Set mode\nq - Quit\n");
                
                break;
            
            
        }
    }
    
    
    
    if(tcsetattr(fd, TCSANOW, &backup) == -1) {
        printf("serial_open(): unable to restore old attributes\n");
        return (-1);
    }

    return 0;
}


void showLog(void)
{
    U16 uTempr;
    float fTemp;
    U8 uHum;
    U16 uLogCount = getDataPointsCount();
    U8 mode = getAllData().mode;
    U8 *tmpdat = dat;
    //Get first data
    U8 uCmdVal = commandTFD('R', dat, 0);
    while ( uCmdVal != NAK && uLogCount > 0 )
    {
        for ( ; uLogCount > 0 && *tmpdat != 0; uLogCount-- )
        {
            switch (mode)
            {
                
                case 3:
                    uTempr = *tmpdat;
                    tmpdat += 2;
                    uHum = *tmpdat;
                    tmpdat++;
                    fTemp = uTempr - ((uTempr & 0x8000) << 1);
                    fTemp = (fTemp / 10.0)+20;
                    printf("\nLogNum %d Temp: %0.1f, Hum: %d",uLogCount, fTemp, uHum);
                    break;
                case 2:
                    uTempr = *tmpdat;
                    tmpdat += 2;
                    fTemp = uTempr - ((uTempr & 0x8000) << 1);
                    fTemp = (fTemp / 10.0)+20;
                    printf("\nLogNum %d Temp: %0.1f",uLogCount, fTemp);
                    break;

                default:
                    break;
            }
        }
        tmpdat = dat;
        //Get next data, last data in block is 0
        uCmdVal = commandTFD('N', dat, 0);
        
    }
    printf("\n");
}

U16 getDataPointsCount(void)
{
    U16 uRetVal=0;
    if ( commandTFD('A', dat, 0) != NAK )
    {
        memcpy(&uRetVal, dat, 2);
    }
    return uRetVal;
}

U16 getVersionNumb(void)
{
    U16 uRetVal=NAK;
    if ( commandTFD('V', dat, 0) != NAK )
    {
        memcpy(&uRetVal, dat, 2);
    }
    return uRetVal;
}

U16 startLogging(U8 mode, U8 interval)
{
    U8 uRetVal;
    struct startData sData;
    sData.sCurDate = getTime();
    sData.mode = mode;
    sData.interval = interval;
    memcpy(dat, &sData, sizeof(struct sDate));
    dat[7] = sData.mode;
    dat[8] = sData.interval;
    if ( commandTFD('S', dat, sizeof(struct startData)) != -1 )
        uRetVal = dat[0];
    else
        uRetVal = -1;
    return uRetVal;
}

U16 stopLogging(void)
{
    U8 uRetVal;
    struct sDate sData;
    sData = getTime();
    memcpy(dat, &sData, sizeof(struct sDate));
    if ( commandTFD('E', dat, sizeof(struct sDate)) != -1 )
        uRetVal = dat[0];
    else
        uRetVal = -1;
    return uRetVal;
}

U8 busy(void)
{
    if (getVersionNumb() == NAK)
        return 1;
    else
        return 0;
}

struct AllData getAllData(void)
{
    struct AllData sData;
    if ( commandTFD('Z', dat, 0) != -1 )
    {
        memcpy(&sData.sStartDate, dat, sizeof(struct sDate));
        sData.mode = dat[7];
        sData.interval = dat[8];
        memcpy(&sData.sStopDate, &dat[9], sizeof(struct sDate));
    }
    return sData;
}

void  showTime(struct sDate Date)
{
;
    
    printf("\n%d %d %d  %d:%d:%d\n",Date.uDay, Date.uMonth+1,  Date.uYear, Date.uHours, Date.uMinutes , Date.uSeconds);
    
}

struct sDate getTime(void)
{
    struct sDate curDate;
    struct tm *sTime;
    time_t tTime = time(0);
    sTime = gmtime(&tTime);
    curDate.uYear = sTime->tm_year;
    curDate.uYear += 1900;
    curDate.uMonth = sTime->tm_mon;
    curDate.uDay = sTime->tm_mday;
    curDate.uHours = sTime->tm_hour;
    curDate.uMinutes = sTime->tm_min;
    curDate.uSeconds = sTime->tm_sec;
    return curDate;
}



int commandTFD(char cmd, U8 *data, int datalen)
{
    char cVal;
    int i;
    writeTFD(STX);
    writeTFD(cmd);
    for ( i = 0; i < datalen ; i++)
    {
        if (data[i] == STX || data[i] == ETX || data[i] == ENQ)
        {
            writeTFD(ENQ);
            writeTFD(data[i]+0x80);
        }
        else
        {
            writeTFD(data[i]);
        }
    }
    writeTFD(ETX);
  
// Answer sequence must start with STX.    
    cVal = readTFD();
    if ( cVal != STX )
    {
        printf("internal error: expected STX, got %c",cmd);
        return -1;
    }

// Then the command itself.
    cVal = readTFD();
    if ( cVal != cmd )
    {
        printf("internal error: expected %c, got %c",cmd, cVal);
        return -1;
    }
    cVal = 0;
    for ( i = 0; cVal != ETX ; i++ )
    {
        cVal = readTFD();
        if (cVal == ENQ )
        {
            data[i]= (readTFD() -0x80);
        }
        else if ( cVal != ETX )
        {
            data[i] = cVal;
        }
    }
    return i;
    

}

void writeTFD(U8 buf)
{
    U8 suc;
    suc = write(fd, &buf, 1);
    //for debug
    //printf("\nwrite value %x, %c, succeed %d",buf,buf, suc);
}

U8 readTFD(void)
{
    U8 buf;
    while (read(fd, &buf, 1 )==-1);
    //for debug
    // printf("\nread value %d, %c, succeed",buf,buf);
    return buf;
}

int init(void)
{
    	//First we open the usbdevice (trying to find the chip 

    if ( ( fd = open( "/dev/ttyUSB0", O_RDWR| O_NOCTTY| O_NDELAY )) < 0 ) {
        fprintf(stderr,"Can't open dev/ttyUSB0\n");
        if ( ( fd = open( "/dev/ttyUSB1", O_RDWR| O_NOCTTY| O_NDELAY )) < 0 ) {
            fprintf(stderr,"Can't open dev/ttyUSB1 either\n");
            return(-1);
        }
    } 
    if ( tcgetattr( fd, &tio ) == -1 )
    { 
        fprintf(stderr,"Can't properly open /dev/ttyUSB0\n"); 
    };
    backup=tio;
	// Setting baudrate
    if(cfsetispeed(&tio, BAUDRATE) == -1) {
        printf("serial_open(): unable to set input-baudrate\n");
        return (-1);
    }
    if(cfsetospeed(&tio, BAUDRATE) == -1) {
        printf("serial_open(): unable to set output-baudrate\n");
        return (-1);
    }

	// Setting the rawmode 
    tio.c_lflag &=~(ECHO|ICANON|ISIG|IEXTEN);
    tio.c_lflag  = tio.c_lflag | (FLUSHO);
    tio.c_iflag &=~ (ICRNL|BRKINT|IXON|IXOFF|ISTRIP|INPCK);
    tio.c_iflag  = tio.c_iflag | (IGNBRK|IMAXBEL|IXANY);
    tio.c_cflag &= ~(CSIZE| PARENB| CSTOPB);
    tio.c_cflag  = tio.c_cflag | (CS8 |CREAD| CLOCAL| PARENB);
    tio.c_oflag &= ~(OPOST);
    tio.c_cc[VMIN]=1;  // Only 1 char to read!
    tio.c_cc[VTIME]=0;

    if (tio.c_lflag & (ECHO|ICANON|ISIG|IEXTEN))
        printf("serial_open(): unable to set terminalmode -lflag ");
    if ( tio.c_iflag & (ICRNL|BRKINT|IXON|ISTRIP|INPCK))
        printf("serial_open(): unable to set terminalmode -iflag \n");


	// now clean the  line ...
    if(tcflush(fd, TCIOFLUSH) == -1) {
        printf("serial_open(): unable to flush data\n");
        return (-1);
    }
	// now clean the  line ...
    if(tcflow(fd, TCIOFLUSH) == -1) {
        printf("serial_open(): unable to flush data\n");
        return (-1);
    }

	// ... and activate the settings for the port
    if(tcsetattr(fd, TCSANOW, &tio) == -1) {
        printf("serial_open(): unable to set new attributes\n");
        return (-1);
    }	
    printf("Sucessfully opened device for read and write\n");
    return 0;
}
