#include <stdint.h>
#include <msp430.h>

// ll = 2 sl = 1 ss = 0

// DIP = .2345

// A ON
// 2 2 2 2 1 0 1 1 1 1 1 0 E

// B ON
// 2 2 2 2 1 1 0 1 1 1 1 0 E

// C ON
// 2 2 2 2 1 1 1 0 1 1 1 0 E

// A OFF
// 2 2 2 2 1 0 1 1 1 1 0 1 E

// B OFF
// 2 2 2 2 1 1 0 1 1 1 0 1 E

// DIP TESTS (none 5 4 3 2 1 all)

// none
// 1 1 1 1 1 0 1 1 1 1 1 0 E

// 5
// 2 1 1 1 1 0 1 1 1 1 1 0 E

// 4
// 1 2 1 1 1 0 1 1 1 1 1 0 E

// 1
// 1 1 1 1 1 0 1 1 1 1 1 0 E

// all
// 2 2 2 2 1 0 1 1 1 1 1 0 E

void delay_ms(uint16_t ms) {
    while (ms--)
        __delay_cycles(16 * 1000);
}

#define PULSE (3216)

void short_pulse() {
    P2OUT |= BIT5;
    __delay_cycles(PULSE);
    P2OUT &= ~BIT5;
    __delay_cycles(PULSE * 3);
}

void long_pulse() {
    P2OUT |= BIT5;
    __delay_cycles(PULSE * 3);
    P2OUT &= ~BIT5;
    __delay_cycles(PULSE);    
}

uint16_t debug[5];

void send_rf(uint16_t data, uint8_t bits, uint8_t twos) {
    uint16_t bit;
    for (bit = (1 << (bits - 1)); bit; bit >>= 1) {
        if (!twos)
            short_pulse();

        if (data & bit)
            long_pulse();
        else
            short_pulse();
        
        if (twos)
            long_pulse();
    }
}

void command(uint16_t house, uint16_t unit, uint16_t on) {
    uint16_t times;

    P2OUT |= BIT5;
    __delay_cycles(400);
    
    for (times = 0; times < 8; times++) {
        send_rf(house, 5, 1);
        send_rf(unit, 4, 0);
        send_rf(1, 1, 0);
        send_rf(((on & 1) << 1) | ((~on) & 1), 2, 0);
        short_pulse();

        delay_ms(8);
    }
}

#define SHORT 0
#define LONG 1
#define VERY_LONG 2

int read_button() {
    int i;
    
    while (!(P1IN & BIT3)) ;
    delay_ms(20);
    while (P1IN & BIT3) ;

    delay_ms(20);

    for (i = 0; i < 1000 && !(P1IN & BIT3); i++) {
        if (i == 201)
            P1OUT &= ~(BIT0 | BIT6);

        delay_ms(1);
    }

    if (i < 100)
        return SHORT;
    else if (i < 600)
        return LONG;

    return VERY_LONG;
}

int main() {
    // Disable watchdog
    WDTCTL = WDTPW | WDTHOLD;

    // 16MHz internal timer
    BCSCTL1 = CALBC1_16MHZ;
    DCOCTL = CALDCO_16MHZ;

    // P2 (XOUT/XIN) as GPIO
    P2SEL = 0x00;
    P2DIR |= BIT5;
    
    P1DIR |= BIT0 | BIT6; // LEDs

    P1REN |= BIT3; // pull up switch
    P1OUT |= BIT3;

    uint16_t unit = 0;

    while (1) {
        P1OUT &= ~(BIT0 | BIT6);

        if (unit == 0)
            P1OUT |= BIT0;
        else if (unit == 1)
            P1OUT |= BIT6;
        else
            P1OUT |= (BIT0 | BIT6);

        int press = read_button();

        switch (press) {
            case SHORT:
                unit++;
                if (unit > 2)
                    unit = 0;

                break;
            
            case LONG:
                command(4 | 8, ~(1 << (unit + 1)), 0);
                break;

            case VERY_LONG:
                command(4 | 8, ~(1 << (unit + 1)), 1);
                break;
        }
    }
}
