/* * 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 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(); } 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 */ 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); } } }