Skip to content

Commit b409732

Browse files
author
George Belmont
committedSep 6, 2019
Added support for KY-040 rotary encoder to replace browse up/down/select buttons; all code
changes were annotated with //ROTARY: for easy review;
1 parent c71fe6e commit b409732

9 files changed

+687
-4
lines changed
 

‎Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
OBJS = armc-start.o armc-cstartup.o armc-cstubs.o armc-cppstubs.o \
22
exception.o main.o rpi-aux.o rpi-i2c.o rpi-mailbox-interface.o rpi-mailbox.o \
3-
rpi-gpio.o rpi-interrupts.o cache.o ff.o interrupt.o Keyboard.o performance.o \
3+
rpi-gpio.o rpi-interrupts.o dmRotary.o cache.o ff.o interrupt.o Keyboard.o performance.o \
44
Drive.o Pi1541.o DiskImage.o iec_bus.o iec_commands.o m6502.o m6522.o \
55
gcr.o prot.o lz.o emmc.o diskio.o options.o Screen.o SSD1306.o ScreenLCD.o \
66
Timer.o FileBrowser.o DiskCaddy.o ROMs.o InputMappings.o xga_font_data.o m8520.o wd177x.o Pi1581.o SpinLock.o

‎options.txt

+21
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,24 @@ GraphIEC = 1
107107
//buttonDown = 3
108108
//buttonBack = 4
109109
//buttonInsert = 5
110+
111+
//ROTARY:
112+
//
113+
// KY-040 Rotary Encoder Support
114+
//
115+
// If you would like to use a KY-040 Rotary Encoder for browse menu up/down
116+
// and select, you can enable it here. Connect as follows:
117+
//
118+
// GPIO 22 - Menu up - Encoder pin A (CLK)
119+
// GPIO 23 - Menu down - Encoder pin B (DT)
120+
// GPIO 27 - Enter/Select - Encoder pushbutton (SW)
121+
//
122+
// ** Using an encoder is incompatible with the button remapping. You must
123+
// use the default values of Enter=1, Up=2, Down=3, Back=4 and Insert=5.
124+
//
125+
// ** This has only been tested using a Raspberry Pi 3. Earlier models may
126+
// or may not work as expected!
127+
//
128+
// Please see dmRotary.h for full implementation details.
129+
//
130+
//RotaryEncoderEnable = 1

‎src/dmRotary.cpp

+285
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
/*
2+
* dmRotary.cpp - A simple decoder to use a KY-040 rotary encoder for browse
3+
* naviation in Pi1541.
4+
*
5+
* Copyright © 2019 devMash.com
6+
*
7+
* https://devMash.com
8+
* https://github.com/devMashHub
9+
*
10+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
11+
* software and associated documentation files (the “Software”), to deal in the Software
12+
* without restriction, including without limitation the rights to use, copy, modify, merge,
13+
* publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
14+
* to whom the Software is furnished to do so, subject to the following conditions:
15+
*
16+
* The above copyright notice and this permission notice shall be included in all copies or
17+
* substantial portions of the Software.
18+
*
19+
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
20+
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21+
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
22+
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24+
* DEALINGS IN THE SOFTWARE.
25+
*
26+
*/
27+
28+
#include "dmRotary.h"
29+
30+
31+
//------------------------------------------------------------------------------
32+
// Initialize
33+
//
34+
void RotaryEncoder::Initialize(rpi_gpio_pin_t clockGpioPin, rpi_gpio_pin_t dataGpioPin, rpi_gpio_pin_t switchGpioPin)
35+
{
36+
37+
#ifdef DM_ROTARY_DEBUG
38+
39+
char message[1024] = "";
40+
41+
WriteToMiniUart("##########\r\n\r\n");
42+
43+
WriteToMiniUart("RotaryEncoder::Initialize()\r\n");
44+
45+
sprintf(message, " clockGpioPin = %d dataGpioPin = %d switchGpioPin = %d\r\n\r\n", clockGpioPin, dataGpioPin, switchGpioPin);
46+
WriteToMiniUart(message);
47+
48+
#endif
49+
50+
//Store specified pins for polling method
51+
_clockPin.SetGpioPin(clockGpioPin);
52+
_dataPin.SetGpioPin(dataGpioPin);
53+
_switchPin.SetGpioPin(switchGpioPin);
54+
55+
//Set pins for input
56+
RPI_SetGpioInput(clockGpioPin);
57+
RPI_SetGpioInput(dataGpioPin);
58+
RPI_SetGpioInput(switchGpioPin);
59+
60+
//Enable pull-ups
61+
unsigned controlSignal = 2;
62+
unsigned gpioPinMask = _clockPin.GetGpioPinMask() | _dataPin.GetGpioPinMask() | _switchPin.GetGpioPinMask();
63+
SetGpioPullUpDown(controlSignal, gpioPinMask);
64+
65+
}
66+
67+
68+
//------------------------------------------------------------------------------
69+
// Poll
70+
//
71+
rotary_result_t RotaryEncoder::Poll()
72+
{
73+
74+
//Read physical pin levels (GPLEV0 is pins 0 to 31)
75+
unsigned gplev0 = read32(ARM_GPIO_GPLEV0);
76+
77+
return Poll(gplev0);
78+
79+
}
80+
81+
//------------------------------------------------------------------------------
82+
// Poll
83+
//
84+
rotary_result_t RotaryEncoder::Poll(unsigned gplev0)
85+
{
86+
87+
rotary_result_t result = NoChange;
88+
89+
#ifdef DM_ROTARY_DEBUG
90+
91+
char message[1024] = "";
92+
93+
#endif
94+
95+
//Decode switch
96+
if (result == NoChange)
97+
{
98+
99+
//Debounce switch and determine state
100+
_switchPin.Update((gplev0 & _switchPin.GetGpioPinMask()) == 0);
101+
bool switchState = _switchPin.GetState();
102+
103+
//Detect switch state change
104+
if (switchState != _currentSwitchState)
105+
{
106+
107+
//Determine result
108+
result = switchState ? ButtonDown : ButtonUp;
109+
110+
//Update switch state
111+
_currentSwitchState = switchState;
112+
113+
}
114+
115+
}
116+
117+
//Decode rotation
118+
if (result == NoChange)
119+
{
120+
121+
//Debounce clock and determine state
122+
_clockPin.Update((gplev0 & _clockPin.GetGpioPinMask()) == 0);
123+
bool clockState = _clockPin.GetState();
124+
125+
//Debounce data and determine state
126+
_dataPin.Update((gplev0 & _dataPin.GetGpioPinMask()) == 0);
127+
bool dataState = _dataPin.GetState();
128+
129+
//Detect rotary state change
130+
int rotaryState = (clockState << 1) | dataState;
131+
if (rotaryState != _currentRotaryState)
132+
{
133+
134+
//Update rotary sequence
135+
_currentRotarySequence = (_currentRotarySequence << 2) | rotaryState;
136+
137+
if (rotaryState == 0)
138+
{
139+
140+
switch (_currentRotarySequence)
141+
{
142+
143+
//Detect positive (clockwise) rotation
144+
//
145+
// 0xb4 - 00 10 11 01 00 - Received and decoded perfect sequence
146+
// 0x2c - 00 10 11 00 - Missed data but decoded unique sequence
147+
// 0x34 - 00 11 01 00 - Missed data but decoded unique sequence
148+
// 0xb8 - 00 10 11 10 00 - Invalid sequence, using best guess
149+
//
150+
case 0xb4:
151+
case 0x2c:
152+
case 0x34:
153+
case 0xb8:
154+
result = RotatePositive;
155+
break;
156+
157+
//Detect negative (counter-clockwise) rotation
158+
//
159+
// 0x78 - 00 01 11 10 00 - Received and decoded perfect sequence
160+
// 0x1c - 00 01 11 00 - Missed data but decoded unique sequence
161+
// 0x38 - 00 11 10 00 - Missed data but decoded unique sequence
162+
// 0x74 - 00 01 11 01 00 - Invalid sequence, using best guess
163+
//
164+
case 0x78:
165+
case 0x1c:
166+
case 0x38:
167+
case 0x74:
168+
result = RotateNegative;
169+
break;
170+
171+
#ifdef DM_ROTARY_DEBUG
172+
173+
//Unable to decode sequence
174+
//
175+
// 0x0c - 00 11 00 - No way to determine rotation direction
176+
//
177+
default:
178+
if (_currentRotarySequence != 0x0c)
179+
{
180+
sprintf(message, "decode failed: %x\r\n", _currentRotarySequence);
181+
WriteToMiniUart(message);
182+
}
183+
break;
184+
185+
#endif
186+
187+
}
188+
189+
//Clear rotary sequence
190+
_currentRotarySequence = 0;
191+
192+
}
193+
194+
//Update rotary state
195+
_currentRotaryState = rotaryState;
196+
197+
}
198+
199+
}
200+
201+
#ifdef DM_ROTARY_DEBUG
202+
203+
switch (result)
204+
{
205+
206+
case NoChange:
207+
break;
208+
209+
case ButtonDown:
210+
WriteToMiniUart("Button Down\r\n");
211+
break;
212+
213+
case ButtonUp:
214+
WriteToMiniUart("Button Up\r\n");
215+
break;
216+
217+
case RotatePositive:
218+
WriteToMiniUart("Clockwise\r\n");
219+
break;
220+
221+
case RotateNegative:
222+
WriteToMiniUart("Counter-Clockwise\r\n");
223+
break;
224+
225+
}
226+
227+
#endif
228+
229+
return result;
230+
231+
}
232+
233+
234+
//------------------------------------------------------------------------------
235+
// SetGpioPullUpDown
236+
//
237+
void RotaryEncoder::SetGpioPullUpDown(unsigned controlSignal, unsigned gpioPinMask)
238+
{
239+
240+
volatile int i;
241+
int delayCycles = 150;
242+
243+
// Write to GPPUD to set the required control signal
244+
//
245+
// 01 = Enable Pull-Down 00 = Off (disable pull-up/down)
246+
// 10 = Enable Pull-Up 11 = Reserved
247+
//
248+
write32(ARM_GPIO_GPPUD, controlSignal);
249+
250+
// Delay cycles (to provide the required set-up time for the control signal)
251+
for (i = 0; i < delayCycles; i++) { }
252+
253+
// Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads
254+
//
255+
// Note: Only the pads which receive a clock will be modified, all others will
256+
// retain their previous state.
257+
//
258+
write32(ARM_GPIO_GPPUDCLK0, gpioPinMask);
259+
260+
// Delay cycles (to provide the required hold time for the control signal)
261+
for (i = 0; i < delayCycles; i++) { }
262+
263+
// Write to GPPUD to remove the control signal
264+
write32(ARM_GPIO_GPPUD, 0);
265+
266+
//Write to GPPUDCLK0/1 to remove the clock
267+
write32(ARM_GPIO_GPPUDCLK0, 0);
268+
269+
}
270+
271+
272+
#ifdef DM_ROTARY_DEBUG
273+
274+
//------------------------------------------------------------------------------
275+
// WriteToMiniUart
276+
//
277+
void RotaryEncoder::WriteToMiniUart(char* pMessage)
278+
{
279+
while(*pMessage)
280+
{
281+
RPI_AuxMiniUartWrite(*pMessage++);
282+
}
283+
}
284+
285+
#endif

‎src/dmRotary.h

+250
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
/*
2+
* dmRrotary.h - A simple decoder to use a KY-040 rotary encoder for browse
3+
* naviation in Pi1541.
4+
*
5+
* Copyright © 2019 devMash.com
6+
*
7+
* https://devMash.com
8+
* https://github.com/devMashHub
9+
*
10+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
11+
* software and associated documentation files (the “Software”), to deal in the Software
12+
* without restriction, including without limitation the rights to use, copy, modify, merge,
13+
* publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
14+
* to whom the Software is furnished to do so, subject to the following conditions:
15+
*
16+
* The above copyright notice and this permission notice shall be included in all copies or
17+
* substantial portions of the Software.
18+
*
19+
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
20+
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21+
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
22+
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24+
* DEALINGS IN THE SOFTWARE.
25+
*
26+
*/
27+
28+
#ifndef DM_ROTARY_H
29+
#define DM_ROTARY_H
30+
31+
extern "C"
32+
{
33+
#include "rpi-aux.h"
34+
#include "rpiHardware.h"
35+
}
36+
37+
//Enable debugging messages on the mini uart
38+
//#define DM_ROTARY_DEBUG
39+
40+
41+
//------------------------------------------------------------------------------
42+
// rotary_result_t
43+
//
44+
typedef enum {
45+
NoChange = 0,
46+
ButtonDown = 1,
47+
ButtonUp = 2,
48+
RotatePositive = 3, // clockwise rotation
49+
RotateNegative = 4 // counter-clockwise rotation
50+
} rotary_result_t;
51+
52+
53+
//------------------------------------------------------------------------------
54+
// RotaryPin
55+
//
56+
// NOTES:
57+
//
58+
// This helper class represents a single rotary encoder pin to encapsulate
59+
// debouncing and state engine logic.
60+
//
61+
class RotaryPin
62+
{
63+
64+
private:
65+
66+
rpi_gpio_pin_t _gpioPin = RPI_GPIO0;
67+
68+
int _count = 0;
69+
int _threshold = 256; // I just like powers of two
70+
71+
bool _currentState = false;
72+
73+
public:
74+
75+
rpi_gpio_pin_t GetGpioPin() const { return _gpioPin; }
76+
void SetGpioPin(rpi_gpio_pin_t value) { _gpioPin = value; }
77+
78+
unsigned GetGpioPinMask() { return (1 << _gpioPin); }
79+
80+
bool GetState() const { return _currentState; }
81+
82+
void Update(bool state)
83+
{
84+
85+
_count += state ? 1 : -1;
86+
87+
bool newState = _currentState;
88+
89+
if (_count <= 0)
90+
{
91+
_count = 0;
92+
newState = false;
93+
}
94+
else if (_count >= _threshold)
95+
{
96+
_count = _threshold;
97+
newState = true;
98+
}
99+
100+
_currentState = newState;
101+
102+
}
103+
104+
};
105+
106+
107+
//------------------------------------------------------------------------------
108+
// RotaryEncoder
109+
//
110+
// NOTES:
111+
//
112+
// The KY-040 rotary encoder has the following pins:
113+
//
114+
// CLK - Encoder pin A
115+
// DT - Encoder pin B
116+
// SW - Pushbutton switch
117+
// VCC - Supply voltage
118+
// GND - Ground
119+
//
120+
//
121+
// Decoding the KY-040
122+
//
123+
// Determining which encoder pin changes state first is how the direction
124+
// of rotation is determined. If CLK changes state first, the encoder
125+
// is rotating in a positive (clockwise) direction. If DT changes state
126+
// first, the encoder is rotating in a negative (counter-clockwise) direction.
127+
//
128+
// The entire rotation sequence can be represented as a predictable bit
129+
// pattern by mapping the CLK state in the higher bit and mapping the DT
130+
// state in the lower bit:
131+
//
132+
// Positive rotation - 00 -> 10 -> 11 -> 01 -> 00 (0xb4)
133+
// Negative rotation - 00 -> 01 -> 11 -> 10 -> 00 (0x78)
134+
//
135+
// To decode, we simply monitor the CLK and DT and watch for one of these
136+
// two patterns.
137+
//
138+
// However, in the real world, some pin transitions can be missed due to
139+
// lag during the polling interval or contact bounce - resulting in less
140+
// than perfect decode sequences. To combat against this, the code will
141+
// also accept several permutations that are 'close enough':
142+
//
143+
// Positive (clockwise) rotation:
144+
//
145+
// 0xb4 - 00 10 11 01 00 - Received and decoded perfect sequence
146+
// 0x2c - 00 10 11 00 - Missed data but decoded unique sequence
147+
// 0x34 - 00 11 01 00 - Missed data but decoded unique sequence
148+
// 0xb8 - 00 10 11 10 00 - Invalid but usually denotes positive
149+
//
150+
// Detect negative (counter-clockwise) rotation:
151+
//
152+
// 0x78 - 00 01 11 10 00 - Received and decoded perfect sequence
153+
// 0x1c - 00 01 11 00 - Missed data but decoded unique sequence
154+
// 0x38 - 00 11 10 00 - Missed data but decoded unique sequence
155+
// 0x74 - 00 01 11 01 00 - Invalid but usually denotes negative
156+
//
157+
//
158+
// Wiring the KY-040
159+
//
160+
// The GPIO pins used for the rotary encoder are specified when initializing
161+
// the class. However, it is probably a good idea to reuse the same pins as
162+
// the original Pi1541 pushbuttons:
163+
//
164+
// GPIO 22 - Menu up - Encoder pin A (CLK)
165+
// GPIO 23 - Menu down - Encoder pin B (DT)
166+
// GPIO 27 - Enter/Select - Encoder pushbutton (SW)
167+
//
168+
//
169+
// USAGE:
170+
//
171+
// *** Please Note! I have only tried this with a Raspberry Pi 3. I have no
172+
// reason to believe this wouldn't also work on an earlier model, but your
173+
// results may vary!
174+
//
175+
// To use the RotaryEncoder, instance the class and initialize with the desired
176+
// GPIO pins like this:
177+
//
178+
// //Initialize using CLK on GPIO22, DT on GPIO32 and SW on GPIO27
179+
// RotaryEncoder rotaryEncoder;
180+
// rotaryEncoder.Initialize(RPI_GPIO22, RPI_GPIO23, RPI_GPIO27);
181+
//
182+
// Monitor the encoder by calling the Poll() method during your main processing
183+
// loop. The polling logic is constrained by only evaluating GPLEV0, which
184+
// restricts usable pins to GPIO00 through GPIO31. An overloaded version of
185+
// Poll() exists to accept a value representing GPLEV0 without having to
186+
// perform a re-read (providing a small optimization when the current value of
187+
// GPLEV0 is already available).
188+
//
189+
// // Read GPLEV0 and decode the rotary state
190+
// rotary_result_t result = rotaryEncoder.Poll();
191+
//
192+
// or
193+
//
194+
// // Read GPLEV0 locally and decode the rotary state
195+
// unsigned gplev0 = read32(ARM_GPIO_GPLEV0);
196+
// { some other logic here }
197+
// rotary_result_t result = rotaryEncoder.Poll(gplev0);
198+
//
199+
// Note, the Poll() logic depends on frequent polling of the encoder. Calling
200+
// Poll() as often as possible/permissable will yield better decode results.
201+
//
202+
// Any event detected by the polling logic will be returned as the result
203+
// from the polling method as a rotary_result_t. The controlling logic can
204+
// then take whatever action is appropriate based on the result.
205+
//
206+
//
207+
// HISTORY:
208+
//
209+
// 09/03/2019 - Initial implementation and notes
210+
// 09/04/2019 - Integration into Pi1541 with shim logic to simulate 'original style' button presses
211+
// 09/05/2019 - Code cleanup, improved documentation, options.txt logic, dynamic button indexes
212+
//
213+
class RotaryEncoder {
214+
215+
private:
216+
217+
// Switch data
218+
219+
RotaryPin _switchPin;
220+
221+
bool _currentSwitchState = false;
222+
223+
// Rotation data
224+
225+
RotaryPin _clockPin;
226+
RotaryPin _dataPin;
227+
228+
int _currentRotaryState = 0;
229+
int _currentRotarySequence = 0;
230+
231+
// Private methods
232+
233+
void SetGpioPullUpDown(unsigned controlSignal, unsigned gpioPinMask);
234+
235+
#ifdef DM_ROTARY_DEBUG
236+
void WriteToMiniUart(char* pMessage);
237+
#endif
238+
239+
public:
240+
241+
// Public methods
242+
243+
void Initialize(rpi_gpio_pin_t clkGpioPin, rpi_gpio_pin_t dtGpioPin, rpi_gpio_pin_t swGpioPin);
244+
245+
rotary_result_t Poll();
246+
rotary_result_t Poll(unsigned gplev0);
247+
248+
};
249+
250+
#endif

‎src/iec_bus.cpp

+56-3
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,68 @@ u32 IEC_Bus::emulationModeCheckButtonIndex = 0;
7373

7474
unsigned IEC_Bus::gplev0;
7575

76+
//ROTARY: Added for rotary encoder support - 09/05/2019 by Geo...
77+
RotaryEncoder IEC_Bus::rotaryEncoder;
78+
bool IEC_Bus::rotaryEncoderEnable;
7679

80+
//ROTARY: Modified for rotary encoder support - 09/05/2019 by Geo...
7781
void IEC_Bus::ReadBrowseMode(void)
7882
{
7983
gplev0 = read32(ARM_GPIO_GPLEV0);
8084

81-
int index;
82-
for (index = 0; index < buttonCount; ++index)
85+
if (IEC_Bus::rotaryEncoderEnable == true)
8386
{
84-
UpdateButton(index, gplev0);
87+
88+
int indexEnter = 0;
89+
int indexUp = 1;
90+
int indexDown = 2;
91+
int indexBack = 3;
92+
int indexInsert = 4;
93+
94+
//Poll the rotary encoder
95+
//
96+
// Note: If the rotary encoder returns any value other than 'NoChange' an
97+
// event has been detected. We force the button state of the original
98+
// input button registers to reflect the desired action, and allow the
99+
// original processing logic to do it's work.
100+
//
101+
rotary_result_t rotaryResult = IEC_Bus::rotaryEncoder.Poll(gplev0);
102+
switch (rotaryResult)
103+
{
104+
105+
case ButtonDown:
106+
SetButtonState(indexEnter, true);
107+
break;
108+
109+
case RotateNegative:
110+
SetButtonState(indexUp, true);
111+
break;
112+
113+
case RotatePositive:
114+
SetButtonState(indexDown, true);
115+
break;
116+
117+
default:
118+
SetButtonState(indexEnter, false);
119+
SetButtonState(indexUp, false);
120+
SetButtonState(indexDown, false);
121+
break;
122+
123+
}
124+
125+
UpdateButton(indexBack, gplev0);
126+
UpdateButton(indexInsert, gplev0);
127+
128+
}
129+
else // Unmolested original logic
130+
{
131+
132+
int index;
133+
for (index = 0; index < buttonCount; ++index)
134+
{
135+
UpdateButton(index, gplev0);
136+
}
137+
85138
}
86139

87140
bool ATNIn = (gplev0 & PIGPIO_MASK_IN_ATN) == (invertIECInputs ? PIGPIO_MASK_IN_ATN : 0);

‎src/iec_bus.h

+62
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
#include "rpi-gpio.h"
2727
#include "rpiHardware.h"
2828

29+
//ROTARY: Added for rotary encoder support - 09/05/2019 by Geo...
30+
#include "dmRotary.h"
31+
2932
#define INPUT_BUTTON_DEBOUNCE_THRESHOLD 20000
3033
#define INPUT_BUTTON_REPEAT_THRESHOLD 460000
3134

@@ -308,6 +311,13 @@ class IEC_Bus
308311
}
309312
RPI_GpioBase->GPPUD = 0;
310313
RPI_GpioBase->GPPUDCLK0 = 0;
314+
315+
//ROTARY: Added for rotary encoder support - 09/05/2019 by Geo...
316+
if (IEC_Bus::rotaryEncoderEnable == true)
317+
{
318+
IEC_Bus::rotaryEncoder.Initialize(RPI_GPIO22, RPI_GPIO23, RPI_GPIO27);
319+
}
320+
311321
}
312322

313323
static inline void LetSRQBePulledHigh()
@@ -349,6 +359,47 @@ class IEC_Bus
349359
}
350360
}
351361

362+
363+
//ROTARY: Added for rotary encoder support - 09/05/2019 by Geo...
364+
//
365+
// Note: This method serves as a shim to allow the rotary encoder
366+
// logic to set a specific input button state (fooling the
367+
// original logic into thinking a button was pressed or
368+
// released).
369+
//
370+
static inline void SetButtonState(int index, bool state)
371+
{
372+
373+
InputButtonPrev[index] = InputButton[index];
374+
inputRepeatPrev[index] = inputRepeat[index];
375+
376+
if (state == true)
377+
{
378+
379+
InputButton[index] = true;
380+
validInputCount[index] = INPUT_BUTTON_DEBOUNCE_THRESHOLD;
381+
inputRepeatThreshold[index] = INPUT_BUTTON_DEBOUNCE_THRESHOLD + INPUT_BUTTON_REPEAT_THRESHOLD;
382+
inputRepeat[index]++;
383+
384+
validInputCount[index] = inputRepeatThreshold[index];
385+
inputRepeat[index]++;
386+
inputRepeatThreshold[index] += INPUT_BUTTON_REPEAT_THRESHOLD / inputRepeat[index];
387+
388+
}
389+
else
390+
{
391+
392+
InputButton[index] = false;
393+
validInputCount[index] = 0;
394+
inputRepeatThreshold[index] = INPUT_BUTTON_REPEAT_THRESHOLD;
395+
inputRepeat[index] = 0;
396+
inputRepeatPrev[index] = 0;
397+
398+
}
399+
400+
}
401+
402+
352403
static void ReadBrowseMode(void);
353404
static void ReadEmulationMode1541(void);
354405
static void ReadButtonsEmulationMode(void);
@@ -544,6 +595,12 @@ class IEC_Bus
544595
ignoreReset = value;
545596
}
546597

598+
//ROTARY: Added for rotary encoder support - 09/05/2019 by Geo...
599+
static inline void SetRotaryEncoderEnable(bool value)
600+
{
601+
rotaryEncoderEnable = value;
602+
}
603+
547604
// CA1 input ATN
548605
// If CA1 is ever set to output
549606
// - CA1 will start to drive pb7
@@ -607,5 +664,10 @@ class IEC_Bus
607664
static u32 inputRepeatThreshold[5];
608665
static u32 inputRepeat[5];
609666
static u32 inputRepeatPrev[5];
667+
668+
//ROTARY: Added for rotary encoder support - 09/05/2019 by Geo...
669+
static RotaryEncoder rotaryEncoder;
670+
static bool rotaryEncoderEnable;
671+
610672
};
611673
#endif

‎src/main.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -1763,6 +1763,9 @@ extern "C"
17631763
IEC_Bus::SetInvertIECOutputs(options.InvertIECOutputs());
17641764
IEC_Bus::SetIgnoreReset(options.IgnoreReset());
17651765

1766+
//ROTARY: Added for rotary encoder support - 09/05/2019 by Geo...
1767+
IEC_Bus::SetRotaryEncoderEnable(options.RotaryEncoderEnable());
1768+
17661769
if (!options.SoundOnGPIO())
17671770
{
17681771
dmaSound = (u32*)malloc(Sample_bin_size * 4);

‎src/options.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ Options::Options(void)
156156
, buttonDown(3)
157157
, buttonBack(4)
158158
, buttonInsert(5)
159+
, rotaryEncoderEnable(0) //ROTARY:
159160

160161
{
161162
autoMountImageName[0] = 0;
@@ -245,6 +246,7 @@ void Options::Process(char* buffer)
245246
ELSE_CHECK_DECIMAL_OPTION(buttonDown)
246247
ELSE_CHECK_DECIMAL_OPTION(buttonBack)
247248
ELSE_CHECK_DECIMAL_OPTION(buttonInsert)
249+
ELSE_CHECK_DECIMAL_OPTION(rotaryEncoderEnable) //ROTARY:
248250
else if ((strcasecmp(pOption, "AutoBaseName") == 0))
249251
{
250252
strncpy(autoBaseName, pValue, 255);

‎src/options.h

+7
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ class Options : public TextParser
100100
inline unsigned int GetButtonBack() const { return buttonBack - 1; }
101101
inline unsigned int GetButtonInsert() const { return buttonInsert - 1; }
102102

103+
//ROTARY: Added for rotary encoder support - 09/05/2019 by Geo...
104+
inline unsigned int RotaryEncoderEnable() const { return rotaryEncoderEnable; }
105+
103106
// Page up and down will jump a different amount based on the maximum number rows displayed.
104107
// Perhaps we should use some keyboard modifier to the the other screen?
105108
inline unsigned int KeyboardBrowseLCDScreen() const { return keyboardBrowseLCDScreen; }
@@ -175,5 +178,9 @@ class Options : public TextParser
175178
char ROMName1581[256];
176179

177180
char newDiskType[32];
181+
182+
//ROTARY: Added for rotary encoder support - 09/05/2019 by Geo...
183+
unsigned int rotaryEncoderEnable;
184+
178185
};
179186
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.