comments added

This commit is contained in:
King Kévin 2013-10-26 17:31:04 +02:00
parent fc48ec6c2e
commit e4ed9649b5
6 changed files with 90 additions and 67 deletions

View File

@ -37,6 +37,7 @@ void time2nec(uint16_t* burst, uint8_t pulses)
return;
}
if (0==i%2) { /* mark */
/* fine the nearest NEC mark time */
bool found = false;
for (j=0; j<(sizeof(MARKS)/sizeof(uint16_t))-1; j++) {
if (burst[i]>((MARKS[j]+MARKS[j+1])/2)) {
@ -49,6 +50,7 @@ void time2nec(uint16_t* burst, uint8_t pulses)
burst[i] = j;
}
} else { /* space */
/* fine the nearest NEC space time */
bool found = false;
for (j=0; j<(sizeof(SPACES)/sizeof(uint16_t))-1; j++) {
if (burst[i]>((SPACES[j]+SPACES[j+1])/2)) {
@ -83,17 +85,18 @@ struct nec nec2data(uint16_t* burst, uint8_t pulses)
to_return.valid = false;
}
}
/* decode the valid data into address and command */
if (to_return.valid) {
uint8_t address = (data>>24)&0xff;
uint8_t naddress = (data>>16)&0xff;
uint8_t command = (data>>8)&0xff;
uint8_t ncommand = (data>>0)&0xff;
if (0xff==(address^naddress)) {
uint8_t address = (data>>24)&0xff; /* first byte is the address */
uint8_t naddress = (data>>16)&0xff; /* second byte is the inverted address */
uint8_t command = (data>>8)&0xff; /* third byte is the command */
uint8_t ncommand = (data>>0)&0xff; /* fourth byte is the inverted command */
if (0xff==(address^naddress)) { /* check if the data is not corrupted (the address comes also inverted) */
to_return.address = address;
} else {
to_return.valid = false;
}
if (0xff==(command^ncommand)) {
if (0xff==(command^ncommand)) { /* check if the data is not corrupted (the command comes also inverted) */
to_return.command = command;
} else {
to_return.valid = false;

View File

@ -17,9 +17,10 @@
* More information at http://www.sbprojects.com/knowledge/ir/nec.php
*/
extern const uint16_t MARKS[2]; /* mark duration in us [start,bit] */
extern const uint16_t SPACES[4]; /* space duration in us [start,repeat,1,0] */
extern const uint16_t MARKS[2]; /* mark duration in µs [start,bit] */
extern const uint16_t SPACES[4]; /* space duration in µs [start,repeat,1,0] */
/* a decoded NEC IR command */
struct nec {
bool valid;
bool repeat;
@ -27,5 +28,7 @@ struct nec {
uint8_t command;
};
/* convert the pulse from µs into NEC mark and spaces */
void time2nec(uint16_t* burst, uint8_t pulses);
/* decode the NEC mark and space into IR command data */
struct nec nec2data(uint16_t* burst, uint8_t pulses);

View File

@ -85,7 +85,7 @@ 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 */
volatile uint8_t timer2_ovf = 0; /* to measure fan speed through the tachometer using timer 2 */
const 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 */
@ -109,8 +109,8 @@ volatile bool channel_flag = false; /* indicate a change in the channel PWM valu
volatile bool learn_flag = false; /* learn an IR command for an action */
enum IR_ACTIONS to_learn = IR_ACTION_END; /* IR action to learn */
/* UART receive interrupt */
ISR(USART_RX_vect) {
/* save the UART input into a string */
ISR(USART_RX_vect) { /* UART receive interrupt */
input[input_i] = getchar(); /* save input */
input[input_i+1] = 0; /* always end the string */
if (input_i<INPUT_MAX) { /* next character, if space is available */
@ -119,7 +119,10 @@ ISR(USART_RX_vect) {
uart_flag = true; /* set flag */
}
/* power ok interrupt */
/* power ok and IR interrupt
* store the new power start
* save the pulse time
*/
ISR(PCINT0_vect) { /* PCI0 Interrupt Vector for PCINT[7:0] */
if (pwr_ok!=(PINB&(1<<PWR_OK))) { /* did the PWR_OK pin state changed */
pwr_ok = PINB&(1<<PWR_OK); /* save new state */
@ -127,8 +130,8 @@ ISR(PCINT0_vect) { /* PCI0 Interrupt Vector for PCINT[7:0] */
} else if (ir!=(PINB&(1<<IR))) { /* did the IR pin state changed */
ir = PINB&(1<<IR); /* save new state */
if (pulse>0) { /* save pulse, except the first */
burst[pulse-1] = (TCNT1*1000UL)/ir_tick;
burst[pulse] = 0;
burst[pulse-1] = (TCNT1*1000UL)/ir_tick; /* pulse time in µs */
burst[pulse] = 0; /* end the burst with 0 */
}
if (pulse<PULSE_MAX-1) { /* prepare to save next pulse */
pulse++;
@ -153,44 +156,45 @@ ISR(PCINT1_vect) { /* PCI0 Interrupt Vector for PCINT[14:8] */
ISR(TIMER2_OVF_vect) { /* timer 2 overflow interrupt vector */
if (timer2_ovf<0xff) { /* prevent overflow */
timer2_ovf++; /* increase tachometer counter */
} else {
} else { /* timeout for tachometer (the tachometer counter should be reseted before this timeout if the fan is on) */
tachometer = 0; /* indicate no speed can be measured */
if (pwr_ok) { /* warn the fan is dead while the power in on */
power_flag = true;
}
timer2_ovf = 0;
timer2_ovf = 0; /* reset the tachometer counter */
}
}
/* timer 1 interrupt used to timeout IR burst */
/* end of IR burst (using a timeout) */
ISR(TIMER1_COMPA_vect) { /* timer 1 OCR1A match interrupt vector */
if (pulse>0 && !ir_flag) { /* warm an burst is ready when the timeout triggered */
if (pulse>0 && !ir_flag) { /* warm a burst is ready to be processed */
ir_flag = true;
}
}
/* timer 0 interrupt used generate a PWM for the channels */
/* generate a PWM for the channel outputs
* this is a bit long for an interrupt, but it's time critical
*/
ISR(TIMER0_COMPA_vect) { /* timer 0 OCR0A match interrupt vector */
ch_tick++;
if (pwr_ok) {
for (int i=0; i<CHANNELS_1+CHANNELS_2; i++) {
if (on[i]==ch_tick) {
if (on[i]!=off[i]) {
if (pwr_ok) { /* only generate PWM if power is on */
for (int i=0; i<CHANNELS_1+CHANNELS_2; i++) { /* generate PWM for every channel */
if (on[i]==ch_tick) { /* time to switch on */
if (on[i]!=off[i]) { /* switch on */
*(PORTS[i]) |= (1<<BITS[i]);
} else if (brightness[mode][i]==0) {
} else if (brightness[mode][i]==0) { /* switch off if it's also the off time and the brightness is 0 */
*(PORTS[i]) &= ~(1<<BITS[i]);
} else {
} else { /* switch on if it's also the off time and the brightness is full */
*(PORTS[i]) |= (1<<BITS[i]);
}
} else if (off[i]==ch_tick && brightness[mode][i]!=0xff) {
} else if (off[i]==ch_tick && brightness[mode][i]!=0xff) { /* time to switch off */
*(PORTS[i]) &= ~(1<<BITS[i]);
}
}
PIND = (1<<LED);
}
}
/* disable watched when booting */
/* disable watchdog when booting */
void wdt_init(void) __attribute__((naked)) __attribute__((section(".init3")));
void wdt_init(void)
{
@ -283,7 +287,7 @@ void ioinit(void)
void help(void)
{
char* str;
for (uint8_t i=0; i<sizeof(help_table)/sizeof(PGM_P); i++) {
for (uint8_t i=0; i<sizeof(help_table)/sizeof(PGM_P); i++) { /* display all help lines */
str = malloc(strlen_PF((uint_farptr_t)pgm_read_word(&(help_table[i]))));
strcpy_PF(str, (uint_farptr_t)pgm_read_word(&(help_table[i])));
printf(str);
@ -296,7 +300,8 @@ int main(void)
ioinit(); /* initialize IOs */
uint8_t command_i = 0; /* command index */
struct nec ir_data; /* last IR data */
/* last IR data */
struct nec ir_data;
ir_data.valid = false;
ir_data.repeat = false;
ir_data.address = 0;
@ -326,10 +331,12 @@ int main(void)
} else {
PORTB |= (1<<nPS_ON);
}
PIND |= ~(1<<LED); /* switch on LED */
while (true) {
/* calculated PWM values */
/* calculated PWM values (on/off times) */
while (channel_flag) {
/* the next channel goes on/starts when the previous goes off, so to distribute the power over the whole range, instead of only using a lot of it in the beginning */
uint8_t start = 0;
for (uint8_t i=0; i<CHANNELS_1+CHANNELS_2; i++) {
on[i] = start;
@ -340,24 +347,28 @@ int main(void)
}
/* handle UART input */
while (uart_flag) {
PIND &= (1<<LED); /* switch off LED */
/* echo back */
char c = 0;
while (command_i<input_i) {
c = input[command_i++];
putchar(c);
}
/* detect end of line */
if ('\n'==c || '\r'==c) {
if ('\r'==c) {
if ('\r'==c) { /* display new line */
puts("");
}
/* process user command */
if (command_i>1) {
input[command_i-1] = '\0';
uart_action(input);
save_settings();
}
input_i = command_i = 0;
input_i = command_i = 0; /* reset input buffer */
}
uart_flag = false;
PIND |= ~(1<<LED); /* switch on LED */
}
/* handle power state */
while (power_flag) {
@ -383,6 +394,7 @@ int main(void)
}
/* handle IR input */
while (ir_flag) {
PIND &= (1<<LED); /* switch off LED */
time2nec(burst,pulse-1); /* convert raw time burst in NEC format */
struct nec ir_tmp = nec2data(burst,pulse-1); /* decode NEC burst */
if (ir_tmp.valid) {
@ -394,8 +406,8 @@ int main(void)
ir_data = ir_tmp;
ir_repeat = 0;
}
if (ir_repeat==0 || ir_repeat>3) {
if (learn_flag) {
if (ir_repeat==0 || ir_repeat>3) { /* process command if new or repeated */
if (learn_flag) { /* learn command */
if (to_learn<IR_ACTION_END) {
ir_keys[to_learn][0] = ir_data.address;
ir_keys[to_learn][1] = ir_data.command;
@ -403,7 +415,7 @@ int main(void)
puts("IR code learned");
to_learn = IR_ACTION_END;
learn_flag = false;
} else {
} else { /* trigger action */
ir_action(ir_data.address,ir_data.command);
}
save_settings();
@ -411,6 +423,7 @@ int main(void)
}
pulse = 0; /* reset burst */
ir_flag = false;
PIND |= ~(1<<LED); /* switch on LED */
}
}
return 0;
@ -418,11 +431,13 @@ int main(void)
void uart_action(char* str)
{
/* split command */
const char* delimiter = " ";
char* word = strtok(str,delimiter);
if (!word) {
goto error;
}
/* parse command */
if (0==strcmp(word,"help")) {
help();
} else if (0==strcmp(word,"reset")) {
@ -463,12 +478,6 @@ void uart_action(char* str)
} else {
printf("fan is off (or not detected)\n");
}
reset_settings();
/* reset using watchdog */
do {
wdt_enable(WDTO_15MS);
for(;;) {}
} while(0);
} else if (0==strcmp(word,"mode")) {
word = strtok(NULL,delimiter);
if (!word) {
@ -597,13 +606,13 @@ void ir_action(uint8_t address, uint8_t command)
{
enum IR_ACTIONS ir_code = IR_ACTION_END;
static uint8_t channel = CHANNELS_1+CHANNELS_2;
uint8_t step = 0xff/LEVELS;
for (ir_code=0; ir_code<IR_ACTION_END; ir_code++) {
uint8_t step = 0xff/LEVELS; /* the brightness increase/decrease steps */
for (ir_code=0; ir_code<IR_ACTION_END; ir_code++) { /* find the action for the current command */
if (ir_keys[ir_code][0]==address && ir_keys[ir_code][1]==command) {
break;
}
}
if (ir_code<IR_ACTION_END) {
if (ir_code<IR_ACTION_END) { /* process action */
switch (ir_code) {
case POWER:
printf("switching power supply ");
@ -627,7 +636,7 @@ void ir_action(uint8_t address, uint8_t command)
brightness[mode][channel] = 0xff;
}
printf("increasing brightness ch %u %u: %u\n",(channel/CHANNELS_1)+1,(channel%CHANNELS_1)+1,brightness[mode][channel]);
} else if (channel==CHANNELS_1+CHANNELS_2) {
} else if (channel==CHANNELS_1+CHANNELS_2) { /* increase all brightness if no channel is selected */
for (uint8_t i=0; i<CHANNELS_1+CHANNELS_2; i++) {
if (brightness[mode][i]<0xff-step) {
brightness[mode][i] += step;
@ -647,7 +656,7 @@ void ir_action(uint8_t address, uint8_t command)
brightness[mode][channel] = 0x00;
}
printf("decreasing brightness ch %u %u: %u\n",(channel/CHANNELS_1)+1,(channel%CHANNELS_1)+1,brightness[mode][channel]);
} else if (channel==CHANNELS_1+CHANNELS_2) {
} else if (channel==CHANNELS_1+CHANNELS_2) { /* decrease all brightness if no channel is selected */
for (uint8_t i=0; i<CHANNELS_1+CHANNELS_2; i++) {
if (brightness[mode][i]>step) {
brightness[mode][i] -= step;
@ -680,6 +689,6 @@ void ir_action(uint8_t address, uint8_t command)
break;
}
} else {
puts("IR command not learned");
puts("unknown IR command");
}
}

View File

@ -32,7 +32,11 @@ extern volatile uint8_t* PORTS[CHANNELS_1+CHANNELS_2]; /* channel ports */
extern volatile uint8_t* DDRS[CHANNELS_1+CHANNELS_2]; /* channel I/O configuration registers */
extern const uint8_t BITS[CHANNELS_1+CHANNELS_2]; /* channel bits */
/* initialize I/O, timers, … */
void ioinit(void);
/* display the help */
void help(void);
/* process user command coming from UART */
void uart_action(char* str);
/* process user command coming from IR */
void ir_action(uint8_t address, uint8_t command);

View File

@ -6,27 +6,28 @@
#include "main.h"
#include "settings.h"
/* initialize variable */
/* initialize variables */
uint8_t power;
uint8_t mode;
uint8_t brightness[MODES][CHANNELS_1+CHANNELS_2];
uint8_t ir_keys[IR_ACTION_END][2];
const uint8_t MAGIC = 0x42; // magic header
const uint8_t MAGIC = 0x42; /* magic header */
bool verify_settings(void)
{
bool to_return;
uint8_t checksum = 0;
uint8_t byte;
uint16_t settings_size = sizeof(MAGIC)+sizeof(power)+sizeof(mode)+sizeof(brightness)+sizeof(ir_keys)+1; // the byte used for the checksum (magic header and checksum included)
for (uint16_t i=0; i<settings_size; i++) {
uint16_t settings_size = sizeof(MAGIC)+sizeof(power)+sizeof(mode)+sizeof(brightness)+sizeof(ir_keys)+1; /* the bytes used for the checksum (magic header and checksum included) */
for (uint16_t i=0; i<settings_size; i++) { /* calculate checksum */
byte = eeprom_read_byte((const uint8_t*)i);
if (0==i && byte!=MAGIC) {
if (0==i && byte!=MAGIC) { /* verify magic header first */
return false;
}
checksum ^= byte;
}
/* verify checkecum */
if (0==checksum) {
to_return = true;
} else {
@ -37,14 +38,14 @@ bool verify_settings(void)
void initialize_settings(void)
{
power = 0;
mode = 0;
for (uint8_t i=0; i<MODES; i++) {
power = 0; /* power is off */
mode = 0; /* first mode used */
for (uint8_t i=0; i<MODES; i++) { /* channel brightness set to 0 */
for (uint8_t j=0; j<CHANNELS_1+CHANNELS_2; j++) {
brightness[i][j] = 0;
}
}
for (uint8_t i=0; i<IR_ACTION_END; i++) {
for (uint8_t i=0; i<IR_ACTION_END; i++) { /* codes for IR actions set to 0 */
ir_keys[i][0] = 0;
ir_keys[i][1] = 0;
}
@ -52,8 +53,8 @@ void initialize_settings(void)
void save_settings(void)
{
uint16_t addr = 0; // the address in the EEPROM
uint8_t checksum = 0;
uint16_t addr = 0; /* address in the EEPROM */
uint8_t checksum = 0; /* checksum of settings (including the magic header, else all 0 settings are calculated as valid) */
eeprom_update_byte((uint8_t*)addr,MAGIC);
checksum ^= MAGIC;
addr++;
@ -83,7 +84,7 @@ void save_settings(void)
void load_settings(void)
{
uint16_t addr = 1; // the address in the EEPROM (skip magic header)
uint16_t addr = 1; /* the address in the EEPROM (skip magic header) */
power = eeprom_read_byte((uint8_t*)addr);
addr++;
mode = eeprom_read_byte((uint8_t*)addr);
@ -104,6 +105,5 @@ void load_settings(void)
void reset_settings(void)
{
/* invalidate magic header */
eeprom_update_byte((uint8_t*)0,0);
eeprom_update_byte((uint8_t*)0,0); /* invalidate magic header so the verification fails */
}

View File

@ -4,8 +4,8 @@ extern uint8_t power; /* power state */
extern uint8_t mode; /* the current mode */
extern uint8_t brightness[MODES][CHANNELS_1+CHANNELS_2]; /* the mode brightness settings for the channels */
/* IR settings */
enum IR_ACTIONS { /* the actions for the infrared remote control */
/* IR settings actions from the infrared remote control */
enum IR_ACTIONS {
POWER = 0,
MODE,
BRIGHTNESS_UP,
@ -14,11 +14,15 @@ enum IR_ACTIONS { /* the actions for the infrared remote control */
CHANNEL_PREVIOUS,
IR_ACTION_END
};
extern uint8_t ir_keys[IR_ACTION_END][2]; // the IR NEC values (address+command) for the actions
extern uint8_t ir_keys[IR_ACTION_END][2]; /* the IR NEC values (address+command) for the actions */
/* function to load/save the settings */
/* verify integrity of the settings */
bool verify_settings(void);
/* create settings */
void initialize_settings(void);
/* save current settings into EEPROM */
void save_settings(void);
/* load settings from EEPROM */
void load_settings(void);
/* invalidate settings in EEPROM */
void reset_settings(void);