/*
 * File:   main.c
 * Author: boos
 *
 * Created on October 17, 2022, 6:11 PM
 */

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF       // Internal/External Switchover Mode (Internal/External Switchover Mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config CPUDIV = CLKDIV6 // CPU System Clock Selection Bit (CPU system clock divided by 6)
#pragma config USBLSCLK = 48MHz // USB Low SPeed Clock Selection bit (System clock expects 48 MHz, FS/LS USB CLKENs divide-by is set to 8.)
#pragma config PLLMULT = 3x     // PLL Multipler Selection Bit (3x Output Frequency Selected)
#pragma config PLLEN = ENABLED  // PLL Enable Bit (3x or 4x PLL Enabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

#include <xc.h>

// define functions
void CD4094_send (unsigned char d);
void CD4094_load (void);
unsigned char CD4021_read (void);
void CD4021_load (void);

// input values
unsigned char v1 = 0;
unsigned char v2 = 0;

// abbreviations for convenience
#define CD4094_DAT RC0
#define CD4094_CLK RC1
#define CD4094_STR RC2
#define CD4021_DAT RC5
#define CD4021_CLK RC4
#define CD4021_LAT RC3

// main function
void main (void) {

    
    // set up ports RC0:4 as outputs
    TRISC0 = 0;
    TRISC1 = 0;
    TRISC2 = 0;
    TRISC3 = 0;
    TRISC4 = 0;
    
    // set up port RC5 as input
    TRISC5 = 1;
    
	// disable analog features on ports RC0, RC1, RC2, and RC3
    ANSC0 = 0;
    ANSC1 = 0;
    ANSC2 = 0;
    ANSC3 = 0;
    
	
    // main loop
    while (1) {
    
        // read out 16 buttons (two bytes)
        CD4021_load();
        v1 = CD4021_read();
        v2 = CD4021_read();
        
		// send out the information
		// (and invert each bit, because of the pullup resistors)
		CD4094_send(~v2);
        CD4094_send(~v1);
        CD4094_load();
		
		// react specifically to SNES buttons
		
		// up
		if ((~v1) & 0b00001000) {
			
		}
		// down
		if ((~v1) & 0b00000100) {
			
		}
		// left
		if ((~v1) & 0b00000010) {
			
		}
		// right
		if ((~v1) & 0b00000001) {
			
		}
		// left shoulder
		if ((~v2) & 0b00100000) {
			
		}
		// right shoulder
		if ((~v2) & 0b00010000) {
			
		}
		// A
		if ((~v2) & 0b10000000) {
			
		}
		// B
		if ((~v1) & 0b10000000) {
			
		}
		// X
		if ((~v2) & 0b01000000) {
			
		}
		// Y
		if ((~v1) & 0b01000000) {
			
		}
		// select
		if ((~v1) & 0b00100000) {
			
		}
		// start
		if ((~v1) & 0b00010000) {
			
		}
		
        
    }
    
    return;
    
}

// This function sends a byte "b" to the CD4094
void CD4094_send (unsigned char b) {

    // send out all eight bits
    for (int i=7; i>=0; i--) {
        CD4094_DAT = (b >> i) & 1;
        CD4094_CLK = 1;
        CD4094_CLK = 0;
    }

}

// This function refreshes the status of all CD4094 outputs
void CD4094_load (void) {
    
    // refresh the status of all CD4094 outputs
    CD4094_STR = 1;
    CD4094_STR = 0;
    
}

// This function reads out a byte "b" from the CD4021
unsigned char CD4021_read (void) {

    // initialize the future return value to 0
    unsigned char b = 0;
    
    // read out all eight bits
    for (int i=7; i>=0; i--) {
        b |= (CD4021_DAT << i);
        CD4021_CLK = 1;
        CD4021_CLK = 0;
    }
    
    // return the byte
    return b;

}

// This function loads the status of all CD4021 inputs
void CD4021_load (void) {
    
    // read the status of all CD4021 inputs
    CD4021_LAT = 1;
    CD4021_LAT = 0;
    
}