/* pilot1.c
 * Ford SWC to Kenwood radio (NEC protocol) adapter
 * Author: Michal Babik <michalb1981@o2.pl>
 */

// Steering wheel remote resistances with a half values to use
// in adc as a compare values
//
// REMOTE KEY   RESISTANCE  ADC VAL     KEY VAL
// NC           5040.0      198         0
//                          152
// SEL          1050.0      106         1
//                          88
// SEEK -       562.0       70          2
//                          56.5
// SEEK +       301.0       43          3
//                          33
// VOL +        147.8       23          4
//                          16
// VOL -        54.4        8           5
//                          4
#define F_CPU 1000000UL

#include <avr/io.h> 
#include <util/delay.h> 
#include <inttypes.h> 

#define sbi(x,y) x |= _BV(y) //set bit - using bitwise OR operator
#define cbi(x,y) x &= ~(_BV(y)) //clear bit - using bitwise AND operator
#define tbi(x,y) x ^= _BV(y) //toggle bit - using bitwise XOR operator
#define is_high(x,y) (x & _BV(y) == _BV(y)) //check if the y'th bit of
//register 'x' is high ... test if its AND with 1 is 1
/* _BV(a) is a macro which returns the value corresponding to 2 to the 
 * power 'a'. Thus _BV(PX3) would be 0x08 or 0b00001000 */

#define NEC_TIME 562.5f // base time in us
#define NEC_LINE_HI 1   // pin value to set line high
#define NEC_LINE_LO 0   // pin value to set line low
#define NEC_PORT PORTB  // kenwood radio remote pin port
#define NEC_PIN PB1     // kenwood radio remote pin
#define NEC_DDR DDRB    // kenwood radio remote direction

#define ADC_SAMPLES 50   // number of samples to read pressed key

// ----------------------------------------------------------------------------

uint8_t adc_read (void);
uint8_t check_pressed_adc_value (uint8_t adc_v);
void couple_more_samples (uint8_t *k_pressed);
void nec_set_pin (uint8_t hilo);
void nec_base (uint8_t hm, uint8_t lm);
void nec_start (void);
void nec_finish (void);
void nec_one (void);
void nec_zero (void);
void nec_8bit (uint8_t *bits);
void nec_data (uint8_t addr, uint8_t dta);

// ----------------------------------------------------------------------------
int
main (void)
{
    /*
    uint8_t k_codes[] = {0x00,    // 0
                         0x01,    // 1
                         0x02,    // 2
                         0x03,    // 3
                         0x04,    // 4
                         0x05,    // 5
                         0x06,    // 6
                         0x07,    // 7
                         0x08,    // 8
                         0x09,    // 9
                         0x0a,    // track -
                         0x0b,    // track +
                         0x0c,    // rev
                         0x0d,    // ff
                         0x0e,    // play / pause
                         0x13,    // source
                         0x14,    // volume +
                         0x15,    // volume -
                         0x16,    // mute
                         0x1c,    // tuner
                         0x1d,    // tape
                         0x1e,    // cd
                         0x1f,    // cd-md-ch
                         0x5e     // dnpp
                         };
    */

    uint8_t ken_code     = 0xb9;
    uint8_t key_codes[]  = {0x00, 0x13, 0x0a, 0x0b, 0x14, 0x15};
    uint8_t key_pressed  = 0;
    uint8_t prev_pressed = 0;

    NEC_DDR = _BV (NEC_PIN); // Communication pin as output
    cbi (NEC_PORT, NEC_PIN); // set nec pin low

    ADMUX= (1 << REFS0) | (1 << ADLAR);  //AVCC, left align
    // only 8 highest adc bits will be used, no need for a 10 bit precision

    //ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);  //ad enable, prescaler 128 (7.8kHz)
    //ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS0);  //ad enable, prescaler 32 (31.25kHz)
    ADCSRA= (1 << ADEN) | (1 << ADPS2);  //ad enable, prescaler 16 (62.5kHz)
    //ADCSRA=(1<<ADEN)|(1<<ADPS1)|(1<<ADPS0);  //ad enable, prescaler 8 (125kHz)

	while (1) { // Infinite loop
        key_pressed = check_pressed_adc_value (adc_read ());
        if (key_pressed != prev_pressed) {
            if ((key_pressed > 0) && (prev_pressed == 0)) {
                couple_more_samples (&key_pressed);
                nec_start ();
                nec_data (ken_code, key_codes[key_pressed]);
                nec_finish ();
            }
            prev_pressed = key_pressed;
        }
	}
	return 0;
}
// ----------------------------------------------------------------------------
uint8_t
adc_read (void)
{
    //Start Single conversion
    ADCSRA |= (1 << ADSC);
    //Wait for conversion to complete
    while (!(ADCSRA & (1 << ADIF)));
    //Clear ADIF by writing one to it
    ADCSRA |= (1 << ADIF);
    return ADCH; // only 8 highest bits
}
// ----------------------------------------------------------------------------
uint8_t
check_pressed_adc_value (uint8_t adc_v)
{
    uint8_t key_val = 0; // nothing (0)
    if (adc_v < 152) {
        key_val++; // SEL (1)
        if (adc_v < 88) {
            key_val++; // SEEK - (2)
            if (adc_v < 57) {
                key_val++; // SEEK + (3)
                if (adc_v < 33) {
                    key_val++; // VOL + (4)
                    if (adc_v < 16 && adc_v > 4) {
                        key_val++; // VOL - (5)
                    }
                }
            }
        }
    }
    return key_val;
}
// ----------------------------------------------------------------------------
void
couple_more_samples (uint8_t *k_pressed)
{
    // take couple more samples and create a small histogram of
    // of values, find which key has most counts
    uint8_t key_rep[] = {0, 0, 0, 0, 0, 0};
    key_rep[*k_pressed]++;
    for (uint8_t i=0; i<ADC_SAMPLES; ++i) {
        key_rep[check_pressed_adc_value (adc_read ())]++;
    }
    uint8_t max_v = 0;
    for (uint8_t j=1; j<6; ++j) {
        if (key_rep[j] > max_v) {
            max_v = key_rep[j];
            *k_pressed = j;
        }
    }
}
// ----------------------------------------------------------------------------
void
nec_set_pin (uint8_t hilo)
{
    if (hilo) sbi (NEC_PORT, NEC_PIN); // set high
    else      cbi (NEC_PORT, NEC_PIN); // set low
}
// ----------------------------------------------------------------------------
void
nec_base (uint8_t hm,
          uint8_t lm)
{
    nec_set_pin (NEC_LINE_HI);
    for (uint8_t i=0; i<hm; ++i) 
        _delay_us (NEC_TIME);
    nec_set_pin (NEC_LINE_LO);
    for (uint8_t i=0; i<lm; ++i) 
        _delay_us (NEC_TIME);
}
// ----------------------------------------------------------------------------
void
nec_start (void)
{
    nec_base (16, 8); // 9ms - 1, 4.5ms - 0
}
// ----------------------------------------------------------------------------
void
nec_finish (void)
{
    nec_base (1, 0); // 562.5us - 1, 0 - 0
}
// ----------------------------------------------------------------------------
void
nec_one (void)
{
    nec_base (1, 3); // 562.5us - 1, 1.6875us - 0
}
// ----------------------------------------------------------------------------
void
nec_zero (void)
{
    nec_base (1, 1); // 562.5us - 1, 562.5us - 0
}
// ----------------------------------------------------------------------------
void
nec_8bit (uint8_t *bits)
{
    for (uint8_t i=0; i<8; ++i) {
        if (*bits & 0x01)
            nec_one ();
        else
            nec_zero ();
        *bits = *bits >> 1;
    }
}
// ----------------------------------------------------------------------------
void
nec_data (uint8_t addr,
          uint8_t dta)
{
    uint8_t naddr = ~addr;
    uint8_t ndta  = ~dta;
    nec_8bit (&addr);
    nec_8bit (&naddr);
    nec_8bit (&dta);
    nec_8bit (&ndta);
}
// ----------------------------------------------------------------------------

