/**
 * This is a very small example that shows how to use
 * protothreads. The program consists of two protothreads that wait
 * for each other to toggle a variable.
 *
 * Modified by Bruce Land to make a timer yield
 * Aug 2014
 */

/* We must always include pt.h in our protothreads code. */
#include <plib.h>
#include "pt.h"
#include <stdio.h> /* For printf(). */

#pragma config FNOSC = FRCPLL, POSCMOD = HS, FPLLIDIV = DIV_2, FPLLMUL = MUL_15, FPBDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FWDTEN = OFF
// frequency we're running at
#define	SYS_FREQ 60000000

// UART parameters
#define BAUDRATE 9600 // must match PC end
#define PB_DIVISOR (1 << OSCCONbits.PBDIV) // read the peripheral bus divider, FPBDIV
#define PB_FREQ SYS_FREQ/PB_DIVISOR // periperhal bus frequency

/* Two flags that the two protothread functions use. */
static int protothread1_flag, protothread2_flag;
volatile int milliSec ;

// === Timer 2 interrupt handler =====================================
// ipl2 means "interrupt priority level 2"
// ASM output is 47 instructions for the ISR
void __ISR(_TIMER_2_VECTOR, ipl2) Timer2Handler(void)
{
    // clear the interrupt flag
    mT2ClearIntFlag();
    // keep time
    milliSec++ ;
}

// === Thread 1 ======================================================
/**
 * The first protothread function. A protothread function must always
 * return an integer, but must never explicitly return - returning is
 * performed inside the protothread statements.
 *
 * The protothread function is driven by the main loop further down in
 * the code.
 */
static PT_THREAD (protothread1(struct pt *pt))
{
  static int time_thread_1;
    # define wait_t1 1000 // mSec

    /* A protothread function must begin with PT_BEGIN() which takes a
     pointer to a struct pt. */
  PT_BEGIN(pt);

  /* We loop forever here. */
  while(1) {
    /* Wait until the other protothread has set its flag. */
    
   // PT_WAIT_UNTIL(pt, protothread2_flag != 0 );
    printf("Protothread 1 running\n");

    /* We then reset the other protothread's flag, and set our own
       flag so that the other protothread can run. */
   // protothread2_flag = 0;
   // protothread1_flag = 1;

    
    //printf("%d, %d\n", milliSec, time_thread_1);
   PT_YIELD_UNTIL(pt, milliSec > time_thread_1);
   time_thread_1 = milliSec + wait_t1 ;
    /* And we loop. */
  } // END WHILE(1)

  /* All protothread functions must end with PT_END() which takes a
     pointer to a struct pt. */
  PT_END(pt);
}

// === Thread 2 ======================================================
/**
 * The second protothread function. This is almost the same as the
 * first one.
 */
static PT_THREAD (protothread2(struct pt *pt))
{
    static int time_thread_2;
    # define wait_t2 4000 // mSec

    PT_BEGIN(pt);

  while(1) {
    
    /* Wait until the other protothread has set its flag. */
    
    //PT_WAIT_UNTIL(pt, protothread1_flag != 0);
    printf("Protothread 2 running\n");
    
    /* We then reset the other protothread's flag. */
    //protothread1_flag = 0;
   // protothread2_flag = 1;

    //printf("%d, %d\n", milliSec, time_thread_2);
    PT_YIELD_UNTIL(pt, milliSec > time_thread_2);
    time_thread_2 = milliSec + wait_t2 ;
    /* And we loop. */
  } // END WHILE(1)
  PT_END(pt);
}

// === Main  ======================================================
/**
 * Finally, we have the main loop. Here is where the protothreads are
 * initialized and scheduled. First, however, we define the
 * protothread state variables pt1 and pt2, which hold the state of
 * the two protothreads.
 */
static struct pt pt1, pt2;

int main(void)
{
  // init the USART i/o pins
  PPSInput (2, U2RX, RPB11); //Assign U2RX to pin RPB11 -- Physical pin 22 on 28 PDIP
  PPSOutput(4, RPB10, U2TX); //Assign U2TX to pin RPB10 -- Physical pin 21 on 28 PDIP

  ANSELA =0; //make sure analog is cleared
  ANSELB =0;

  // init the uart2
  UARTConfigure(UART2, UART_ENABLE_PINS_TX_RX_ONLY);
  UARTSetLineControl(UART2, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1);
  UARTSetDataRate(UART2, PB_FREQ, BAUDRATE);
  UARTEnable(UART2, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));
  printf("pt start..\n\r");

  // Set up timer2 on,  interrupts, internal clock, prescalar 1, toggle rate
  // run at 30000 ticks is 1 mSec
  OpenTimer2(T2_ON | T2_SOURCE_INT | T2_PS_1_1, 30000);
  // set up the timer interrupt with a priority of 2
  ConfigIntTimer2(T2_INT_ON | T2_INT_PRIOR_2);
  mT2ClearIntFlag(); // and clear the interrupt flag
  milliSec = 0;
  // setup system wide interrupts  ///
  INTEnableSystemMultiVectoredInt();

  // === now the threads ===
  // init  flags
  protothread2_flag = 1;
  protothread1_flag = 0;

    /* Initialize the protothread state variables with PT_INIT(). */
  PT_INIT(&pt1);
  PT_INIT(&pt2);
  /*
   * Then we schedule the two protothreads by repeatedly calling their
   * protothread functions and passing a pointer to the protothread
   * state variables as arguments.
   */
  while(1) {
    PT_SCHEDULE(protothread1(&pt1));
    PT_SCHEDULE(protothread2(&pt2));
  }
}
