# SPDX-License-Identifier: LGPL-3.0-or-later
# Copyright (C) 2020 Daniel Thompson

"""Generic lithium ion battery driver
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
import micropython
from machine import Pin, ADC

class Battery(object):
    """Generic lithium ion battery driver.

    .. automethod:: __init__
    """

    def __init__(self, battery, charging, power=None):
        """Specify the pins used to provide battery status.

        :param Pin battery:  The ADC-capable pin that can be used to measure
                             battery voltage.
        :param Pin charging: A pin (or Signal) that reports the charger status.
        :param Pin power:    A pin (or Signal) that reports whether the device
                             has external power, defaults to None (which means
                             use the charging pin for power reporting too).
        """
        self._battery = ADC(battery)
        self._charging = charging
        self._power = power

    @micropython.native
    def charging(self):
        """Get the charging state of the battery.

        :returns: True if the battery is charging, False otherwise.
        """
        return self._charging.value() 

    def power(self):
        """Check whether the device has external power.

        :returns: True if the device has an external power source, False
                  otherwise.
        """
        if self._power:
            return self._power.value()
        return self._charging.value()

    def voltage_mv(self):
        """Read the battery voltage.

        Assumes a 50/50 voltage divider and a 3.3v power supply

        :returns: Battery voltage, in millivolts.
        """
        raw = self._battery.read_u16()
        return (2 * 3300 * raw) // 65535

    def level(self):
        """Estimate the battery level.

        The current the estimation approach is extremely simple. It is assumes
        the discharge from 4v to 3.5v is roughly linear and 4v is 100% and
        that 3.5v is 5%. Below 3.5v the voltage will start to drop pretty
        sharply to we will drop from 5% to 0% pretty fast... but we'll
        live with that for now.

        :returns: Estimate battery level in percent.
        """
        mv = self.voltage_mv()
        level = ((19 * mv) // 100) - 660
        if level > 100:
            return 100
        if level < 0:
            return 0
        return level