pt_cornell_1_2_2.h

/*
 * File:   pt_cornell_1_2_2.h
 * Author: brl4
 *
 * Created on Oct 30, 2017
 */

/*
 * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file is part of the Contiki operating system.
 *
 * Author: Adam Dunkels <adam@sics.se>
 *
 * $Id: pt.h,v 1.7 2006/10/02 07:52:56 adam Exp $
 */
#define _SUPPRESS_PLIB_WARNING
#define _DISABLE_OPENADC10_CONFIGPORT_WARNING
#include <plib.h>
/**
 * \addtogroup pt
 * @{
 */

/**
 * \file
 * Protothreads implementation.
 * \author
 * Adam Dunkels <adam@sics.se>
 *
 */

#ifndef __PT_H__
#define __PT_H__

/////////////////////////////////
// set up clock parameters
// system cpu clock
#define sys_clock 40000000

// sys_clock/FPBDIV
#define pb_clock sys_clock / 1  // divide by one in this case

////////////////////////
//#include "lc.h"
////////////////////////
/**
 * \file lc.h
 * Local continuations
 * \author
 * Adam Dunkels <adam@sics.se>
 *
 */

#ifdef DOXYGEN
/**
 * Initialize a local continuation.
 *
 * This operation initializes the local continuation, thereby
 * unsetting any previously set continuation state.
 *
 * \hideinitializer
 */
#define LC_INIT(lc)

/**
 * Set a local continuation.
 *
 * The set operation saves the state of the function at the point
 * where the operation is executed. As far as the set operation is
 * concerned, the state of the function does <b>not</b> include the
 * call-stack or local (automatic) variables, but only the program
 * counter and such CPU registers that needs to be saved.
 *
 * \hideinitializer
 */
#define LC_SET(lc)

/**
 * Resume a local continuation.
 *
 * The resume operation resumes a previously set local continuation, thus
 * restoring the state in which the function was when the local
 * continuation was set. If the local continuation has not been
 * previously set, the resume operation does nothing.
 *
 * \hideinitializer
 */
#define LC_RESUME(lc)

/**
 * Mark the end of local continuation usage.
 *
 * The end operation signifies that local continuations should not be
 * used any more in the function. This operation is not needed for
 * most implementations of local continuation, but is required by a
 * few implementations.
 *
 * \hideinitializer
 */
#define LC_END(lc)

/**
 * \var typedef lc_t;
 *
 * The local continuation type.
 *
 * \hideinitializer
 */
#endif /* DOXYGEN */

//#ifndef __LC_H__
//#define __LC_H__

//#ifdef LC_INCLUDE
//#include LC_INCLUDE
//#else

/////////////////////////////
//#include "lc-switch.h"
/////////////////////////////

//#ifndef __LC_SWITCH_H__
//#define __LC_SWITCH_H__

/* WARNING! lc implementation using switch() does not work if an
   LC_SET() is done within another switch() statement! */

/** \hideinitializer */
/*
typedef unsigned short lc_t;

#define LC_INIT(s) s = 0;

#define LC_RESUME(s) switch(s) { case 0:

#define LC_SET(s) s = __LINE__; case __LINE__:

#define LC_END(s) }

#endif /* __LC_SWITCH_H__ */

/** @} */

//#endif /* LC_INCLUDE */

//#endif /* __LC_H__ */

/** @} */
/** @} */

/////////////////////////////
//#include "lc-addrlabels.h"
/////////////////////////////

#ifndef __LC_ADDRLABELS_H__
#define __LC_ADDRLABELS_H__

/** \hideinitializer */
typedef void *lc_t;

#define LC_INIT(s) s = NULL

#define LC_RESUME(s) \
  do {               \
    if (s != NULL) { \
      goto *s;       \
    }                \
  } while (0)

#define LC_CONCAT2(s1, s2) s1##s2
#define LC_CONCAT(s1, s2) LC_CONCAT2(s1, s2)

#define LC_SET(s)                                                          \
  do {                                                                     \
    LC_CONCAT(LC_LABEL, __LINE__) : (s) = &&LC_CONCAT(LC_LABEL, __LINE__); \
  } while (0)

#define LC_END(s)

#endif /* __LC_ADDRLABELS_H__ */

//////////////////////////////////////////

typedef struct pt {
  lc_t lc;
  int pri;
} pt_t;

#define PT_WAITING 0
#define PT_YIELDED 1
#define PT_EXITED 2
#define PT_ENDED 3

/**
 * \name Initialization
 * @{
 */

/**
 * Initialize a protothread.
 *
 * Initializes a protothread. Initialization must be done prior to
 * starting to execute the protothread.
 *
 * \param pt A pointer to the protothread control structure.
 *
 * \sa PT_SPAWN()
 *
 * \hideinitializer
 */
#define PT_INIT(pt) LC_INIT((pt)->lc)

/** @} */

/**
 * \name Declaration and definition
 * @{
 */

/**
 * Declaration of a protothread.
 *
 * This macro is used to declare a protothread. All protothreads must
 * be declared with this macro.
 *
 * \param name_args The name and arguments of the C function
 * implementing the protothread.
 *
 * \hideinitializer
 */
#define PT_THREAD(name_args) char name_args

/**
 * Declare the start of a protothread inside the C function
 * implementing the protothread.
 *
 * This macro is used to declare the starting point of a
 * protothread. It should be placed at the start of the function in
 * which the protothread runs. All C statements above the PT_BEGIN()
 * invokation will be executed each time the protothread is scheduled.
 *
 * \param pt A pointer to the protothread control structure.
 *
 * \hideinitializer
 */
#define PT_BEGIN(pt)        \
  {                         \
    char PT_YIELD_FLAG = 1; \
    LC_RESUME((pt)->lc)

/**
 * Declare the end of a protothread.
 *
 * This macro is used for declaring that a protothread ends. It must
 * always be used together with a matching PT_BEGIN() macro.
 *
 * \param pt A pointer to the protothread control structure.
 *
 * \hideinitializer
 */
#define PT_END(pt)   \
  LC_END((pt)->lc);  \
  PT_YIELD_FLAG = 0; \
  PT_INIT(pt);       \
  return PT_ENDED;   \
  }

/** @} */

/**
 * \name Blocked wait
 * @{
 */

/**
 * Block and wait until condition is true.
 *
 * This macro blocks the protothread until the specified condition is
 * true.
 *
 * \param pt A pointer to the protothread control structure.
 * \param condition The condition.
 *
 * \hideinitializer
 */
#define PT_WAIT_UNTIL(pt, condition) \
  do {                               \
    LC_SET((pt)->lc);                \
    if (!(condition)) {              \
      return PT_WAITING;             \
    }                                \
  } while (0)

/**
 * Block and wait while condition is true.
 *
 * This function blocks and waits while condition is true. See
 * PT_WAIT_UNTIL().
 *
 * \param pt A pointer to the protothread control structure.
 * \param cond The condition.
 *
 * \hideinitializer
 */
#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond))

/** @} */

/**
 * \name Hierarchical protothreads
 * @{
 */

/**
 * Block and wait until a child protothread completes.
 *
 * This macro schedules a child protothread. The current protothread
 * will block until the child protothread completes.
 *
 * \note The child protothread must be manually initialized with the
 * PT_INIT() function before this function is used.
 *
 * \param pt A pointer to the protothread control structure.
 * \param thread The child protothread with arguments
 *
 * \sa PT_SPAWN()
 *
 * \hideinitializer
 */
#define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread))

/**
 * Spawn a child protothread and wait until it exits.
 *
 * This macro spawns a child protothread and waits until it exits. The
 * macro can only be used within a protothread.
 *
 * \param pt A pointer to the protothread control structure.
 * \param child A pointer to the child protothread's control structure.
 * \param thread The child protothread with arguments
 *
 * \hideinitializer
 */
#define PT_SPAWN(pt, child, thread) \
  do {                              \
    PT_INIT((child));               \
    PT_WAIT_THREAD((pt), (thread)); \
  } while (0)

/** @} */

/**
 * \name Exiting and restarting
 * @{
 */

/**
 * Restart the protothread.
 *
 * This macro will block and cause the running protothread to restart
 * its execution at the place of the PT_BEGIN() call.
 *
 * \param pt A pointer to the protothread control structure.
 *
 * \hideinitializer
 */
#define PT_RESTART(pt) \
  do {                 \
    PT_INIT(pt);       \
    return PT_WAITING; \
  } while (0)

/**
 * Exit the protothread.
 *
 * This macro causes the protothread to exit. If the protothread was
 * spawned by another protothread, the parent protothread will become
 * unblocked and can continue to run.
 *
 * \param pt A pointer to the protothread control structure.
 *
 * \hideinitializer
 */
#define PT_EXIT(pt)   \
  do {                \
    PT_INIT(pt);      \
    return PT_EXITED; \
  } while (0)

/** @} */

/**
 * \name Calling a protothread
 * @{
 */

/**
 * Schedule a protothread.
 *
 * This function shedules a protothread. The return value of the
 * function is non-zero if the protothread is running or zero if the
 * protothread has exited.
 *
 * \param f The call to the C function implementing the protothread to
 * be scheduled
 *
 * \hideinitializer
 */
#define PT_SCHEDULE(f) ((f) < PT_EXITED)
//#define PT_SCHEDULE(f) ((f))

/** @} */

/**
 * \name Yielding from a protothread
 * @{
 */

/**
 * Yield from the current protothread.
 *
 * This function will yield the protothread, thereby allowing other
 * processing to take place in the system.
 *
 * \param pt A pointer to the protothread control structure.
 *
 * \hideinitializer
 */
#define PT_YIELD(pt)          \
  do {                        \
    PT_YIELD_FLAG = 0;        \
    LC_SET((pt)->lc);         \
    if (PT_YIELD_FLAG == 0) { \
      return PT_YIELDED;      \
    }                         \
  } while (0)

/**
 * \brief      Yield from the protothread until a condition occurs.
 * \param pt   A pointer to the protothread control structure.
 * \param cond The condition.
 *
 *             This function will yield the protothread, until the
 *             specified condition evaluates to true.
 *
 *
 * \hideinitializer
 */
#define PT_YIELD_UNTIL(pt, cond)           \
  do {                                     \
    PT_YIELD_FLAG = 0;                     \
    LC_SET((pt)->lc);                      \
    if ((PT_YIELD_FLAG == 0) || !(cond)) { \
      return PT_YIELDED;                   \
    }                                      \
  } while (0)

/** @} */

#endif /* __PT_H__ */

#ifndef __PT_SEM_H__
#define __PT_SEM_H__

//#include "pt.h"

struct pt_sem {
  unsigned int count;
};

/**
 * Initialize a semaphore
 *
 * This macro initializes a semaphore with a value for the
 * counter. Internally, the semaphores use an "unsigned int" to
 * represent the counter, and therefore the "count" argument should be
 * within range of an unsigned int.
 *
 * \param s (struct pt_sem *) A pointer to the pt_sem struct
 * representing the semaphore
 *
 * \param c (unsigned int) The initial count of the semaphore.
 * \hide initializer
 */
#define PT_SEM_INIT(s, c) (s)->count = c

/**
 * Wait for a semaphore
 *
 * This macro carries out the "wait" operation on the semaphore. The
 * wait operation causes the protothread to block while the counter is
 * zero. When the counter reaches a value larger than zero, the
 * protothread will continue.
 *
 * \param pt (struct pt *) A pointer to the protothread (struct pt) in
 * which the operation is executed.
 *
 * \param s (struct pt_sem *) A pointer to the pt_sem struct
 * representing the semaphore
 *
 * \hideinitializer
 */
#define PT_SEM_WAIT(pt, s)             \
  do {                                 \
    PT_WAIT_UNTIL(pt, (s)->count > 0); \
    --(s)->count;                      \
  } while (0)

/**
 * Signal a semaphore
 *
 * This macro carries out the "signal" operation on the semaphore. The
 * signal operation increments the counter inside the semaphore, which
 * eventually will cause waiting protothreads to continue executing.
 *
 * \param pt (struct pt *) A pointer to the protothread (struct pt) in
 * which the operation is executed.
 *
 * \param s (struct pt_sem *) A pointer to the pt_sem struct
 * representing the semaphore
 *
 * \hideinitializer
 */
#define PT_SEM_SIGNAL(pt, s) ++(s)->count

#endif /* __PT_SEM_H__ */

//=====================================================================
//=== BRL4 additions for PIC 32 =======================================
//=====================================================================

extern volatile unsigned int time_tick_millsec;
// void __ISR(_TIMER_5_VECTOR, IPL2AUTO) Timer5Handler(void);
void PT_setup(void);
// macro to time a thread execution interveal in millisec
// max time 4000 sec
//#include <plib.h>
//#include <limits.h>
//#include "config.h"

#define PT_YIELD_TIME_msec(delay_time)                          \
  do {                                                          \
    static unsigned int time_thread;                            \
    time_thread = time_tick_millsec + (unsigned int)delay_time; \
    PT_YIELD_UNTIL(pt, (time_tick_millsec >= time_thread));     \
  } while (0);

// macro to return system time
#define PT_GET_TIME() (time_tick_millsec)

// init rate sehcduler
//#define PT_INIT(pt, priority)   LC_INIT((pt)->lc ; (pt)->pri = priority)
// PT_PRIORITY_INIT
#define PT_RATE_INIT() int pt_pri_count = 0;
// maitain proority frame count
// PT_PRIORITY_LOOP maitains a counter used to control execution
#define PT_RATE_LOOP() pt_pri_count = (pt_pri_count + 1) & 0xf;
// schecedule priority thread
// PT_PRIORITY_SCHEDULE
// 5 levels
// rate 0 is highest -- every time thru loop
// priority 1 -- every 2 times thru loop
// priority 2 -- every 4 times thru loop
//  3 is  -- every 8 times thru loop
#define PT_RATE_SCHEDULE(f, rate)                                \
  if ((rate == 0) | (rate == 1 && ((pt_pri_count & 0b1) == 0)) | \
      (rate == 2 && ((pt_pri_count & 0b11) == 0)) |              \
      (rate == 3 && ((pt_pri_count & 0b111) == 0)) |             \
      (rate == 4 && ((pt_pri_count & 0b1111) == 0)))             \
    PT_SCHEDULE(f);

// macro to use 4 bit DAC as debugger output
// level range 0-15; duration in microseconds
// -- with zero meaning HOLD it on forever
// while((signed int)ReadTimer45() <= time_hold){};
// time_hold = duration + ReadTimer45() ;
#define PT_DEBUG_VALUE(level, duration)    \
  \
do {                                       \
    static int i;                          \
    CVRCON = CVRCON_setup | (level & 0xf); \
    if (duration > 0) {                    \
      for (i = 0; i < duration * 7; i++) { \
      };                                   \
      CVRCON = CVRCON_setup;               \
    }                                      \
  \
}                                     \
  while (0)                                \
    ;

// macros to manipulate a semaphore without blocking
#define PT_SEM_SET(s) (s)->count = 1
#define PT_SEM_CLEAR(s) (s)->count = 0
#define PT_SEM_READ(s) (s)->count
#define PT_SEM_ACCEPT(s) \
  s->count;              \
  if (s->count) s->count--;

//====================================================================
//=== serial setup ===================================================
#ifdef use_uart_serial
///////////////////////////
// UART parameters

#define PB_DIVISOR \
  (1 << OSCCONbits.PBDIV)  // read the peripheral bus divider, FPBDIV
#define PB_FREQ sys_clock / PB_DIVISOR  // periperhal bus frequency
#define clrscr() printf("\x1b[2J")
#define home() printf("\x1b[H")
#define pcr() printf('\r')
#define crlf     \
  putchar(0x0a); \
  putchar(0x0d);
#define backspace 0x7f  // make sure your backspace matches this!
#define max_chars 64    // for input/output buffer
//====================================================================
// build a string from the UART2 /////////////
//////////////////////////////////////////////
char PT_term_buffer[max_chars];
int num_char;

int PT_GetSerialBuffer(struct pt *pt) {
  static char character;
  // mark the beginnning of the input thread
  PT_BEGIN(pt);

  num_char = 0;
  // memset(term_buffer, 0, max_chars);

  while (num_char < max_chars) {
    // get the character
    // yield until there is a valid character so that other
    // threads can execute
    PT_YIELD_UNTIL(pt, UARTReceivedDataIsAvailable(UART2));
    // while(!UARTReceivedDataIsAvailable(UART2)){};
    character = UARTGetDataByte(UART2);
    PT_YIELD_UNTIL(pt, UARTTransmitterIsReady(UART2));
    UARTSendDataByte(UART2, character);

    // unomment to check backspace character!!!
    // printf("--%x--",character );

    // end line
    if (character == '\r') {
      PT_term_buffer[num_char] = 0;  // zero terminate the string
      // crlf; // send a new line
      PT_YIELD_UNTIL(pt, UARTTransmitterIsReady(UART2));
      UARTSendDataByte(UART2, '\n');
      break;
    }  // backspace
    else if (character == backspace) {
      PT_YIELD_UNTIL(pt, UARTTransmitterIsReady(UART2));
      UARTSendDataByte(UART2, ' ');
      PT_YIELD_UNTIL(pt, UARTTransmitterIsReady(UART2));
      UARTSendDataByte(UART2, backspace);
      num_char--;
      // check for buffer underflow
      if (num_char < 0) {
        num_char = 0;
      }
    } else {
      PT_term_buffer[num_char++] = character;
    }
    // if (character == backspace)

  }  // end while(num_char < max_size)

  // kill this input thread, to allow spawning thread to execute
  PT_EXIT(pt);
  // and indicate the end of the thread
  PT_END(pt);
}

//====================================================================
// === send a string to the UART2 ====================================
char PT_send_buffer[max_chars];
int num_send_chars;

int PutSerialBuffer(struct pt *pt) {
  PT_BEGIN(pt);
  num_send_chars = 0;
  while (PT_send_buffer[num_send_chars] != 0) {
    PT_YIELD_UNTIL(pt, UARTTransmitterIsReady(UART2));
    UARTSendDataByte(UART2, PT_send_buffer[num_send_chars]);
    num_send_chars++;
  }
  // kill this output thread, to allow spawning thread to execute
  PT_EXIT(pt);
  // and indicate the end of the thread
  PT_END(pt);
}

//====================================================================
// === DMA send string to the UART2 ==================================

int PT_DMA_PutSerialBuffer(struct pt *pt) {
  PT_BEGIN(pt);
  // mPORTBSetBits(BIT_0);
  // check for null string
  if (PT_send_buffer[0] == 0) PT_EXIT(pt);
  // sent the first character
  PT_YIELD_UNTIL(pt, UARTTransmitterIsReady(UART2));
  UARTSendDataByte(UART2, PT_send_buffer[0]);
  // DmaChnStartTxfer(DMA_CHANNEL1, DMA_WAIT_NOT, 0);
  // start the DMA
  DmaChnEnable(DMA_CHANNEL1);
  // wait for DMA done
  // mPORTBClearBits(BIT_0);
  PT_YIELD_UNTIL(pt, DmaChnGetEvFlags(DMA_CHANNEL1) & DMA_EV_BLOCK_DONE);
  // wait until the transmit buffer is empty
  PT_YIELD_UNTIL(pt, U2STA & 0x100);

  // kill this output thread, to allow spawning thread to execute
  PT_EXIT(pt);
  // and indicate the end of the thread
  PT_END(pt);
}
#endif  //#ifdef use_uart_serial