/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
/* This is the main part of the LED light controller program.
* It handles all peripherals (power, fan, channels, IR, serial)
*/
/* This program is specifically designed for hardware version A,
* with schematic revision 2, and layout revision 5.
*/
#include /* Standard Integer Types */
#include /* Standard IO facilities */
#include /* General utilities */
#include /* Boolean */
#include /* Strings */
#include /* AVR device-specific IO definitions */
#include /* Convenience functions for busy-wait delay loops */
#include /* Interrupts */
#include "main.h"
#include "uart.h"
#include "ir_nec.h"
/* global variables */
#define INPUT_MAX 255 /* max length for user input string */
char input[INPUT_MAX+2]; /* user input from USART */
volatile uint8_t input_i = 0; /* user input index */
volatile uint8_t pwr_ok; /* is power ok */
volatile uint8_t fan; /* fan signal state, to measure tachometer */
volatile uint8_t timer2_ovf = 0; /* to measure fan speed using timer 2 */
uint16_t TIMER2_PRESCALE[8] = {0,1,8,32,64,128,256,1024}; /* timer 2 CS2[2:0] values */
volatile uint16_t tachometer = 0; /* the tachometer time (from timer) */
volatile uint8_t ir; /* IR signal state, to measure IR code */
uint16_t TIMER1_PRESCALE[8] = {0,1,8,64,256,1024,0,0}; /* timer 1 CS1[2:0] values */
volatile uint16_t ir_tick; /* number of counter ticks per millisecond */
volatile uint8_t pulse = 0; /* pulse index within the burst */
#define PULSE_MAX 128 /* maximum number of pulses to save */
uint16_t burst[PULSE_MAX]; /* pulse times forming a burst (from timer) */
/* channel variables */
#define LEVELS 10 /* the number of PWM levels */
uint8_t ch_tick = 0; /* the tick counter for the channel PWM */
#define OUTPUTS_1 5 /* the number of outputs for channel 1 */
#define OUTPUTS_2 5 /* the number of outputs for channel 2 */
volatile uint8_t* PORTS_1[OUTPUTS_1] = {&PORTC,&PORTC,&PORTC,&PORTC,&PORTC}; /* channel 1 output ports */
volatile uint8_t* PORTS_2[OUTPUTS_2] = {&PORTD,&PORTD,&PORTD,&PORTD,&PORTD}; /* channel 2 output ports */
uint8_t BITS_1[OUTPUTS_1] = {PC0,PC1,PC2,PC3,PC4}; /* channel 1 output bits */
uint8_t BITS_2[OUTPUTS_2] = {PD2,PD3,PD4,PD5,PD7}; /* channel 2 output bits */
uint8_t ch_1[OUTPUTS_1]; /* the level value for the channel 1 outputs */
uint8_t ch_2[OUTPUTS_2]; /* the level value for the channel 2 outputs */
/* flags, set in the interrupts and handled in the main program */
volatile bool uart_flag = false; /* an incoming activity on the UART */
volatile bool power_flag = false; /* a change in the power or fan */
volatile bool ir_flag = false; /* to process a burst */
volatile bool pwm_flag = false; /* to trigger a PWM tick */
volatile bool channel_flag = false; /* indicate a change in the channel PWM values */
/* UART receive interrupt */
ISR(USART_RX_vect) {
input[input_i] = getchar(); /* save input */
input[input_i+1] = 0; /* always end the string */
if (input_i0) { /* save pulse, except the first */
burst[pulse-1] = (TCNT1*1000UL)/ir_tick;
burst[pulse] = 0;
}
if (pulse0 && !ir_flag) { /* warm an burst is ready when the timeout triggered */
ir_flag = true;
}
}
/* timer 0 interrupt used generate a PWM for the channels */
ISR(TIMER0_COMPA_vect) { /* timer 0 OCR0A match interrupt vector */
ch_tick = (ch_tick+1)%LEVELS;
pwm_flag = true;
}
static void ioinit(void)
{
/* configure power */
DDRB |= (1<>CS10]; /* timer 1 presacler */
if (0!=prescale) {
ir_tick = F_CPU/(1000*prescale); /* ticks per ms */
OCR1A = (uint32_t)(15*F_CPU)/(1000*prescale); /* set clear time to 15 ms (no IR toggle should be longer) */
}
TIFR1 &= ~(1<3) {
ir_action(ir_data.address,ir_data.command);
}
}
pulse = 0; /* reset burst */
ir_flag = false;
}
}
return 0;
}
static void uart_action(char c)
{
switch (c) {
case 'l':
PIND |= (1<0) {
OCR0A--;
}
printf("decreasing LED: %u\n",OCR0A);
break;
case '+':
if (OCR0A<0xff) {
OCR0A++;
}
printf("increasing LED: %u\n",OCR0A);
break;
case 't':
if (tachometer) {
uint16_t prescale = TIMER2_PRESCALE[TCCR2B&((1<