diff --git a/firmware/src/Makefile b/firmware/src/Makefile index 99ded03..f792d8e 100644 --- a/firmware/src/Makefile +++ b/firmware/src/Makefile @@ -13,7 +13,7 @@ OBJCOPY := avr-objcopy SIZE := avr-size AVRDUDE := avrdude -CFLAGS := -mmcu=$(MCU) -Os -Wall -Werror -Wextra -Wpedantic +CFLAGS := -mmcu=$(MCU) -Os -Wall -Werror -Wextra all: $(TARGET) diff --git a/firmware/src/main.c b/firmware/src/main.c index fa60126..97b51f2 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -1,4 +1,4 @@ -#define F_CPU 8000000UL +#define F_CPU 8000000UL #include #include @@ -26,6 +26,45 @@ static const uint8_t sacred_chao[200] = { 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0x static const uint8_t onders_org[96] = { 0xE0, 0x60, 0xE0, 0x00, 0x00, 0xE0, 0x60, 0xE0, 0x00, 0x00, 0xE0, 0x60, 0xF8, 0x00, 0x00, 0xE0, 0xA0, 0xE0, 0x00, 0x00, 0xE0, 0x20, 0x60, 0x00, 0x00, 0xE0, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x60, 0xE0, 0x00, 0x00, 0xE0, 0x20, 0x60, 0x00, 0x00, 0xE0, 0x60, 0xE0, 0x03, 0x02, 0x03, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x03, 0x02, 0x03, 0x00, 0x00, 0x03, 0x02, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x02, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x0A, 0x0F}; +struct symbol { + uint8_t length; + uint8_t symbol[]; +}; + +static const struct symbol sym_c = { 5, { 0xF8, 0xFC, 0x0C, 0x1C, 0x18, + 0x1F, 0x3F, 0x30, 0x38, 0x18 } }; +static const struct symbol sym_h = { 6, { 0xFC, 0xFC, 0x80, 0x80, 0xFC, 0xFC, + 0x3F, 0x3F, 0x01, 0x01, 0x3F, 0x3F } }; + +static const struct symbol sym_0 = { 5, { 0xF8, 0xFC, 0x0C, 0xFC, 0xF8, + 0x1F, 0x3F, 0x30, 0x3F, 0x1F } }; +static const struct symbol sym_1 = { 5, { 0x30, 0x30, 0xFC, 0xFC, 0x00, + 0x30, 0x30, 0x3F, 0x3F, 0x30 } }; +static const struct symbol sym_2 = { 5, { 0x18, 0x1C, 0x8C, 0xFC, 0xF8, + 0x38, 0x3E, 0x3F, 0x33, 0x30 } }; +static const struct symbol sym_3 = { 5, { 0x18, 0x9C, 0x8C, 0xFC, 0x78, + 0x18, 0x39, 0x31, 0x3F, 0x1E } }; +static const struct symbol sym_4 = { 5, { 0x80, 0xE0, 0x78, 0xFC, 0xFC, + 0x07, 0x07, 0x06, 0x3F, 0x3F } }; +static const struct symbol sym_5 = { 5, { 0xFC, 0xFC, 0x8C, 0x8C, 0x0C, + 0x1C, 0x3D, 0x31, 0x3F, 0x1F } }; +static const struct symbol sym_6 = { 5, { 0xF8, 0xFC, 0x8C, 0xBC, 0x38, + 0x1F, 0x3F, 0x31, 0x3F, 0x1F } }; +static const struct symbol sym_7 = { 5, { 0x0C, 0x0C, 0xEC, 0xFC, 0x1C, + 0x00, 0x3E, 0x3F, 0x01, 0x00 } }; +static const struct symbol sym_8 = { 5, { 0x78, 0xFC, 0x8C, 0xFC, 0x78, + 0x1E, 0x3F, 0x31, 0x3F, 0x1E } }; +static const struct symbol sym_9 = { 5, { 0xF8, 0xFC, 0x8C, 0xFC, 0xF8, + 0x1C, 0x3D, 0x31, 0x3F, 0x1F } }; + +static const struct symbol sym_setup = { 19, { 0xF8, 0x98, 0xB8, 0x00, 0xF8, 0x98, 0x18, 0x00, 0x18, 0xF8, 0x18, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x98, 0xF8, + 0x1D, 0x19, 0x1F, 0x00, 0x1F, 0x19, 0x18, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x00, 0x1F, 0x01, 0x01 } }; + +enum input {cw, ccw}; + +static enum state {home} current_state = home; +static enum home_state {ch1, ch2, ch3, setup} current_home_state = ch1; + static uint8_t enc = 0; void spi_init(void) { @@ -78,6 +117,25 @@ void lcd_fill(uint8_t data) { } } +static void lcd_write_kerning(const uint8_t length, + const bool invert) { + for (uint8_t i = 0; i < length; i++) + if (invert) + lcd_write(0xFF); + else + lcd_write(0x00); +} + +static void lcd_write_symbol_page(const struct symbol* sym, + uint8_t page, + bool invert) { + for (uint8_t i = 0; i < sym->length; i++) + if (invert) + lcd_write(~sym->symbol[page * sym->length + i]); + else + lcd_write(sym->symbol[page * sym->length + i]); +} + void lcd_splash(void) { lcd_fill(0x00); @@ -105,6 +163,118 @@ void lcd_splash(void) { } } +static void lcd_home(void) { + lcd_fill(0x00); + + bool ch1_selected = false; + bool ch2_selected = false; + bool ch3_selected = false; + bool setup_selected = false; + + switch(current_home_state) { + case ch1: + ch1_selected = true; + break; + case ch2: + ch2_selected = true; + break; + case ch3: + ch3_selected = true; + break; + default: // setup + setup_selected = true; + break; + } + + for (uint8_t i = 0; i < 2; i++) { + SPI_PORT &= ~(1 << LCD_CD); + lcd_write(0x00); + lcd_write(0x10); + lcd_write(0xB0 + i); + SPI_PORT |= (1 << LCD_CD); + + lcd_write_kerning(2, ch1_selected); + lcd_write_symbol_page(&sym_c, i, ch1_selected); + lcd_write_kerning(2, ch1_selected); + lcd_write_symbol_page(&sym_h, i, ch1_selected); + lcd_write_kerning(2, ch1_selected); + lcd_write_symbol_page(&sym_1, i, ch1_selected); + lcd_write_kerning(2, ch1_selected); + + SPI_PORT &= ~(1 << LCD_CD); + lcd_write(0x00); + lcd_write(0x10); + lcd_write(0xB2 + i); + SPI_PORT |= (1 << LCD_CD); + + lcd_write_kerning(2, ch2_selected); + lcd_write_symbol_page(&sym_c, i, ch2_selected); + lcd_write_kerning(2, ch2_selected); + lcd_write_symbol_page(&sym_h, i, ch2_selected); + lcd_write_kerning(2, ch2_selected); + lcd_write_symbol_page(&sym_2, i, ch2_selected); + lcd_write_kerning(2, ch2_selected); + + SPI_PORT &= ~(1 << LCD_CD); + lcd_write(0x00); + lcd_write(0x10); + lcd_write(0xB4 + i); + SPI_PORT |= (1 << LCD_CD); + + lcd_write_kerning(2, ch3_selected); + lcd_write_symbol_page(&sym_c, i, ch3_selected); + lcd_write_kerning(2, ch3_selected); + lcd_write_symbol_page(&sym_h, i, ch3_selected); + lcd_write_kerning(2, ch3_selected); + lcd_write_symbol_page(&sym_3, i, ch3_selected); + lcd_write_kerning(2, ch3_selected); + + SPI_PORT &= ~(1 << LCD_CD); + lcd_write(0x00); + lcd_write(0x10); + lcd_write(0xB6 + i); + SPI_PORT |= (1 << LCD_CD); + + lcd_write_kerning(2, setup_selected); + lcd_write_symbol_page(&sym_setup, i, setup_selected); + lcd_write_kerning(3, setup_selected); + } +} + +static void update_home(enum input event) { + switch (event) { + case cw: + current_home_state++; + if (current_home_state > setup) + current_home_state = ch1; + lcd_home(); + break; + case ccw: + current_home_state--; + if (current_home_state > setup) + current_home_state = setup; + lcd_home(); + break; + } +} + +static void update_state(enum input event) { + switch (current_state) { + case home: + update_home(event); + break; + } +} + +static void change_state(enum state new_state) { + switch(new_state) { + case home: + lcd_home(); + current_state = home; + break; + } +} + // Encoder rotation interrupt ISR(PCINT0_vect) { cli(); @@ -119,8 +289,10 @@ ISR(PCINT0_vect) { case 1: if (ENC_A && ENC_B) { enc = 2; + update_state(cw); } else if (!ENC_A && !ENC_B) { enc = 0; + update_state(ccw); } break; case 2: @@ -132,8 +304,10 @@ ISR(PCINT0_vect) { case 3: if (!ENC_A && !ENC_B) { enc = 0; + update_state(cw); } else if (ENC_A && ENC_B) { enc = 2; + update_state(ccw); } break; } @@ -162,8 +336,10 @@ int main(void) { PCICR |= (1 << PCIE0); PCMSK0 |= (1 << PCINT6) | (1 << PCINT7); - // Show splash screen + // Show splash screen and load the menu lcd_splash(); + _delay_ms(250); + change_state(current_state); // Enable interrupts sei();