--- 模块功能：GPIO 功能配置，包括输入输出IO和上升下降沿中断IO
-- @module pins
-- @author openLuat
-- @license MIT
-- @copyright openLuat
-- @release 2017.09.23 11:34
require "sys"
module(..., package.seeall)
local interruptCallbacks = {}
local dirs = {}
--- 配置GPIO模式
-- @number pin，GPIO ID
-- GPIO 0到GPIO 31表示为pio.P0_0到pio.P0_31
-- GPIO 32到GPIO XX表示为pio.P1_0到pio.P1_(XX-32)，例如GPIO33 表示为pio.P1_1
-- GPIO 64到GPIO XX表示为pio.P2_0到pio.P2_(XX-64)，例如GPIO65 表示为pio.P2_1
-- @param val，number、nil或者function类型
-- 配置为输出模式时，为number类型，表示默认电平，0是低电平，1是高电平
-- 配置为输入模式时，为nil
-- 配置为中断模式时，为function类型，表示中断处理函数
-- @param pull, number, pio.PULLUP：上拉模式 。pio.PULLDOWN：下拉模式。pio.NOPULL：高阻态
-- 如果没有设置此参数，默认的上下拉参考模块的硬件设计说明书
-- @return function
-- 配置为输出模式时，返回的函数，可以设置IO的电平
-- 配置为输入或者中断模式时，返回的函数，可以实时获取IO的电平
-- @usage setOutputFnc = pins.setup(pio.P1_1,0)，配置GPIO 33，输出模式，默认输出低电平；
--执行setOutputFnc(0)可输出低电平，执行setOutputFnc(1)可输出高电平
-- @usage getInputFnc = pins.setup(pio.P1_1,intFnc)，配置GPIO33，中断模式
-- 产生中断时自动调用intFnc(msg)函数：上升沿中断时：msg为cpu.INT_GPIO_POSEDGE；下降沿中断时：msg为cpu.INT_GPIO_NEGEDGE
-- 执行getInputFnc()即可获得当前电平；如果是低电平，getInputFnc()返回0；如果是高电平，getInputFnc()返回1
-- @usage getInputFnc = pins.setup(pio.P1_1),配置GPIO33，输入模式
--执行getInputFnc()即可获得当前电平；如果是低电平，getInputFnc()返回0；如果是高电平，getInputFnc()返回1
-- @usage
--有些GPIO需要打开对应的ldo电压域之后，才能正常配置工作，电压域和对应的GPIO关系如下
--pmd.ldoset(x,pmd.LDO_VSIM1) -- GPIO 29、30、31
--pmd.ldoset(x,pmd.LDO_VLCD) -- GPIO 0、1、2、3、4
--pmd.ldoset(x,pmd.LDO_VMMC) -- GPIO 24、25、26、27、28
--x=0时：关闭LDO
--x=1时：LDO输出1.716V
--x=2时：LDO输出1.828V
--x=3时：LDO输出1.939V
--x=4时：LDO输出2.051V
--x=5时：LDO输出2.162V
--x=6时：LDO输出2.271V
--x=7时：LDO输出2.375V
--x=8时：LDO输出2.493V
--x=9时：LDO输出2.607V
--x=10时：LDO输出2.719V
--x=11时：LDO输出2.831V
--x=12时：LDO输出2.942V
--x=13时：LDO输出3.054V
--x=14时：LDO输出3.165V
--x=15时：LDO输出3.177V
--除了上面列举出的GPIO外，其余的GPIO不需要打开特定的电压域，可以直接配置工作
function setup(pin, val, pull)
    -- 关闭该IO
    pio.pin.close(pin)
    -- 中断模式配置
    if type(val) == "function" then
        pio.pin.setdir(pio.INT, pin)
        if pull then pio.pin.setpull(pull or pio.PULLUP, pin) end
        --注册引脚中断的处理函数
        interruptCallbacks[pin] = val
        dirs[pin] = false
        return function()
            return pio.pin.getval(pin)
        end
    end
    -- 输出模式初始化默认配置
    if val ~= nil then
        dirs[pin] = true
        pio.pin.setdir(val == 1 and pio.OUTPUT1 or pio.OUTPUT, pin)
    else
        -- 输入模式初始化默认配置
        dirs[pin] = false
        pio.pin.setdir(pio.INPUT, pin)
        if pull then pio.pin.setpull(pull or pio.PULLUP, pin) end
    end
    -- 返回一个自动切换输入输出模式的函数
    return function(val)
        val = tonumber(val)
        if (not val and dirs[pin]) or (val and not dirs[pin]) then
            pio.pin.close(pin)
            pio.pin.setdir(val and (val == 1 and pio.OUTPUT1 or pio.OUTPUT) or pio.INPUT, pin)
            if not val and pull then pio.pin.setpull(pull or pio.PULLUP, pin) end
            dirs[pin] = val and true or false
            return val or pio.pin.getval(pin)
        end
        if val then
            pio.pin.setval(val, pin)
            return val
        else
            return pio.pin.getval(pin)
        end
    end
end

--- 关闭GPIO模式
-- @number pin，GPIO ID
--
-- GPIO 0到GPIO 31表示为pio.P0_0到pio.P0_31
--
-- GPIO 32到GPIO XX表示为pio.P1_0到pio.P1_(XX-32)，例如GPIO33 表示为pio.P1_1
-- @usage pins.close(pio.P1_1)，关闭GPIO33
function close(pin)
    pio.pin.close(pin)
end

rtos.on(rtos.MSG_INT, function(msg)
    if interruptCallbacks[msg.int_resnum] == nil then
        log.warn('pins.rtos.on', 'warning:rtos.MSG_INT callback nil', msg.int_resnum)
    end
    interruptCallbacks[msg.int_resnum](msg.int_id)
end)
