// Project: pa blink
// Copyright (c) 2023, Framework Labs

#include "proto_activities.h"

#define pa_get_time_ms millis()

// Common activities

/* Toggles a state on each positive edge of trigger. */
pa_activity (EdgeTriggeredToggle, pa_ctx(), bool trigger, bool& val) {
  val = false;
  pa_every (trigger) {
    val = !val;
    pa_await (!trigger);
  } pa_every_end;
} pa_activity_end;

// Button

void initButton(unsigned pin) {
  pinMode(pin, INPUT_PULLUP);
}

bool readButton(unsigned pin) {
  return digitalRead(pin) == LOW;
}

/* Continuously reads and returns the button pressed state. */
pa_activity (ButtonReader, pa_ctx_tm(), unsigned pin, bool& pressed) {
  initButton(pin);

  pa_repeat {
    pressed = readButton(pin);
    pa_delay_ms (100);
  }
} pa_end;

// Led

void initLed(unsigned pin) {
  pinMode(pin, OUTPUT);
}

void setLed(unsigned pin) {
  digitalWrite(pin, HIGH);
}

void clearLed(unsigned pin) {
  digitalWrite(pin, LOW);
}

/* Blinks an led of given pin with given on-tick and off-tick intervals. */
pa_activity (Blinker, pa_ctx_tm(), unsigned pin, unsigned onTimeMs, unsigned offTimeMs) {
  initLed(pin);

  pa_repeat {
    setLed(pin);
    pa_delay_ms (onTimeMs);

    clearLed(pin);
    pa_delay_ms (offTimeMs);
  }
} pa_end;

/* Alternates Blinking the led slow and quickly. */
pa_activity (AlternatingBlinker, pa_ctx_tm(pa_use(Blinker))) {
  pa_repeat {
    /* Blink slowly for 3 second */
    pa_after_s_abort (3, Blinker, 2, 500, 500);

    /* Blink quickly for 2 second */
    pa_after_s_abort (2, Blinker, 2, 200, 200);
  }
} pa_end;

/* Starts and stops the alternating blinker depending on the on value. */
pa_activity (BlinkerController, pa_ctx(pa_use(AlternatingBlinker)), bool on) {
  pa_every (on) {
    pa_when_abort (!on, AlternatingBlinker);
    clearLed(2);
  } pa_every_end;
} pa_end;

// Main

/* Sets up a button reader, a state toggle and the blinker controller. */
pa_activity (Main, pa_ctx(pa_co_res(3); pa_use(ButtonReader); pa_use(EdgeTriggeredToggle); pa_use(BlinkerController); 
                   bool pressed; bool isOn)) {
  pa_co(3) {
    pa_with (ButtonReader, 4, pa_self.pressed);
    pa_with (EdgeTriggeredToggle, pa_self.pressed, pa_self.isOn);
    pa_with (BlinkerController, pa_self.isOn);
  } pa_co_end;
} pa_end;

pa_use(Main);

// Setup and Loop

void setup() {
  Serial.begin(9600);
}

void loop() {
  pa_tick(Main);
}