Added state changing, counting and setting. Updated TODO

This commit is contained in:
nedko 2022-10-28 17:36:19 +03:00
parent dc94dcc940
commit 0f7d7c8a69
2 changed files with 485 additions and 254 deletions

4
TODO
View File

@ -1,5 +1,7 @@
--- main.c ---
fix main()
Menu printing
Battery printing
Battery icon
--- Menu ---
Attach - Attempt to attach spool

View File

@ -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;
}