# cpb_pump_control.py

# Demonstrate control of an air pump based on a DC motor driven via a MOSFET
# transistor driver circuit *or* a DRV8833 motor driver in a single-ended mode.
#
#  1. The driver PWM input           connects to A2
#  2. The battery ground line        connects to GND     

# Related documentation:
# https://circuitpython.readthedocs.io/en/latest/shared-bindings/pwmio/index.html#module-pwmio
# https://circuitpython.readthedocs.io/projects/motor/en/latest/api.html#module-adafruit_motor.servo

# ----------------------------------------------------------------
# Import standard Python modules.
import time, math

# Import the board-specific input/output library.
from adafruit_circuitplayground import cp

# Import the low-level hardware libraries.
import board
import pwmio

# ----------------------------------------------------------------
# Initialize hardware.

# Create a PWMOut object on pad A2 to generate control signals.
pwm = pwmio.PWMOut(board.A2, duty_cycle=0, frequency=20000)

# ----------------------------------------------------------------
# Initialize global variables for the main loop.

phase_angle = 0.0
cycle_duration = 12                       # seconds per cycle
phase_rate  = 2*math.pi / cycle_duration  # radians/second
next_pwm_update = time.monotonic_ns()
next_status_update = time.monotonic_ns()

# ----------------------------------------------------------------
# Enter the main event loop.
while True:
    # Read the current integer clock.
    now = time.monotonic_ns()

    # If the time has arrived to update the servo command signal:
    if now >= next_pwm_update:
        next_pwm_update += 20000000  # 20 msec in nanoseconds (50 Hz update)
        pwm_level = 0.5 + 0.5 * math.sin(phase_angle)

        # convert a unit-range (0 to 1) pwm_level to a 16-bit integer representing a fraction
        new_duty_cycle = min(max(int(pwm_level * 2**16), 0), 2**16-1)

        # If the new value is less than a reasonable minimum, clamp to zero.
        # The pump motor will stall if the PWM fraction is too low; this turns
        # it off instead.
        if new_duty_cycle < 48000:
            pwm.duty_cycle = 0
        else:
            pwm.duty_cycle = new_duty_cycle
            
        phase_angle = (phase_angle + phase_rate * 0.020) % (2 * math.pi)

    # If either button is pressed, override the generated servo signal and run the motor.
    if cp.button_a or cp.button_b:
        pwm.duty_cycle = 2**16-1
        
    # If the time has arrived to display the status:
    if now >= next_status_update:
        next_status_update += 500000000  # 0.5 sec in nanoseconds (2 Hz update)
        print(pwm.duty_cycle)
    
