From fad43aa28bdf319d346c4d6ca1dd4b6971267eca Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 3 Jan 2012 01:50:41 +0100 Subject: Bring some structure to this whole mess --- Makefile | 4 +- command.c | 84 ++++++++++++++++++++++++++++ moodlamp.c | 183 ++----------------------------------------------------------- pwm.c | 60 ++++++++++++++++++++ pwm.h | 26 +++++++++ serial.c | 96 ++++++++++++++++++++++++++++++++ serial.h | 30 ++++++++++ util.c | 50 +++++++++++++++++ util.h | 27 +++++++++ 9 files changed, 382 insertions(+), 178 deletions(-) create mode 100644 command.c create mode 100644 pwm.c create mode 100644 pwm.h create mode 100644 serial.c create mode 100644 serial.h create mode 100644 util.c create mode 100644 util.h diff --git a/Makefile b/Makefile index b2eb01c..00c8f33 100644 --- a/Makefile +++ b/Makefile @@ -83,7 +83,7 @@ OBJDIR = . # List C source files here. (C dependencies are automatically generated.) -SRC = $(TARGET).c +SRC = $(wildcard *.c) # List C++ source files here. (C dependencies are automatically generated.) @@ -154,6 +154,8 @@ CFLAGS += -fpack-struct CFLAGS += -fshort-enums CFLAGS += -Wall CFLAGS += -Wstrict-prototypes +CFLAGS += -Werror +CFLAGS += -pedantic #CFLAGS += -mshort-calls #CFLAGS += -fno-unit-at-a-time #CFLAGS += -Wundef diff --git a/command.c b/command.c new file mode 100644 index 0000000..91489e6 --- /dev/null +++ b/command.c @@ -0,0 +1,84 @@ +/* + * Copyright 2012 (C) Christian Franke + * + * 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 . + * + */ + +#include +#include +#include + +#include "pwm.h" +#include "serial.h" +#include "util.h" + +static void command_error(void) +{ + serial_send("?\r\n", 3, 1); +} + +static void command_success(void) +{ + serial_send(":)\r\n", 4, 0); +} + +static void handle_immediate(char *buffer, uint16_t len) +{ + if (len < sizeof("irrggbb\r") - 1) { + command_error(); + return; + } + + uint8_t new_red, new_blue, new_green; + + if (parse_hex_number(&buffer[1], &new_red) + || parse_hex_number(&buffer[3], &new_green) + || parse_hex_number(&buffer[5], &new_blue)) { + command_error(); + return; + } + + pwm_set_rgb(new_red, new_green, new_blue); + command_success(); +} + +uint16_t serial_rx_cb(char *buffer, uint16_t len) +{ + switch (buffer[len - 1]) { + case '\r': + case '\n': + serial_send("\r\n", 2, 0); + break; + default: + serial_send(&buffer[len - 1], 1, 0); + return 0; + } + + switch (buffer[0]) { + case 'i': + case 'I': + handle_immediate(buffer, len); + break; + case 'q': + case 'Q': + serial_toggle_verbose(); + command_success(); + break; + default: + command_error(); + } + + return len; +} diff --git a/moodlamp.c b/moodlamp.c index 9d3f312..2cdd5b5 100644 --- a/moodlamp.c +++ b/moodlamp.c @@ -18,186 +18,15 @@ #include #include -#include -#include -char output_buffer[512]; -uint16_t output_offset = 0; -uint16_t output_end = 0; - -char input_buffer[512]; -uint16_t input_end = 0; - -volatile uint16_t value_red = 3072; -volatile uint16_t value_green = 2048; -volatile uint16_t value_blue = 1024; - -uint8_t verbose = 0; - -static void send(const char *buffer, uint16_t len) -{ - cli(); - - if (sizeof(output_buffer) - output_end < len) { - memmove(output_buffer, output_buffer + output_offset, output_end - - output_offset); - output_end -= output_offset; - output_offset = 0; - } - - uint16_t size = len; - - if (size > sizeof(output_buffer) - output_end) - size = sizeof(output_buffer) - output_end; - - memcpy(&output_buffer[output_end], buffer, size); - - uint8_t send_needed = output_end == output_offset; - - output_end += size; - sei(); - - if (send_needed) { - output_offset++; - UDR1 = output_buffer[output_offset - 1]; - } -} - -ISR(USART1_TX_vect) -{ - if (output_end == output_offset) - return; - - UDR1 = output_buffer[output_offset]; - output_offset++; -} - -static void send_confusion(void) -{ - send("?\r\n", 3); -} - -static void send_success(void) -{ - if (verbose) { - send(":)\r\n", 4); - } -} - -static uint8_t parse_hex(char *buffer, uint8_t *target) -{ - if (buffer[0] >= '0' && buffer[0] <= '9') { - *target = 16 * (buffer[0] - '0'); - } else if (buffer[0] >= 'A' && buffer[0] <= 'F') { - *target = 16 * (buffer[0] - 'A' + 10); - } else if (buffer[0] >= 'a' && buffer[0] <= 'f') { - *target = 16 * (buffer[0] - 'a' + 10); - } else { - return 1; - } - - if (buffer[1] >= '0' && buffer[1] <= '9') { - *target += buffer[1] - '0'; - } else if (buffer[1] >= 'A' && buffer[1] <= 'F') { - *target += buffer[1] - 'A' + 10; - } else if (buffer[1] >= 'a' && buffer[1] <= 'f') { - *target += buffer[1] - 'a' + 10; - } else { - return 1; - } - - return 0; -} - -static void handle_immediate(void) -{ - if (input_end < sizeof("irrggbb\r") - 1) { - send_confusion(); - return; - } - - uint8_t new_red, new_blue, new_green; - - if (parse_hex(&input_buffer[1], &new_red) - || parse_hex(&input_buffer[3], &new_green) - || parse_hex(&input_buffer[5], &new_blue)) { - send_confusion(); - return; - } - - value_red = (uint16_t)new_red << 4; - value_green = (uint16_t)new_green << 4; - value_blue = (uint16_t)new_blue << 4; - send_success(); -} - -static void parse_buffer(void) -{ - switch (input_buffer[input_end - 1]) { - case '\r': - case '\n': - if (verbose) - send("\r\n", 2); - break; - default: - if (verbose) - send(input_buffer + input_end - 1, 1); - return; - } - - switch (input_buffer[0]) { - case 'i': - case 'I': - handle_immediate(); - break; - case 'q': - case 'Q': - verbose = 1 - verbose; - send_success(); - break; - default: - send_confusion(); - } - - input_end = 0; -} - -ISR(USART1_RX_vect) -{ - if (input_end == sizeof(input_buffer)) - input_end = 0; - - input_buffer[input_end++] = UDR1; - parse_buffer(); -} +#include "serial.h" +#include "pwm.h" int main(void) { - UBRR1 = 4; /* Set baud rate to 230400 */ - UCSR1A = 0x00; - UCSR1B = (1 << RXCIE1) | (1 << TXCIE1) | (1 << RXEN1) | (1 << TXEN1); - UCSR1C = (1 << UCSZ11) | (1 << UCSZ10); - - sei(); /* Enable interrupts */ + serial_init(); + pwm_init(); - PORTA = 0x00; - DDRA = (1 << PA0) | (1 << PA1) | (1 << PA2); - - for (;;) { - if (value_red) - PORTA |= (1 << PA0); - if (value_green) - PORTA |= (1 << PA1); - if (value_blue) - PORTA |= (1 << PA2); - - for (uint16_t i = 0; i < 4096; i++) { - if (value_red < i) - PORTA &= ~(1 << PA0); - if (value_green < i) - PORTA &= ~(1 << PA1); - if (value_blue < i) - PORTA &= ~(1 << PA2); - } - } + sei(); + pwm_worker_loop(); } diff --git a/pwm.c b/pwm.c new file mode 100644 index 0000000..e981e2d --- /dev/null +++ b/pwm.c @@ -0,0 +1,60 @@ +/* + * Copyright 2012 (C) Christian Franke + * + * 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 . + * + */ + +#include +#include +#include +#include + +volatile uint16_t value_red = 3072; +volatile uint16_t value_green = 2048; +volatile uint16_t value_blue = 1024; + +void pwm_set_rgb(uint8_t r, uint8_t g, uint8_t b) +{ + value_red = r << 4; + value_green = g << 4; + value_blue = b << 4; +} + +void pwm_worker_loop(void) +{ + for (;;) { + if (value_red) + PORTA |= (1 << PA0); + if (value_green) + PORTA |= (1 << PA1); + if (value_blue) + PORTA |= (1 << PA2); + + for (uint16_t i = 0; i < 4096; i++) { + if (value_red < i) + PORTA &= ~(1 << PA0); + if (value_green < i) + PORTA &= ~(1 << PA1); + if (value_blue < i) + PORTA &= ~(1 << PA2); + } + } +} + +void pwm_init(void) +{ + PORTA = 0x00; + DDRA = (1 << PA0) | (1 << PA1) | (1 << PA2); +} diff --git a/pwm.h b/pwm.h new file mode 100644 index 0000000..fd479e8 --- /dev/null +++ b/pwm.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 (C) Christian Franke + * + * 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 . + * + */ + +#ifndef PWM_H +#define PWM_H + +void pwm_set_rgb(uint8_t r, uint8_t g, uint8_t b); +void pwm_worker_loop(void); +void pwm_init(void); + +#endif diff --git a/serial.c b/serial.c new file mode 100644 index 0000000..d5ec5aa --- /dev/null +++ b/serial.c @@ -0,0 +1,96 @@ +/* + * Copyright 2012 (C) Christian Franke + * + * 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 . + * + */ + +#include +#include +#include +#include + +#include "serial.h" + +static char output_buffer[512]; +static uint16_t output_offset = 0; +static uint16_t output_end = 0; + +static char input_buffer[512]; +static uint16_t input_end = 0; + +static uint8_t verbose = 0; + +void serial_send(const char *buffer, uint16_t len, uint8_t urgent) +{ + if (!urgent && !verbose) + return; + + cli(); + + if (sizeof(output_buffer) - output_end < len) { + memmove(output_buffer, output_buffer + output_offset, output_end - + output_offset); + output_end -= output_offset; + output_offset = 0; + } + + uint16_t size = len; + + if (size > sizeof(output_buffer) - output_end) + size = sizeof(output_buffer) - output_end; + + memcpy(&output_buffer[output_end], buffer, size); + + uint8_t send_needed = output_end == output_offset; + + output_end += size; + sei(); + + if (send_needed) { + output_offset++; + UDR1 = output_buffer[output_offset - 1]; + } +} + +ISR(USART1_TX_vect) +{ + if (output_end == output_offset) + return; + + UDR1 = output_buffer[output_offset]; + output_offset++; +} + +ISR(USART1_RX_vect) +{ + if (input_end == sizeof(input_buffer)) + input_end = 0; + + input_buffer[input_end++] = UDR1; + input_end -= serial_rx_cb(input_buffer, input_end); +} + +void serial_toggle_verbose(void) +{ + verbose = 1 - verbose; +} + +void serial_init(void) +{ + UBRR1 = 4; /* Set baud rate to 230400 */ + UCSR1A = 0x00; + UCSR1B = (1 << RXCIE1) | (1 << TXCIE1) | (1 << RXEN1) | (1 << TXEN1); + UCSR1C = (1 << UCSZ11) | (1 << UCSZ10); +} diff --git a/serial.h b/serial.h new file mode 100644 index 0000000..5f6d7b6 --- /dev/null +++ b/serial.h @@ -0,0 +1,30 @@ +/* + * Copyright 2012 (C) Christian Franke + * + * 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 . + * + */ +#ifndef SERIAL_H +#define SERIAL_H + +#include + +extern uint16_t serial_rx_cb(char *buffer, uint16_t len); + +void serial_send(const char *buffer, uint16_t len, uint8_t urgent); +void serial_toggle_verbose(void); +void serial_init(void); + +#endif + diff --git a/util.c b/util.c new file mode 100644 index 0000000..8ab720f --- /dev/null +++ b/util.c @@ -0,0 +1,50 @@ +/* + * Copyright 2012 (C) Christian Franke + * + * 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 . + * + */ + +#include "util.h" + +uint8_t parse_hex_char(char input) +{ + if (input >= '0' && input <= '9') + return input - '0'; + + if (input >= 'A' && input <= 'F') + return 10 + input - 'A'; + + if (input >= 'a' && input <= 'f') + return 10 + input - 'a'; + + return -1; +} + +uint8_t parse_hex_number(char *buffer, uint8_t *target) +{ + uint8_t rv; + + rv = parse_hex_char(buffer[0]); + if (rv == -1) + return 1; + *target = rv << 4; + + rv = parse_hex_char(buffer[1]); + if (rv == -1) + return 1; + *target += rv; + + return 0; +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..5438075 --- /dev/null +++ b/util.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012 (C) Christian Franke + * + * 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 . + * + */ + +#ifndef UTIL_H +#define UTIL_H + +#include + +uint8_t parse_hex_char(char input); +uint8_t parse_hex_number(char *buffer, uint8_t *target); + +#endif -- cgit v1.2.1