coding it as an explicit FSM would be pretty ugly (16 states, three transitions out of each state).
Here would be one implementation:
static uint8_t enc_states=0; //encoder states: AB_prev..AB_now, lowest four bits effective
enc_states <<=2; //left shift previous states
enc_states |= (IO_GET(ENCA_PORT, ENC_CHA)?0x02:0x00) | (IO_GET(ENCB_PORT, ENC_CHB)?0x01:0x00); //read current encoder pin states
return enc_outcome[enc_states & 0x0f]; //return encoder output from a look-up table, lowest four bits effective
If you want, you can actually write it out on a single return line - not terribly readable but 100% functional.
Ah... you are missing the important bit. The output is based on the last two
transitions, not the last two
readings.
Say on a click to the left you add 1 to a counter, and on the click to the right you take 2 off the counter..
Here is the data for two clicks to the left, with a bit of switch bounce on the first transition ("00" => "01")
...."00", "01","00","01","00", 01","00","01","11","11"...
If you base it on the last two reading, because of the bounce in the middle you get +1, -2, +1, -2,+1, -2, +1, +1, a total of -1.
Change input last output
1: 01 00 +1
2: 00 01 -2
3: 01 00 +1
4: 00 01 -2
5: 01 00 +1
6: 00 01 -2
7: 01 00 +1
8: 11 01 +1
7: 11 11 0
If you base your on the last two transitions you get a reliable output - when you get two "click to the right" or "click to the left" in a row, only then do you act on it.
Change input prior_values transitions output
1: 01 00 01 L R 0
2: 00 01 00 R L 0
3: 01 00 01 L R 0
4: 00 01 00 R L 0
5: 01 00 01 L R 0
6: 00 01 00 R L 0
7: 01 00 01 L R 0
8: 11 01 00 R R +1
In my case I was "zoom <= zoom * 3/4" one way, and "zoom <= zoom * 5/4", with my problem being that "(3*5)/(4*4) = 15/16, 15/16 != 1", so switch bounce in the encoder would show up as a visible jump in the zooming.