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

#include "DVIinit_640x480x4_v0.h"
#include "pt_cornell_rp2040_v1_4.h"

float core_temp ;

// ==================================================
// === 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 float x_pos1 = 50.0f, x_dir1=-0.25f ;
    static int x_pos2 = 0, x_dir2=1 ;
    static int k ;
    static int frame_count ;
    static char round_color, round_color1 ;
    
    // Title block -- put static stuff at top
      fillRect(0, 0, 639, 39,rgb332(1,1,1));
      fillRect(0, 39, 639, 2, 0xff);
      drawTextTiny8(2, 2, "Cornell ECE4760", 0xff, rgb332(1,1,1));
      drawTextTiny8(2, 12, "Pico2 rp2350", 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, "04nov2026", 0xff, rgb332(1,1,1));
      drawTextTiny8(550, 1, "DVI Ver 1", 0xff, rgb332(1,1,1));
      
      // end title block
      //
      clearLowFrame(0, 0);

      drawTextGLCD(5, 330, "GLCD - abcdefghijklmnopqurstuvwxyz 1234567890",WHITE, 0);
      drawTextGLCD(5, 340, "ABCDEFGHIJKLMNOPQRSTUVWXYZ !@#$^&*()",WHITE, 0);
      //
      drawTextVGA437(5, 350, "VGA437 - abcdefghijklmnopqurstuvwxyz 123457890",GREEN, 0);
      drawTextVGA437(5, 368, "ABCDEFGHIJKLMNOPQRSTUVWXYZ !@#$^&*()",GREEN, 0);
      //
      drawTextArial24(5, 385, "Arial24 - abcdefghijklmnopqurstuvwxyz ",WHITE, 0);
      drawTextArial24(5, 411, "ABCDEFGHIJKLMNOPQRSTUVWXYZ !@#$^&*()",WHITE, 0);
      //
      drawTextGrotesk32(5, 436, "Grotesk32 - ABCDEFGHIJKLmnopqurstuvwxyz ",GREEN, 0);
      //drawTextGrotesk32(5, 450, "       ABCDEFGHIJKLMNOPQRSTUVWXYZ !@#$^&*()",GREEN, 0);

      // title bar
      drawTextArial24(180, 7, "DVI 640x480 4-bit", WHITE, 0);
      drawTextTiny8(2, 3, "Cornell ECE4760", 0xf, 0);
      drawTextTiny8(2, 15, "Pico2 rp2350", 0xf, 0);
      drawTextTiny8(2, 25, "Hunter Adams", 0xf, 0);
      drawTextTiny8(550, 25, "Bruce Land", 0xf, 0);
      drawTextTiny8(550, 15, "15oct2026", 0xf, 0);
      drawTextTiny8(550, 3, "DVI4 Ver 0", 0xf, 0);
      fillRect(0, 40, 639, 2, 15) ;
      // char str[20]; 
      // sprintf(str, "clk_sys=%3u MHz", sys_clock_actual/1000000);
      // drawTextVGA437 (180, 22, str, YELLOW, 0);
      //
       char video_buffer[64];
     // The color pallette
    //setTextColor2(WHITE, BLACK) ;
    //setTextSize(1) ;
    for (int i=0; i<4; i++) {
      for (int j=0; j<4; j++){
        fillRect(i*70+5, 50+j*70, 60, 49, i+4*j);  
        //setCursor(i*70+20, 150+j*70) ; 
        sprintf(video_buffer, " %02d ", i+4*j);
        drawTextGLCD(i*70+5, 50+j*70, video_buffer, WHITE, BLACK);
      }
    }
    // now the color names
    drawTextGLCD(0*70+5, 100+0*70, "BLACK", WHITE, BLACK);
    drawTextGLCD(1*70+5, 100+0*70, "DARK_GREEN", WHITE, BLACK);
    drawTextGLCD(2*70+5, 100+0*70, "MED_GREEN", WHITE, BLACK);
    drawTextGLCD(3*70+5, 100+0*70, "GREEN", WHITE, BLACK);
    drawTextGLCD(0*70+5, 100+1*70, "DARK_BLUE", WHITE, BLACK);
    drawTextGLCD(1*70+5, 100+1*70, "BLUE", WHITE, BLACK);
    drawTextGLCD(2*70+5, 100+1*70, "LIGHT_BLUE", WHITE, BLACK);
    drawTextGLCD(3*70+5, 100+1*70, "CYAN", WHITE, BLACK);

    drawTextGLCD(0*70+5, 100+2*70, "RED", WHITE, BLACK);
    drawTextGLCD(1*70+5, 100+2*70, "DARK_ORANGE", WHITE, BLACK);
    drawTextGLCD(2*70+5, 100+2*70, " ORANGE", WHITE, BLACK);
    drawTextGLCD(3*70+5, 100+2*70, "YELLOW", WHITE, BLACK);
    drawTextGLCD(0*70+5, 100+3*70, "MAGENTA", WHITE, BLACK);
    drawTextGLCD(1*70+5, 100+3*70, "PINK", WHITE, BLACK);
    drawTextGLCD(2*70+5, 100+3*70, "LIGHT_PINK", WHITE, BLACK);
    drawTextGLCD(3*70+5, 100+3*70, "WHITE", WHITE, BLACK);
    // 640x480 boundary box
    drawHLine(0, 0, 640, WHITE) ;
    drawHLine(0, 479, 640, WHITE) ;
    drawVLine(0,0,480, WHITE) ;
    drawVLine(639,0,480, WHITE) ;
    
      while(1) {
        //
        // wait here for frame start
        PT_YIELD_UNTIL(pt, start_frame==1);
        //gpio_put(2,1);
        start_frame = false;

        // clear buffer
        // above 40 is static image
        clearRect(290, 50, 639, 330, 0) ;
        frame_count++ ;
        //
        // animation control for three different trajectories
        if (x_pos2>150) x_dir2 = -1 ;
        else if (x_pos2<0) x_dir2 = 1;
        x_pos2 += x_dir2 ;
        //
        if (x_pos>80) x_dir = -1 ;
        else if (x_pos<0) x_dir = 1;
        x_pos += x_dir ;
        //
        if (x_pos1>50.0f) x_dir1 = -0.25f ;
        else if (x_pos1<5.0f) x_dir1 = 0.25f;
        x_pos1 += x_dir1 ;        
        //
        //drawRect(x_pos, 210, 40, 35, YELLOW);
        //fillRect(x_pos, 250, 40, 35, YELLOW);
        //
        fillCircle(400, 180, (int)x_pos1+10, RED);
        fillCircle(400, 180, (int)x_pos1, LIGHT_BLUE);
        //
        fillTri(500+x_pos, 122, 550+x_pos, 133+x_pos, 525, 200+x_pos, MED_GREEN) ;
       // short point_list[4][2] = {500, 132, 550, 140, 525, 210, 500, 132} ; //550 to 530
       short point_list[4][2] = {500, 122, 550, 133, 525, 200, 500, 122} ; //
        drawMultiLine(4, point_list, GREEN) ;

        fillRoundRect(300+x_pos2, 300, 160, 30, 5, ORANGE) ;
        if(x_dir2 == 1){
          drawTextArial24(302+x_pos2, 302, "move right", BLACK, ORANGE);
        }
        else {
          drawTextArial24(302+x_pos2, 302, "move left", BLACK, ORANGE);
        }
        
       //gpio_put(2,0);
        // NEVER exit WHILE in a thread
      } // END WHILE(1)
      // every thread ends with PT_END(pt);
      PT_END(pt);
} // end draw thread

// ==================================================
// ADC read thread protothread
// ==================================================
// this currently reads the internal temperature
// and populates a circuilar buffer 100 long
static PT_THREAD (protothread_temp(struct pt *pt)){
    PT_BEGIN(pt);
    
    
    const float conversion_factor = 3.3f / 4096.0f ;

    adc_init();
    adc_set_temp_sensor_enabled(true);
    adc_select_input(4);

    while(true) {  
        PT_YIELD_usec(1000000);
        // conver to volts
        float result = (float)adc_read() * conversion_factor;
        //printf("adc %d v %f \n", adc_read(), result);
        /// convert volts to ~temp (from hardare manual)
        core_temp = 27.0f - (result -0.706f)/0.001721f ;
    }   
    PT_END(pt);
}
// ========================================
// === core 1 main -- started in main below
// ========================================
void core1_main(){ 
    //  === add threads  ====================
    // for core 1
    pt_add_thread(protothread_temp);
    //
    // === initalize the scheduler ==========
    pt_sched_method = SCHED_ROUND_ROBIN ;
    pt_schedule_start ;
    // NEVER exits
    // ======================================
  } 

// ========================================
// === core 0 main
// ========================================
// VREG_VOLTAGE_1_30 = 0b01111,    // 300 MHz
// #if !PICO_RP2040
//     // Above this point you will need to set POWMAN_VREG_CTRL_DISABLE_VOLTAGE_LIMIT
//     VREG_VOLTAGE_1_35 = 0b10000,
//     VREG_VOLTAGE_1_40 = 0b10001, // 450 MHz
//     VREG_VOLTAGE_1_50 = 0b10010,

int main(){
  // set the core voltage only necessarey for 300 MHz 
  vreg_disable_voltage_limit ();
  vreg_set_voltage(VREG_VOLTAGE_1_30 );
  // set the clock 250 works
  set_sys_clock_khz (252000, false); //375
  // 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 ////
///////////
