/*
 * File:   main.c
 * Author: witkatz
 *
 * Created on 1. Dezember 2015, 13:28
 */

#include <xc.h>
#include <stdint.h>

// CONFIG
#pragma config FOSC = INTRCIO   // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disnabled)
#pragma config PWRTE = OFF      // Power-Up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = ON       // Brown-out Detect Enable bit (BOD enabled)
#pragma config CP = OFF         // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)

#define _XTAL_FREQ 4000000
#define clockpin GPIObits.GP4
#define datapin GPIObits.GP5
#define DI1pin GPIObits.GP2
#define DI2pin GPIObits.GP3

union {
    struct{
        uint16_t ADC1_Rohwert;
        uint16_t ADC2_Rohwert;
    };
    uint8_t ByteArr[4];
    struct{
        uint8_t ADC1_Lowbyte: 8;
        uint8_t unused: 8;
        uint8_t ADC2_Lowbyte: 8;
        uint8_t ADC1_Highbits: 2;
        uint8_t ADC2_Highbits: 2;
        uint8_t DI1: 1;
        uint8_t DI2: 1;
        uint8_t ChkSum: 2;
    }TgrmData;
} DataBuf;

void InitMCU(void){
    GPIO = 0;
    CMCON = 0x07; // Comparator off
    ADCON0bits.ADFM = 1; // Rigth justified
    ADCON0bits.VCFG = 0; // Vref = Vdd 
    ADCON0bits.ADON = 1; // A/D on
    
    ANSELbits.ADCS = 0b101; // TAD = 4µs
    ANSELbits.ANS = 0b0011; // AN0,AN1 
    TRISIO = 0b001111;
}

void wait5ms(void){
    __delay_ms(5);
}

void sendByte(uint8_t s){
    uint8_t mask = 0b00000001;
    while(mask){
        datapin = (s & mask) ? 1 : 0;
        clockpin = 1;
        wait5ms();
        clockpin = 0;
        wait5ms();
        mask <<= 1;
    }
}

uint8_t checksum(uint8_t b){
    uint8_t chks = 0;
    while(b){
        if(b & 1)
            chks++;
        b >>= 1;
    }
    return (chks);
}

void ADC_Read(uint16_t *Res){
    uint8_t i;
    __delay_us(20);
    *Res = 0;
    for(i = 0x80; i; i>>=1){
        ADCON0bits.GO = 1;
        while (ADCON0bits.GO_nDONE){;}
        *Res += (ADRESH << 8) + ADRESL;
        wait5ms();
    }
    *Res /= 8;    
}

void main(void) {
    
    InitMCU();
    while(1){
        
        // AD Channel 0
        ADCON0bits.CHS = 0;
        ADC_Read(&DataBuf.ADC1_Rohwert);

        // AD Channel 1
        ADCON0bits.CHS = 1;
        ADC_Read(&DataBuf.ADC2_Rohwert);

        // High Bits ins Telegrammbyte kopieren
        DataBuf.ByteArr[3] <<= 2;
        DataBuf.ByteArr[3] |= DataBuf.ByteArr[1];

        // DIO
        if(DI1pin) DataBuf.TgrmData.DI1 = 1;
        if(DI2pin) DataBuf.TgrmData.DI2 = 1;
        
        // Checksum 
        DataBuf.TgrmData.unused = checksum(DataBuf.TgrmData.ADC1_Lowbyte);
        DataBuf.TgrmData.unused += checksum(DataBuf.TgrmData.ADC2_Lowbyte);
        DataBuf.TgrmData.unused += checksum(DataBuf.ByteArr[3]);
        DataBuf.TgrmData.ChkSum = DataBuf.TgrmData.unused;
        
        // Send Data
        sendByte(DataBuf.TgrmData.ADC1_Lowbyte);        
        sendByte(DataBuf.TgrmData.ADC2_Lowbyte);        
        sendByte(DataBuf.ByteArr[3]);        
    }
}
