/**
 * Kap17-I2C-RTC-mit-DS3231
 * ========================
 *
 * @brief Betrieb einer Echtzeituhr (RTC) mit dem DS3231SN an I2C.
 *
 * Die I2C-Startadresse ist 0xD0. Der ebenfalls integrierte Temperatursensor
 * wird nicht verwendet.
 *
 * @note
 * Dieses Beispiel ist nicht besonders nuetzlich: Es zeigt ausschliesslich,
 * wie I2C initialisiert wird. Die Funktionen in der Datei ds3231RTC.c ver-
 * wenden nur MCAL-Funktionen. Mit Hilfe des Debuggers laesst sich aber die
 * Registerprogrammierung nachvollziehen. Ein immer noch sehr einfaches,
 * aber dennoch besseres Beispiel folgt im Anschluss an die Beschreibung der
 * SPI-Schnittstelle: Dann wird ein 7-Segment-Display zur Anzeige der Uhrzeit
 * und des Datums verwendet.
 */

#include <stm32f4xx.h>
#include <stdint.h>
#include <stdbool.h>

/**
 * Kommentar in Zeile 25 entfernen, wenn Sie die MCAL testen möchten.
 */
//#define MCAL

#include <mcalGPIO.h>
#include <mcalI2C.h>
#include <mcalSystem.h>
#include <ds3231RTC.h>

int main(void)
{
    GPIO_TypeDef *port = GPIOB;
    I2C_TypeDef  *i2c  = I2C1;

    uint32_t pclk1Freq = 0UL;
    uint8_t seconds = 0U;
    uint8_t minutes = 0U;
    uint8_t hours = 0U;

//    uint8_t  tempSign  = 0;
//    uint8_t  tempUpper = 0;
//    float    tempLower = 0.0F;

#ifdef MCAL     // Start der MCAL-Version

    // GPIOB-Bustakt aktivieren wegen der Verwendung von PB8/PB9.
    gpioInitPort(port);
    gpioSelectPinMode(port, PIN8, ALTFUNC);
    gpioSelectAltFunc(port, PIN8, AF4);         // PB8 : I2C1 SCL
    gpioSelectPinMode(port, PIN9, ALTFUNC);
    gpioSelectAltFunc(port, PIN9, AF4);         // PB9 : I2C1 SDA
    gpioSetOutputType(port, PIN8, OPENDRAIN);
    gpioSetOutputType(port, PIN9, OPENDRAIN);

    /**
     * Die beiden folgenden Zeilen muessen auskommentiert werden,
     * wenn Sie externe Pull-Up-Widerstände verwenden.
     */
    gpioSelectPushPullMode(port, PIN8, PULLUP); // Verwendung des internen Pullup-Widerstandes
    gpioSelectPushPullMode(port, PIN9, PULLUP); // Verwendung des internen Pullup-Widerstandes

    // Initialisierung des I2C-Controllers
    pclk1Freq = sysGetPclk1Freq();
    i2cSelectI2C(i2c);
    i2cInit(i2c, pclk1Freq, I2C_DUTY_CYCLE_2, 17, I2C_CLOCK_100);

#else       // Ende der MCAL-Version, Beginn: Direkter Registerzugriff

    // GPIO konfigurieren
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;        // GPIO(B): Bustakt aktivieren
    port->MODER  &= ~GPIO_MODER_MODE8_Msk;      // PB8    : Reset
    port->MODER  |= GPIO_MODER_MODE8_1;         // PB8    : Modus = AF
    port->OTYPER &= ~GPIO_OTYPER_OT8_Msk;       // PB8    : Output-Typ reset
    port->OTYPER |= GPIO_OTYPER_OT8;            // PB8    : Open Drain
    port->AFR[1] &= ~GPIO_AFRH_AFSEL8_Msk;      // PB8    : AF zuruecksetzen
    port->AFR[1] |= GPIO_AFRH_AFSEL8_2;         // PB8    : AF4 waehlen

    port->MODER  &= ~GPIO_MODER_MODE9_Msk;      // PB9    : Reset
    port->MODER  |= GPIO_MODER_MODE9_1;         // PB9    : Modus = AF
    port->OTYPER &= ~GPIO_OTYPER_OT9_Msk;       // PB9    : Output-Typ reset
    port->OTYPER |= GPIO_OTYPER_OT9;            // PB9    : Open Drain
    port->AFR[1] &= ~GPIO_AFRH_AFSEL9_Msk;      // PB9    : AF zuruecksetzen
    port->AFR[1] |= GPIO_AFRH_AFSEL9_2;         // PB9    : AF4 waehlen

    // I2C konfigurieren
    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;         // I2C1   : Bustakt aktivieren
    i2c->CR1     =  0;                          // I2C1   : CR1 reset
    i2c->CR2     =  0;                          // I2C1   : CR2 reset
    i2c->CR2     =  0x0010;                     // I2C1   : PCLK = 16 MHz
    i2c->CCR     =  0x0050;                     // I2C1   : 100 kHz Datenrate
    i2c->TRISE   =  0x0011;                     // I2C1   : Max. Anstiegszeit der Flanke
    i2c->CR1     |= I2C_CR1_PE;                 // I2C1   : Enable

#endif      // Ende: Direkter Registerzugriff

    ds3231SetBlinkMode(i2c, DS3231_ADDR, RTC_BLINK_ON);
    ds3231SetTime(i2c, DS3231_ADDR, 12, 31, 30);
    ds3231GetTime(i2c, DS3231_ADDR, &hours, &minutes, &seconds);

    while (1)
    {
        ;
    }
}
