-
Notifications
You must be signed in to change notification settings - Fork 3.1k
/
Copy pathjoystick.lua
256 lines (218 loc) · 6.3 KB
/
joystick.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
-- ChiliPeppr Joystick controller
-- Used to control analog joysticks that are implemented just using
-- variable resistors where you feed in 3.3v and get out a variable voltage
-- based on position of the joystick. Joysticks like the Playstation portable
-- or Xbox joysticks work this way and are readily available on Amazon, Ebay,
-- or Aliexpress.
--
-- Working example of using this library:
-- https://www.youtube.com/watch?v=ITgh5epyPRk
--
-- Visit http://chilipeppr.com/esp32
-- By John Lauer
--
-- There is no license needed to use/modify this software. It is given freely
-- to the open source community. Modify at will.
--
-- To use:
-- joystick = require("joystick")
-- joystick.on("xy", function(x, y)
-- print("Got xy change. x:", x, "y:", y)
-- end)
-- joystick.on("x", function(x)
-- print("Got x change. x:", x)
-- end)
-- joystick.on("y", function(y)
-- print("Got y change. y:", y)
-- end)
-- joystick.on("xcenter", function()
-- print("Got x center")
-- end)
-- joystick.on("ycenter", function()
-- print("Got y center")
-- end)
-- joystick.on("button", function(val)
-- print("Got button:", val)
-- end)
-- joystick.init()
-- For test/debug
-- if m.tmr then m.tmr:stop(); m.tmr:unregister() end
local m = {}
-- m = {}
m.pinAdcX = 6 -- ADC 6: GPIO34
-- m.pinAdcY = 3 -- ADC 3: GPIO39
-- m.pinAdcY = 7 -- ADC 7: GPIO35
m.pinAdcY = 5 -- ADC 5: GPIO33
-- m.pinSwitch = 18
m.pinSwitch = 32
-- For TTGO
-- m.centerX = 1850
-- m.centerXMin = 1800
-- m.centerXMax = 1915
-- m.centerY = 1850
-- m.centerYMin = 1800
-- m.centerYMax = 1915
-- For Wemos battery powered
m.centerX = 1800
m.centerXMin = 1700
m.centerXMax = 1870
m.centerY = 1800
m.centerYMin = 1700
m.centerYMax = 1870
m.isInitted = false
m.tmr = tmr.create()
---
-- @name init
-- @description Call this first to setup your ADC ports and button port. You
-- need to connect X to ADC 6: GPIO34, Y to ADC5: GPIO33, and the button to GPIO32.
-- If you need to use alternate ports you should change the code in joystick.lua.
-- Also, 11db attenuation is turned on by default because it is the best
-- performance for analog joysticks. If you are finding a broader range of voltage
-- is coming back from your joystick, adjust the attenuation in the init() method.
-- @returns nil
function m.init()
if m.isInitted then
return
end
print("Initting joystick pins. X: " .. m.pinAdcX .. ", Y: " .. m.pinAdcY .. ", Switch: " .. m.pinSwitch)
-- Initialise the pins
gpio.config( { gpio=m.pinSwitch, dir=gpio.IN, pull=gpio.PULL_UP } )
m.startSwitchInterrupt()
-- adc.setwidth(adc.ADC1, 9) -- read 9 bit on ADC
adc.setwidth(adc.ADC1, 12) -- read 12 bit on ADC
adc.setup(adc.ADC1, m.pinAdcX, adc.ATTEN_11db )
adc.setup(adc.ADC1, m.pinAdcY, adc.ATTEN_11db )
m.tmr:alarm(250, tmr.ALARM_AUTO, function()
m.readXY()
-- m.readY()
-- m.readX()
end)
m.isInitted = true
end
m.onX = nil
m.onXCenter = nil
m.onY = nil
m.onYCenter = nil
m.onXY = nil
m.onButton = nil
---
-- @name on
-- @description Attach to the callback events available from this joystick library
-- @param event_name A string of the event you want a callback on. "x", "y", "xy", "xcenter", "ycenter", "button"
-- @param func The callback to receive after the event
-- @returns nil
function m.on(event_name, func)
if event_name == "x" then
m.onX = func
elseif event_name == "xcenter" then
m.onXCenter = func
elseif event_name == "y" then
m.onY = func
elseif event_name == "ycenter" then
m.onYCenter = func
elseif event_name == "xy" then
m.onXY = func
elseif event_name == "button" then
m.onButton = func
end
end
m.lastX = 0
function m.readX()
local val = adc.read(adc.ADC1, m.pinAdcX)
if m.lastX == val then return end
m.lastX = val
print("X: " .. val)
if m.onX then m.onX(val) end
end
m.lastY = 0
function m.readY()
local val = adc.read(adc.ADC1, m.pinAdcY)
if m.lastY == val then return end
m.lastY = val
print("Y: " .. val)
if m.onY then m.onY(val) end
end
m.lastXWasCenter = true
m.lastYWasCenter = true
function m.readXY()
local valX = adc.read(adc.ADC1, m.pinAdcX)
local valY = adc.read(adc.ADC1, m.pinAdcY)
-- if x or y is new value then send xy update
local isXYUpdated = false
-- do some level setting for center point
if valX >= m.centerXMin and valX <= m.centerXMax then
-- consider it a center point
-- valX = m.centerX
-- see if last X was center, and if so ignore
if m.lastXWasCenter then
-- do nothing
else
-- last x was not center, so fire off event
m.lastXWasCenter = true
if m.onXCenter then
node.task.post(node.task.LOW_PRIORITY, function()
m.onXCenter(m.centerX)
end)
end
end
else
-- x is not on center, so fire event
m.lastXWasCenter = false
isXYUpdated = true
if m.onX then
node.task.post(node.task.LOW_PRIORITY, function()
m.onX(valX)
end)
end
end
if valY >= m.centerYMin and valY <= m.centerYMax then
-- consider it a center point
-- valY = m.centerY
-- see if last Y was center, and if so ignore
if m.lastYWasCenter then
-- do nothing
else
-- last x was not center, so fire off event
m.lastYWasCenter = true
if m.onYCenter then
node.task.post(node.task.LOW_PRIORITY, function()
m.onYCenter(m.centerY)
end)
end
end
else
-- y is not on center, so fire event
m.lastYWasCenter = false
isXYUpdated = true
if m.onY then
node.task.post(node.task.LOW_PRIORITY, function()
m.onY(valY)
end)
end
end
if isXYUpdated then
if m.onXY then
node.task.post(node.task.LOW_PRIORITY, function()
m.onXY(valX, valY)
end)
end
end
-- print("X: " .. valX .. ", Y: " .. valY)
end
function m.readSwitch()
local val = gpio.read(m.pinSwitch)
print("Switch: ", val)
if m.onButton then m.onButton(val) end
end
function m.startSwitchInterrupt()
gpio.trig(m.pinSwitch, gpio.INTR_UP_DOWN, m.onSwitchInterrupt)
print("Set interrupt for switch.")
end
m.lastSwitchVal = 0
function m.onSwitchInterrupt(pin, level)
if level == m.lastSwitchVal then return end
m.lastSwitchVal = level
print("Got switch interrupt. pin: ", pin, ", level: ", level)
end
-- m.init()
return m