/*
 * File:        TFT, LED, SPAWN test
 *              1.3.2 spawn example
 *              1.3.2 Modified scheduler
 * 
 * Author:      Bruce Land
 * For use with Sean Carroll's Big Board
 * http://people.ece.cornell.edu/land/courses/ece4760/PIC32/target_board.html
 * Target PIC:  PIC32MX250F128B
 */

////////////////////////////////////
// clock AND protoThreads configure!
// You MUST check this file!
#include "config_1_3_2.h"
// threading library
#include "pt_cornell_1_3_2.h"

////////////////////////////////////
// graphics libraries
// SPI channel 1 connections to TFT
#include "tft_master.h"
#include "tft_gfx.h"

////////////////////////////////////
// === print a line on TFT =====================================================
// Utilities to print a line on the TFT
// Predefined colors definitions (from tft_master.h)
//#define	ILI9340_BLACK   0x0000
//#define	ILI9340_BLUE    0x001F
//#define	ILI9340_RED     0xF800
//#define	ILI9340_GREEN   0x07E0
//#define ILI9340_CYAN    0x07FF
//#define ILI9340_MAGENTA 0xF81F
//#define ILI9340_YELLOW  0xFFE0
//#define ILI9340_WHITE   0xFFFF

// print a line on the TFT
// string buffer
char tft_str_buffer[60];
void tft_printLine(int line_number, int indent, char* print_buffer, short text_color, short back_color, short char_size){
    // This routine prints one line of text with controlled screen position, color and size.
    // This rouitine is TEXT oriented. Therefore, all positions are in
    // units of LINE NUMBER and CHARACTER INDENT. 
    // Both are related to the SIZE of the text you choose.
    // SIZEs are small positive integers. Useful range is 1-6 or so
    // I find SIZE=2 to be the most useful
    // For size=1 
    // -- tft_setRotation(0) give 39 lines, each line 36 characters
    // -- tft_setRotation(1) give 29 lines, each line 49 characters
    // For size=2  
    // -- tft_setRotation(0) give 19 lines, each line 18 characters
    // -- tft_setRotation(1) give 14 lines, each line 25 characters
    // For size=3  
    // -- tft_setRotation(0) give 12 lines, each line 12 characters
    // -- tft_setRotation(1) give 9 lines, each line 18 characters
    // For size=4  
    // -- tft_setRotation(0) give 9 lines, each line 10 characters
    // -- tft_setRotation(1) give 6 lines, each line 12 characters
    
    // print_buffer is the string to print
    int v_pos, h_pos;
    char_size = (char_size>0)? char_size : 1 ;
    //
    v_pos = line_number * 8 * char_size ;
    h_pos = indent * 6 * char_size ;
    // erase the pixels
    //tft_fillRoundRect(0, v_pos, 239, 8, 1, back_color);// x,y,w,h,radius,color
    tft_setTextColor2(text_color, back_color); 
    tft_setCursor(h_pos, v_pos);
    tft_setTextSize(char_size);
    tft_writeString(print_buffer);
}

//=== spawnable draw thread =================================================
// Do NOT schedule this thread !!!
// thread spawn control structure
static struct pt tft_spawn ;
// system 1 second interval tick
// prints on TFT 
int sys_time_seconds ;
// spawn this thread
int protothread_tft_draw_time(struct pt *pt)
{
    PT_BEGIN(pt);
    // system time convert to string
    sprintf(tft_str_buffer,"Time= %04d", sys_time_seconds);
    // print a line
    //tft_printLine(line_number, indent, print_buffer, text_color, back_color, char_size)
    tft_printLine(1,0, tft_str_buffer, ILI9340_GREEN, ILI9340_BLACK, 2);
    
    // kill this draw thread, to allow spawning thread to execute
    PT_EXIT(pt);
    // and indicate the end of the thread
    PT_END(pt);
}

// === Timer Thread =========================================================
// update a 1 second tick counter
static PT_THREAD (protothread_timer(struct pt *pt))
{
    PT_BEGIN(pt);     
      while(1) {        
        // draw sys_time
        PT_YIELD_TIME_msec(1000) ;
        sys_time_seconds++;   
        // spawn a thread to print time to LCD
        PT_SPAWN(pt, &tft_spawn, protothread_tft_draw_time(&tft_spawn)) ;
        
        // NEVER exit while
      } // END WHILE(1)
  PT_END(pt);
} // timer thread

// === blink thread ==========================================================
static PT_THREAD (protothread_blink(struct pt *pt))
{
    PT_BEGIN(pt);
    // set up LED port A0 to blink
    mPORTASetBits(BIT_0 );	//Clear bits to ensure light is off.
    mPORTASetPinsDigitalOut(BIT_0);    //Set port as output
    while(1){
        // yield time 1 second
        PT_YIELD_TIME_msec(200) ;
        // toggle the LED on the big board
        mPORTAToggleBits(BIT_0);         
    } // END WHILE(1)   
    PT_END(pt);  
} // thread blink

// === Main  ======================================================

void main(void) {
    
  // === setup system wide interrupts  ========
  INTEnableSystemMultiVectoredInt();
  
  // === TFT setup ============================
  // init the display in main since more than one thread uses it.
  // NOTE that this init assumes SPI channel 1 connections
  tft_init_hw();
  tft_begin();
  tft_fillScreen(ILI9340_BLACK);
  //240x320 vertical display
  tft_setRotation(1); // Use tft_setRotation(1) for 320x240
  
  // === config threads ========================
  PT_setup();
  
  // === identify the threads to the scheduler =====
  // add the thread function pointers to be scheduled
  // --- Two parameters: function_name and rate. ---
  // rate=0 fastest, rate=1 half, rate=2 quarter, rate=3 eighth, rate=4 sixteenth,
  // rate=5 or greater DISABLE thread!
  // If you need to access specific thread descriptors (to change rate), 
  // then return the list index
  pt_add(protothread_timer, 0);
  pt_add(protothread_blink, 2);

  // === initalize the scheduler ====================
  PT_INIT(&pt_sched) ;
  // >>> CHOOSE the scheduler method: <<<
  // (1)
  // SCHED_ROUND_ROBIN just cycles thru all defined threads
  //pt_sched_method = SCHED_ROUND_ROBIN ;
  
  // (2)
  // SCHED_RATE executes some threads more often then others
  // -- rate=0 fastest, rate=1 half, rate=2 quarter, rate=3 eighth, rate=4 sixteenth,
  // -- rate=5 or greater DISABLE thread!
  // pt_sched_method = SCHED_RATE ;
  
  pt_sched_method = SCHED_ROUND_ROBIN ;
  
  // === scheduler thread =======================
  // scheduler never exits
  PT_SCHEDULE(protothread_sched(&pt_sched));
  // ============================================
  
} // main

// === end  ======================================================

