/*Programm für Universalbox1, Accu Entlader mit Kapazitätsmessung
  (c) 2004 by Malte Marwedel
  www.marwedels.de/malte
  Version 1.0
  Die Verwendung geschieht auf eigene Verantwortung, es wird nicht garantiert,
  dass diese Datei fehlerfrei ist.
  Die Datei darf frei verwendet werden.
  Änderungen sind erlaubt solage kenntlich gemacht wird, dass es sich
  nicht mehr um die original Datei handelt.

A/D 0 : Ermitter des Transistors
A/D 1 : Plus der Batterie
PD2   : Ausgang zum Transistor


Wichtig: Damit die Werte des Accus korrekt gemessen werden, muss die
Betriebsspannung des Controllers möglichst genau 5V betragen, da sie auch als
Referezsmannung der A/D Wandler verwendet wird.

*******************************************
*********************--------**************
***|-----------------|10KOhm|----o**A/D1***
***|*************|***--------**************
***|*************|*************************
***|************---************************
***|************|1|************************
***|************|0|************************
***|************|O|************************
***|***A********|h|************************
*-----*C********|m|************************
**---**C********|-|************************
***|***U*********|*************************
***|*************|***--------**************
***|*************|---|10KOhm|----o**A/D0***
***|*************|***--------**************
***|*************|*************************
***|*************\*************************
***|**************\|***--------************
***|***************|---|470Ohm|--o**PD2****
***|***********NPN/|***--------************
***|-------------/*************************
**---*GND**********************************
*******************************************

*/

//Konstanten
#define frequency 8000000 // 8 Mhz, wird für den UART benötigt
#define the_resistor 10   // 10 Ohm Entladewiderstand
#define largevalue (the_resistor*18432)

//Externe Funktionen
#include <io.h>
#include <inttypes.h>
#include <interrupt.h>
#include <sig-avr.h>
#include <string.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>

#include "../boxlib.h"
/* Funktionen:
led_red();led_green();led_yellow();led_off();led_toggle();
key_white_pressed, key_red_pressed
*/

#include "../../basicad.h"
/* Funktionen:
uint16_t getadc(uint8_t channel); init_ad();
*/

#include "../../basicuart.h"
/*
uart_init();uart_get();uart_put(uint8_t value);
*/

//Um zu wissen für was uint8_t u.s.w. steht siehe inttypes.h
typedef uint8_t  u08;
typedef int8_t   s08;
typedef uint16_t u16;
typedef int16_t  s16;
typedef uint32_t u32;
typedef int32_t  s32;

//Globale Variablen
u08 systemmode;
/* Systemmode:
   0 -> noch kein Accu angeschlossen/zu wenig Spanung
   1 -> Akku zum Entladen bereit
   2 -> Accu wird entladen
   3 -> Accu ist entladen
   4 -> Entladevorgang wurde abgebrochen
*/
u08 numberofcells = 1; //Anzahl der Zellen min: 1, max: 4
u32 capturedvalue; /*Wieviel A/h entnommen wurde (captured walue muss zuvor
                   umgerechnet werden) */
u16 dischargetime; //Wie lange schon entladen wird (in Sekunden -> max 18Std)
u08 smalldurch; //für die LEDs-schaltet immer zwischen Null und Eins hin und her
u16 currvoltage;//Spannung in mV
u16 gesstrom; //Entnommene mA/h
u08 rs232rausstring[60] =
    "Mode=x, Zellen=x, U=xxxxmV, C=xxxxmA/h, T=xxxx.xxMinuten";

void wordtostr(u32 nummer, u08 digits, u08 strposition) {
while (digits > 0) {
digits--;
rs232rausstring[strposition+digits] = nummer%10+48;
nummer = nummer / 10;
}
}


void taster_test(void) {
  u08 rs232input;
  if ((systemmode == 2) && (key_red_pressed)) {
    //Stoppe Entladen
    systemmode = 4;
  }
  if ((systemmode == 1) && (key_white_pressed)) {
    //Starte Entladen
    systemmode = 2;
    dischargetime = 0;
    capturedvalue = 0;
  }
  rs232input = uart_get();
  if ((rs232input > 48) && (rs232input < 53) && (systemmode < 2)) {
    //Setze Zellenzahl
    numberofcells = rs232input - 48;
  }
  if ((systemmode > 2)&&(rs232input == 114)) { //Reboot bei "r" Eingabe
   systemmode = 0;
   numberofcells = 1;
   capturedvalue = 0;
   dischargetime = 0;
   uart_put(10); //Neue Zeile für neues Entladen
  }
   
}

void set_leds(void) {
/*0:Wenn Prog gestartet, jedoch die Spannung unter 800mV blinkt die LED grün
  1:Wenn Prog gestartet und Spannung oberhalb von 800mV leuchtet die LED grün
  2:Beim Entladen blinkt die LED zwischen Gelb und Rot
  3:Wenn fertig entladen, dann blinkt die LED rot
  4:Wenn abgebrochen, dann leuchtet die LED rot
*/
  smalldurch = 1 - smalldurch; //wechselt so immer zwischen = 0 und 1
  if (systemmode == 1) { //über 800mV
    led_green();
  }
  if (systemmode == 4) { //Abgebrochen
    led_red();
  }
  if (smalldurch == 0) {
    if ((systemmode == 0)||(systemmode == 3)) { //unter 800mV; fertig Entladen
      led_off();
    }
    if (systemmode == 2) { //Beim Entladen
      led_yellow();
    }
  } else {
    if ((systemmode == 2)||(systemmode == 3)) { //unter 800mV; fertig Entladen
      led_red();
    }
    if (systemmode == 0) { //unter 800mV
      led_green();
    }
  }
}
    
void calc_volt_amps(void){
/*-Berechnung der Spannung:
   Ein Digit entspricht 5V/1024=0,0048828V, das bedeutet, dass sobald
   (0,8V*numberofcells) / 0,04882813 = 164*numberofcells
   an A/D 1 unterschritten wird, der Transistor abgeschaltet werden muss
   A/D 1 Wert mal 488 durch 100 (weil wir mit ganzen Zahlen rechnen) ergibt den
   tatsächlichen Wert in mV.
  -Berechnung des Stromes:
   Von A/D 1 wird A/D 0 Abgezogen. Der resultierende Wert wird sekündlich zu
   capturedvalue addiert und die Sekunden gezählt.
   C (in mA/h) = (capturedvalue*25)/(R*18432)
   capturedvalue wir mittels R in die entnommene Kapazität umgerechnet und
   läge in (A/s) wenn mann die A/D Werte zuvor in einen realen Spannungswert
   umgerechnet hätte. der Faktor 25/18432 ermöglicht die Umrechnung in mA/h und
   berücksichtigt dass 5V/1024 = 0,0048828V ist.
   (5V/1024)*(1000/(60*60)) = 25/18432
   Die 5V/1024 ist der Umrechnungsfaktor (5V Betriebsspannung, 10Bit A/D Wandler
   2^10Bit=1024) um aus dem A/D Werten die Spannung zu erhalten.
   Das *1000 mach aus den Volt Millivolt. Das Teilen durch 60*60
   macht aus den Sekunden Stunden. Die Berechnung des Stromes aus der Spannung
   erfolg mittels R = U/I.
*/
u32 adc0val,adc1val;
u16 adcdelta;
u32 largetemp;

  adc0val = getadc(0);
  adc1val = getadc(1);
  largetemp = adc1val * 488;
  largetemp /= 100;
  currvoltage = largetemp;

  if (systemmode == 2) {
    if (adc1val >= adc0val) {
    adcdelta = adc1val - adc0val;
    }else{
      adcdelta = 0;
    }
    capturedvalue += adcdelta;
    dischargetime++;
  }
  largetemp = (capturedvalue*25);
  largetemp /= 184320;
  gesstrom = largetemp;
}

void accu_control(void) {
  if ((systemmode == 0) && (currvoltage > (800*numberofcells))) {
    systemmode = 1;
    cbi(PORTD,2);
  }
  if ((systemmode == 1) && (currvoltage < (800*numberofcells))) {
    systemmode = 0;
    cbi(PORTD,2);
  }
  if (systemmode == 2) { //Wenn läuft
    if (currvoltage > (800*numberofcells)) {
      sbi(PORTD,2);
    }else{
      systemmode = 3;
      cbi(PORTD,2);
    }
  }
  if (systemmode > 2) { //im Zweifelsfall immer aus
    cbi(PORTD,2);
  }
}
  
void rs232_print(void) {
u08 senddurch;
  wordtostr(systemmode,1,5);
  wordtostr(numberofcells,1,15);
  wordtostr(currvoltage,4,20);
  wordtostr(gesstrom,4,30);
  wordtostr(dischargetime / 60,4,42);
  wordtostr(dischargetime % 60,2,47);
  rs232rausstring[58] = 13;//Damit die alte Statuszeile überschrieben wird
  for (senddurch = 0;senddurch < 60;senddurch++) {
    uart_put(rs232rausstring[senddurch]);
  }
}

int main( void ){

DDRB = 0x05;//LED Ausgänge
DDRC = 0;
DDRD = 0x04;//Transistor Ausgang
init_ad();
uart_init();
TCNT1 = 0;  //setzt den Timer1 auf null (reset timer1)
TCCR1B = 4;  //startet timer1, Divider: 256
for (;;) {
  /*Wenn Weiße Taste, dann entladen starten, alle Variablen zurück auf Anfang!!
    Wenn Rote Taste, dann Stoppen
    Wenn unter 800mV dann ebenfalls Stoppen
    Der Kontroller sendet jede Sektunde den Status per RS232
    Vor dem Entladen kann per UART die Zellenzahl eingegeben werden
  */

  taster_test();
  set_leds();
  accu_control();
  calc_volt_amps();
  rs232_print();
  
  // Wir reduzieren den Durchlauf auf einmal pro Sekunde
  while (TCNT1 < 31249) {
  asm volatile("nop");
  }
  TCNT1 = 0;
}//ende Endlosschleife
}

