
//
//
#include "pico/stdlib.h"
#include <stdio.h>
#include <string.h>
#include <pico/multicore.h>
#include "stdlib.h"
#include "hardware/vreg.h"
#include "hardware/clocks.h"
#include "math.h"

#include "DVIinit_640x480x8_v1.h"
#include "pt_cornell_rp2040_v1_4.h"

// ==================================================
// === dvi test thread 
// ==================================================
//   
static PT_THREAD (protothread_dvi(struct pt *pt))
{
    // every thread begins with PT_BEGIN(pt);
    PT_BEGIN(pt);
    // animation state variables
    static int x_pos = 50, x_dir=1 ;
    static int x_pos1 = 50, x_dir1=1 ;
    static int x_pos2 = 50, x_dir2=1 ;

      while(1) {
        //
        // wait here for frame start
        PT_YIELD_UNTIL(pt, start_frame==1);
        start_frame = false;
        // clear buffer
        // 
        gpio_put(2,1);
        clearRegion(0,480,rgb332(1,1,1)) ;
        gpio_put(2,0);
        //
        // Title block -- put static stuff at top
        //fillRect(0, 0, 639, 39,rgb332(1,1,1));
        //drawTextVGA437(200, 2, "DVI 640x480 8-bit", 0xff, rgb332(1,1,1));
        drawTextTiny8(2, 2, "Cornell ECE4760", 0xff, rgb332(1,1,1));
        drawTextTiny8(2, 12, "rp2350, 300 MHz", 0xff, rgb332(1,1,1));
        drawTextTiny8(2, 22, "Hunter Adams", 0xff, rgb332(1,1,1));
        drawTextArial24(180, 2, "DVI 640x480 8-bit", 0xff, rgb332(1,1,1));
        drawTextTiny8(550, 22, "Bruce Land", 0xff, rgb332(1,1,1));
        drawTextTiny8(550, 12, "14Sept2026", 0xff, rgb332(1,1,1));
        drawTextTiny8(550, 1, "DVI Ver 1", 0xff, rgb332(1,1,1));
        char str[20]; 
        sprintf(str, "clk_sys = %u MHz", sys_clock_actual/1000000);
        drawTextVGA437 (200, 22, str, 0xff, rgb332(1,1,1));

        // end title block

        // color pallet samples
        #define sq_wide 20
        #define sq_high 15
        #define top_start 40
        for(int k=0; k<4; k++){   
            for(int j=0; j<8; j++){
                for(int i=0; i<8; i++){
                    fillRect(i*sq_wide+k*8*sq_wide, j*sq_high+top_start, 
                        sq_wide-1, sq_high-1, rgb332(i,j,k));
                }
            }
        }
        // gray scale
        fillRect(100,162,20, 20,rgb332(7,7,3));
        fillRect(120,162,20, 20,rgb332(6,6,3));
        fillRect(140,162,20, 20,rgb332(5,5,2));
        fillRect(160,162,20, 20,rgb332(3,3,1));
        fillRect(180,162,20, 20,rgb332(2,2,1));
        fillRect(200,162,20, 20,rgb332(1,1,0));
        drawTextTiny8(230, 164, "Grey Scale", 0xff, rgb332(1,1,1));
        //
        //
        fillTri(5, 479, 635, 479, x_pos1, 300, rgb332(6, 4, 1)) ;
        fillTri(5, 200, 5, 400, x_pos, 300, 
                hsv2rgb(fmodf((float)x_pos/10.0f, 360.0f), 1, 1)); 
        fillTri(635, 180, 635, 300, x_pos2, 250, rgb332(7, 2, 0)) ;

        // animation control
        if (x_pos2>500) x_dir2 = -2 ;
        else if (x_pos2<102) x_dir2 = 2;
        x_pos2 += x_dir2 ;
        fillCircle(x_pos2, 300, 100 ,rgb332(1, 7, 3));

       // 
        if (x_pos>550) x_dir = -1 ;
        else if (x_pos<52) x_dir = 1;
        x_pos += x_dir ;
        fillCircle(x_pos, 350, 50 ,rgb332(0, 3, 1));
        fillCircle(x_pos, 350, 40 ,rgb332(0, 4, 1));
        fillCircle(x_pos, 350, 30 ,rgb332(0, 5, 1));
        fillCircle(x_pos, 350, 20 ,rgb332(0, 6, 1));
        fillCircle(x_pos, 350, 10 ,rgb332(0, 7, 1));
        //
        //fillCircle(x_pos1, 275, 50 ,rgb332(0, 0, 0));
        if (x_pos1>550) x_dir1 = -2 ;
        else if (x_pos1<52) x_dir1 = 2;
        x_pos1 += x_dir1 ;
        fillCircle(x_pos1, 275, 50 ,rgb332(3, 3, 0));
        fillCircle(x_pos1, 275, 40 ,rgb332(4, 4, 0));
        fillCircle(x_pos1, 275, 30 ,rgb332(5, 5, 0));
        fillCircle(x_pos1, 275, 20 ,rgb332(6, 6, 0));
        fillCircle(x_pos1, 275, 10 ,rgb332(7, 7, 0));

        // line to maek sure we are drawing whole screen
        drawHLine(200, 479, 200, 0xff);
        // samples of the 4 fonts
        drawTextTiny8(220, 390, "Test Tiny8 font", 0, rgb332(6, 4, 1));
        drawTextVGA437(200, 405, "Test Block 437 font", 0, rgb332(6, 4, 1));
        drawTextArial24(180, 420, "Test Arial 24 font", 0, rgb332(6, 4, 1));       
        drawTextGrotesk32(140, 446, "Test Grotesk32 font", 0, rgb332(6,4,1));

        // test number of objects
        // look like at 300 MHz can draw >1000 raadius 5 particles
        // 150 MHz half that
        for (int i=0; i<600; i++){
          //fillCircle(x_pos1, 250+i/5, 5 ,rgb332(7, 7, 3));
        }
        // NEVER exit WHILE in a thread
      } // END WHILE(1)
      // every thread ends with PT_END(pt);
      PT_END(pt);
} // end blink thread

// ========================================
// === core 1 main -- started in main below
// ========================================
void core1_main(){ 
    //  === add threads  ====================
    // for core 1
    //pt_add_thread(protothread_toggle25_off);
    //
    // === initalize the scheduler ==========
    pt_sched_method = SCHED_ROUND_ROBIN ;
    pt_schedule_start ;
    // NEVER exits
    // ======================================
  }

// ========================================
// === core 0 main
// ========================================
int main(){
  // set the core voltage only necessarey for 300 MHz 
  vreg_set_voltage(VREG_VOLTAGE_1_30 );
  // set the clock
  set_sys_clock_khz (150000, false);
  // stablize clock
  sleep_ms(10);
  // record clock for HSTX setup
  sys_clock_actual = clock_get_hz(clk_sys) ;

  //===  start the serial i/o ==================
  stdio_init_all() ;
  // announce the threader version on system reset
  // if there is a seral terminal attached
  printf("\n\rProtothreads RP2040 v1.4 two-core, priority\n\r");

  // fire up the HSTX
  DVIinit() ;

  // JUIST FOR TIMING
  gpio_init(2) ;	
  gpio_set_dir(2, GPIO_OUT) ;

  // start core 1 threads
  multicore_reset_core1();
  multicore_launch_core1(&core1_main);

  // === config threads ========================
  // for core 0 two threads
  pt_add_thread(protothread_dvi);
  //pt_add_thread(protothread_serial);
  
  // === initalize the scheduler ===============
  // method is either:
  //   SCHED_PRIORITY or SCHED_ROUND_ROBIN
  pt_sched_method = SCHED_ROUND_ROBIN ;
  pt_schedule_start ;
  // !!pt_schedule_start NEVER exits
  // ===========================================
} // end main
///////////
// end ////
///////////
