Skip to content

Commit 63eae2b

Browse files
committed
parts: add rotary encoder part
Add a rotary encoder virtual part, based on the Panasonic EVEP rotary encoder. This could easily be extended to virtualise other rotary encoders.
1 parent 5669a06 commit 63eae2b

File tree

2 files changed

+244
-0
lines changed

2 files changed

+244
-0
lines changed

examples/parts/rotenc.c

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
rotenc.c
3+
4+
Copyright 2018 Doug Szumski <d.s.szumski@gmail.com>
5+
6+
This file is part of simavr.
7+
8+
simavr is free software: you can redistribute it and/or modify
9+
it under the terms of the GNU General Public License as published by
10+
the Free Software Foundation, either version 3 of the License, or
11+
(at your option) any later version.
12+
13+
simavr is distributed in the hope that it will be useful,
14+
but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
GNU General Public License for more details.
17+
18+
You should have received a copy of the GNU General Public License
19+
along with simavr. If not, see <http://www.gnu.org/licenses/>.
20+
*/
21+
22+
#include <stdlib.h>
23+
#include <stdio.h>
24+
#include <string.h>
25+
26+
#include "sim_avr.h"
27+
#include "rotenc.h"
28+
29+
const rotenc_pins_t state_table[ROTENC_STATE_COUNT] = {
30+
{ 0, 0 },
31+
{ 1, 0 },
32+
{ 1, 1 },
33+
{ 0, 1 }
34+
};
35+
36+
static avr_cycle_count_t
37+
rotenc_state_change(
38+
avr_t * avr,
39+
avr_cycle_count_t when,
40+
void * param)
41+
{
42+
rotenc_t * rotenc = (rotenc_t *) param;
43+
44+
switch (rotenc->direction) {
45+
case ROTENC_CW_CLICK:
46+
// Advance phase forwards
47+
if (++rotenc->phase >= ROTENC_STATE_COUNT) {
48+
rotenc->phase = 0;
49+
}
50+
if (rotenc->verbose) {
51+
printf("ROTENC: CW twist, pins A:%x, B:%x\n",
52+
state_table[rotenc->phase].a_pin,
53+
state_table[rotenc->phase].b_pin);
54+
}
55+
break;
56+
case ROTENC_CCW_CLICK:
57+
// Advance phase backwards
58+
if (--rotenc->phase < 0) {
59+
rotenc->phase = ROTENC_STATE_COUNT - 1;
60+
}
61+
if (rotenc->verbose) {
62+
printf("ROTENC: CCW twist, pins: A:%x, B:%x\n",
63+
state_table[rotenc->phase].a_pin,
64+
state_table[rotenc->phase].b_pin);
65+
}
66+
break;
67+
default:
68+
// Invalid direction
69+
break;
70+
}
71+
avr_raise_irq(
72+
rotenc->irq + IRQ_ROTENC_OUT_A_PIN,
73+
state_table[rotenc->phase].a_pin);
74+
avr_raise_irq(
75+
rotenc->irq + IRQ_ROTENC_OUT_B_PIN,
76+
state_table[rotenc->phase].b_pin);
77+
return 0;
78+
}
79+
80+
/*
81+
* This function exists purely as a wrapper so that the first state change
82+
* doesn't get cancelled when it's registered with the cycle timer.
83+
*/
84+
static avr_cycle_count_t
85+
rotenc_second_state_change(
86+
avr_t * avr,
87+
avr_cycle_count_t when,
88+
void * param)
89+
{
90+
return rotenc_state_change(avr, when, param);
91+
}
92+
93+
static avr_cycle_count_t
94+
rotenc_button_auto_release(
95+
avr_t * avr,
96+
avr_cycle_count_t when,
97+
void * param)
98+
{
99+
rotenc_t * rotenc = (rotenc_t *) param;
100+
avr_raise_irq(rotenc->irq + IRQ_ROTENC_OUT_BUTTON_PIN, 1);
101+
if (rotenc->verbose) {
102+
printf("ROTENC: Button release\n");
103+
}
104+
return 0;
105+
}
106+
107+
void
108+
rotenc_button_press(rotenc_t * rotenc)
109+
{
110+
// Press down
111+
if (rotenc->verbose) {
112+
printf("ROTENC: Button press\n");
113+
}
114+
avr_raise_irq(rotenc->irq + IRQ_ROTENC_OUT_BUTTON_PIN, 0);
115+
116+
// Pull up later
117+
avr_cycle_timer_register_usec(
118+
rotenc->avr,
119+
ROTENC_BUTTON_DURATION_US,
120+
rotenc_button_auto_release,
121+
rotenc);
122+
}
123+
124+
/*
125+
* Simulates one "click" of the rotary encoder.
126+
*/
127+
void
128+
rotenc_twist(
129+
rotenc_t * rotenc,
130+
rotenc_twist_t direction)
131+
{
132+
rotenc->direction = direction;
133+
134+
// Half way to detent
135+
avr_cycle_timer_register_usec(
136+
rotenc->avr,
137+
ROTENC_CLICK_DURATION_US/2,
138+
rotenc_state_change,
139+
rotenc);
140+
141+
// Detent point, 'click'
142+
avr_cycle_timer_register_usec(
143+
rotenc->avr,
144+
ROTENC_CLICK_DURATION_US,
145+
rotenc_second_state_change,
146+
rotenc);
147+
}
148+
149+
static const char * _rotenc_irq_names[IRQ_ROTENC_COUNT] = {
150+
[IRQ_ROTENC_OUT_A_PIN] = ">rotenc_a_pin.out",
151+
[IRQ_ROTENC_OUT_B_PIN] = ">rotenc_b_pin.out",
152+
[IRQ_ROTENC_OUT_BUTTON_PIN] = ">rotenc_button_pin.out",
153+
};
154+
155+
void
156+
rotenc_init(
157+
avr_t *avr,
158+
rotenc_t * rotenc)
159+
{
160+
memset(rotenc, 0, sizeof(*rotenc));
161+
162+
rotenc->irq = avr_alloc_irq(
163+
&avr->irq_pool,
164+
0,
165+
IRQ_ROTENC_COUNT,
166+
_rotenc_irq_names);
167+
rotenc->avr = avr;
168+
}
169+

examples/parts/rotenc.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
rotenc.h
3+
4+
Copyright 2018 Doug Szumski <d.s.szumski@gmail.com>
5+
6+
This file is part of simavr.
7+
8+
simavr is free software: you can redistribute it and/or modify
9+
it under the terms of the GNU General Public License as published by
10+
the Free Software Foundation, either version 3 of the License, or
11+
(at your option) any later version.
12+
13+
simavr is distributed in the hope that it will be useful,
14+
but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
GNU General Public License for more details.
17+
18+
You should have received a copy of the GNU General Public License
19+
along with simavr. If not, see <http://www.gnu.org/licenses/>.
20+
*/
21+
22+
/*
23+
This 'part' is based on a Panasonic EVEP rotary encoder with a push
24+
button. It could easily be extended to support modelling other
25+
rotary encoders.
26+
*/
27+
28+
#ifndef __ROTENC_H__
29+
#define __ROTENC_H__
30+
31+
#include "rotenc.h"
32+
33+
#define ROTENC_CLICK_DURATION_US 100000UL
34+
#define ROTENC_BUTTON_DURATION_US 100000UL
35+
#define ROTENC_STATE_COUNT 4
36+
37+
typedef enum {
38+
ROTENC_CW_CLICK = 0,
39+
ROTENC_CCW_CLICK
40+
} rotenc_twist_t;
41+
42+
typedef struct rotenc_pin_state_t {
43+
uint8_t a_pin;
44+
uint8_t b_pin;
45+
} rotenc_pins_t;
46+
47+
enum {
48+
IRQ_ROTENC_OUT_A_PIN = 0,
49+
IRQ_ROTENC_OUT_B_PIN,
50+
IRQ_ROTENC_OUT_BUTTON_PIN,
51+
IRQ_ROTENC_COUNT
52+
};
53+
54+
typedef struct rotenc_t {
55+
avr_irq_t * irq; // output irq
56+
struct avr_t * avr;
57+
uint8_t verbose;
58+
rotenc_twist_t direction;
59+
int phase; // current position
60+
} rotenc_t;
61+
62+
void
63+
rotenc_init(
64+
struct avr_t * avr,
65+
rotenc_t * rotenc);
66+
67+
void
68+
rotenc_twist(
69+
rotenc_t * rotenc,
70+
rotenc_twist_t direction);
71+
72+
void
73+
rotenc_button_press(rotenc_t * rotenc);
74+
75+
#endif /* __ROTENC_H__*/

0 commit comments

Comments
 (0)