//PicoBasic Tiny3216 V2.2 
#include <EEPROM.h>
#include <math.h>
#include <avr/io.h>
#include <util/delay.h>
#define F_CPU 20000000
#define USART0_BAUD_RATE(BAUD_RATE) ((float)(20000000 * 64 /(16 * (float)BAUD_RATE)))
uint16_t code[256] = {0x4900}; 
uint8_t ram[256];
uint8_t ram2[512];
uint8_t a = 0, b = 0, c = 0, d = 0;
uint16_t ad;
uint16_t rx = 1000;
char ch;
uint8_t adr = 0;
uint8_t return_adr[10];
uint8_t return_nr = 0;
uint8_t kom = 0;
uint8_t dat = 0;
uint32_t warten, weiter,Timer_hi;
uint16_t eedat;



void USART0_init(void){
    PORTB.DIRSET = 0x04;    //TXD an PB2
    PORTA.DIRCLR = 0x08;    //RXD an PB3
    USART0.BAUD = (uint16_t)USART0_BAUD_RATE(1000000);
    USART0.CTRLB |= USART_RXEN_bm | USART_TXEN_bm;  
}                  

void USART0_sendChar(char c){
    while (!(USART0.STATUS & USART_DREIF_bm));
    USART0.TXDATAL = c;
}

void USART0_printByte(uint8_t n){
    if (n>99){
      while (!(USART0.STATUS & USART_DREIF_bm));
      USART0.TXDATAL = 48+n/100;
      n=n-100*(n/100);
      while (!(USART0.STATUS & USART_DREIF_bm));
      USART0.TXDATAL = 48+n/10;
      n=n-10*(n/10);
      while (!(USART0.STATUS & USART_DREIF_bm));
      USART0.TXDATAL = 48+n;
    }
    else{
      if (n>9){
        while (!(USART0.STATUS & USART_DREIF_bm));
        USART0.TXDATAL = 48+n/10;
        n=n-10*(n/10);
      }
      while (!(USART0.STATUS & USART_DREIF_bm));
      USART0.TXDATAL = 48+n;
    }
    while (!(USART0.STATUS & USART_DREIF_bm));
    USART0.TXDATAL = 13;
    while (!(USART0.STATUS & USART_DREIF_bm));
    USART0.TXDATAL = 10;
}

char USART0_readChar(void){
  while (!(USART0.STATUS & USART_RXCIF_bm));
  return USART0.RXDATAL; 
}

void USART0_flush(void){
  char c;
  //delay(1);
  if (USART0.STATUS & USART_RXCIF_bm){c=USART0.RXDATAL;}
  if (USART0.STATUS & USART_RXCIF_bm){c=USART0.RXDATAL;}
  if (USART0.STATUS & USART_RXCIF_bm){c=USART0.RXDATAL;}
}

uint16_t USART0_readInt(void){
  char c;
  uint16_t n=0;
  while (!(USART0.STATUS & USART_RXCIF_bm));
  c= USART0.RXDATAL; 
  while (c > 13){
    if (c>47 && c<58){
      n=n*10;
      n+=c-48;
    }
    while (!(USART0.STATUS & USART_RXCIF_bm));
    c= USART0.RXDATAL; 
  }
   return n;
}

uint8_t adc(uint8_t ch){
   ADC0.MUXPOS = ch; 
   ADC0.COMMAND = ADC_STCONV_bm;
   while (!(ADC0.INTFLAGS & ADC_RESRDY_bm));
   return (ADC0.RES & 255);  
}

void extensions(void){
  if (dat==240){TCA0.SPLIT.CTRLA =1 | (7-a)<<1;}   //PWM Freq 
  if (dat==241){                               //AD Ref
    if (a==0) {ADC0.CTRLC = ADC_PRESC_DIV8_gc ;  
      VREF.CTRLA =  VREF_DAC0REFSEL_0V55_gc|VREF_ADC0REFSEL_0V55_gc;} 
    if (a==1) {ADC0.CTRLC = ADC_PRESC_DIV8_gc ;  //Ref
      VREF.CTRLA =  VREF_DAC0REFSEL_1V1_gc|VREF_ADC0REFSEL_1V1_gc;} 
    if (a==2) {ADC0.CTRLC = ADC_PRESC_DIV8_gc ;  //Ref
      VREF.CTRLA =  VREF_DAC0REFSEL_1V5_gc|VREF_ADC0REFSEL_1V5_gc;} 
    if (a==3) {ADC0.CTRLC = ADC_PRESC_DIV8_gc ;  //Ref
      VREF.CTRLA =  VREF_DAC0REFSEL_2V5_gc|VREF_ADC0REFSEL_2V5_gc;} 
    if (a==4) {ADC0.CTRLC = ADC_PRESC_DIV8_gc ;  //Ref
      VREF.CTRLA =  VREF_DAC0REFSEL_4V34_gc|VREF_ADC0REFSEL_4V34_gc;} 
    if (a==5) {ADC0.CTRLC = ADC_PRESC_DIV8_gc|0x10 ;  //VDD  
      VREF.CTRLA =  VREF_DAC0REFSEL_4V34_gc;} 
  }
  if (dat==242){            //Hispeed Scope
    for (uint16_t n=0;n<256;n++){ram[n]=adc(4);}
  }
  if (dat==243){            //Zweikanal Scope
    for (uint16_t n=0;n<256;n++){ram2[n*2]=adc(4);ram2[n*2+1]=adc(7);}
    for (uint16_t n=0;n<500;n++){USART0_printByte(ram2[n]);}
  }
  if (dat==244){            //Sinustabelle
    for (uint16_t n=0;n<256;n++){ram[n]=127+127*sin(3.14159*2*n/256);}
  }
  if (dat==245){            //DDS + Scope
    uint8_t akku = 0;
    for (uint8_t m=0;m<5;m++){      
      for (uint16_t n=0;n<512;n++){
        DAC0.DATA = ram[akku]; akku += a;
        ram2[n]=adc(4);
        //delayMicroseconds(1);
      }
    }
    for (uint16_t n=0;n<500;n++){USART0_printByte(ram2[n]);}
  }
  if (dat==246){      //Sweep
    uint8_t akku = 0;
    for (uint16_t n=0;n<512;n++){
      DAC0.DATA = ram[akku]; 
      akku = akku +a + (n>>4);
      ram2[n]=adc(4);
      delayMicroseconds(11);
    }  
    for (uint16_t n=0;n<500;n++){USART0_printByte(ram2[n]);} 
  }
  if (dat==247){}
  if (dat==248){}
  if (dat==249){}
  if (dat==250){}
  if (dat==251){}
  if (dat==252){}
  if (dat==253){}
  if (dat==254){}
  if (dat==255){} 
}

 void k1(){a = dat;adr++;}  
 void k2(){b = dat;adr++;} 
 void k3(){c = dat;adr++;} 
 void k4(){d = dat;adr++;} 
 void np(){adr++;}    
 void k8(){PORTB.OUT=(PORTB.OUT&254)|(dat&1);PORTC.OUT=dat>>1;PORTA.OUT=(PORTA.OUT&241)|(dat>>4); adr++;} //Pout dat
 void k9(){PORTB.DIR=(PORTB.DIR&254)|(dat&1);PORTC.DIR=dat>>1;PORTA.DIR=(PORTA.DIR&241)|(dat>>4); adr++;} //Pdir dat
 void k10(){PORTB.PIN0CTRL=(dat&1)<<3; PORTC.PIN0CTRL=(dat&2)<<2; PORTC.PIN1CTRL=(dat&4)<<1; PORTC.PIN2CTRL=(dat&8);
  PORTC.PIN3CTRL=(dat&16)>>1; PORTA.PIN1CTRL=(dat&32)>>2; PORTA.PIN2CTRL=(dat&64)>>3; PORTA.PIN3CTRL=(dat&128)>>4; adr++;} //Pullup dat                      {PORTD=(dat<<2)|3;
 void k11(){adr++;} //Pulldown dat, nicht beim Nano    
 void k16(){TCA0.SPLIT.HCMP2=dat;adr++;} //PWM1 
 void k17(){DAC0.DATA =dat;adr++;} //PWM2/DAC 
 void k18(){a &= dat;adr++;} // A = A AND dat
 void k19(){a |= dat;adr++;} // A = A Or dat
 void k24(){delayMicroseconds(dat);adr++;} // Delay µs
 void k25(){warten = dat;adr++;}         // Dekay ms
 void k26(){warten = dat*1000;adr++;}    // Delay s
 void k27(){warten = dat*60000;adr++;}   // Delay min
 void k32(){adr++;adr = dat;} // Goto L
 void k33(){adr++;if (dat<240){return_nr++;return_adr[return_nr]=adr; adr = dat;}
      if (dat>239){extensions();}} // Gosub L  
 void k34(){adr++;if (a == b){adr = dat;};} // If A = B Goto L
 void k35(){adr++;if (a > b){adr = dat;};} // If A > B Goto L
 void k36(){adr++;if (a < b){adr = dat;};} // If A < B Goto L
 void k37(){adr++;if (c > 0){adr = dat;}; c--;} // C*Goto L 
 void k38(){adr++;if (d > 0){adr = dat;}; d--;} // D*Goto L  
 void k40(){a += 1;adr++;} // A = A + 1
 void k41(){a -= 1;adr++;} // A = A - 1
 void k42(){a += b;adr++;} // A = A + B
 void k43(){a -= b;adr++;} // A = A - B
 void k44(){a = a*b;adr++;} // A = A * B
 void k45(){a /= b;adr++;} // A = A / B
 void k46(){a &= b;adr++;} // A = A AND B
 void k47(){a |= b;adr++;} // A = A OR B
 void k48(){a = a^b;adr++;} // A = A XOR B
 void k49(){a = a << 1;adr++;} // A = Shl 1
 void k50(){a = a >> 1;adr++;} // A = Shr 1
 void k51(){a = ~a;adr++;} // A = NOT A
 void k52(){b = a;adr++;} // B = A
 void k53(){a = b;adr++;} // A = B
 void k54(){c = a;adr++;} // C = A
 void k55(){a = c;adr++;} // A = C
 void k56(){d = a;adr++;} // D = A
 void k57(){a = d;adr++;} // A = D
 void k58(){a = ram[b];b++;adr++;} // A = [B+] 
 void k59(){ram[b] = a;b++;adr++;} // [B+] = A  
 void k60(){a = adc(4);adr++;} // A = AD0   
 void k61(){a = adc(7);adr++;} // A = AD1   
 void k62(){a = adc(8);adr++;} // A = AD2  
 void k63(){a = PORTB.IN & 1; a+=((PORTC.IN &15)<<1); a+=((PORTA.IN &14)<<4); adr++;} // A = Pin   
 void k64(){a = 1 & (PORTB.IN );adr++;} // A = Pin0   
 void k65(){if(rx < 1000){a = rx; rx = 1000;}adr++;} // Input A    
 void k66(){USART0_printByte(a);adr++;} // Print A   
 void k67(){TCA0.SPLIT.HCMP2=a;adr++;} // PWM1 = A  
 void k68(){DAC0.DATA =a;adr++;} // PWM2/DAC = A 
 void k69(){PORTB.OUT=(PORTB.OUT&254)|(a&1);PORTC.OUT=a>>1;PORTA.OUT=(PORTA.OUT&241)|(a>>4); adr++;} // Pout = A 
 void k72(){adr++;adr = return_adr[return_nr]; return_nr--;} // Ret  
 void k73(){adr++;adr--;} // End  

  void d65(){USART0_printByte(a);}  //A 
  void d66(){USART0_printByte(b);}  //B
  void d67(){USART0_printByte(c);}  //C
  void d68(){USART0_printByte(d);}  //D
  void d69(){USART0_printByte(adc(4));}  //E  AD0
  void d70(){USART0_printByte(adc(7));}  //F  AD1
  void d71(){USART0_printByte(adc(8));}  //G  AD2
  void d72(){USART0_printByte((PORTB.IN & 1)+((PORTC.IN &15)<<1)+((PORTA.IN &14)<<4));} //H  Pin
  void d73(){weiter = 0xFFFFFFFF;} //I  Stop!
  void d74(){weiter = 0;} //J  Go!
  void d75(){uint16_t n = USART0_readInt();PORTB.DIR=(PORTB.DIR&254)|(n&1);PORTC.DIR=n>>1;PORTA.DIR=(PORTA.DIR&241)|(n>>4);} //K  DIR
  void d76(){uint16_t n = USART0_readInt();PORTB.OUT=(PORTB.OUT&254)|(n&1);PORTC.OUT=n>>1;PORTA.OUT=(PORTA.OUT&241)|(n>>4);} //L  OUT
  void d77(){uint16_t n = USART0_readInt();PORTB.PIN0CTRL=(n&1)<<3; PORTC.PIN0CTRL=(n&2)<<2; PORTC.PIN1CTRL=(n&4)<<1; PORTC.PIN2CTRL=(n&8);
  PORTC.PIN3CTRL=(n&16)>>1; PORTA.PIN1CTRL=(n&32)>>2; PORTA.PIN2CTRL=(n&64)>>3; PORTA.PIN3CTRL=(n&128)>>4;} //M  Pullup
  void d78(){uint16_t n = USART0_readInt();} //N  Pulldown
  void d79(){uint16_t n = USART0_readInt();TCA0.SPLIT.HCMP2=n;} //O  PWM1
  void d80(){uint16_t n = USART0_readInt();DAC0.DATA =n;} //P  PWM2/DAC
  void d81(){for(int j=0; j<256; j++){uint16_t n = USART0_readInt();ram[j]=n;}} //Q  RAM füllen
  void d82(){uint16_t n = USART0_readInt();a = n;} //R  A=
  void d83(){uint16_t n = USART0_readInt();b = n;} //S  B=
  void d84(){uint16_t n = USART0_readInt();c = n;} //T  C=
  void d85(){uint16_t n = USART0_readInt();d = n;} //U  D=
  void d86(){uint16_t n = USART0_readInt();  TCA0.SPLIT.CTRLA =1 | n<<1;} //V PWM-Vorteiler   
  void d87(){                                       //W  Referenz
    uint16_t n = USART0_readInt();
    if (n==0) {ADC0.CTRLC = ADC_PRESC_DIV8_gc ;  //Ref
    VREF.CTRLA =  VREF_DAC0REFSEL_0V55_gc|VREF_ADC0REFSEL_0V55_gc;} 
    if (n==1) {ADC0.CTRLC = ADC_PRESC_DIV8_gc ;  //Ref
    VREF.CTRLA =  VREF_DAC0REFSEL_1V1_gc|VREF_ADC0REFSEL_1V1_gc;} 
    if (n==2) {ADC0.CTRLC = ADC_PRESC_DIV8_gc ;  //Ref
    VREF.CTRLA =  VREF_DAC0REFSEL_1V5_gc|VREF_ADC0REFSEL_1V5_gc;} 
    if (n==3) {ADC0.CTRLC = ADC_PRESC_DIV8_gc ;  //Ref
    VREF.CTRLA =  VREF_DAC0REFSEL_2V5_gc|VREF_ADC0REFSEL_2V5_gc;} 
    if (n==4) {ADC0.CTRLC = ADC_PRESC_DIV8_gc ;  //Ref
    VREF.CTRLA =  VREF_DAC0REFSEL_4V34_gc|VREF_ADC0REFSEL_4V34_gc;} 
    if (n==5) {ADC0.CTRLC = ADC_PRESC_DIV8_gc|0x10 ;  //VDD  
    VREF.CTRLA =  VREF_DAC0REFSEL_4V34_gc;} 
  }

void (*befehl[76])() = {
  np, k1, k2, k3, k4, np, np, np, 
  k8, k9, k10, k11, np, np, np, np,
  k16, k17, k18, k19, np, np, np, np,
  k24, k25, k26, k27, np, np, np, np,
  k32, k33, k34, k35, k36, k37, k38, np,
  k40, k41, k42, k43, k44, k45, k46, k47,
  k48, k49, k50, k51, k52, k53, k54, k55,
  k56, k57, k58, k59, k60, k61, k62, k63,
  k64, k65, k66, k67, k68, k69, np, np,
  k72, k73, np};

void (*direkt[23])() = {d65, d66, d67, d68, d69, d70, d71, d72, 
  d73, d74, d75, d76, d77, d78, d79, d80,  d81, d82, d83, d84, d85, d86, d87};
  
  
int main(void){ 
  _PROTECTED_WRITE (CLKCTRL_MCLKCTRLB, 0);  // 20 MHz
  USART0_init();
  ADC0.CTRLA = ADC_ENABLE_bm;          
  ADC0.MUXPOS = ADC_MUXPOS_AIN4_gc;     
  ADC0.CTRLA = ADC_ENABLE_bm | ADC_RESSEL_8BIT_gc;   
  ADC0.CTRLC = ADC_PRESC_DIV8_gc;     //|0x10 ;  //VDD
  VREF.CTRLA = VREF_DAC0REFSEL_2V5_gc|VREF_ADC0REFSEL_2V5_gc; 
  DAC0.CTRLA  = DAC_OUTEN_bm|DAC_ENABLE_bm; 
  PORTB.PIN1CTRL=8;
  PORTA.DIR=32; //PA5 PWM
  TCA0.SPLIT.CTRLD = TCA_SPLIT_SPLITM_bm;
  TCA0.SPLIT.CTRLB = TCA_SPLIT_HCMP2EN_bm ; 
  TCA0.SPLIT.HPER = 0xFF;  
  TCA0.SPLIT.HCMP2 = 0x00;  
  TCA0.SPLIT.CTRLA = 11; 

  TCB0.CTRLB = TCB_CNTMODE_INT_gc;
  TCB0.CCMP = 19999; 
  TCB0.CTRLA = TCB_ENABLE_bm;

  for (adr = 0; adr < 128; adr++) {
    uint16_t data; 
    data = (EEPROM.read(2*adr+0x1400))<<8;        
    data = data + EEPROM.read(2*adr+1+0x1400);    
    if (data>0x4A00){data=0x4A00;}    
    code[adr] = data;
  } 
  adr=0;
  weiter = 0; //keine Wartezeit
  warten = 0;
  TCB0.CTRLA=0; //Timer aus
  
  while(1){
    if (USART0.STATUS & USART_RXCIF_bm){
      ch = USART0_readChar();
      if (ch>47 && ch<58){
        rx = ch - 48;
        while (ch!=13){
          if (USART0.STATUS & USART_DREIF_bm){
            ch = USART0_readChar();
            if (ch>47 && ch<58){
              rx = rx * 10;
              rx = rx + ch - 48;
              rx = rx & 255;
            }
          }
        }
      USART0_printByte(rx);
      }
      if (ch==112){   //p       
        uint16_t n = USART0_readInt();
        for (uint16_t i=0;i<n;i++){
          uint16_t pdat = USART0_readInt();
          code[i] = pdat;
        }
        USART0_flush();
        adr = 0; 
        a=0; b=0; c=0; d=0;
        return_nr = 0;
        rx = 1000;
        weiter = 0; //keine Wartezeit
        warten = 0;
        TCB0.CTRLA=0; //Timer aus
      }
      if (ch==101){   //e
        uint16_t n = USART0_readInt();
        for (uint8_t i=0;i<n;i++){
          uint16_t pdat = USART0_readInt();
          code[i] = pdat;
          EEPROM.write(2*i, pdat>>8);
          EEPROM.write(2*i+1, pdat&255);
        }
        USART0_flush();
        adr = 0; 
        a=0; b=0; c=0; d=0;
        return_nr = 0;
        rx = 1000;
        weiter = 0; //keine Wartezeit
        warten = 0;
        TCB0.CTRLA=0; //Timer aus
      }
      if (ch>64 && ch<88){
        direkt[ch-65]();
      }
    }
    if(warten>0){weiter = Timer_hi + warten; warten = 0; TCB0.CTRLA=1;}
    if (TCB0.INTFLAGS & TCB_CAPT_bm){Timer_hi++;TCB0.INTFLAGS = TCB_CAPT_bm;}
    if(Timer_hi >= weiter){
      kom = code[adr] >> 8;
      dat = code[adr] & 255;
      befehl[kom]();
    }
    if ((PORTB.IN & 2)==0){_PROTECTED_WRITE (WDT_CTRLA,PERIOD_64CLK_gc);_delay_ms(1000);}// Reset an PB1
  }
}
