#include <avr/io.h>
#include <util/delay.h>
#include "morse_pwm.h"

uint8_t _morsetab[] = {     
    /* 1 - no code */
    107, /* ASCII 33 ! */
    82,  /* ASCII 34 " */
    1,   /* ASCII 35 # */
    137, /* ASCII 36 $ */
    1,   /* ASCII 37 % */
    40,  /* ASCII 38 & */
    94,  /* ASCII 39 ' */
    109, /* ASCII 40 ( */
    109, /* ASCII 41 ) */
    1,   /* ASCII 42 * */
    42,  /* ASCII 43 + */
    115, /* ASCII 44 , */
    97,  /* ASCII 45 - */
    85,  /* ASCII 46 . */
    50,  /* ASCII 47 / */
    63,  /* ASCII 48 0 */
    62,  /* ASCII 49 1 */
    60,  /* ASCII 50 2 */
    56,  /* ASCII 51 3 */
    48,  /* ASCII 52 4 */
    32,  /* ASCII 53 5 */
    33,  /* ASCII 54 6 */
    35,  /* ASCII 55 7 */
    39,  /* ASCII 56 8 */
    47,  /* ASCII 57 9 */
    120, /* ASCII 58 : */
    53,  /* ASCII 59 ; */
    1,   /* ASCII 60 < */
    49,  /* ASCII 61 = */
    1,   /* ASCII 62 > */
    76,  /* ASCII 63 ? */
    69,  /* ASCII 64 @ */
    6,   /* ASCII 65 A */
    17,  /* ASCII 66 B */
    21,  /* ASCII 67 C */
    9,   /* ASCII 68 D */
    2,   /* ASCII 69 E */
    20,  /* ASCII 70 F */
    11,  /* ASCII 71 G */
    16,  /* ASCII 72 H */
    4,   /* ASCII 73 I */
    30,  /* ASCII 74 J */
    13,  /* ASCII 75 K */
    18,  /* ASCII 76 L */
    7,   /* ASCII 77 M */
    5,   /* ASCII 78 N */
    15,  /* ASCII 79 O */
    22,  /* ASCII 80 P */
    27,  /* ASCII 81 Q */
    10,  /* ASCII 82 R */
    8,   /* ASCII 83 S */
    3,   /* ASCII 84 T */
    12,  /* ASCII 85 U */
    24,  /* ASCII 86 V */
    14,  /* ASCII 87 W */
    25,  /* ASCII 88 X */
    29,  /* ASCII 89 Y */
    19,  /* ASCII 90 Z */
    1,   /* ASCII 91 [ */
    1,   /* ASCII 92 \ */
    1,   /* ASCII 93 ] */
    1,   /* ASCII 94 ^ */
    77,  /* ASCII 95 _ */
    94,  /* ASCII 96 ` */
};
	
void morse_pwm_init()
{
    /* output for LED  and speaker */
    MORSE_PWM_DDR |= 1<<MORSE_PWM_LED_PIN | 1<<MORSE_PWM_SPK_PIN;

	/* LED and speaker OFF (they sink current) */
	MORSE_PWM_PORT |= 1<<MORSE_PWM_LED_PIN | 1<<MORSE_PWM_SPK_PIN;

	/* timer0 */
	/* We need to generate a 700Hz tone (usual tone for morse transmissions) */
	/* 700Hz 50% square wave chages at 1400Hz, period = 1/1400 = 714 uS */
	/* Using /64 preescaler from 8Mhz we get a precision of 8uS, so 714/8 = 89.25 ~ 89  */
	TCCR0A = 1<<WGM01 | 1<<WGM00; /* Fast PWM, top OCR0A */
	TCCR0B = 1<<WGM02 | 1<<CS01 | 1<<CS00;    /* Preescaler = /64 */
	TCNT0 = 0;	/* counter = 0 */

	OCR0A = 89; /* top value */
}

void morse_pwm_dash()
{
    MORSE_PWM_PORT &= ~(1<<MORSE_PWM_LED_PIN);
	TCCR0A |= 1<<COM0A0;	/* toggles OC0A on compare match */
    _delay_ms(DASHLEN);
    MORSE_PWM_PORT |= 1<<MORSE_PWM_LED_PIN;
	TCCR0A &= ~(1<<COM0A0); /* disconnects OC0A */
    _delay_ms(DOTLEN);
}

void morse_pwm_dit()
{
    MORSE_PWM_PORT &= ~(1<<MORSE_PWM_LED_PIN);
	TCCR0A |= 1<<COM0A0;  /* toggles OC0A on compare match */
    _delay_ms(DOTLEN);
    MORSE_PWM_PORT |= 1<<MORSE_PWM_LED_PIN;
	TCCR0A &= ~(1<<COM0A0); /* disconnects OC0A */
    _delay_ms(DOTLEN);
}


void morse_pwm_sendc(char c)
{
    uint8_t _i;
    uint8_t _p;

    // Send space
    if (c == ' ') {
        _delay_ms(7*DOTLEN) ;
        return;
    }
    // Do a table lookup to get morse data
    else {
        _i = ((uint8_t) c) - 33;
        _p = _morsetab[_i];
    }

    // Main algoritm for each morse sign
    while (_p != 1) {
        if (_p & 1)
            morse_pwm_dash();
        else
            morse_pwm_dit();
    _p = _p / 2;
    }
    // Letterspace
    _delay_ms(3*DOTLEN);
}

void morse_pwm_send(char *msg)
{
    while (*msg)
        morse_pwm_sendc(*msg++);
}

