Browse Source

MCP23017 module refactorings to save some heap (#3317)

* mcp23017: functions to metatable

Avoids closures for each module.

* mcp23017: inline constants

Saves nearly half a kilobyte of heap.
Nathaniel Wesley Filardo 3 years ago
parent
commit
0cafaca4cb
1 changed files with 87 additions and 117 deletions
  1. 87 117
      lua_modules/mcp23017/mcp23017.lua

+ 87 - 117
lua_modules/mcp23017/mcp23017.lua

@@ -1,62 +1,40 @@
 --[[
-	This Lua module provides access to the MCP23017 module.
+    This Lua module provides access to the MCP23017 module.
 
-    The MCP23017 is a port expander and provides 16 channels for inputs and outputs.
-    Up to 8 devices (128 channels) are possible by the configurable address (A0 - A2 Pins).
+    The MCP23017 is a port expander and provides 16 channels for inputs and
+    outputs.  Up to 8 devices (128 channels) are possible by the configurable
+    address (A0 - A2 Pins).
 
-    Due to the 16 channels, 2 bytes are required for switching outputs or reading input signals. These are A and B.
-    A single pin can be set or a whole byte.
+    Due to the 16 channels, 2 bytes are required for switching outputs or
+    reading input signals. These are A and B.  A single pin can be set or a
+    whole byte.
 
-    The numbering of the individual pins starts at 0 and ends with 7.
-    The numbers are for each register GPIO A and GPIO B.
+    The numbering of the individual pins starts at 0 and ends with 7.  The
+    numbers are for each register GPIO A and GPIO B.
 
-	The module requires `i2c` and `bit` C module built into firmware.
+    The module requires `i2c` and `bit` C module built into firmware.
 
-	@author Marcel P. | Plomi.net
-	@github https://github.com/plomi-net
-	@version 1.0.0
-]]
+    For register name <-> number mapping, see the MCP23017 data sheet, table
+    3-1 on page 12 (as of Revision C, July 2016).  This module uses the
+    IOCON.BANK=0 numbering (the default) throughout.
 
-local i2c, string, issetBit, setBit, clearBit, error =
-      i2c, string, bit.isset, bit.set, bit.clear, error
-local isINPUT, isGPB, isHIGH = true, true, true
-
--- registers (not used registers are commented out)
-local MCP23017_IODIRA = 0x00
-local MCP23017_IODIRB = 0x01
-local MCP23017_DEFVALA = 0x06
-local MCP23017_DEFVALB = 0x07
-local MCP23017_GPIOA = 0x12
-local MCP23017_GPIOB = 0x13
---[[
-local MCP23017_IPOLA = 0x02
-local MCP23017_IPOLB = 0x03
-local MCP23017_GPINTENA = 0x04
-local MCP23017_GPINTENB = 0x05
-local MCP23017_DEFVALA = 0x06
-local MCP23017_DEFVALB = 0x07
-local MCP23017_INTCONA = 0x08
-local MCP23017_INTCONB = 0x09
-local MCP23017_IOCON = 0x0A
-local MCP23017_IOCON2 = 0x0B
-local MCP23017_GPPUA = 0x0C
-local MCP23017_GPPUB = 0x0D
-local MCP23017_INTFA = 0x0E
-local MCP23017_INTFB = 0x0F
-local MCP23017_INTCAPA = 0x10
-local MCP23017_INTCAPB = 0x11
-local MCP23017_OLATA = 0x14
-local MCP23017_OLATB = 0x15
+    @author Marcel P. | Plomi.net
+    @github https://github.com/plomi-net
+    @version 1.0.0
 ]]
 
+local i2c, string, issetBit, setBit, clearBit =
+      i2c, string, bit.isset, bit.set, bit.clear
+
 -- metatable
 local mcp23017 = {
-    INPUT = isINPUT,
-    OUTPUT = not isINPUT,
-    GPA = not isGPB,
-    GPB = isGPB,
-    HIGH = isHIGH,
-    LOW = not isHIGH
+    -- convenience parameter enumeration names
+    INPUT = true,
+    OUTPUT = false,
+    GPA = false,
+    GPB = true,
+    HIGH = true,
+    LOW = false
 }
 mcp23017.__index = mcp23017
 
@@ -98,13 +76,65 @@ local function checkPinIsInRange(pin)
     return pin
 end
 
-local function reset(address, i2cId)
-    writeByte(address, i2cId, MCP23017_IODIRA, 0xFF)
-    writeByte(address, i2cId, MCP23017_IODIRB, 0xFF)
+function mcp23017:writeIODIR(bReg, newByte)
+    writeByte(self.address, self.i2cId,
+        bReg and 0x1 --[[IODIRB register]] or 0x0 --[[IODIRA register]], newByte)
+end
+
+function mcp23017:writeGPIO(bReg, newByte)
+    writeByte(self.address, self.i2cId,
+        bReg and 0x13 --[[GPIOB register]] or 0x12 --[[GPIOA register]], newByte)
+end
+
+function mcp23017:readGPIO(bReg)
+    return readByte(self.address, self.i2cId,
+        bReg and 0x13 --[[GPIOB register]] or 0x12 --[[GPIOA register]])
+end
+
+-- read pin input
+function mcp23017:getPinState(bReg, pin)
+    return issetBit(readByte(self.address, self.i2cId,
+        bReg and 0x13 --[[GPIOB register]] or 0x12 --[[GPIOA register]]),
+        checkPinIsInRange(pin))
 end
 
--- setup device
-local function setup(address, i2cId)
+-- set pin to low or high
+function mcp23017:setPin(bReg, pin, state)
+    local a, i = self.address, self.i2cId
+    local inReq = bReg and 0x13 --[[GPIOB register]] or 0x12 --[[GPIOA register]]
+    local inPin = checkPinIsInRange(pin)
+    local response = readByte(a, i, inReq)
+    writeByte(a, i, inReq,
+        state and setBit(response, inPin) or clearBit(response, inPin))
+    return true
+end
+
+-- set mode for a pin
+function mcp23017:setMode(bReg, pin, mode)
+    local a, i = self.address, self.i2cId
+    local inReq = bReg and 0x1 --[[IODIRB register]] or 0x0 --[[IODIRA register]]
+    local inPin = checkPinIsInRange(pin)
+    local response = readByte(a, i, inReq)
+    writeByte(a, i, inReq,
+        mode and setBit(response, inPin) or clearBit(response, inPin))
+    return true
+end
+
+-- reset gpio mode
+function mcp23017:reset()
+    local a, i = self.address, self.i2cId
+    writeByte(a, i, 0x0 --[[IODIRA register]], 0xFF)
+    writeByte(a, i, 0x1 --[[IODIRB register]], 0xFF)
+end
+
+-- setup internal pullup
+function mcp23017:setInternalPullUp(bReg, iByte)
+    writeByte(self.address, self.i2cId,
+        bReg and 0x7 --[[DEFVALB register]] or 0x6 --[[DEFVALA register]], iByte)
+end
+
+return function(address, i2cId)
+    local self = setmetatable({}, mcp23017)
 
     -- check device address (0x20 to 0x27)
     if (address < 32 or address > 39) then
@@ -113,73 +143,13 @@ local function setup(address, i2cId)
 
     if (checkDevice(address, i2cId) ~= true) then
         error("MCP23017 device on " .. string.format('0x%02X', address) .. " not found")
-    else
-        reset(address, i2cId)
-        return 1
     end
-end
 
-return function(address, i2cId)
-    local self = setmetatable({}, mcp23017)
+    self.address = address
+    self.i2cId = i2cId
 
-    if setup(address, i2cId) then
-        self.writeIODIR = function(sf, bReg, newByte) -- luacheck: no unused
-            writeByte(address, i2cId,
-                bReg == isGPB and MCP23017_IODIRB or MCP23017_IODIRA,
-                newByte)
-        end
-
-        self.writeGPIO = function(sf, bReg, newByte) -- luacheck: no unused
-            writeByte(address, i2cId,
-                bReg == isGPB and MCP23017_GPIOB or MCP23017_GPIOA, newByte)
-        end
-
-        self.readGPIO = function(sf, bReg) -- luacheck: no unused
-            return readByte(address, i2cId, -- upvals
-                bReg == isGPB and MCP23017_GPIOB or MCP23017_GPIOA)
-        end
-
-        -- read pin input
-        self.getPinState = function(sf, bReg, pin) -- luacheck: no unused
-            return issetBit(readByte(address, i2cId,
-                bReg == isGPB and MCP23017_GPIOB or MCP23017_GPIOA),
-                checkPinIsInRange(pin))
-        end
-
-        -- set pin to low or high
-        self.setPin = function(sf, bReg, pin, state) -- luacheck: no unused
-            local inReq = bReg == isGPB and MCP23017_GPIOB or MCP23017_GPIOA
-            local inPin = checkPinIsInRange(pin)
-            local response = readByte(address, i2cId, inReq)
-            writeByte(address, i2cId, inReq,
-                state == isHIGH and setBit(response, inPin) or clearBit(response, inPin))
-            return true
-        end
-
-        -- set mode for a pin
-        self.setMode = function(sf, bReg, pin, mode) -- luacheck: no unused
-            local inReq = bReg == isGPB and MCP23017_IODIRB or MCP23017_IODIRA
-            local inPin = checkPinIsInRange(pin)
-            local response = readByte(address, i2cId, inReq)
-            writeByte(address, i2cId, inReq,
-                mode == isINPUT and setBit(response, inPin) or clearBit(response, inPin))
-            return true
-        end
-
-        -- reset gpio mode
-        self.reset = function(sf) -- luacheck: no unused
-            reset(address, i2cId)
-        end
-
-        -- setup internal pullup
-        self.setInternalPullUp = function(sf, bReg, iByte) -- luacheck: no unused
-            writeByte(address, i2cId,
-                bReg == isGPB and MCP23017_DEFVALB or MCP23017_DEFVALA, iByte)
-        end
-
-        return self
-    end
-    return nil
+    self:reset()
+    return self
 end