RF Motion Controlled Robot

ECE 4760
A Project By Drew Mera (dnm54), Rohit Krishnakumar (rk496), and Asad Marghoob (am2242).


Demonstration Video



Introduction

For our final project, we designed and implemented a remote-control car with a user-controlled steering wheel interface. We wanted a user interface that was immediately intuitive and familiar, which we thought a steering wheel with an onboard accelerometer definitely accomplished. Additionally, we wanted a system that could realize reliable real-time remote communication, so we felt that an RF-controlled vehicle would be a viable way to see this through. Today, remote motion-control applications has an ever-growing presence in areas such as robotics and video games, so we thought it would be a great idea to become acquainted with this type of technology ourselves.


High Level Design

For the motion-controlled wheel, we knew that an accelerometer would be the most reliable bet when considering how to read motion input from a user. Additionally, considering the small range at which we needed to send data as well as the low complexity of the data packets themselves, we knew that the remote communication could be accomplished with a relatively cheap RF transmitter/receiver system. These types of modules tend to be unreliable and lacking in signal strengths across many applications, so we took it upon ourselves to see if we could implement it in a reliable manner.

The overall design includes two PIC32s, one of which is on the steering wheel (transmit side) and one of which is on the car (receive side). Naturally, the steering wheel has a transmitter, and the car has a receiver. The steering wheel has a button, which when pressed, allows remote communication to take place. The car also has two servo-controlled wheels that receive data from the receive-side PIC32.

The accelerometer is the first layer after the user interface; the motion from the user is detected by the accelerometer, and then sent to the PIC32 via I2C. Then, via a UART function, we put the values of the read accelerometer values onto the transmitter along with other pertinent bytes for control and termination. Then the values are sent via RF to the receiver, whose contents we read via another UART protothreads function. Upon decoding this information, we set the servos using PWM control according to the information sent in the payload (which reflects the motion input of the user).

Although the hardware modules for the transmit and receive were not expected to deliver perfect signal strength, it was inexpensive and we felt we could improve the reliability with both hardware and software considerations. For the software, there is a chance we could have come up with a novel and more effective protocol for RF communication; however, we opted to leverage existing Protothread UART library functions which worked just fine. Even so, we were able to build off of these functions and characterize them to work with our system’s needs.


Design

Software:

Acceleromter:

We used a Kionix KMX62 3-axis accelerometer mounted on a KMX61 evaluation board to detect the motion of the steering wheel and convert the motion into driving directions for the car. The KMX62 communicates with the PIC using I2C channel 1. For our communication, we defined two helper functions to initiate reads and writes from the PIC, both of which follow the protocols in the KMX62 manual (also see our commented code in the Appendix for specific details). Both the read and write functions use external functions defined in plib.h that properly send start signals, stop signals, and perform writes on the data line. The KMX62 stores the accelerometer values recorded from all three axes in registers divided into high and low bytes. To simplify this, we defined a read_int() function that reads the high and low bytes for a given axis and returns an integer that is the concatenation of the two bytes. These bytes are then converted to represent the direction in which the steering wheel is tilted, which corresponds to a driving direction. Tilting the wheel in the –z direction corresponds to the car driving forward, while tilting it in the +z direction corresponds to the car driving backward. Similarly, rotating the wheel toward the –x direction corresponds to turning right, and rotating it in the +x direction corresponds to turning left. All of these motions have two thresholds to indicate two different speeds—a normal and a fast threshold. The absolute thresholds are defined to be 6000 and 11000 for the normal and fast speeds, respectively. When the accelerometer is not tilted in either the x or z directions past these threshold values, the transmitter will send a stop signal to turn off the servos.






Pressure Sensor Picture

Further, we included a button on the front side of the steering wheel to serve as an ignition. It is connected to pin RA2 on the PIC using an internal pull-down resistor, and causes the accelerometer to not be read unless it is pressed. Thus, until the button is pressed, the transmission side sends a stop signal to the robot. Only when the button is pressed does the transmitter send valid directions to the robot to cause it to move.

RF Communication

When the data read from the accelerometer is sent to the steering wheel PIC, we then used a Protothreads library (outlined in the Bruce Land’s ece4760 documentation) to send bits to the transmitter. We used a 433.92 MHz Remote Transmitter module, and a 433.92 MHz Hi Sensitivity Receiver module. When the data reaches the receiver, we used the opposing functions from the same UART library for the PIC to retrieve the data the receiver. Now, we will detail the protocol by which we processed the accelerometer data, sent it to the transmitter and, in turn, the receiver side PIC32.


Transmit

As mentioned in the accelerometer description (see above), our program stipulated multiple threshold values across two axes that were key to the information we sent remotely to the system deployed on the car’s MCU. The file containing our accelerometer logic also included our transmit protocol. The transmission we are sending is run every 150 ms, and first checks for if the button on the steering wheel is being pressed. If it is, the rest of the transmit logic can follow. Our options regarding the packets of information that can be sent to the transmitter are back, forward, right, left, “fast” versions of these four, and stop. Mapped to our z-axis readings is the forward and backwards direction; if the value is above our predetermined threshold, we command “forward”, if it is above the predetermined “fast” threshold, we command “forward fast”. The negation of these values is used for the “back” and “back fast” functionality. This structure is parallel to that of the x-axis reading for left and right (left is triggered for values above positive thresholds, while right is triggered for values below the negative thresholds).

Pressure Sensor Picture

In every case, regardless of which direction we arrive on, a series of 8 bytes will be sent. First, we send 0xaa, 0xaa. The receiver inherently amplifies noise to make for a discernible signal, and so it will always output a signal of reasonable magnitude even if it actually only detecting noise. If we were to send our payload immediately, the gain factor on the receiver would obscure our data since it has very recently of working with noise. We send two bytes of 0xaa as a mechanism to allow the device to calibrate to the appropriate gain for the values we will be working with. Our 0xff byte is next in the succession to hold this newly found gain parameter to the right amount. The first byte of our start signal, 0xfa, comes next. This value is unique enough such that it will not likely be emulated by noise and therefore have the rest of the sequence be inadvertently triggered by a false positive. To take this idea one step further and make the signal even more uncharacteristic of noise, we add another 0xfa for good measure. This two byte start signal is defined on our receiver side (see below), allowing it to know where the actual pertinent payload begins. Next comes our payload. Here we have the first (and only) source of deviation between the nine options of packages being sent across the 8-byte sequence. Based off of which conditional case we are in (each corresponding to a given normal direction, fast direction, or stop), we put a specific byte next in the sequence that is hardcoded to a particular command. Each one of the nine options has a specific hard-coded byte that will remain static across the transmission to the receiver. After this byte, we transmit 0x77, which is the stop signal to let the receiver know that we are ending the transmission sequence. Finally, we send 0x00 to indicate the end of our transmission.

Across all of this processing, however, our data has not ventured to the transmitter itself. This is accomplished by the UART functions in the Protothreads libraries mentioned earlier (found in ece4760 documentation). In order for the 8-byte sequence to be sent, we needed to first print the bytes into the right buffer, which is the PT_send_buffer. This is the buffer used in the function PT_DMA_PutSerialBuffer(), which sends the information to the transmitter via UART2.


Receive

The transmitted signals are read from the receiver to the PIC through port RA1 which serves as the UART2 RX port. We used Bruce Lands Protothreads library here again to facilitate the UART communication to read values from the receiver into a buffer that could in turn by sent to the servos via PWM. Specifically, we used the GetMachineBuffer() function to retrieve the data being sent to the receiver. We made a few modifications to this function, one of which was adding a check for framing errors and exiting from the current loop. The reason for this goes back to the fact that the receiver will amplify whatever signal it receives, including noise, to what it considers a valid level. When the receiver is amplifying noise there is almost always a framing error that occurs because the noise is unstructured. Thus by checking for framing errors and timing out, we are able to essentially ignore the noise from our surroundings.

Pressure Sensor Picture

We also added in a system for timing out while trying to read characters that prevents our robot from hanging if transmission stops. If there is a timeout, we clear the information in the buffer and therefore do not send a valid value for the wheels to turn. However, in the event that the system does not timeout, we put the contents of the PT_term_buffer into our cmd variable, of which cmd[1] contains our encoding for the direction that we want the wheels to follow. Now, we have multiple case blocks based off of this cmd[1] value that will set the wheels according to the byte that was encoded on the transmit side. To reiterate from before, this is the value that has been maintained across the remote transmission (7th byte in the transmission package). For more information on the PWM control to the wheels, refer to the PWM section. In the transmit package, we also had a signal 0x77 that told the receiver to stop reading and processing transmitted information. This idea was implemented in the receive code with PT_terminate_char = '\x77', which tells the program to terminate upon reading this signal.

Servos:

To control the Parallax servos, we used two different PWM channels using Output Compare Units 2 and 3 running off of Timer 2. Timer 2 is set to time out after 53333 clock cycles, along with a prescaler of 16. These values were chosen to give approximately 20 ms between pulses, as specified in the datasheet for the servos. Since we were having trouble setting the 20 ms pause between pulses, we changed the timeout of the timer and the prescaler while observing the output of the PWM channel on the oscilloscope until we received the desired waveform. Then, we adjusted the number of clock cycles for which the PWM is high, using pwm_on_time(), to determine the pulse width of a 1 ms pulse. Once we found this to be 2500 cycles, we were able to simply modulate the servos’ motion by changing the pulse width from 1.3 ms (clockwise) to 1.7 ms (counterclockwise) by multiplying 2500 by the desired pulse width.




Pressure Sensor Picture

Hardware:

Transmit Side Circuitry:

The Transmit Side Schematic (shown in the Schematic Appendix) depicts all the hardware on the steering wheel side including the accelerometer, transmitter, and transmit button. The transmitter had four pins, ground, power, data input, and an antenna. We soldered on a 22 pF capacitor to the antenna pin and then a wire to create a 17 cm long antenna overall. The antenna was made to be 17cm as this is the optimal length for reliable transmissions. We used the PIC’s 3.3V as power, however we also placed a choke on the power from the MCU. This choke was just a piece of wire coiled which then acts as an inductor because at high frequencies (such as 433 MHz) this acts as a transmission line. The choke helps to filter out noise from the power supply. Ground was also connected to the PIC’s ground, the only addition here was that we placed a 10 uF capacitor between power and ground on the breadboard. We also placed a .1 uF capacitor between ground and power again but this time directly on the board for the transmit module. Lastly, the data in pin was connected to RB10 as this was the UART2 TX pin.

The KMX62 accelerometer circuit consists of a typical master-slave configuration for I2C applications as can be seen in the schematic in Appendix C. We use six pins on the accelerometer: VDD, IO_VDD, ADDR, GND, SCL, and SDA. VDD powers the device and is set to 2.6 V, sourced from a diode connected in series with a resistor and a capacitor in parallel (see the transmit schematic below). IO_VDD is the power supply for the digital communication bus and is also set to 2.6 V. ADDR can be tied to either IO_VDD or GND, allowing the user to change the slave address of the device. In this case, we drive ADDR high with 2.6 V, corresponding to read and write addresses of 0x1F and 0x1E, respectively. SCL is the serial clock for I2C that is outputted from the PIC through RB8. SDA is the serial data line over which data is sent between the master and the slave and is connected to the PIC via RB9. Both SDA and SDL are tied to 2.6 V with 5 kΩ pull-up resistors. I2C devices can only pull these lines low due to their internal hardware, so the pull-up resistors are needed to pull the lines high.

For the transmit button, since we utilized internal pulldowns we simply had to connect the button to 3.3V from the MCU and then connect the other pin of the button to RA2. This enabled us to read the button state and use this to toggle transmission.


Pressure Sensor Picture

Receive Side Circuitry

The Receive Side Schematic (shown in the Schematic Appendix) shows the hardware we implemented for the robot end of the project. This circuit included the receiver module and the two servos for robot movement.

The receiver module had three pins for ground and two pins for Vcc which we connected to the MCU ground and power. We again utilized a choke between power and ground just as with the transmit circuit in order to serve as a low pass filter for noise from the power supply. We also had a 10 uF capacitor between ground and power. The receiver module also had a pin that worked as the antenna on which we connected a 22 pF capacitor and soldered a 17cm wire. We also made sure to keep the orientation of the antennas the same on the transmit and receive ends, meaning that they were pointed in the same direction, say upwards, so that the polarization of the signal would be the same. Lastly, the receiver had a digital out pin on which is sent the signals it was reading. We connected this pin to MCU pin RA1 which was the UART2 RX pin. All of these factors in our receiver circuitry helped to improve signal strength and reliability.

The servos were also wired along with the receiver module as this was the robot end of project. The servos had three pins each, power, ground, and control. The servos required a separate power and ground as seen in the schematic above. We accomplished this by utilizing a battery pack mounted on the underside of the robot chassis. The control lines were of the servo were connected to pins RA3 and RB5 where we outputted our PWM control signals.


Pressure Sensor Picture

Results

Our design worked well, especially considering the difficulty of using RF 434 MHz wireless transmission. We were able to achieve a range in which the car responded consistently of over a meter. This consistent response was achieved by sending data quickly so if there is a transmission miss or two, the response by the receiver was not delayed too much. However, sending the data more quickly caused the robot to jitter more often, potentially because the receiver does in fact receive data but that data has been corrupted somehow. Receiving a byte of data that does not match one of the directions simply causes the robot to stop until it received the next direction to move. This jitter can be seen in our movie below when we drive the robot, despite the fact that we increased the time between transmissions to 150 ms. We also reduced the baud rate of our data transmission from 4800 to 2400 bps to make the data transmission slower but cleaner. Other than this, it is hard to quantify the performance of our robot, for the range highly depends on the environment and the angles at which the steering wheel is pointed relative to the robot.

The main way that we ensured safety in the design was to make sure that PT_GetMachineBuffer() times out when unsuccessfully looking for a signal. Before we fixed this, when the robot would move out of range, it would continue to search for a valid data transmission until it received one. During this time, the robot would continue to move in the last valid direction that it received, making it move farther out of range. Now, when a timeout occurs, the robot will clear the command buffer and stop moving. In addition, we implemented an ignition button so the robot does not move until the button is pressed. This way, the steering wheel can be placed down without causing the robot to inadvertently move.

Since we used RF transmission, there is a possibility of RF interference with our design. We are confident that our design is tolerant to RF interference, unless of course the interference corrupts our actual data transmission. Our design uses UART to get rid of any potential errors, and then each transmission contains two start characters of 0xFA. Both start characters must be read in order to determine that any data received is valid, so the system is quite robust to other sources of RF interference. In terms of our device interfering with other designs, our range is not incredibly high so there should not be many issues. Even if we receive incorrect or corrupted data somehow, the robot will just stop moving, keeping it safe from crashing and damaging anything. Further, prudence would suggest that any other design should use a robust garbage collection technique similar to that which we implemented to only receive valid data.

Overall, we created a device that works well given the transmission device that we used. Although RF 434 transmission was difficult, it made us define our own protocol that is robust to noise and interference. We were also able to ensure that the car stops when going out of range, ensuring safety. Our design was meant to have a natural feel, with the movement of the steering wheel mimicking that of a real car’s steering wheel. Tilting the wheel forward and backward makes the car move accordingly. Usability is further improved by having two different speeds for each direction by tilting the wheel at different angles.


Conclusion

Our final results definitely satisfied our expectations for the project, as our desire to make an intuitive interface coupled with a responsive RC component was ultimately realized. The reliability of our system surpassed our initial expectations as we were unsure as to how consistent our transmission of signals would be. In addition, we added in two different speeds for the robot based on the angle of tilt of the steering wheel which was a convenient feature that we did not originally expect in our final results.

If we were to replicate this project or do something very similar for next time (and used 434 Mhz RF again), I think we would be more cognizant of how to deal with signal strength from the beginning. For this project, we constantly found ourselves confused during the debugging process for scoping an actual signal from RF. If we were to implement RF again, we would research what hardware measures (chokes, capacitors) to incorporate to improve our signal strength. Additionally, we would be more careful in how we checked for the signal at different stages. In other words, we often checked to see if the signal was being transmitted across without meticulously checking that the integrity of the signal was being maintained across every previous step in its path.

If we were to improve upon our project, we would probably use a transmission technology that is easier to work with and has a higher range. We mainly chose to do RF 434 because using a simpler technology would have been less interesting in terms of a classroom project. If we had not used it, we would not have learned nearly as much. Realistically, we recognize that this choice was not necessarily a choice of feasibility but rather a choice to make our project more interesting and intellectually stimulating.

We needed to keep FCC standards in mind due to our use of a transmitter. The FCC stipulates that if the use of RF is designated under “General Population/Uncontrolled Exposure” (which our project is), then we have to conform to certain standards with our power density. FCC guidelines rule that if the frequency we are working with is in the range of 300-1500 MHz, the power density must be less than f/1500. Other ethics and safety considerations are making sure that the immediate vicinity is clear of any unsuspecting persons to avoid possibly harmful collisions in addition to the safety measures explained in the Results section.

In terms of intellectual property, we only used code from Bruce Land’s website and the Pose project (attributed below) for I2C code. Our inspiration also came online from a Hand Motion Controlled Vehicle project, but our design is sufficiently different and is using a different microcontroller.




Appendix A:

The group approves this report for inclusion on the course website.
The group approves the video for inclusion on the course YouTube channel.

Appendix B: Schematics

Generic placeholder image

Schematic 1: Transmission Side Schematic


Generic placeholder image

Schematic 2: Receive Side Schematic

Appendix C: Parts List

  • Kionix KMX62 Acceleromter $0 - ECE 4760 Surplus
  • RF 434 tx/rx module $0 - ECE 4760 Surplus
  • 2 Parallax Continuous Rotation Servos $20 - ECE 4760 Lab
  • Robot Chassis $25 - Bruce's Office
  • 5 Jumper Cables $.50 - ECE 4760 Lab
  • 2 Microstick II's $2 - ECE 4760 Lab
  • 2 Small Boards $8 - ECE 4760 Lab
  • 2 Solder Boards $5 - ECE 4760 Lab
  • 2 PIC32MX250F128B's $10 - ECE 4760 Lab
  • 1 Push Button $0 - ECE 4760 Surplus
  • 2 9V Batteries $4 - Purchased from 7/11
  • Total: $75

    Appendix D: Work Distribution

    Generic placeholder image

    Drew

    dnm54@cornell.edu

    • Soldered the Small Boards
    • Worked on the Accelerometer and I2C
    • Soldered TX Protoboard
    • Helped with finishing touches on RF (improving signal strength with capacitors and inductors and with modifying PT_GetMachineBuffer())
    Generic placeholder image

    Rohit

    rk496@cornell.edu

    • Soldered the RX Protoboard
    • Worked on the RF Communication
    • Helped with Servo PWM
    • Worked on improving signal strength of RF communication
    Generic placeholder image

    Asad

    am2242@cornell.edu

    • Soldered the RX Protoboard
    • Worked on the RF Communication
    • Helped with Servo PWM
    • Worked on improving signal strength of RF communication

    Appendix E: References

    Inspiration from Hand Motion Controlled Robot Vehicle
    Kionix KMX61 evaluation board pinout (Kionix’s datasheets were incorrect). I2C code also adapted from here.
    Kionix KMX62 User Manual
    434 RF Link Receiver
    434 RF Link Transmitter
    Parallax Continuous Rotation Servo Datasheet
    Bruce Land's Protothreads
    Transmitter Image

    Website Template given by Joe Skovira, ECE 5725


    Appendix F: Code

    
                      /*
                      ************************************************************************
                      
                      Motion Controlled RF Car: RX Code
                      
                      By:  Drew Mera, Rohit Krishnakumar, and Asad Marghoob
                      
                      Adapted from: ECE 4760 "TFT, keypad, DAC, LED, PORT EXPANDER test
                      With serial interface to PuTTY console" sample code
                      
                      Used with PIC32 small board
                      
                      ************************************************************************
                      */
                      
                      ////////////////////////////////////
                      // clock AND protoThreads configure!
                      // You MUST check this file!
                      #include "config.h"
                      // threading library
                      #include "pt_cornell_rx.h"
                      
                      
                      // === thread structures ============================================
                      // thread control structs
                      static struct pt pt_serial;
                      // note that UART input and output are threads
                      // The following threads are necessary for UART control
                      static struct pt pt_input, pt_output, pt_DMA_output ;
                      
                      
                      //=== Serial terminal thread =================================================
                      static char buffer [120];
                      static PT_THREAD (protothread_serial(struct pt *pt))
                      {
                      PT_BEGIN(pt);
                      // the command buffer where the RF sequence of bytes gets dumped when
                      // we use sscanf() to get ethe contents of the PT_term_buffer
                      static char cmd[30];
                      
                      // another part of the PT_term_buffer that we discard
                      static float value;
                      
                      while(1) {
                      // Terminate after exactly 5 characters
                      // or
                      // Terminate after 0.5 seconds
                      // or when the terminate character, '\x77', is encountered
                      PT_terminate_char = '\x77' ;
                      PT_terminate_count = 5 ;
                      PT_terminate_time = 500 ;
                      
                      // gets a string of bytes from the digital output of the rx module
                      // and puts it into the PT_term_buffer
                      PT_SPAWN(pt, &pt_input, PT_GetMachineBuffer(&pt_input) );
                      
                      // returns when the thread dies on the termination condition
                      // IF using PT_GetMachineBuffer, could be on timeout, terminate count,
                      // or the terminate character
                      if(PT_timeout==0) {
                      sscanf(PT_term_buffer, "%s %f", cmd, &value);
                      }
                      // no actual string if the read timed out, so zero the buffer values;
                      // this should be done by PT_GetMachineBuffer anyway
                      else {
                      cmd[0] = 0 ;
                      cmd[1] = 0 ;
                      cmd[2] = 0 ;
                      }
                      
                      // decode the input received; cmd[1] stores the byte indicating
                      // direction and speed sent from accelerometer
                      // set the PWM values of the servos accordingly; for 2500*x,
                      // x indicates the width of the pulse in milliseconds;
                      // 1.7 and 1.3 are the two extremes according to the datasheet
                      switch(cmd[1]) {
                      // back fast
                      case '\x82':
                      SetDCOC3PWM(2500*1.7);
                      SetDCOC2PWM(2500*1.3);
                      break;
                      // back
                      case '\x81':
                      SetDCOC3PWM(2500*1.55);
                      SetDCOC2PWM(2500*1.475);
                      break;
                      // forward fast
                      case '\x22':
                      SetDCOC3PWM(2500*1.3);
                      SetDCOC2PWM(2500*1.7);
                      break;
                      // forward
                      case '\x21':
                      SetDCOC3PWM(2500*1.485);
                      SetDCOC2PWM(2500*1.55);
                      break;
                      // left fast
                      case '\x12':
                      SetDCOC3PWM(2500*1.3);
                      SetDCOC2PWM(2500*1.52);
                      break;
                      // left
                      case '\x11':
                      SetDCOC3PWM(2500*1.45);
                      SetDCOC2PWM(2500*1.52);
                      break;
                      // right fast
                      case '\x42':
                      SetDCOC3PWM(2500*1.515);
                      SetDCOC2PWM(2500*1.7);
                      break;
                      // right
                      case '\x41':
                      SetDCOC3PWM(2500*1.515);
                      SetDCOC2PWM(2500*1.55);
                      break;
                      // stop if anything else; our explicit stop character is '\x23'
                      default:
                      SetDCOC3PWM(2500*1.515);
                      SetDCOC2PWM(2500*1.52);
                      
                      }
                      // never exit while
                      } // END WHILE(1)
                      PT_END(pt);
                      } // thread 3
                      
                      
                      // === Main  ======================================================
                      void main(void) {
                      
                      ANSELA = 0; ANSELB = 0;
                      
                      // === Config timer and output compare to make PWM ========
                      
                      // set timeout to be 53,333 ticks
                      int gen_period =  40000000/750;
                      
                      // set up timer2 to generate period with 20 ms in between pulses;
                      // gen_period and prescaler values determined by using oscilloscope
                      OpenTimer2(T2_ON | T2_SOURCE_INT | T2_PS_1_16, gen_period);
                      
                      ConfigIntTimer2(T2_INT_ON | T2_INT_PRIOR_2);
                      mT2ClearIntFlag(); // and clear the interrupt flag 
                      
                      // set up output compare3 for PWM  
                      
                      // initially stop the servos; 2500 cycles gives a pulse width of 1 ms;
                      // servo datasheet says that 1.5 ms is stop width
                      // 1.515 ms is what actually stops servo 1
                      int pwm_on_time =  2500*1.515;
                      
                      OpenOC3(OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE , pwm_on_time, pwm_on_time); // 
                      // OC3 is PPS group 4, map to RPB9 (pin 18) 
                      PPSOutput(4, RPA3, OC3);
                      
                      // set up output compare2 for other PWM using the same timer
                      
                      // 1.515 ms is what actually stops servo 2
                      int pwm_on_time_2 =  2500*1.52;
                      
                      OpenOC2(OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE , pwm_on_time_2, pwm_on_time_2); // 
                      // OC2 is PPS group 2, map to RPB5
                      PPSOutput(2, RPB5, OC2);
                      
                      
                      // === config threads ==========
                      // turns OFF UART support and debugger pin, unless defines are set
                      PT_setup();
                      
                      // init the threads
                      PT_INIT(&pt_serial);
                      
                      // round-robin scheduler for threads
                      while (1){
                      PT_SCHEDULE(protothread_serial(&pt_serial));
                      }
                      } // main
                      // === end  ======================================================
                  
    
                      /*
                      * File:   config_1_2_3.h
                      * Author: Syed Tahmid Mahbub
                      * Modifed by: Bruce Land
                      * Created on July 10, 2018
                      *
                      */
                      
                      #ifndef CONFIG_H
                      #define	CONFIG_H
                      #define _SUPPRESS_PLIB_WARNING
                      #define _DISABLE_OPENADC10_CONFIGPORT_WARNING
                      #include 
                          // serial stuff
                          #include 
                              
                              //=============================================================
                              // 60 MHz
                              #pragma config FNOSC = FRCPLL, POSCMOD = OFF
                              #pragma config FPLLIDIV = DIV_2, FPLLMUL = MUL_20, FPLLODIV = DIV_2  //40 MHz
                              #pragma config FPBDIV = DIV_1 // PB 40 MHz
                              #pragma config FWDTEN = OFF,  JTAGEN = OFF
                              #pragma config FSOSCEN = OFF  //PINS 11 and 12 to secondary oscillator!
                              #pragma config DEBUG = OFF   // RB4 and RB5
                              //==============================================================
                              // Protothreads configure
                              
                              // IF use_vref_debug IS defined, pin 25 is Vref output
                              //#define use_vref_debug
                              
                              // IF use_uart_serial IS defined, two pins are used by the uart
                              // Go to pt_cornell_1_2_3.h and search for "SET UART i/o PINS"
                              #define use_uart_serial
                              #define BAUDRATE 2400 // must match PC terminal emulator setting 38400 works
                              
                              /////////////////////////////////
                              // 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
                              
                              #endif	/* CONFIG_H */
                  
    
                      /*
                      ************************************************************************
                      
                      Motion Controlled RF Car: TX Code
                      
                      By:  Drew Mera, Rohit Krishnakumar, and Asad Marghoob
                      
                      Adapted from: ECE 4760 "TFT, keypad, DAC, LED, PORT EXPANDER test
                      With serial interface to PuTTY console" sample code
                      
                      Used with PIC32 small board
                      
                      ************************************************************************
                      */
                      
                      ////////////////////////////////////
                      // clock AND protoThreads configure!
                      // You MUST check this file!
                      #include "config.h"
                      // threading library
                      #include "pt_cornell_tx.h"
                      #include 
                          #include "plib.h"
                          
                          // the read and write addresses for the accelerometer; taken from KMX62 manual
                          // for case where ADDR is high
                          #define ADDR_Read 0x1F
                          #define ADDR_Write 0x1E
                          
                          // the thresholds for the accelerometer readings
                          #define THRESHOLD 6000
                          #define THRESHOLD_FAST 11000
                          
                          // Macro for enabling internal pull-downs for buttons
                          #define EnablePullDownA(bits) CNPUACLR=bits;CNPDASET=bits;
                          
                          // wait function for I2C using NOPs
                          void i2c_wait(unsigned int t) {
                          while(--t) {
                          asm("nop");
                          asm("nop");
                          }
                          }
                          
                          // [reg_addr] is the register address for the KMX62 to which we want to write
                          // [value] is the value we want to write to [reg_addr]
                          // [write(reg_addr, value)] writes [value] to [reg_addr] using I2C protocol
                          // with the KMX62 accelerometer
                          void write(char reg_addr, char value) {
                          // send the start condition
                          StartI2C1();
                          IdleI2C1();
                          
                          // indicate we would like to initiate a write and wait for completion
                          MasterWriteI2C1(ADDR_Write);
                          IdleI2C1();
                          while(I2C1STATbits.ACKSTAT);
                          
                          // send the register to which we want to write and wait
                          MasterWriteI2C1(reg_addr);
                          IdleI2C1();
                          while(I2C1STATbits.ACKSTAT);
                          
                          // send the value we want to write to the above register
                          MasterWriteI2C1(value);
                          IdleI2C1();
                          while(I2C1STATbits.ACKSTAT);
                          
                          // send the stop condition
                          StopI2C1();
                          IdleI2C1();
                          }
                          
                          // [reg_addr] is the register in the KMX62 from which we would like to read
                          // [read(reg_addr)] returns the value stored in [reg_addr]
                          char read(char reg_addr) {
                          // send the start condition
                          StartI2C1();
                          IdleI2C1();
                          
                          // indicate we would like to initiate a write and wait for completion
                          MasterWriteI2C1(ADDR_Write);
                          IdleI2C1();
                          while(I2C1STATbits.ACKSTAT);
                          
                          // send the register address from which we wish to read
                          MasterWriteI2C1(reg_addr);
                          IdleI2C1();
                          while(I2C1STATbits.ACKSTAT);
                          
                          // sent the restart condition and wait for 20 NOP cycles
                          RestartI2C1();
                          i2c_wait(10);
                          IdleI2C1();
                          
                          // indicate that we would like to read
                          MasterWriteI2C1(ADDR_Read);
                          IdleI2C1();
                          while(I2C1STATbits.ACKSTAT);
                          
                          // retrive the value that was read out from the KMX62 and wait
                          char data = MasterReadI2C1();
                          IdleI2C1();
                          i2c_wait(10);
                          
                          // send the NACK to finish the read operation
                          NotAckI2C1();
                          
                          // sent the stop signal
                          StopI2C1();
                          IdleI2C1();
                          
                          return data;
                          
                          }
                          
                          // [axis] is the axis from which we would like to read on the KMX62;
                          // [axis] can be either 'X', 'Y', or 'Z'
                          // [read_int(axis)] returns an int that is the concatenation of the
                          // high and low bit values from the KMX62 for the given axis
                          short read_int(char axis) {
                          int byte_high, byte_low;
                          int output;
                          
                          // read different registers depending on the axis; get both bytes
                          // by reading characters from the high and low registers
                          // register values can be found in the KMX62 manual
                          switch (axis){
                          case 'X':
                          byte_high = (int)read(0x0B);
                          byte_low = (int)read(0x0A);
                          break;
                          case 'Y':
                          byte_high = (int)read(0x0D);
                          byte_low = (int)read(0x0C);
                          break;
                          case 'Z':
                          byte_high = (int)read(0x0F);
                          byte_low = (int)read(0x0E);
                          break;
                          default:
                          byte_high = 0;
                          byte_low = 0;
                          }
                          
                          
                          // shift the high byte left a full byte and add the lower byte,
                          // giving the full integer value read out from the accelerometer
                          output = (byte_high << 8) + byte_low ;
                              
                              return output;
                              
                              }
                              
                              // === thread structures ============================================
                              // thread control structs
                              static struct pt pt_serial;
                              // note that UART input and output are threads
                              // The following threads are necessary for UART control
                              static struct pt pt_input, pt_output, pt_DMA_output ;
                              
                              // accelerometer values from each access
                              int accel_x, accel_y, accel_z;
                              
                              //=== Serial terminal thread =================================================
                              static PT_THREAD (protothread_serial(struct pt *pt))
                              {
                              PT_BEGIN(pt);
                              while(1) {
                              
                              // we are sending a transmission ever 150 ms
                              PT_YIELD_TIME_msec(150) ;
                              
                              // if the button is pressed down, we will transmit the accelerometer values
                              if (mPORTAReadBits(BIT_2) != 0) {
                              // send the prompt via DMA to serial
                              
                              
                              // get the accelerometer values
                              accel_x = read_int('X');
                              accel_y = read_int('Y');
                              accel_z = read_int('Z');
                              
                              /*
                              
                              ************ about the byte sequences below ************
                              
                              *  "\xaa\xaa\xff" is the beginnig sequence to start up the rx module
                              *  "\xfa\xfa" are the start characters that help the rx code
                              determine if a transmission is valid and has a valid payload
                              *  the next byte that follows is the actual payload
                              *  '\x77' is the stop character for the rx to know a transmission ended
                              *  '\x00' is the stop character for PT_DMA_PutSerialBuffer() to stop transmission
                              
                              */
                              
                              // determine direction to send using the pre-defined accelerometer
                              // tresholds; forward and back have precedence over turning
                              
                              // back fast
                              if (accel_z > THRESHOLD_FAST) {
                              sprintf(PT_send_buffer,"\xaa\xaa\xff\xfa\xfa\x82\x77\x00");
                              }
                              // back
                              else if (accel_z > THRESHOLD) {
                              sprintf(PT_send_buffer,"\xaa\xaa\xff\xfa\xfa\x81\x77\x00");
                              }
                              
                              // forward fast
                              else if (accel_z < -THRESHOLD_FAST) {
                                  sprintf(PT_send_buffer,"\xaa\xaa\xff\xfa\xfa\x22\x77\x00");
                                  }
                                  // forward 
                                  else if (accel_z < -THRESHOLD) {
                                  sprintf(PT_send_buffer,"\xaa\xaa\xff\xfa\xfa\x21\x77\x00");
                                  }
                                  // right fast
                                  else if (accel_x < -THRESHOLD_FAST) {
                                  sprintf(PT_send_buffer,"\xaa\xaa\xff\xfa\xfa\x42\x77\x00");
                                  }
                                  // right
                                  else if (accel_x < -THRESHOLD) {
                                  sprintf(PT_send_buffer,"\xaa\xaa\xff\xfa\xfa\x41\x77\x00");
                                  }
                                  // left fast
                                  else if (accel_x > THRESHOLD_FAST) {
                                  sprintf(PT_send_buffer,"\xaa\xaa\xff\xfa\xfa\x12\x77\x00");
                                  }
                                  // left
                                  else if (accel_x > THRESHOLD) {
                                  sprintf(PT_send_buffer,"\xaa\xaa\xff\xfa\xfa\x11\x77\x00");
                                  }
                                  // stop
                                  else{
                                  sprintf(PT_send_buffer,"\xaa\xaa\xff\xfa\xfa\x23\x77\x00");
                                  }
                                  
                                  }
                                  
                                  // send the stop byte if the button is not pressed
                                  else sprintf(PT_send_buffer,"\xaa\xaa\xff\xfa\xfa\x23\x77\x00");
                                  
                                  
                                  // send our byte sequence by spawning a print thread
                                  PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
                                  
                                  // never exit while
                                  } // END WHILE(1)
                                  PT_END(pt);
                                  }
                                  
                                  // === Main  ======================================================
                                  void main(void) {  
                                  ANSELA = 0; ANSELB = 0; 
                                  
                                  // start the I2C w/ PGD of 104 ns and FSCK of 400 kHz
                                  OpenI2C1(I2C_ON, 0x02C);
                                  
                                  // write 0x00 to CTL2 to disable sensor
                                  write(0x3A, 0x00);
                                  
                                  // write 0x22 to ODCTL to set ODR to 50 Hz
                                  write(0x2c, 0x22);
                                  
                                  // write 0x0F to CTL2 to disable temp sense, set accel to
                                  // operating mode, disable the Magnetometer
                                  write(0x3A, 0x0D);
                                  
                                  
                                  // set the button pin as an input and enable the internal pulldown
                                  mPORTASetPinsDigitalIn(BIT_2);
                                  EnablePullDownA(BIT_2)
                                  
                                  // === config threads ==========
                                  // turns OFF UART support and debugger pin, unless defines are set
                                  PT_setup();
                                  
                                  // === setup system wide interrupts  ========
                                  INTEnableSystemMultiVectoredInt();
                                  
                                  // init the threads
                                  PT_INIT(&pt_serial);
                                  
                                  // round-robin scheduler for threads
                                  while (1){
                                  PT_SCHEDULE(protothread_serial(&pt_serial));
                                  }
                                  } // main
                                  // === end ======================================================
                  
    
                      /*
                      * File:   pt_cornell_tx.h; same as pt_cornell_1_2_3.h
                      * Author: brl4
                      * Bruce R Land, Cornell University
                      * Created on July 10, 2018
                      */
                      
                      /*
                      * 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 
                          *
                          * $Id: pt.h,v 1.7 2006/10/02 07:52:56 adam Exp $
                          */
                          #include 
                              /**
                              * \addtogroup pt
                              * @{
                              */
                              
                              /**
                              * \file
                              * Protothreads implementation.
                              * \author
                              * Adam Dunkels 
                                  *
                                  */
                                  
                                  #ifndef __PT_H__
                                  #define __PT_H__
                                  
                                  ////////////////////////
                                  //#include "lc.h"
                                  ////////////////////////
                                  /**
                                  * \file lc.h
                                  * Local continuations
                                  * \author
                                  * Adam Dunkels 
                                      *
                                      */
                                      
                                      #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 not 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__ */
                                      
                                      
                                      
                                      //////////////////////////////////////////
                                      struct pt {
                                      lc_t lc;
                                      int pri;
                                      };
                                      
                                      #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 =======================================
                                          //=====================================================================
                                          
                                          // macro to time a thread execution interveal in millisec
                                          // max time 4000 sec
                                          //#include 
                                              //#include 
                                                  //#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; icount=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
                                                              // PuTTY serial terminal control codes
                                                              // see 
                                                              // http://ascii-table.com/ansi-escape-sequences-vt-100.php
                                                              #define cursor_pos(line,column) printf("\x1b[%02d;%02dH",line,column) 
                                                              #define clr_right printf("\x1b[K")
                                                              // from http://www.comptechdoc.org/os/linux/howlinuxworks/linux_hlvt100.html
                                                              // and colors from http://www.termsys.demon.co.uk/vtansi.htm
                                                              #define green_text printf("\x1b[32m")
                                                              #define yellow_text printf("\x1b[33m")
                                                              #define red_text printf("\x1b[31m")
                                                              #define rev_text printf("\x1b[7m")
                                                              #define normal_text printf("\x1b[0m")
                                                              //====================================================================
                                                              // build a string from the UART2 /////////////
                                                              // assuming that a HUMAN is typing at a terminal!
                                                              //////////////////////////////////////////////
                                                              char PT_term_buffer[max_chars];
                                                              int PT_GetSerialBuffer(struct pt *pt)
                                                              {
                                                              static char character;
                                                              static int num_char;
                                                              // mark the beginnning of the input thread
                                                              PT_BEGIN(pt);
                                                              
                                                              num_char = 0;
                                                              // clear buffer
                                                              memset(PT_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);
                                                              }
                                                              
                                                              //====================================================================
                                                              // build a string from the UART2 /////////////
                                                              // assuming MACHINE input
                                                              //////////////////////////////////////////////
                                                              // !!! you MUST specify EITHER a termination character or a count!!
                                                              //////////////////////////////////////////////
                                                              // -- terminator character could be  '\r'
                                                              // or any other characcter, e.g. '#' or can be set to ZERO
                                                              // if there is no termination character
                                                              // -- Termination count will return after N characters, regardless of
                                                              // the terminator character
                                                              // Set to ZERO if there is no termination count.
                                                              // -- Termination time is the longest the routine will wait 
                                                              // for a terminator event in milliseconds
                                                              char PT_terminate_char, PT_terminate_count ;
                                                              // terminate time default million seconds
                                                              int PT_terminate_time = 1000000000 ;
                                                              // timeout return value
                                                              int PT_timeout = 0; 
                                                              
                                                              // system time updated in TIMER5 ISR below
                                                              volatile unsigned int time_tick_millsec ;
                                                              
                                                              int PT_GetMachineBuffer(struct pt *pt)
                                                              {
                                                              static char character;
                                                              static unsigned int num_char, start_time;
                                                              // mark the beginnning of the input thread
                                                              PT_BEGIN(pt);
                                                              
                                                              // actual number received
                                                              num_char = 0;
                                                              //record milliseconds for timeout calculation
                                                              start_time = time_tick_millsec ;
                                                              // clear timeout flag
                                                              PT_timeout = 0;
                                                              // clear input buffer
                                                              memset(PT_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) || 
                                                                  ((PT_terminate_time>0) && (time_tick_millsec >= PT_terminate_time+start_time)));
                                                                  // grab the character from the uart buffer
                                                                  character = UARTGetDataByte(UART2);
                                                                  
                                                                  // Terminate on character match
                                                                  if ((character>0) && (character == PT_terminate_char)) {
                                                                  PT_term_buffer[num_char] = 0; // zero terminate the string
                                                                  // and leave the while loop
                                                                  break;
                                                                  }    
                                                                  // Terminate on count
                                                                  else if ( ((PT_terminate_count>0) && (num_char+1 >= PT_terminate_count))){
                                                                  // record the last character
                                                                  PT_term_buffer[num_char++] = character ; 
                                                                  // and terminate
                                                                  PT_term_buffer[num_char] = 0; // zero terminate the string
                                                                  // and leave the while loop
                                                                  break;
                                                                  }
                                                                  // terminate on timeout
                                                                  else if ((PT_terminate_time>0) && (time_tick_millsec >= PT_terminate_time+start_time)){
                                                                  // set the timeout flag
                                                                  PT_timeout = 1;
                                                                  // clear (probably invalid) input buffer
                                                                  memset(PT_term_buffer, 0, max_chars);
                                                                  // and  leave the while loop
                                                                  break ;
                                                                  }
                                                                  // continue recording input characters
                                                                  else {
                                                                  PT_term_buffer[num_char++] = character ;  
                                                                  }
                                                                  } //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
                                                                      
                                                                      //======================================================================
                                                                      // vref confing (if used)
                                                                      int CVRCON_setup ;
                                                                      
                                                                      
                                                                      // force full context save
                                                                      //int w;
                                                                      //void waste(void){w=1;};
                                                                      // Timer 5 interrupt handler ///////
                                                                      // ipl2 means "interrupt priority level 2"
                                                                      void __ISR(_TIMER_5_VECTOR, IPL2AUTO) Timer5Handler(void) //_TIMER_5_VECTOR
                                                                      {
                                                                      // clear the interrupt flag
                                                                      mT5ClearIntFlag();
                                                                      //count milliseconds
                                                                      time_tick_millsec++ ;
                                                                      //waste();
                                                                      }
                                                                      
                                                                      void PT_setup (void)
                                                                      {
                                                                      // Configure the device for maximum performance but do not change the PBDIV
                                                                      // Given the options, this function will change the flash wait states, RAM
                                                                      // wait state and enable prefetch cache but will not change the PBDIV.
                                                                      // The PBDIV value is already set via the pragma FPBDIV option above..
                                                                      SYSTEMConfig(sys_clock, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
                                                                      
                                                                      ANSELA =0; //make sure analog is cleared
                                                                      ANSELB =0;
                                                                      
                                                                      #ifdef use_uart_serial
                                                                      // === init the uart2 ===================
                                                                      // SET UART i/o PINS
                                                                      // The RX pin must be one of the Group 2 input pins
                                                                      // RPA1, RPB1, RPB5, RPB8, RPB11
                                                                      PPSInput (2, U2RX, RPA1); //Assign U2RX to pin RPA1 -- 
                                                                      // The TX pin must be one of the Group 4 output pins
                                                                      // RPA3, RPB0, RPB9, RPB10, RPB14 
                                                                      PPSOutput(4, RPB10, U2TX); //Assign U2TX to pin RPB10 -- 
                                                                      
                                                                      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_clock, BAUDRATE);
                                                                      UARTEnable(UART2, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));
                                                                      // Feel free to comment this out
                                                                      clrscr();
                                                                      home();
                                                                      // reverse video control codes
                                                                      normal_text;
                                                                      rev_text ;
                                                                      printf("...protothreads 1_2_3 07/10/18...");
                                                                      normal_text ;
                                                                      // === set up DMA for UART output =========
                                                                      // configure the channel and enable end-on-match
                                                                      DmaChnOpen(DMA_CHANNEL1, DMA_CHN_PRI2, DMA_OPEN_MATCH);
                                                                      // trigger a byte everytime the UART is empty
                                                                      DmaChnSetEventControl(DMA_CHANNEL1, DMA_EV_START_IRQ_EN|DMA_EV_MATCH_EN|DMA_EV_START_IRQ(_UART2_TX_IRQ));
                                                                      // source and destination
                                                                      DmaChnSetTxfer(DMA_CHANNEL1, PT_send_buffer+1, (void*)&U2TXREG, max_chars, 1, 1);
                                                                      // signal when done
                                                                      DmaChnSetEvEnableFlags(DMA_CHANNEL1, DMA_EV_BLOCK_DONE);
                                                                      // set null as ending character (of a string)
                                                                      DmaChnSetMatchPattern(DMA_CHANNEL1, 0x00);
                                                                      #endif //#ifdef use_uart_serial
                                                                      
                                                                      // ===Set up timer5 ======================
                                                                      // timer 5: on,  interrupts, internal clock, 
                                                                      // set up to count millsec
                                                                      OpenTimer5(T5_ON  | T5_SOURCE_INT | T5_PS_1_1 , pb_clock/1000);
                                                                      // set up the timer interrupt with a priority of 2
                                                                      ConfigIntTimer5(T5_INT_ON | T5_INT_PRIOR_2);
                                                                      mT5ClearIntFlag(); // and clear the interrupt flag
                                                                      // zero the system time tick
                                                                      time_tick_millsec = 0;
                                                                      
                                                                      //=== Set up VREF as a debugger output =======
                                                                      #ifdef use_vref_debug
                                                                      // set up the Vref pin and use as a DAC
                                                                      // enable module| eanble output | use low range output | use internal reference | desired step
                                                                      CVREFOpen( CVREF_ENABLE | CVREF_OUTPUT_ENABLE | CVREF_RANGE_LOW | CVREF_SOURCE_AVDD | CVREF_STEP_0 );
                                                                      // And read back setup from CVRCON for speed later
                                                                      // 0x8060 is enabled with output enabled, Vdd ref, and 0-0.6(Vdd) range
                                                                      CVRCON_setup = CVRCON; //CVRCON = 0x8060 from Tahmid http://tahmidmc.blogspot.com/
                                                                      
                                                                      #endif //#ifdef use_vref_debug
                                                                      
                                                                      }
                  
    
                      /*
                      * File:   pt_cornell_rx.h; modified from pt_cornell_1_2_3.h
                      * Author: brl4
                      * Bruce R Land, Cornell University
                      * Created on July 10, 2018
                      *
                      * Modifications made to PT_GetMachineBuffer() for garbage collection
                      * when using RF 434 wireless transmission
                      * Modifications by: Drew Mera, Rohit Krishnakumar, Asad Marghoob
                      */
                      
                      /*
                      * 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 
                          *
                          * $Id: pt.h,v 1.7 2006/10/02 07:52:56 adam Exp $
                          */
                          #include 
                              /**
                              * \addtogroup pt
                              * @{
                              */
                              
                              /**
                              * \file
                              * Protothreads implementation.
                              * \author
                              * Adam Dunkels 
                                  *
                                  */
                                  
                                  #ifndef __PT_H__
                                  #define __PT_H__
                                  
                                  ////////////////////////
                                  //#include "lc.h"
                                  ////////////////////////
                                  /**
                                  * \file lc.h
                                  * Local continuations
                                  * \author
                                  * Adam Dunkels 
                                      *
                                      */
                                      
                                      #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 not 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__ */
                                      
                                      
                                      
                                      //////////////////////////////////////////
                                      struct pt {
                                      lc_t lc;
                                      int pri;
                                      };
                                      
                                      #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 =======================================
                                          //=====================================================================
                                          
                                          // macro to time a thread execution interveal in millisec
                                          // max time 4000 sec
                                          //#include 
                                              //#include 
                                                  //#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; icount=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
                                                              // PuTTY serial terminal control codes
                                                              // see 
                                                              // http://ascii-table.com/ansi-escape-sequences-vt-100.php
                                                              #define cursor_pos(line,column) printf("\x1b[%02d;%02dH",line,column)	
                                                              #define clr_right printf("\x1b[K")
                                                              // from http://www.comptechdoc.org/os/linux/howlinuxworks/linux_hlvt100.html
                                                              // and colors from http://www.termsys.demon.co.uk/vtansi.htm
                                                              #define green_text printf("\x1b[32m")
                                                              #define yellow_text printf("\x1b[33m")
                                                              #define red_text printf("\x1b[31m")
                                                              #define rev_text printf("\x1b[7m")
                                                              #define normal_text printf("\x1b[0m")
                                                              //====================================================================
                                                              // build a string from the UART2 /////////////
                                                              // assuming that a HUMAN is typing at a terminal!
                                                              //////////////////////////////////////////////
                                                              char PT_term_buffer[max_chars];
                                                              int PT_GetSerialBuffer(struct pt *pt)
                                                              {
                                                              static char character;
                                                              static int num_char;
                                                              // mark the beginnning of the input thread
                                                              PT_BEGIN(pt);
                                                              
                                                              num_char = 0;
                                                              // clear buffer
                                                              memset(PT_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);
                                                              }
                                                              
                                                              //====================================================================
                                                              // build a string from the UART2 /////////////
                                                              // assuming MACHINE input
                                                              //////////////////////////////////////////////
                                                              // !!! you MUST specify EITHER a termination character or a count!!
                                                              //////////////////////////////////////////////
                                                              // -- terminator character could be  '\r'
                                                              // or any other characcter, e.g. '#' or can be set to ZERO
                                                              // if there is no termination character
                                                              // -- Termination count will return after N characters, regardless of
                                                              // the terminator character
                                                              // Set to ZERO if there is no termination count.
                                                              // -- Termination time is the longest the routine will wait 
                                                              // for a terminator event in milliseconds
                                                              char PT_terminate_char, PT_terminate_count ;
                                                              // terminate time default million seconds
                                                              int PT_terminate_time = 1000000000 ;
                                                              // timeout return value
                                                              int PT_timeout = 0; 
                                                              
                                                              // system time updated in TIMER5 ISR below
                                                              volatile unsigned int time_tick_millsec ;
                                                              int PT_GetMachineBuffer(struct pt *pt)
                                                              {
                                                              static char character, last;
                                                              
                                                              static unsigned int num_char, start_time;
                                                              // mark the beginnning of the input thread
                                                              PT_BEGIN(pt);
                                                              
                                                              // index into the PT_term_buffer; also allows us to not save to the 
                                                              // buffer when set higher than 4, i.e. when we don't have valid data
                                                              num_char = 10;
                                                              
                                                              //record milliseconds for timeout calculation
                                                              start_time = time_tick_millsec ;
                                                              
                                                              // clear timeout flag
                                                              PT_timeout = 0;
                                                              
                                                              // clear input buffer
                                                              memset(PT_term_buffer, 0, max_chars);
                                                              
                                                              // keeps track of iterations of the while loop
                                                              int n = 0;
                                                              
                                                              while(n < max_chars)
                                                                  {
                                                                  // exit the while if the UART detects errors and set timeout flag
                                                                  if(UART2GetErrors() & 0x02){
                                                                  UART2ClearAllErrors();
                                                                  PT_timeout = 1;
                                                                  break;
                                                                  }
                                                                  
                                                                  n++;
                                                                  
                                                                  // get the character
                                                                  // yield until there is a valid character so that other
                                                                  // threads can execute; also stop if timeout occurs
                                                                  PT_YIELD_UNTIL(pt, 
                                                                  UARTReceivedDataIsAvailable(UART2) || 
                                                                  ((PT_terminate_time>0) && (time_tick_millsec >= PT_terminate_time+start_time)));
                                                                  
                                                                  // keep track of the last character and the current character from UART
                                                                  last = character;
                                                                  character = UARTGetDataByte(UART2);
                                                                  
                                                                  // if the last and current characters equal the start characters, reset
                                                                  // num_char so we can start adding to the PT_term_buffer
                                                                  if(last == '\xfa' &&  character == '\xfa') num_char = 0;
                                                                  
                                                                  
                                                                  // Terminate if we receive the terminate character specified in rx.c
                                                                  if ((character>0) && (character == PT_terminate_char)) {
                                                                  PT_term_buffer[num_char] = 0; // zero terminate the string
                                                                  // and leave the while loop
                                                                  break;
                                                                  }  
                                                                  
                                                                  // if num_char has been set low and we have received fewer than 4 bits
                                                                  // already, we want to update the PT_term_buffer
                                                                  if(num_char < 5) {
                                                                      // Terminate if we receive the terminate character specified in rx.c
                                                                      if ((character>0) && (character == PT_terminate_char)) {
                                                                      PT_term_buffer[num_char] = 0; // zero terminate the string
                                                                      // and leave the while loop
                                                                      break;
                                                                      }    
                                                                      
                                                                      // Terminate if we reach the terminate count specified in rx.c
                                                                      else if ( ((PT_terminate_count>0) && (num_char+1 >= PT_terminate_count))){
                                                                      // record the last character
                                                                      PT_term_buffer[num_char++] = character ; 
                                                                      // and terminate
                                                                      PT_term_buffer[num_char] = 0; // zero terminate the string
                                                                      // and leave the while loop
                                                                      break;
                                                                      }
                                                                      
                                                                      // terminate on timeout, with timeout time set in rx.c
                                                                      else if ((PT_terminate_time>0) && (time_tick_millsec >= PT_terminate_time+start_time)){
                                                                      // set the timeout flag
                                                                      PT_timeout = 1;
                                                                      // clear (probably invalid) input buffer
                                                                      memset(PT_term_buffer, 0, max_chars);
                                                                      // and  leave the while loop
                                                                      break ;
                                                                      }
                                                                      // otherwise store the character and increment num_char
                                                                      else {
                                                                      PT_term_buffer[num_char++] = character ;  
                                                                      }
                                                                      }
                                                                      
                                                                      // terminate on timeout
                                                                      if ((PT_terminate_time>0) && (time_tick_millsec >= PT_terminate_time+start_time)){
                                                                      // set the timeout flag
                                                                      PT_timeout = 1;
                                                                      // clear (probably invalid) input buffer
                                                                      memset(PT_term_buffer, 0, max_chars);
                                                                      // and  leave the while loop
                                                                      break ;
                                                                      }
                                                                      
                                                                      
                                                                      
                                                                      } //end while(num_char < max_size)
                                                                          
                                                                          // if we exit the while hitting the maximum number of characters, we consider
                                                                          // this a timeout; clear the buffer
                                                                          if (n == max_chars) {
                                                                          // clear (probably invalid) input buffer
                                                                          PT_timeout = 1;
                                                                          memset(PT_term_buffer, 0, max_chars);
                                                                          }
                                                                          
                                                                          // 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
                                                                          
                                                                          //======================================================================
                                                                          // vref confing (if used)
                                                                          int CVRCON_setup ;
                                                                          
                                                                          
                                                                          // force full context save
                                                                          //int w;
                                                                          //void waste(void){w=1;};
                                                                          // Timer 5 interrupt handler ///////
                                                                          // ipl2 means "interrupt priority level 2"
                                                                          void __ISR(_TIMER_5_VECTOR, IPL2AUTO) Timer5Handler(void) //_TIMER_5_VECTOR
                                                                          {
                                                                          // clear the interrupt flag
                                                                          mT5ClearIntFlag();
                                                                          //count milliseconds
                                                                          time_tick_millsec++ ;
                                                                          //waste();
                                                                          }
                                                                          
                                                                          void PT_setup (void)
                                                                          {
                                                                          // Configure the device for maximum performance but do not change the PBDIV
                                                                          // Given the options, this function will change the flash wait states, RAM
                                                                          // wait state and enable prefetch cache but will not change the PBDIV.
                                                                          // The PBDIV value is already set via the pragma FPBDIV option above..
                                                                          SYSTEMConfig(sys_clock, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
                                                                          
                                                                          ANSELA =0; //make sure analog is cleared
                                                                          ANSELB =0;
                                                                          
                                                                          #ifdef use_uart_serial
                                                                          // === init the uart2 ===================
                                                                          // SET UART i/o PINS
                                                                          // The RX pin must be one of the Group 2 input pins
                                                                          // RPA1, RPB1, RPB5, RPB8, RPB11
                                                                          PPSInput (2, U2RX, RPA1); //Assign U2RX to pin RPA1 -- 
                                                                          // The TX pin must be one of the Group 4 output pins
                                                                          // RPA3, RPB0, RPB9, RPB10, RPB14 
                                                                          PPSOutput(4, RPB10, U2TX); //Assign U2TX to pin RPB10 -- 
                                                                          
                                                                          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_clock, BAUDRATE);
                                                                          UARTEnable(UART2, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));
                                                                          // Feel free to comment this out
                                                                          clrscr();
                                                                          home();
                                                                          // reverse video control codes
                                                                          normal_text;
                                                                          rev_text ;
                                                                          printf("...protothreads 1_2_3 07/10/18...");
                                                                          normal_text ;
                                                                          // === set up DMA for UART output =========
                                                                          // configure the channel and enable end-on-match
                                                                          DmaChnOpen(DMA_CHANNEL1, DMA_CHN_PRI2, DMA_OPEN_MATCH);
                                                                          // trigger a byte everytime the UART is empty
                                                                          DmaChnSetEventControl(DMA_CHANNEL1, DMA_EV_START_IRQ_EN|DMA_EV_MATCH_EN|DMA_EV_START_IRQ(_UART2_TX_IRQ));
                                                                          // source and destination
                                                                          DmaChnSetTxfer(DMA_CHANNEL1, PT_send_buffer+1, (void*)&U2TXREG, max_chars, 1, 1);
                                                                          // signal when done
                                                                          DmaChnSetEvEnableFlags(DMA_CHANNEL1, DMA_EV_BLOCK_DONE);
                                                                          // set null as ending character (of a string)
                                                                          DmaChnSetMatchPattern(DMA_CHANNEL1, 0x00);
                                                                          #endif //#ifdef use_uart_serial
                                                                          
                                                                          // ===Set up timer5 ======================
                                                                          // timer 5: on,  interrupts, internal clock, 
                                                                          // set up to count millsec
                                                                          OpenTimer5(T5_ON  | T5_SOURCE_INT | T5_PS_1_1 , pb_clock/1000);
                                                                          // set up the timer interrupt with a priority of 2
                                                                          ConfigIntTimer5(T5_INT_ON | T5_INT_PRIOR_2);
                                                                          mT5ClearIntFlag(); // and clear the interrupt flag
                                                                          // zero the system time tick
                                                                          time_tick_millsec = 0;
                                                                          
                                                                          //=== Set up VREF as a debugger output =======
                                                                          #ifdef use_vref_debug
                                                                          // set up the Vref pin and use as a DAC
                                                                          // enable module| eanble output | use low range output | use internal reference | desired step
                                                                          CVREFOpen( CVREF_ENABLE | CVREF_OUTPUT_ENABLE | CVREF_RANGE_LOW | CVREF_SOURCE_AVDD | CVREF_STEP_0 );
                                                                          // And read back setup from CVRCON for speed later
                                                                          // 0x8060 is enabled with output enabled, Vdd ref, and 0-0.6(Vdd) range
                                                                          CVRCON_setup = CVRCON; //CVRCON = 0x8060 from Tahmid http://tahmidmc.blogspot.com/
                                                                          
                                                                          #endif //#ifdef use_vref_debug
                                                                          
                                                                          }