// ***********************************************************
// Project: Logger5  RTC, pressure/temp sensor/data buffer
// Uses RS232 Output (rather than USB)
// Author: Dr. Simon Schrödle
//
// Started: 09.04.2016
// ***********************************************************


#define F_CPU 16000000UL  // 16 MHz

#define BAUD    38400UL
#define UBRR_BAUD   ((F_CPU/(16UL*BAUD))-1)

#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)  
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))    
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) 
#if ((BAUD_ERROR<970) || (BAUD_ERROR>1030))
  #error Systematischer Fehler der Baudrate grösser 3% und damit zu hoch!
#endif


#include <avr\io.h>
#include <avr\interrupt.h>
#include <avr\signal.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <avr/wdt.h>
#include "usbdrv/usbdrv.h"
#include <util/delay.h>

#include "i2csoft.c"
#include "bmp085.c"
#include "rtc.c"


#define USB_INFOMSG 	0

#define USB_RTIC 60
#define USB_RTIC1 61 //current reading debug

#define USB_RDPK 64 //read last datapack

#define USB_BMP085GETR 70
#define USB_BMP085INIT 71
#define USB_BMP085GETT 72
#define USB_BMP085GETP 73

#define USB_GTIME 80
#define USB_TSET1 81
#define USB_TSET2 82
#define USB_TSET3 83
#define USB_TSET  84 //set time based on values transfered by tset1...tset3


void wait_10k(void) {  /*wait 10 k cycles*/
uint16_t counter;

  counter=10000;
  do {
  } while (--counter);
}

void wait_100(void) {  /*wait 100 cycles*/
uint16_t counter;

  counter=100;
  do {
  } while (--counter);
}


static uint8_t upc;

// USART initialisieren
void uart_init(void)
{
    // Baudrate einstellen (Normaler Modus)
    UBRRH = (uint8_t) (UBRR_BAUD>>8);
    UBRRL = (uint8_t) (UBRR_BAUD & 0x0ff);

    // Aktivieren von receiver und transmitter
      UCSRB = (1<<RXEN)|(1<<TXEN);

	// make sure we're not in double speed or mpm mode	
    UCSRA = 0;	

    // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
    UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);

    upc=15; //nothing yet received
}


static uint8_t ucurrent[16] = "XXXXXXXXXXXXXXX";
static uint8_t lastmeas[16] = "XXXXXXXXXXXXXXX";

void u_receivehandler(void)
{
  uint8_t udat_t,i;

 if ((UCSRA &(1<<RXC)))

  {
    udat_t=UDR;

    if (upc<12) {upc++;}


    if (udat_t=='T')
    {
       if (!(upc<12)) //ensure that frame end detected
       {
          upc=0;//first character of new message
       }
    }

    ucurrent[upc]=udat_t;

    if ((udat_t=='E')&&(upc==11)) //last character of message, correct frame length
    {
      for (i=0;i<12;i++) {lastmeas[i]=ucurrent[i];} //last message into buffer
      lastmeas[15]='U'; //mark message as unread
      lastmeas[14]='N'; //mark message as not process/timestamped
    }


  }
}


// end USART


static uchar replyBuf[16] = "TWSLOG R01 SN01";
static uchar usbd_val[3] = "QX";
static uchar usbd_val2[5] = "QXQX";
static dateTime timestamp, timesetd;
static uchar usbd_val3[7] = "123567";

static uint8_t usbd_datapack[30] = "012345678901234567890123456789";
// 3 byte start "TIC"    0..2
// 2 byte temp           3..4
// 4 byte pressure       5..8
// 6 byte RTC time       9..14
// 8 byte timestamp      15..22
// 2 byte reserved       23..24
// 2 byte counter        25..26
// 1 byte already read flag  27   U - unread, R - read
// 1 byte "E" end statement  28
// total 29 bytes

double tempr;
int tempi;
int32_t tempp;


// this gets called when custom control message is received
USB_PUBLIC uchar usbFunctionSetup(uchar data[8]) {
    usbRequest_t *rq = (void *)data; // cast data to correct type

    switch(rq->bRequest) { // custom command is in the bRequest field

     case USB_TSET1:
        timesetd.hour = rq->wValue.bytes[1];
        timesetd.minute = rq->wValue.bytes[0];
        return 0;
     case USB_TSET2:
        timesetd.second = rq->wValue.bytes[1];
        timesetd.date = rq->wValue.bytes[0];
        return 0;
     case USB_TSET3:
        timesetd.month = rq->wValue.bytes[1];
        timesetd.year = rq->wValue.bytes[0];
        return 0;
     case USB_TSET:
        set_date_time(timesetd);
        return 0;
     case USB_BMP085GETR:
        i2c_start();
        i2c_writebyte(0xEE);
        i2c_writebyte(0xAA);
        i2c_start();
        i2c_writebyte(0xEF);
        usbd_val[0]=i2c_readbyte(1); //ack
        usbd_val[1]=i2c_readbyte(0); //nack
        i2c_stop();

        usbMsgPtr = (uint16_t) ((uint8_t*)usbd_val);
        return sizeof(usbd_val);
     case USB_BMP085INIT:
        bmp085_init();
        usbd_val[0]=0x40;
        usbd_val[1]=0x41;
        usbMsgPtr = (uint16_t) ((uint8_t*)usbd_val);
        return sizeof(usbd_val);
     case USB_BMP085GETT:
        tempr=bmp085_gettemperature();
        tempr=tempr*10;
        tempi=(int)tempr;
        usbd_val[0]=(tempi>>8)&0x00ff;
        usbd_val[1]=tempi&0x00ff;
        usbMsgPtr = (uint16_t) ((uint8_t*)usbd_val);
        return sizeof(usbd_val);
     case USB_BMP085GETP:
        tempp=bmp085_getpressure();
        usbd_val2[0]=(tempp>>24)&0x000000ff;
        usbd_val2[1]=(tempp>>16)&0x000000ff;
        usbd_val2[2]=(tempp>>8)&0x000000ff;
        usbd_val2[3]=tempp&0x000000ff;
        usbMsgPtr = (uint16_t) ((uint8_t*)usbd_val2);
        return sizeof(usbd_val2);
     case USB_GTIME:
        timestamp=get_date_time();
        usbd_val3[0]=timestamp.hour;
        usbd_val3[1]=timestamp.minute;
        usbd_val3[2]=timestamp.second;
        usbd_val3[3]=timestamp.date;
        usbd_val3[4]=timestamp.month;
        usbd_val3[5]=timestamp.year;
        usbMsgPtr = (uint16_t) ((uint8_t*)usbd_val3);
        return sizeof(usbd_val3);

      case USB_RTIC: // TIC4 data
        if (lastmeas[15]=='U')
        {
          lastmeas[15]='R'; //message has been read first time
        } else {lastmeas[0]='R';} //repeated read

        usbMsgPtr =(uint16_t) ((uint8_t*) lastmeas);
        return sizeof(lastmeas);

      case USB_RDPK: // data package transmit
        if (usbd_datapack[27]=='U')
        {
          usbd_datapack[27]='R'; //message has been read first time
        } else {usbd_datapack[0]='R';} //repeated read - RIC instead of TIC start

        usbMsgPtr =(uint16_t) ((uint8_t*) usbd_datapack);
        return sizeof(usbd_datapack);

       case USB_RTIC1: // TIC4 data   current data debug

        usbMsgPtr =(uint16_t) ((uint8_t*) ucurrent);
        return sizeof(ucurrent);

      case USB_INFOMSG: // send data to PC
        usbMsgPtr =(uint16_t) ((uint8_t*) replyBuf);
        return sizeof(replyBuf);
    }
    return 0; // should not get here

}




void u_sendhandler(void)
{

    uint8_t i;

    if (usbd_datapack[27]=='U')
    {
         usbd_datapack[27]='R'; //message has been read first time


        for (i=0;i<29;i++) {
           while ( !( UCSRA & (1<<UDRE)) )
                ;
          UDR = usbd_datapack[i];
        }

    }

}


static uint16_t datapcnt;

void stamp_handler(void) //carries out T, p and RTC timestamp handling
{
  if (lastmeas[14]=='N') //non-processed new result?
  {
    usbd_datapack[0]='T';
    usbd_datapack[1]='I';
    usbd_datapack[2]='C';


    timestamp=get_date_time();
    usbd_datapack[9]=timestamp.hour;
    usbd_datapack[10]=timestamp.minute;
    usbd_datapack[11]=timestamp.second;
    usbd_datapack[12]=timestamp.date;
    usbd_datapack[13]=timestamp.month;
    usbd_datapack[14]=timestamp.year;

    usbd_datapack[15]=lastmeas[1];
    usbd_datapack[16]=lastmeas[2];
    usbd_datapack[17]=lastmeas[3];
    usbd_datapack[18]=lastmeas[4];
    usbd_datapack[19]=lastmeas[5];
    usbd_datapack[20]=lastmeas[6];
    usbd_datapack[21]=lastmeas[7];
    usbd_datapack[22]=lastmeas[8];

    tempr=bmp085_gettemperature();
    tempr=tempr*10;
    tempi=(int)tempr;
    usbd_datapack[3]=(tempi>>8)&0x00ff;
    usbd_datapack[4]=tempi&0x00ff;

    tempp=bmp085_getpressure(); //will check temperature again, but don't mind
    usbd_datapack[5]=(tempp>>24)&0x000000ff;
    usbd_datapack[6]=(tempp>>16)&0x000000ff;
    usbd_datapack[7]=(tempp>>8)&0x000000ff;
    usbd_datapack[8]=tempp&0x000000ff;

    usbd_datapack[23]=0xff; //reserved
    usbd_datapack[24]=0xff; //reserved


    datapcnt++;
    usbd_datapack[25]=(datapcnt>>8)&0x00ff;
    usbd_datapack[26]=datapcnt&0x00ff;

    usbd_datapack[27]='U'; //unread data pack
    usbd_datapack[28]='E'; //end of pack
    lastmeas[14]='S'; //timestamp info processed
  }
}


int main(void) {
   uint8_t i;

   uart_init();

   i2c_init();
   bmp085_init();

   rtc_init();

   timestamp=get_date_time();

   DDRD&=~0x08; //PD3 as input - S1 switch
   PORTD|=0x08; //pull up on

   if (!(PIND&0x08)) //connect via USB - if key S1 pressed at startup!
   {
     wdt_enable(WDTO_1S); // enable 1s watchdog timer
     usbInit();
     usbDeviceDisconnect(); // enforce re-enumeration



     for(i = 0; i<250; i++) { // wait 500 ms
       wdt_reset(); // keep the watchdog happy
       _delay_ms(2);
      }
     usbDeviceConnect();

     sei(); // Enable interrupts after re-enumeration

     do {
       wdt_reset(); // keep the watchdog happy
       usbPoll();

       u_receivehandler();
       stamp_handler();

      } while(1);
   }


   sei(); // Enable interrupts after re-enumeration

   do {
       u_receivehandler();
       stamp_handler();
       u_sendhandler();
  } while (1);

 return 0;
}




















