diff --git a/TODO b/TODO index 443a385..5020464 100644 --- a/TODO +++ b/TODO @@ -1,13 +1,6 @@ --- main.c --- -Menu printing -Battery printing Battery icon - ---- Menu --- -Attach - Attempt to attach spool -Detach - Attempt to detach spool -Adjust - Adjust Spool Value -Battery - Print Battery Info - mAh (+ %) - Voltage, Temp +Check when to read battery --- UI --- 123456mm >A diff --git a/code/main.c b/code/main.c index b00a7cf..94990b9 100644 --- a/code/main.c +++ b/code/main.c @@ -28,7 +28,7 @@ #define BATTERY_VOLT_MULT 244 #define BATTERY_VOLT_DIV 100 #define BATTERY_TEMP_MULT 125 -#define BATTERY_TEMP_DIV 1000 +#define BATTERY_TEMP_DIV 100 #define CHAR_SIZE 5 @@ -57,6 +57,7 @@ #define PTR_INC(x) ((x) = events + ((((x) - events) + 1) % MAX_EVENT_COUNT)) #define MENU_COUNT 3 +#define MENU_STRLEN 8 enum event_e { @@ -155,8 +156,31 @@ const uint8_t PROGMEM unfold_table[16] = 0xAA }; +#define CHAR_0 0 +#define CHAR_A 10 +#define CHAR_B 11 +#define CHAR_C 12 +#define CHAR_D 13 +#define CHAR_V 14 +#define CHAR_a 15 +#define CHAR_c 16 +#define CHAR_d 17 +#define CHAR_e 18 +#define CHAR_h 19 +#define CHAR_j 20 +#define CHAR_m 21 +#define CHAR_r 22 +#define CHAR_s 23 +#define CHAR_t 24 +#define CHAR_u 25 +#define CHAR_y 26 +#define CHAR_dot 27 +#define CHAR_lt 28 +#define CHAR_gt 29 +#define CHAR_deg 30 + // Bottom -> Top (In Byte); Left -> Right (In Row) -const uint8_t PROGMEM symbols[90] = +const uint8_t PROGMEM symbols[31 * CHAR_SIZE] = { 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0 0x00, 0x42, 0x7F, 0x40, 0x00, // 1 @@ -171,14 +195,34 @@ const uint8_t PROGMEM symbols[90] = 0x7E, 0x11, 0x11, 0x11, 0x7E, // A 0x7F, 0x49, 0x49, 0x49, 0x36, // B 0x3E, 0x41, 0x41, 0x41, 0x22, // C + 0x7F, 0x41, 0x41, 0x41, 0x3E, // D 0x1F, 0x20, 0x40, 0x20, 0x1F, // V + 0x20, 0x54, 0x54, 0x54, 0x78, // a + 0x38, 0x44, 0x44, 0x44, 0x20, // c + 0x38, 0x44, 0x44, 0x48, 0x7F, // d + 0x38, 0x54, 0x54, 0x54, 0x18, // e 0x7F, 0x08, 0x04, 0x04, 0x78, // h + 0x20, 0x40, 0x44, 0x3D, 0x00, // j 0x7C, 0x04, 0x78, 0x04, 0x78, // m + 0x7C, 0x08, 0x04, 0x04, 0x08, // r + 0x48, 0x54, 0x54, 0x54, 0x40, // s + 0x04, 0x3F, 0x44, 0x40, 0x20, // t + 0x3C, 0x40, 0x40, 0x20, 0x7C, // u + 0x0C, 0x50, 0x50, 0x50, 0x3C, // y 0x00, 0x60, 0x60, 0x00, 0x00, // . + 0x00, 0x08, 0x14, 0x22, 0x41, // < 0x41, 0x22, 0x14, 0x08, 0x00, // > 0x0E, 0x11, 0x11, 0x0E, 0x00 // deg }; +const char PROGMEM menu_strings[(MENU_COUNT + 1) * MENU_STRLEN] = +{ + CHAR_A, CHAR_t, CHAR_t, CHAR_a, CHAR_c, CHAR_h, 0xFF, 0xFF, 0xFF, + CHAR_A, CHAR_d, CHAR_j, CHAR_u, CHAR_s, CHAR_t, 0xFF, 0xFF, 0xFF, + CHAR_B, CHAR_a, CHAR_t, CHAR_t, CHAR_e, CHAR_r, CHAR_y, 0xFF, 0xFF, + CHAR_D, CHAR_e, CHAR_t, CHAR_a, CHAR_c, CHAR_h, 0xFF, 0xFF, 0xFF +}; + // 1 / (4 * ROT_PULSE_COUNT) * (2 * pi * ROT_WHEEL_RAD) const float rot_coeff = 1.57f * ROT_WHEEL_RAD / ROT_PULSE_COUNT; float count_value_fine = 0; @@ -193,7 +237,7 @@ uint8_t spool_counting = 0; uint32_t sleep_when_ms = 0; uint32_t long_press_when_ms = 0xFFFFFFFF; -uint8_t highlight = 0xFF; +uint8_t count_highlight = 0xFF; uint8_t dir_highlight = 0xFF; uint8_t needs_update = 0; @@ -201,7 +245,12 @@ uint8_t needs_update = 0; uint8_t state; uint8_t menu_option = 0; -void (*menu[3])(); + +int16_t battery_mAh = 0; +int16_t battery_mV = 0; +int16_t battery_temp = 0; + +void (*menu[MENU_COUNT])(); // Init direct hardware void simple_init(); @@ -229,12 +278,38 @@ void get_symbol16(uint8_t index, uint8_t *out); void print_symbol(uint8_t symbol_idx, uint8_t x, uint8_t y, uint8_t invert); // Print the length left with mm and highlight the required digit -// 0 - no highlight, 0xFF - clears everything -void print_mm(uint32_t value, uint8_t highlight); +// uses count_value for the value +// count_highlight - for highlit digit +// 0 - no highlight +// 1 -- 6 (rigth to left digit) +// 0xFF - clear all text +void print_mm(); -// Print the direction of the filament -// 0xFF - clears everything -void print_direction(uint8_t is_A, uint8_t highlight); +// Print the direction of the filament based on +// rot_dir_is_A - direction +// dir_highlight - 0 - no, 1 - yes, 0xFF - clear +void print_direction(); + +// Clears the menu/data area +void print_clear_menu_area(); + +// Print the menu +void print_menu(uint8_t force_draw); + +// Prints the option in the correct place +void print_option(uint8_t option); + +// Prints the battery icon depending on battery percentage +void print_battery_icon(); + +// Prints battery statistics in menu area +void print_battery_stat(uint8_t force_draw); + +// Prints single battery stat on row using symbols +void print_battery_single_stat(uint8_t y, int16_t bat_stat, uint8_t *symbols, uint8_t decimal_idx); + +// Prints battery temp +void print_battery_temp(); // Find the current eeprom data idx of the attached spool int16_t find_eeprom_idx(); @@ -426,6 +501,7 @@ int main() i2c_init(); display_init(); reset_battery(); + read_battery(&battery_mAh, &battery_mV, &battery_temp); // Attempt to attach spool on initial startup attach_detach_spool(); @@ -445,19 +521,25 @@ int main() process_menu(); break; - case STATE_SETTING: + case STATE_ADJUST: process_setting(); break; + + case STATE_BATTERY: + process_battery(); + break; } - // No Need? - // print_mm and print_dir already work standalone + print_mm(); + print_direction(); + print_battery_icon(); - // if (needs_update) - // { - // update_display(count_value, highlight, move_dir, dir_highlight); - // needs_update = 0; - // } + if (sleep_when_ms > ms) + { + sleep_when_ms = 0xFFFFFFFF; + do_sleep(); + read_battery(&battery_mAh, &battery_mV, &battery_temp); + } } } @@ -494,6 +576,7 @@ void simple_init() menu[0] = attach_detach_spool; menu[1] = set_adjust_spool; menu[2] = set_battery_state; +} void display_send_cmd(uint8_t cmd) { @@ -683,7 +766,7 @@ void print_symbol(uint8_t symbol_idx, uint8_t x, uint8_t y, uint8_t invert) display_send_data(unfolded_symbol, sizeof(unfolded_symbol)); } -void print_mm(uint32_t value, uint8_t highlight) +void print_mm() { static_uint8_t old_symbols[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static uint8_t old_highlight = 0xFF; @@ -701,8 +784,8 @@ void print_mm(uint32_t value, uint8_t highlight) // Print 6 digits (only needed ones) for (i = 6; i > 0; --i) { - symbol = extract_digit(value, i); - if (highlight == i) + symbol = extract_digit(count_value, i); + if (count_highlight == i) { invert = 1; } @@ -715,8 +798,8 @@ void print_mm(uint32_t value, uint8_t highlight) // There's no highlight, this is the first digit to write, it's 0 // and it's not the last digit // or everything is removed - if ((is_first && (0 == highlight) && (0 == symbol) && (1 != i)) || - (0xFF == highlight)) + if ((is_first && (0 == count_highlight) && (0 == symbol) && (1 != i)) || + (0xFF == count_highlight)) { symbol = 0xFF; } @@ -727,7 +810,7 @@ void print_mm(uint32_t value, uint8_t highlight) // Update only necessary digits // On highlight change or on symbol change - if ((old_highlight != highlight) || (symbol != old_symbols[6 - i])) + if ((old_highlight != count_highlight) || (symbol != old_symbols[6 - i])) { print_symbol(symbol, x, y, invert); old_symbols[6 - i] = symbol; @@ -736,40 +819,40 @@ void print_mm(uint32_t value, uint8_t highlight) } // Print 'mm' (only after clear) - if ((0xFF == old_highlight) && (0xFF != highlight)) + if ((0xFF == old_highlight) && (0xFF != count_highlight)) { - print_symbol(15, x, y, 0); + print_symbol(CHAR_m, x, y, 0); x += (CHAR_SIZE + 1) * 2; - print_symbol(15, x, y, 0); + print_symbol(CHAR_m, x, y, 0); } // Clear 'mm' - if (0xFF == highlight) + if (0xFF == count_highlight) { print_symbol(0xFF, x, y, 0); x += (CHAR_SIZE + 1) * 2; print_symbol(0xFF, x, y, 0); } - old_highlight = highlight; + old_highlight = count_highlight; } -void print_direction(uint8_t is_A, uint8_t highlight) +void print_direction() { uint8_t symbol; static uint8_t old_is_A = 0; static uint8_t old_highlight = 0xFF; - if (is_A) + if (rot_dir_is_A) { - symbol = 10; + symbol = CHAR_A; } else { - symbol = 11; + symbol = CHAR_B; } // Clear it all - if ((0xFF == highlight) && (old_highlight != highlight)) + if ((0xFF == dir_highlight) && (old_highlight != dir_highlight)) { print_symbol(0xFF, OLED_X_SIZE - (CHAR_SIZE + 1) * 2 * 2, 0, 0); print_symbol(0xFF, OLED_X_SIZE - (CHAR_SIZE + 1) * 2, 0, 0); @@ -779,17 +862,198 @@ void print_direction(uint8_t is_A, uint8_t highlight) // Print '>' only when display is comming from clear if (0xFF == old_highlight) { - print_symbol(symbol_index[0], OLED_X_SIZE - (CHAR_SIZE + 1) * 2 * 2, 0, 0); + print_symbol(CHAR_gt, OLED_X_SIZE - (CHAR_SIZE + 1) * 2 * 2, 0, 0); } // Print symbol on change or highlight change - if ((old_is_A != is_A) || (old_highlight != highlight)) + if ((old_is_A != is_A) || (old_highlight != dir_highlight)) { - print_symbol(symbol, OLED_X_SIZE - (CHAR_SIZE + 1) * 2, 0, highlight); + print_symbol(symbol, OLED_X_SIZE - (CHAR_SIZE + 1) * 2, 0, dir_highlight); } } - old_is_A = is_A; - old_highlight = highlight; + old_is_A = rot_dir_is_A; + old_highlight = dir_highlight; +} + +void print_clear_menu_area() +{ + uint16_t i; + uint16_t count; + uint8_t bytes; + uint8_t data[16]; + uint8_t cmd_list[6] = + { + 0x21, // Set Column Address + 0x00, // Start Address + 0x00, // End Address + 0x22, // Set Page Address + 0x02, // Start Page 2 - Skip Top Row Where Spool Data Is + 0x00 // End Page + }; + + // End X - Do Not Clear Battery Symbol + cmd_list[2] = OLED_X_SIZE - (CHAR_SIZE + 1) * 2 * 2 - 1; + + // End Y - Depends On OLED Size + cmd_list[5] = (OLED_Y_SIZE / 8) - 1; + + for (i = 0; i < sizeof(cmd_list); ++i) + { + display_send_cmd(cmd_list[i]); + } + + for (i = 0; i < sizeof(data); ++i) + { + data[i] = 0x00; + } + + count = (cmd_list[2] + 1) * (cmd_list[5] - cmd_list[4] + 1); + + i = 0; + while (i < count) + { + // If remaining bytes is smaller than buffer - send only required number + bytes = count - i < sizeof(data) ? count - i, sizeof(data); + display_send_data(data, bytes); + i += bytes; + } +} + +void print_menu(uint8_t force_draw) +{ + static uint8_t old_option = 0xFF; + uint8_t i; + + if (force_draw || (old_option != menu_option)) + { + for (i = 0; i < MENU_COUNT; ++i) + { + if (force_draw || (i == old_option) || (i == menu_option)) + { + print_option(i); + } + } + } +} + +void print_option(uint8_t option) +{ + uint8_t invert = 0; + uint8_t x = 0; + uint8_t y = 1 + option; + uint8_t i; + + // Whether to invert or not + if (option == menu_option) + { + invert = 1; + } + + // Whether to display "Attach" or "Detach" + if ((0 == option) && spool_attached) + { + option += MENU_COUNT; + } + + for (i = 0; i < MENU_STRLEN; ++i) + { + // Get the symbol index from the menu_strings + print_symbol(pgm_read_byte(&(menu_strings[option * MENU_STRLEN + i])), x, y, invert); + x += (CHAR_SIZE + 1) * 2; + } +} + +void print_battery_icon() +{ + +} + +void print_battery_stat(uint8_t force_draw) +{ + uint8_t symbols[MENU_STRLEN] = {0xFF, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF}; + int16_t old_mAh = 0xFFFF; + int16_t old_mV = 0xFFFF; + int16_t old_temp = 0xFFFF; + + if ((old_mAh != battery_mAh) || force_draw) + { + symbols[5] = CHAR_m; + symbols[6] = CHAR_A; + symbols[7] = CHAR_h; + + print_battery_single_stat(1, battery_mAh, symbols, 0xFF); + old_mAh = battery_mAh; + } + + if ((old_mV != battery_mV) || force_draw) + { + symbols[5] = CHAR_m; + symbols[6] = CHAR_V; + symbols[7] = 0xFF; + + print_battery_single_stat(1, battery_mV, symbols, 0xFF); + old_mV = battery_mV; + } + + if ((old_temp != battery_temp) || force_draw) + { + symbols[5] = CHAR_deg; + symbols[6] = CHAR_C; + symbols[7] = 0xFF; + + print_battery_single_stat(1, battery_temp, symbols, 3); + old_temp = battery_temp; + } +} + +void print_battery_single_stat(uint8_t y, int16_t bat_stat, uint8_t *symbols, uint8_t decimal_idx) +{ + uint8_t x = 0; + uint8_t i; + uint16_t stat = bat_stat; + + // Show +/- + if (bat_stat < 0) + { + symbols[0] = CHAR_lt; + stat = -stat; + } + else + { + symbols[0] = CHAR_gt; + } + + // Extract 4 digits + for (i = 0; i < 4; ++i) + { + if ((4 - i) == decimal_idx) + { + symbols[decimal_idx] = CHAR_dot; + continue; + } + symbols[4 - i] = stat % 10; + stat /= 10; + } + + // Remove leading zeroes + for (i = 1; i < 5; ++i) + { + if (0 == symbols[i] && (decimal_idx != (i + 1))) + { + symbols[i] = 0xFF; + } + else + { + break; + } + } + + // Do the actual print + for (i = 0; i < MENU_STRLEN; ++i) + { + print_symbol(symbols[i], x, y, 0); + x += (CHAR_SIZE + 1) * 2; + } } int16_t find_eeprom_idx() @@ -918,32 +1182,50 @@ int8_t read_battery(int16_t *mAh, int16_t *mV, int16_t *temp) return -1; } - // Calc mAh - (*mAh) = buf[BATTERY_CHARGE + 1]; - (*mAh) <<= 8; - (*mAh) |= buf[BATTERY_CHARGE]; + // Read mAh bits + val = buf[BATTERY_CHARGE + 1]; + val <<= 8; + val |= buf[BATTERY_CHARGE]; - val = (*mAh); + // If bit 15 is set + if (val & 0x00008000) + { + val -= 65536; + } + + // Transform into mAh val *= BATTERY_CHARGE_MULT; val /= BATTERY_CHARGE_DIV; (*mAh) = val; - // Calc mV - (*mV) = buf[BATTERY_VOLT + 1]; - (*mV) <<= 8; - (*mV) |= buf[BATTERY_VOLT]; + // Read mV bits + val = buf[BATTERY_VOLT + 1]; + val <<= 8; + val |= buf[BATTERY_VOLT]; - val = (*mV); + // If bit 11 is set + if (val & 0x00000800) + { + val -= 2048; + } + + // Transform into mV val *= BATTERY_VOLT_MULT; val /= BATTERY_VOLT_DIV; (*mV) = val; - // Calc temp - (*temp) = buf[BATTERY_TEMP + 1]; - (*temp) <<= 8; - (*temp) |= buf[BATTERY_TEMP]; + // Read temp bits + val = buf[BATTERY_TEMP + 1]; + val <<= 8; + val |= buf[BATTERY_TEMP]; - val = (*temp); + // If bit 11 is set + if (val & 0x00000800) + { + val -= 2048; + } + + // Transform into temp val *= BATTERY_TEMP_MULT; val /= BATTERY_TEMP_DIV; (*temp) = val; @@ -1030,7 +1312,7 @@ void do_sleep() // Reset ms counter cli(); - ms = 2; + ms = 0; sei(); // Disable sleep @@ -1114,7 +1396,6 @@ void spool_count(uint8_t event) // Turn Display ON to show value display_enable(1); sleep_when_ms = ms + DISPLAY_DELAY; - needs_update = 1; } else { @@ -1128,12 +1409,6 @@ void spool_count(uint8_t event) write_eeprom_val(eeprom_idx, (uint32_t) count_value_fine, move_dir); } count_value = (uint32_t) count_value_fine; - - // Update display if it's on - if ((sleep_when_ms > ms)) - { - needs_update = 1; - } } } } @@ -1159,6 +1434,8 @@ void process_idle() case EVENT_BTN_UP: long_press_when_ms = 0xFFFFFFFF; + // Click - update battery info + read_battery(&battery_mAh, &battery_mV, &battery_temp); break; } } @@ -1169,6 +1446,7 @@ void process_idle() state = STATE_MENU; menu_option = 0; long_press_when_ms = 0xFFFFFFFF; + print_menu(1); } } @@ -1217,13 +1495,14 @@ void process_menu() // Hold button to exit menu if (ms >= long_press_when_ms) { - // TODO: Clear menu area + print_clear_menu_area(); state = STATE_IDLE; long_press_when_ms = 0xFFFFFFFF; } else { - // TODO: Print Menu + // Print Menu in auto mode + print_menu(0); } } @@ -1232,7 +1511,7 @@ void process_adjust() uint8_t curr_event; uint32_t digit_val = 1; - for (uint8_t i = 1; i < highlight; ++i) + for (uint8_t i = 1; i < count_highlight; ++i) { digit_val *= 10; } @@ -1252,10 +1531,10 @@ void process_adjust() if (0xFFFFFFFF != long_press_when_ms) { // Button Clicked - Go to next digit or direction - if (highlight) + if (count_highlight) { - --highlight; - if (0 == highlight) + --count_highlight; + if (0 == count_highlight) { dir_highlight = 1; } @@ -1264,7 +1543,7 @@ void process_adjust() { // Wrap around dir_highlight = 0; - highlight = 6; + count_highlight = 6; } } long_press_when_ms = 0xFFFFFFFF; @@ -1272,9 +1551,9 @@ void process_adjust() case EVENT_SEL_UP: // Digit ++ - if (0 != highlight) + if (0 != count_highlight) { - if (9 == extract_digit(count_value, highlight)) + if (9 == extract_digit(count_value, count_highlight)) { count_value -= digit_val * 10; } @@ -1288,9 +1567,9 @@ void process_adjust() case EVENT_SEL_DOWN: // Digit -- - if (0 != highlight) + if (0 != count_highlight) { - if (0 == extract_digit(count_value, highlight)) + if (0 == extract_digit(count_value, count_highlight)) { count_value += digit_val * 10; } @@ -1347,7 +1626,9 @@ void process_battery() if (0xFFFFFFFF != long_press_when_ms) { // Button Clicked - Update Battery Info - // TODO: read_battery(); + read_battery(&battery_mAh, &battery_mV, &battery_temp); + print_battery_icon(); + print_battery_stat(); } long_press_when_ms = 0xFFFFFFFF; break; @@ -1357,19 +1638,10 @@ void process_battery() // Hold button to return to idle if (ms >= long_press_when_ms) { - // TODO: Clear menu area + print_clear_menu_area(); state = STATE_IDLE; long_press_when_ms = 0xFFFFFFFF; } - - if (ms >= sleep_when_ms) - { - // TODO: Clear menu area - state = STATE_IDLE; - long_press_when_ms = 0xFFFFFFFF; - } - - // TODO: Print battery info } void attach_detach_spool() @@ -1385,7 +1657,7 @@ void attach_detach_spool() spool_counting = 0; spool_attached = 0; - highlight = 0xFF; + count_highlight = 0xFF; dir_highlight = 0xFF; // Disable rotary encoder interrupts @@ -1421,7 +1693,7 @@ void attach_detach_spool() count_value_fine = count_value; } spool_attached = 1; - highlight = 0; + count_highlight = 0; dir_highlight = 0; // Enable rotary encoder interrupts @@ -1436,14 +1708,15 @@ void set_adjust_spool() return; } - // TODO: Clear menu area - highlight = 6; + print_clear_menu_area(); + count_highlight = 6; spool_counting = 0; state = STATE_ADJUST; } void set_battery_state() { - // TODO: Clear menu area + print_clear_menu_area(); state = STATE_BATTERY; + print_battery_stat(1); }