diff --git a/lua_modules/joystick/joystick.lua b/lua_modules/joystick/joystick.lua new file mode 100644 index 0000000000..bf134c3eb3 --- /dev/null +++ b/lua_modules/joystick/joystick.lua @@ -0,0 +1,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 + + + \ No newline at end of file diff --git a/lua_modules/joystick/joystick_test.lua b/lua_modules/joystick/joystick_test.lua new file mode 100644 index 0000000000..c2edde47d8 --- /dev/null +++ b/lua_modules/joystick/joystick_test.lua @@ -0,0 +1,44 @@ +-- 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. +-- +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() +