diff --git a/TODO b/TODO index 494eeb9..443a385 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,7 @@ --- main.c --- -fix main() +Menu printing +Battery printing +Battery icon --- Menu --- Attach - Attempt to attach spool diff --git a/code/main.c b/code/main.c index 943cc26..b00a7cf 100644 --- a/code/main.c +++ b/code/main.c @@ -56,6 +56,8 @@ #define MAX_EVENT_COUNT 64 #define PTR_INC(x) ((x) = events + ((((x) - events) + 1) % MAX_EVENT_COUNT)) +#define MENU_COUNT 3 + enum event_e { EVENT_NONE, @@ -77,6 +79,14 @@ enum btn_state_e BTN_DOWN14 }; +enum main_state_e +{ + STATE_IDLE, + STATE_MENU, + STATE_ADJUST, + STATE_BATTERY +}; + // These are set on hardware init uint8_t old_btn_pin_state; uint8_t old_rot_pin_state; @@ -169,6 +179,30 @@ const uint8_t PROGMEM symbols[90] = 0x0E, 0x11, 0x11, 0x0E, 0x00 // deg }; +// 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; +uint32_t count_value = 0; +int8_t rot_value = 0; +uint8_t rot_dir_is_A = 1; + +int16_t eeprom_idx = 0; +uint8_t spool_attached = 0; +uint8_t spool_counting = 0; + +uint32_t sleep_when_ms = 0; +uint32_t long_press_when_ms = 0xFFFFFFFF; + +uint8_t highlight = 0xFF; +uint8_t dir_highlight = 0xFF; + +uint8_t needs_update = 0; + +uint8_t state; + +uint8_t menu_option = 0; +void (*menu[3])(); + // Init direct hardware void simple_init(); @@ -231,6 +265,27 @@ void do_sleep(); // 1 - ones, 2 - tens, 3 - hundreds ... uint8_t extract_digit(uint32_t value, uint8_t digit_num); +// Returns an event from the queue or EVENT_NONE +// EVENT_NONE could be from the queue +uint8_t consume_event(); + +// Adjusts count value based on event +void spool_count(uint8_t event); + +void process_idle(); +void process_menu(); +void process_adjust(); +void process_battery(); + +// Attaches or detaches spool (Menu 0) +void attach_detach_spool(); + +// Sets the state to adjust spool (Menu 1) +void set_adjust_spool(); + +// Sets the state to battery info (Menu 3) +void set_battery_state(); + // Updates the ms counter ISR(TIMER1_OVF_vect) { @@ -363,272 +418,46 @@ ISR(PCINT1_vect) int main() { - // 1 / (4 * ROT_PULSE_COUNT) * (2 * pi * ROT_WHEEL_RAD) - const float rot_coeff = 1.57f * ROT_WHEEL_RAD / ROT_PULSE_COUNT; - uint32_t sleep_when_ms = 0; - uint32_t long_press_when_ms = 0; - uint32_t count_value = 0; - float count_value_fine = 0; - uint32_t eeprom_value = 0; - uint16_t eeprom_idx = 0; - uint8_t move_dir = 0; - int8_t rot_value = 0; - uint8_t dir_highlight = 0; - uint8_t highlight = 0; - uint8_t needs_update = 0; - uint8_t curr_event; - uint8_t state; // Init Direct Hardware simple_init(); i2c_init(); display_init(); + reset_battery(); - state = STATE_COUNTING; + // Attempt to attach spool on initial startup + attach_detach_spool(); - eeprom_idx = find_eeprom_idx(); - if (EEPROM_SIZE == eeprom_idx) - { - eeprom_idx = 0; - state = STATE_SETTING; - highlight = 6; - needs_update = 1; - } - else - { - read_eeprom_val(eeprom_idx, &eeprom_value, &move_dir); - if (0 == eeprom_value) - { - state = STATE_SETTING; - highlight = 6; - needs_update = 1; - } - else - { - count_value = eeprom_value; - count_value_fine = eeprom_value; - } - } - - if (STATE_COUNTING == state) - { - sleep_when_ms = 1; - display_enable(0); - } + state = STATE_IDLE; sei(); while(1) { switch (state) { - case STATE_COUNTING: - while (event_count > 0) - { - // Consume Event - cli(); - curr_event = *event_read; - PTR_INC(event_read); - --event_count; - sei(); - - // Process Event - switch(curr_event) - { - case EVENT_BUTTON_DOWN: - long_press_when_ms = ms + LONG_PRESS; - sleep_when_ms = ms + DISPLAY_DELAY; - display_enable(1); - needs_update = 1; - break; - - case EVENT_BUTTON_UP: - long_press_when_ms = 0; - break; - - case EVENT_ROT_CW: - if (0 != move_dir) - { - --rot_value; - } - else - { - ++rot_value; - } - break; - - case EVENT_ROT_CCW: - if (0 != move_dir) - { - ++rot_value; - } - else - { - --rot_value; - } - break; - } - } - - if (rot_value / (ROT_PULSE_COUNT * 4 / ROT_DETENTS) != 0) - { - count_value_fine += rot_coeff * rot_value; - rot_value = 0; - - if (count_value_fine < 0) - { - // Write the zero to EEPROM - ++eeprom_idx; - eeprom_idx %= EEPROM_SIZE; - write_eeprom_val(eeprom_idx, 0, move_dir); - - count_value_fine = 0; - display_enable(1); - - // Switch State - sleep_when_ms = 0; - long_press_when_ms = 0; - highlight = 6; - needs_update = 1; - state = STATE_SETTING; - } - - // Update EEPROM When Meter Value Changes - if ((uint32_t)count_value_fine / 1000 != count_value / 1000) - { - ++eeprom_idx; - eeprom_idx %= EEPROM_SIZE; - write_eeprom_val(eeprom_idx, (uint32_t) count_value_fine, move_dir); - } - count_value = (uint32_t) count_value_fine; - - if ((0 != sleep_when_ms) && (sleep_when_ms > ms)) - { - needs_update = 1; - } - } - - if ((0 != long_press_when_ms) && (long_press_when_ms < ms)) - { - // Switch State - sleep_when_ms = 0; - long_press_when_ms = 0; - highlight = 6; - needs_update = 1; - state = STATE_SETTING; - } - - if ((0 != sleep_when_ms) && (sleep_when_ms < ms)) - { - display_enable(0); - do_sleep(); - sleep_when_ms = 1; - } - - // STATE_COUNTING + case STATE_IDLE: + process_idle(); + break; + + case STATE_MENU: + process_menu(); break; case STATE_SETTING: - while (event_count > 0) - { - // Consume Event - cli(); - curr_event = *event_read; - PTR_INC(event_read); - --event_count; - sei(); - - // Process Event - switch(curr_event) - { - case EVENT_BUTTON_DOWN: - long_press_when_ms = ms + LONG_PRESS; - break; - - case EVENT_BUTTON_UP: - if (long_press_when_ms > ms) - { - // Short Press - - if (0 != dir_highlight) - { - if (0 == move_dir) - { - move_dir = 1; - } - else - { - move_dir = 0; - } - } - - if (0 != highlight) - { - uint32_t temp_count = count_value; - uint32_t div = 1; - uint8_t i; - - for (i = 1; i < highlight; ++i) - { - div *= 10; - } - - temp_count = count_value % (div * 10); - count_value -= temp_count; - temp_count += div; - temp_count %= div * 10; - count_value += temp_count; - count_value_fine = count_value; - } - - needs_update = 1; - } - long_press_when_ms = 0; - - // EVENT_BUTTON_UP - break; - } - } - - if ((0 != long_press_when_ms) && (long_press_when_ms < ms)) - { - // Long press - - if (0 != highlight) - { - --highlight; - if (0 == highlight) - { - dir_highlight = 1; - } - } - else if (0 != dir_highlight) - { - // Switch state - sleep_when_ms = ms + DISPLAY_DELAY; - dir_highlight = 0; - state = STATE_COUNTING; - - // Write starting value to EEPROM - ++eeprom_idx; - eeprom_idx %= EEPROM_SIZE; - write_eeprom_val(eeprom_idx, count_value, move_dir); - } - - needs_update = 1; - long_press_when_ms = 0; - } - - // STATE_SETTING + process_setting(); break; } - if (needs_update) - { - update_display(count_value, highlight, move_dir, dir_highlight); - needs_update = 0; - } + // No Need? + // print_mm and print_dir already work standalone + + // if (needs_update) + // { + // update_display(count_value, highlight, move_dir, dir_highlight); + // needs_update = 0; + // } } } @@ -651,8 +480,8 @@ void simple_init() // Interrupt on rotary encoder pins PCMSK1 = (1 << PCINT8) | (1 << PCINT9); - // Enable Interrupt on pin-changes - GIMSK = (1 << PCIE0) | (1 << PCIE1); + // Enable Interrupt on pin-changes (only button) + GIMSK = (1 << PCIE0); // Sleep mode - power down MCUCR = (1 << SM1); @@ -662,7 +491,9 @@ void simple_init() old_btn_pin_state = 0x2F; old_rot_pin_state = (PINB & 0x03); -} + menu[0] = attach_detach_spool; + menu[1] = set_adjust_spool; + menu[2] = set_battery_state; void display_send_cmd(uint8_t cmd) { @@ -895,9 +726,8 @@ void print_mm(uint32_t value, uint8_t highlight) } // Update only necessary digits - // On first run, on highlight change or on symbol change - if ((0xFF == old_highlight) || (old_highlight != highlight) || - (symbol != old_symbols[6 - i])) + // On highlight change or on symbol change + if ((old_highlight != highlight) || (symbol != old_symbols[6 - i])) { print_symbol(symbol, x, y, invert); old_symbols[6 - i] = symbol; @@ -905,14 +735,15 @@ void print_mm(uint32_t value, uint8_t highlight) x += (CHAR_SIZE + 1) * 2; } - // Print 'mm' (only on first run) - if (0xFF == old_highlight) + // Print 'mm' (only after clear) + if ((0xFF == old_highlight) && (0xFF != highlight)) { print_symbol(15, x, y, 0); x += (CHAR_SIZE + 1) * 2; print_symbol(15, x, y, 0); } + // Clear 'mm' if (0xFF == highlight) { print_symbol(0xFF, x, y, 0); @@ -1218,3 +1049,401 @@ uint8_t extract_digit(uint32_t value, uint8_t digit_num) } return value % 10; } + +uint8_t consume_event() +{ + uint8_t curr_event; + + if (event_count > 0) + { + cli(); + curr_event = *event_read; + PTR_INC(event_read); + --event_count; + sei(); + } + else + { + curr_event = EVENT_NONE; + } + + return curr_event; +} + +void spool_count(uint8_t event) +{ + if ((!spool_attached) || (!spool_counting)) + { + return; + } + + // A / CW = + + // B / CCW = + + + // B / CW = - + // A / CCW = - + if ((rot_dir_is_A && (event == EVENT_ROT_CW)) || + (!rot_dir_is_A && (event == EVENT_ROT_CCW))) + { + ++rot_value; + } + else + { + --rot_value; + } + + if (rot_value / (ROT_PULSE_COUNT * 4 / ROT_DETENTS) != 0) + { + count_value_fine += rot_coeff * rot_value; + rot_value = 0; + + if (count_value_fine <= 0) + { + // Update EEPROM with 0 + + // Clear old cell & write to next one + write_eeprom_val(eeprom_idx, 0xFFFFFFFF, 0xFF); + ++eeprom_idx; + eeprom_idx %= EEPROM_SIZE / EEPROM_IDX_SIZE; + write_eeprom_val(eeprom_idx, 0, rot_dir_is_A); + + count_value_fine = 0; + count_value = 0; + spool_counting = 0; + + // Turn Display ON to show value + display_enable(1); + sleep_when_ms = ms + DISPLAY_DELAY; + needs_update = 1; + } + else + { + // Update EEPROM every 100 mm + if ((uint32_t)count_value_fine / 100 != count_value / 100) + { + // Clear old cell & write to next one + write_eeprom_val(eeprom_idx, 0xFFFFFFFF, 0xFF); + ++eeprom_idx; + eeprom_idx %= EEPROM_SIZE; + 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; + } + } + } +} + +void process_idle() +{ + uint8_t curr_event; + + while (event_count > 0) + { + curr_event = consume_event(); + switch (curr_event) + { + case EVENT_ROT_CW: // Fall-through + case EVENT_ROT_CCW: + spool_count(curr_event); + break; + + case EVENT_BTN_DOWN: + long_press_when_ms = ms + LONG_PRESS; + sleep_when_ms = ms + DISPLAY_DELAY; + break; + + case EVENT_BTN_UP: + long_press_when_ms = 0xFFFFFFFF; + break; + } + } + + // Hold button to enter menu + if (ms >= long_press_when_ms) + { + state = STATE_MENU; + menu_option = 0; + long_press_when_ms = 0xFFFFFFFF; + } +} + +void process_menu() +{ + uint8_t curr_event; + + while (event_count > 0) + { + curr_event = consume_event(); + switch (curr_event) + { + case EVENT_ROT_CW: // Fall-through + case EVENT_ROT_CCW: + spool_count(curr_event); + break; + + case EVENT_BTN_DOWN: + long_press_when_ms = ms + LONG_PRESS; + sleep_when_ms = ms + DISPLAY_DELAY; + break; + + case EVENT_BTN_UP: + if (0xFFFFFFFF != long_press_when_ms) + { + // Button Clicked - Do whatever is selected + menu[menu_option](); + } + long_press_when_ms = 0xFFFFFFFF; + break; + + case EVENT_SEL_UP: + sleep_when_ms = ms + DISPLAY_DELAY; + menu_option += MENU_COUNT - 1; + menu_option %= MENU_COUNT; + break; + + case EVENT_SEL_DOWN: + sleep_when_ms = ms + DISPLAY_DELAY; + ++menu_option; + menu_option %= MENU_COUNT; + break; + } + } + + // Hold button to exit menu + if (ms >= long_press_when_ms) + { + // TODO: Clear menu area + state = STATE_IDLE; + long_press_when_ms = 0xFFFFFFFF; + } + else + { + // TODO: Print Menu + } +} + +void process_adjust() +{ + uint8_t curr_event; + uint32_t digit_val = 1; + + for (uint8_t i = 1; i < highlight; ++i) + { + digit_val *= 10; + } + + // NO SLEEP + sleep_when_ms = 0xFFFFFFFF; + while (event_count > 0) + { + curr_event = consume_event(); + switch (curr_event) + { + case EVENT_BTN_DOWN: + long_press_when_ms = ms + LONG_PRESS; + break; + + case EVENT_BTN_UP: + if (0xFFFFFFFF != long_press_when_ms) + { + // Button Clicked - Go to next digit or direction + if (highlight) + { + --highlight; + if (0 == highlight) + { + dir_highlight = 1; + } + } + else + { + // Wrap around + dir_highlight = 0; + highlight = 6; + } + } + long_press_when_ms = 0xFFFFFFFF; + break; + + case EVENT_SEL_UP: + // Digit ++ + if (0 != highlight) + { + if (9 == extract_digit(count_value, highlight)) + { + count_value -= digit_val * 10; + } + count_value += digit_val; + } + else + { + rot_dir_is_A = !rot_dir_is_A; + } + break; + + case EVENT_SEL_DOWN: + // Digit -- + if (0 != highlight) + { + if (0 == extract_digit(count_value, highlight)) + { + count_value += digit_val * 10; + } + count_value -= digit_val; + } + else + { + rot_dir_is_A = !rot_dir_is_A; + } + break; + } + } + + // Hold button to stop + if (ms >= long_press_when_ms) + { + count_value_fine = count_value; + + // Write to EEPROM + // Clear old cell & write to next one + write_eeprom_val(eeprom_idx, 0xFFFFFFFF, 0xFF); + ++eeprom_idx; + eeprom_idx %= EEPROM_SIZE / EEPROM_IDX_SIZE; + write_eeprom_val(eeprom_idx, (uint32_t) count_value, rot_dir_is_A); + + // Go back to idle + state = STATE_IDLE; + long_press_when_ms = 0xFFFFFFFF; + sleep_when_ms = ms + DISPLAY_DELAY; + spool_counting = 1; + } +} + +void process_battery() +{ + uint8_t curr_event; + + while (event_count > 0) + { + curr_event = consume_event(); + switch (curr_event) + { + case EVENT_ROT_CW: // Fall-through + case EVENT_ROT_CCW: + spool_count(curr_event); + break; + + case EVENT_BTN_DOWN: + sleep_when_ms = ms + DISPLAY_DELAY; + long_press_when_ms = ms + LONG_PRESS; + break; + + case EVENT_BTN_UP: + if (0xFFFFFFFF != long_press_when_ms) + { + // Button Clicked - Update Battery Info + // TODO: read_battery(); + } + long_press_when_ms = 0xFFFFFFFF; + break; + } + } + + // Hold button to return to idle + if (ms >= long_press_when_ms) + { + // TODO: 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() +{ + if (spool_attached) + { + // Detach + // Clear old cell & write to next one + write_eeprom_val(eeprom_idx, 0xFFFFFFFF, 0xFF); + ++eeprom_idx; + eeprom_idx %= EEPROM_SIZE; + write_eeprom_val(eeprom_idx, (uint32_t) count_value_fine, move_dir); + + spool_counting = 0; + spool_attached = 0; + highlight = 0xFF; + dir_highlight = 0xFF; + + // Disable rotary encoder interrupts + GIMSK &= (~(1 << PCIE1)); + } + else + { + // Attach + // Detect EEPROM + eeprom_idx = find_eeprom_idx(); + if (-1 == eeprom_idx) + { + return; + } + + // Read Value + if (0 != read_eeprom_val(eeprom_idx, &count_value, &rot_dir_is_A)) + { + return; + } + + // New EEPROM + if (0x00FFFFFF == count_value) + { + is_counting = 0; + count_value = 0; + count_value_fine = 0; + rot_dir_is_A = 1; + } + else + { + is_counting = 1; + count_value_fine = count_value; + } + spool_attached = 1; + highlight = 0; + dir_highlight = 0; + + // Enable rotary encoder interrupts + GIMSK |= (1 << PCIE1); + } +} + +void set_adjust_spool() +{ + if (!spool_attached) + { + return; + } + + // TODO: Clear menu area + highlight = 6; + spool_counting = 0; + state = STATE_ADJUST; +} + +void set_battery_state() +{ + // TODO: Clear menu area + state = STATE_BATTERY; +}