/*
 * serIO.c:
 * Eingabe und Ausgabe ueber die serielle Schnittstelle.
 *
 * Jan Bredereke, 2019, 2024
 */

/* Die eigene Header-Datei: */
#include "serIO.h"

/* Die Definitionen von Special-Funktion-Registern fuer den
 * Mikrocontroller C515C: */
#include <REG515C.H>


/* Die oeffentlichen Methoden: */
/* --------------------------- */

/* Holt ein einzelnes Zeichen von der seriellen Schnittstelle, ohne
 * darauf zu warten. */
/* Falls kein Zeichen da ist, wird Null zurueckgegeben. */
char serIn(void) {
    /* Pruefe, ob ein Zeichen gelesen worden ist.
     * (Dann wird das Receiver-Interrupt-Flag gesetzt.) */
    if (RI) {
        /* Loesche das Receiver-Interrupt-Flag wieder. */
        RI = 0;
        /* Hole das Zeichen und gib es zurueck. */
        return SBUF;
    } else {
        /* Sonst gib Null zurueck. */
        return '\0';
    }
}

/* Holt ein einzelnes Zeichen von der seriellen Schnittstelle und
 * wartet ggf., bis eines da ist. */
char serWaitIn(void) {
    /* Warte, bis ein Zeichen empfangen wurde. (Dann wird das
     * Receiver-Interrupt-Flag gesetzt.) */
    while (!RI);
    /* Loesche das Receiver-Interrupt-Flag wieder. */
    RI = 0;
    /* Hole das empfangene Zeichen und gib es zurueck. */
    return SBUF;
}

/* Gibt ein Zeichen ueber die serielle Schnittstelle aus. */
/* Wartet nur, falls zur Zeit eine fruehrere solche Ausgabeoperation
 * noch nicht abgeschlossen ist. */
void serCharOut(char zeichen) {
    /* Warte ggf., bis das vorige Zeichen fertig ausgegeben ist.
     * (Dann wird das Transmitter-Interrupt-Flag gesetzt.) */
     while (!TI);
    /* Loesche das Transmitter-Interrupt-Flag wieder. */
    TI = 0;
    /* Lege das Zeichen in Sendepuffer und beginne die Uebertragung, ohne
     * auf deren Ende zu Warten. */
    SBUF = zeichen;
}

/* Gibt einen String ueber die serielle Schnittstelle aus. */
void serStringOut(char *string) {
    char z; /* Das naechste zu druckende Zeichen */

    while (z = *string++) {
        serCharOut(z);
    }
}

/* Initialisiert die Eingabe+Ausgabe ueber die serielle Schnittstelle. */
void serInit(void) {
    /* Initialisiert die serielle Schnittstelle des C515C
     * auf 9600 Baud, 1 Stoppbit, kein Paritybit.
     * Ein Aufruf ist bei der echten Mikrocontrollerkarte im Labor
     * nicht noetig (aber auch nicht schaedlich), da fuer das Laden des
     * Programms schon eine Initialisierung durch uVision erfolgt.
     * Siehe auch das C515C-User-Manual, Seite 6-48ff.
    */

    /* Laedt Baud-Rate-Zaehler, oberer Teil
     * (Formel im User-Manual auf S. 6-54).
    */
    SRELH = 0x03;
    /* Laedt Baud-Rate-Zaehler, unterer Teil, und setze Zaehler zurueck. */
    SRELL = 0xbf;
    /* Setzt SMOD-Bit im Register PCON (verdoppelt Baud-Rate). */
    PCON |= 0x80;
    /* Setzt BD-Bit im Register ADCON0 (Baud rate generator enable). */
    BD = 1;
    /* Setzt Bits im Register SCON (von links nach rechts):
     * SM0=0, SM1=1, SM2=0:
     *   serial mode 1, also 8-Bit-UART
     *   mit variabler Baud-Rate,
     *   einem Stoppbit und keinem
     *   Paritybit.
     * REN=1: Receiver enable.
     * TB8=0: unbenutzt (9. Sendebit).
     * RB8=0: unbenutzt (9. Empfangsbit).
     * TI=1: Transmitter-Interrupt-Flag.
     * RI=0: Receiver-Interrupt-Flag.
    */
    SCON = 0x52;
}
