#   Copyright 2012-2013 Eric Ptak - trouch.com
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

from webiopi.decorators.rest import request, response
from webiopi.utils.types import M_JSON

class ADC():
    def __init__(self, channelCount, resolution, vref):
        self._analogCount = channelCount
        self._analogResolution = resolution
        self._analogMax = 2**resolution - 1
        self._analogRef = vref
    
    def __family__(self):
        return "ADC"

    def checkAnalogChannel(self, channel):
        if not 0 <= channel < self._analogCount:
            raise ValueError("Channel %d out of range [%d..%d]" % (channel, 0, self._analogCount-1))

    def checkAnalogValue(self, value):
        if not 0 <= value <= self._analogMax:
            raise ValueError("Value %d out of range [%d..%d]" % (value, 0, self._analogMax))
    
    @request("GET", "analog/count")
    @response("%d")
    def analogCount(self):
        return self._analogCount

    @request("GET", "analog/resolution")
    @response("%d")
    def analogResolution(self):
        return self._analogResolution
    
    @request("GET", "analog/max")
    @response("%d")
    def analogMaximum(self):
        return int(self._analogMax)
    
    @request("GET", "analog/vref")
    @response("%.2f")
    def analogReference(self):
        return self._analogRef
    
    def __analogRead__(self, channel, diff):
        raise NotImplementedError
    
    @request("GET", "analog/%(channel)d/integer")
    @response("%d")
    def analogRead(self, channel, diff=False):
        self.checkAnalogChannel(channel)
        return self.__analogRead__(channel, diff)
    
    @request("GET", "analog/%(channel)d/float")
    @response("%.2f")
    def analogReadFloat(self, channel, diff=False):
        return self.analogRead(channel, diff) / float(self._analogMax)
    
    @request("GET", "analog/%(channel)d/volt")
    @response("%.2f")
    def analogReadVolt(self, channel, diff=False):
        if self._analogRef == 0:
            raise NotImplementedError
        return self.analogReadFloat(channel, diff) * self._analogRef
    
    @request("GET", "analog/*/integer")
    @response(contentType=M_JSON)
    def analogReadAll(self):
        values = {}
        for i in range(self._analogCount):
            values[i] = self.analogRead(i)
        return values
            
    @request("GET", "analog/*/float")
    @response(contentType=M_JSON)
    def analogReadAllFloat(self):
        values = {}
        for i in range(self._analogCount):
            values[i] = float("%.2f" % self.analogReadFloat(i))
        return values
    
    @request("GET", "analog/*/volt")
    @response(contentType=M_JSON)
    def analogReadAllVolt(self):
        values = {}
        for i in range(self._analogCount):
            values[i] = float("%.2f" % self.analogReadVolt(i))
        return values
    
class DAC(ADC):
    def __init__(self, channelCount, resolution, vref):
        ADC.__init__(self, channelCount, resolution, vref)
    
    def __family__(self):
        return "DAC"
    
    def __analogWrite__(self, channel, value):
        raise NotImplementedError
    
    @request("POST", "analog/%(channel)d/integer/%(value)d")
    @response("%d")    
    def analogWrite(self, channel, value):
        self.checkAnalogChannel(channel)
        self.checkAnalogValue(value)
        self.__analogWrite__(channel, value)
        return self.analogRead(channel)
    
    @request("POST", "analog/%(channel)d/float/%(value)f")        
    @response("%.2f")    
    def analogWriteFloat(self, channel, value):
        self.analogWrite(channel, int(value * self._analogMax))
        return self.analogReadFloat(channel)
    
    @request("POST", "analog/%(channel)d/volt/%(value)f")        
    @response("%.2f")    
    def analogWriteVolt(self, channel, value):
        self.analogWriteFloat(channel, value /self._analogRef)
        return self.analogReadVolt(channel)
    

class PWM():
    def __init__(self, channelCount, resolution, frequency):
        self._pwmCount = channelCount
        self._pwmResolution = resolution
        self._pwmMax = 2**resolution - 1
        self.frequency = frequency
        self.period = 1.0/frequency
        
        # Futaba servos standard
        self.servo_neutral = 0.00152
        self.servo_travel_time = 0.0004
        self.servo_travel_angle = 45.0
        
        self.reverse = [False for i in range(channelCount)]
         
    def __family__(self):
        return "PWM"

    def checkPWMChannel(self, channel):
        if not 0 <= channel < self._pwmCount:
            raise ValueError("Channel %d out of range [%d..%d]" % (channel, 0, self._pwmCount-1))

    def checkPWMValue(self, value):
        if not 0 <= value <= self._pwmMax:
            raise ValueError("Value %d out of range [%d..%d]" % (value, 0, self._pwmMax))
    
    def __pwmRead__(self, channel):
        raise NotImplementedError
    
    def __pwmWrite__(self, channel, value):
        raise NotImplementedError
    
    @request("GET", "pwm/count")
    @response("%d")
    def pwmCount(self):
        return self._pwmCount

    @request("GET", "pwm/resolution")
    @response("%d")
    def pwmResolution(self):
        return self._pwmResolution
    
    @request("GET", "pwm/max")
    @response("%d")
    def pwmMaximum(self):
        return int(self._pwmMax)
    
    @request("GET", "pwm/%(channel)d/integer")
    @response("%d")
    def pwmRead(self, channel):
        self.checkPWMChannel(channel)
        return self.__pwmRead__(channel)
    
    @request("GET", "pwm/%(channel)d/float")
    @response("%.2f")
    def pwmReadFloat(self, channel):
        return self.pwmRead(channel) / float(self._pwmMax)
    
    @request("POST", "pwm/%(channel)d/integer/%(value)d")
    @response("%d")    
    def pwmWrite(self, channel, value):
        self.checkPWMChannel(channel)
        self.checkPWMValue(value)
        self.__pwmWrite__(channel, value)
        return self.pwmRead(channel)
    
    @request("POST", "pwm/%(channel)d/float/%(value)f")        
    @response("%.2f")    
    def pwmWriteFloat(self, channel, value):
        self.pwmWrite(channel, int(value * self._pwmMax))
        return self.pwmReadFloat(channel)
    
    def getReverse(self, channel):
        self.checkChannel(channel)
        return self.reverse[channel]
    
    def setReverse(self, channel, value):
        self.checkChannel(channel)
        self.reverse[channel] = value
        return value
    
    def RatioToAngle(self, value):
        f = value
        f *= self.period
        f -= self.servo_neutral
        f *= self.servo_travel_angle
        f /= self.servo_travel_time
        return f

    def AngleToRatio(self, value):
        f = value
        f *= self.servo_travel_time
        f /= self.servo_travel_angle
        f += self.servo_neutral
        f /= self.period
        return f
    
    @request("GET", "pwm/%(channel)d/angle")
    @response("%.2f")
    def pwmReadAngle(self, channel):
        f = self.pwmReadFloat(channel)
        f = self.RatioToAngle(f)
        if self.reverse[channel]:
            f = -f
        else:
            f = f
        return f
        
    @request("POST", "pwm/%(channel)d/angle/%(value)f")
    @response("%.2f")
    def pwmWriteAngle(self, channel, value):
        if self.reverse[channel]:
            f = -value
        else:
            f = value
        f = self.AngleToRatio(f)
        self.pwmWriteFloat(channel, f)
        return self.pwmReadAngle(channel)

    @request("GET", "pwm/*")
    @response(contentType=M_JSON)
    def pwmWildcard(self):
        values = {}
        for i in range(self._pwmCount):
            val = self.pwmReadFloat(i)
            values[i] = {}
            values[i]["float"] = float("%.2f" % val)
            values[i]["angle"] = float("%.2f" % self.RatioToAngle(val))
        return values
    
DRIVERS = {}
DRIVERS["ads1x1x"] = ["ADS1014", "ADS1015", "ADS1114", "ADS1115"]
DRIVERS["mcp3x0x"] = ["MCP3002", "MCP3004", "MCP3008", "MCP3204", "MCP3208"]
DRIVERS["mcp4725"] = ["MCP4725"]
DRIVERS["mcp48XX"] = ["MCP4802", "MCP4812", "MCP4822"]
DRIVERS["mcp492X"] = ["MCP4921", "MCP4922"]
DRIVERS["pca9685"] = ["PCA9685"]
DRIVERS["pcf8591"] = ["PCF8591"]

[((1370, 1400), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""analog/count"""'], {}), "('GET', 'analog/count')\n", (1377, 1400), False, 'from webiopi.decorators.rest import request, response\n'), ((1406, 1420), 'webiopi.decorators.rest.response', 'response', (['"""%d"""'], {}), "('%d')\n", (1414, 1420), False, 'from webiopi.decorators.rest import request, response\n'), ((1487, 1522), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""analog/resolution"""'], {}), "('GET', 'analog/resolution')\n", (1494, 1522), False, 'from webiopi.decorators.rest import request, response\n'), ((1528, 1542), 'webiopi.decorators.rest.response', 'response', (['"""%d"""'], {}), "('%d')\n", (1536, 1542), False, 'from webiopi.decorators.rest import request, response\n'), ((1623, 1651), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""analog/max"""'], {}), "('GET', 'analog/max')\n", (1630, 1651), False, 'from webiopi.decorators.rest import request, response\n'), ((1657, 1671), 'webiopi.decorators.rest.response', 'response', (['"""%d"""'], {}), "('%d')\n", (1665, 1671), False, 'from webiopi.decorators.rest import request, response\n'), ((1747, 1776), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""analog/vref"""'], {}), "('GET', 'analog/vref')\n", (1754, 1776), False, 'from webiopi.decorators.rest import request, response\n'), ((1782, 1798), 'webiopi.decorators.rest.response', 'response', (['"""%.2f"""'], {}), "('%.2f')\n", (1790, 1798), False, 'from webiopi.decorators.rest import request, response\n'), ((1955, 1999), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""analog/%(channel)d/integer"""'], {}), "('GET', 'analog/%(channel)d/integer')\n", (1962, 1999), False, 'from webiopi.decorators.rest import request, response\n'), ((2005, 2019), 'webiopi.decorators.rest.response', 'response', (['"""%d"""'], {}), "('%d')\n", (2013, 2019), False, 'from webiopi.decorators.rest import request, response\n'), ((2168, 2210), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""analog/%(channel)d/float"""'], {}), "('GET', 'analog/%(channel)d/float')\n", (2175, 2210), False, 'from webiopi.decorators.rest import request, response\n'), ((2216, 2232), 'webiopi.decorators.rest.response', 'response', (['"""%.2f"""'], {}), "('%.2f')\n", (2224, 2232), False, 'from webiopi.decorators.rest import request, response\n'), ((2366, 2407), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""analog/%(channel)d/volt"""'], {}), "('GET', 'analog/%(channel)d/volt')\n", (2373, 2407), False, 'from webiopi.decorators.rest import request, response\n'), ((2413, 2429), 'webiopi.decorators.rest.response', 'response', (['"""%.2f"""'], {}), "('%.2f')\n", (2421, 2429), False, 'from webiopi.decorators.rest import request, response\n'), ((2631, 2665), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""analog/*/integer"""'], {}), "('GET', 'analog/*/integer')\n", (2638, 2665), False, 'from webiopi.decorators.rest import request, response\n'), ((2671, 2699), 'webiopi.decorators.rest.response', 'response', ([], {'contentType': 'M_JSON'}), '(contentType=M_JSON)\n', (2679, 2699), False, 'from webiopi.decorators.rest import request, response\n'), ((2875, 2907), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""analog/*/float"""'], {}), "('GET', 'analog/*/float')\n", (2882, 2907), False, 'from webiopi.decorators.rest import request, response\n'), ((2913, 2941), 'webiopi.decorators.rest.response', 'response', ([], {'contentType': 'M_JSON'}), '(contentType=M_JSON)\n', (2921, 2941), False, 'from webiopi.decorators.rest import request, response\n'), ((3135, 3166), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""analog/*/volt"""'], {}), "('GET', 'analog/*/volt')\n", (3142, 3166), False, 'from webiopi.decorators.rest import request, response\n'), ((3172, 3200), 'webiopi.decorators.rest.response', 'response', ([], {'contentType': 'M_JSON'}), '(contentType=M_JSON)\n', (3180, 3200), False, 'from webiopi.decorators.rest import request, response\n'), ((3666, 3721), 'webiopi.decorators.rest.request', 'request', (['"""POST"""', '"""analog/%(channel)d/integer/%(value)d"""'], {}), "('POST', 'analog/%(channel)d/integer/%(value)d')\n", (3673, 3721), False, 'from webiopi.decorators.rest import request, response\n'), ((3727, 3741), 'webiopi.decorators.rest.response', 'response', (['"""%d"""'], {}), "('%d')\n", (3735, 3741), False, 'from webiopi.decorators.rest import request, response\n'), ((3962, 4015), 'webiopi.decorators.rest.request', 'request', (['"""POST"""', '"""analog/%(channel)d/float/%(value)f"""'], {}), "('POST', 'analog/%(channel)d/float/%(value)f')\n", (3969, 4015), False, 'from webiopi.decorators.rest import request, response\n'), ((4029, 4045), 'webiopi.decorators.rest.response', 'response', (['"""%.2f"""'], {}), "('%.2f')\n", (4037, 4045), False, 'from webiopi.decorators.rest import request, response\n'), ((4217, 4269), 'webiopi.decorators.rest.request', 'request', (['"""POST"""', '"""analog/%(channel)d/volt/%(value)f"""'], {}), "('POST', 'analog/%(channel)d/volt/%(value)f')\n", (4224, 4269), False, 'from webiopi.decorators.rest import request, response\n'), ((4283, 4299), 'webiopi.decorators.rest.response', 'response', (['"""%.2f"""'], {}), "('%.2f')\n", (4291, 4299), False, 'from webiopi.decorators.rest import request, response\n'), ((5536, 5563), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""pwm/count"""'], {}), "('GET', 'pwm/count')\n", (5543, 5563), False, 'from webiopi.decorators.rest import request, response\n'), ((5569, 5583), 'webiopi.decorators.rest.response', 'response', (['"""%d"""'], {}), "('%d')\n", (5577, 5583), False, 'from webiopi.decorators.rest import request, response\n'), ((5644, 5676), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""pwm/resolution"""'], {}), "('GET', 'pwm/resolution')\n", (5651, 5676), False, 'from webiopi.decorators.rest import request, response\n'), ((5682, 5696), 'webiopi.decorators.rest.response', 'response', (['"""%d"""'], {}), "('%d')\n", (5690, 5696), False, 'from webiopi.decorators.rest import request, response\n'), ((5771, 5796), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""pwm/max"""'], {}), "('GET', 'pwm/max')\n", (5778, 5796), False, 'from webiopi.decorators.rest import request, response\n'), ((5802, 5816), 'webiopi.decorators.rest.response', 'response', (['"""%d"""'], {}), "('%d')\n", (5810, 5816), False, 'from webiopi.decorators.rest import request, response\n'), ((5886, 5927), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""pwm/%(channel)d/integer"""'], {}), "('GET', 'pwm/%(channel)d/integer')\n", (5893, 5927), False, 'from webiopi.decorators.rest import request, response\n'), ((5933, 5947), 'webiopi.decorators.rest.response', 'response', (['"""%d"""'], {}), "('%d')\n", (5941, 5947), False, 'from webiopi.decorators.rest import request, response\n'), ((6069, 6108), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""pwm/%(channel)d/float"""'], {}), "('GET', 'pwm/%(channel)d/float')\n", (6076, 6108), False, 'from webiopi.decorators.rest import request, response\n'), ((6114, 6130), 'webiopi.decorators.rest.response', 'response', (['"""%.2f"""'], {}), "('%.2f')\n", (6122, 6130), False, 'from webiopi.decorators.rest import request, response\n'), ((6237, 6289), 'webiopi.decorators.rest.request', 'request', (['"""POST"""', '"""pwm/%(channel)d/integer/%(value)d"""'], {}), "('POST', 'pwm/%(channel)d/integer/%(value)d')\n", (6244, 6289), False, 'from webiopi.decorators.rest import request, response\n'), ((6295, 6309), 'webiopi.decorators.rest.response', 'response', (['"""%d"""'], {}), "('%d')\n", (6303, 6309), False, 'from webiopi.decorators.rest import request, response\n'), ((6515, 6565), 'webiopi.decorators.rest.request', 'request', (['"""POST"""', '"""pwm/%(channel)d/float/%(value)f"""'], {}), "('POST', 'pwm/%(channel)d/float/%(value)f')\n", (6522, 6565), False, 'from webiopi.decorators.rest import request, response\n'), ((6579, 6595), 'webiopi.decorators.rest.response', 'response', (['"""%.2f"""'], {}), "('%.2f')\n", (6587, 6595), False, 'from webiopi.decorators.rest import request, response\n'), ((7414, 7453), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""pwm/%(channel)d/angle"""'], {}), "('GET', 'pwm/%(channel)d/angle')\n", (7421, 7453), False, 'from webiopi.decorators.rest import request, response\n'), ((7459, 7475), 'webiopi.decorators.rest.response', 'response', (['"""%.2f"""'], {}), "('%.2f')\n", (7467, 7475), False, 'from webiopi.decorators.rest import request, response\n'), ((7701, 7751), 'webiopi.decorators.rest.request', 'request', (['"""POST"""', '"""pwm/%(channel)d/angle/%(value)f"""'], {}), "('POST', 'pwm/%(channel)d/angle/%(value)f')\n", (7708, 7751), False, 'from webiopi.decorators.rest import request, response\n'), ((7757, 7773), 'webiopi.decorators.rest.response', 'response', (['"""%.2f"""'], {}), "('%.2f')\n", (7765, 7773), False, 'from webiopi.decorators.rest import request, response\n'), ((8032, 8055), 'webiopi.decorators.rest.request', 'request', (['"""GET"""', '"""pwm/*"""'], {}), "('GET', 'pwm/*')\n", (8039, 8055), False, 'from webiopi.decorators.rest import request, response\n'), ((8061, 8089), 'webiopi.decorators.rest.response', 'response', ([], {'contentType': 'M_JSON'}), '(contentType=M_JSON)\n', (8069, 8089), False, 'from webiopi.decorators.rest import request, response\n')]