/* 
 * File:   main.c
 * Author: Honza
 *
 * Created on 7. dubna 2016, 23:19
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// DSPIC33EP512MU810 Configuration Bit Settings

// 'C' source line config statements

#include <xc.h>
#include <p33EP512MU810.h>
#include "asm_fce.h"


unsigned int reverse(unsigned int);
//unsigned int reverse2(unsigned int);
//extern void read_AD_ASM();
void read_AD(void);
unsigned int READ_PMP (void);
void  WRITE_PMP (unsigned int);
void trigr (unsigned int,unsigned char);
long Soucet=0,mezihodnota=0; 
int buffer=0;
unsigned int nastaveni=64,nastaveni2=0,TRIG_offset=0,TRIG=1,RUN=4,STOP=0,RUN_old=4,trig_lvl,DRUH=0,SWITCH=0,OV=0,mull,trig_lim,trig_start;
float c=0.2;
char    SHIFT;
const unsigned int Pocet_vzorku = 5120;
unsigned char Data[5120],Data2[5120];
static const unsigned char BitReverseTable256[] = 
{
  0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 
  0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 
  0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 
  0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 
  0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 
  0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
  0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 
  0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
  0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
  0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 
  0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
  0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
  0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 
  0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
  0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 
  0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
// DSPIC33EP512MU810 Configuration Bit Settings
// 'C' source line config statements

#include <xc.h>

// FGS
#pragma config GWRP = OFF               // General Segment Write-Protect bit (General Segment may be written)
#pragma config GSS = OFF                // General Segment Code-Protect bit (General Segment Code protect is disabled)
#pragma config GSSK = OFF               // General Segment Key bits (General Segment Write Protection and Code Protection is Disabled)

// FOSCSEL
#pragma config FNOSC = FRCPLL           // Initial Oscillator Source Selection Bits (Internal Fast RC with PLL (FRCPLL))
#pragma config IESO = OFF               // Two-speed Oscillator Start-up Enable bit (Start up with user-selected oscillator source)

// FOSC
#pragma config POSCMD = EC              // Primary Oscillator Mode Select bits (EC (External Clock) Mode)
#pragma config OSCIOFNC = OFF           // OSC2 Pin Function bit (OSC2 is clock output)
#pragma config IOL1WAY = ON             // Peripheral pin select configuration (Allow only one reconfiguration)
#pragma config FCKSM = CSECME           // Clock Switching Mode bits (Both Clock switching and Fail-safe Clock Monitor are enabled)

// FWDT
#pragma config WDTPOST = PS32768        // Watchdog Timer Postscaler Bits (1:32,768)
#pragma config WDTPRE = PR128           // Watchdog Timer Prescaler bit (1:128)
#pragma config PLLKEN = ON              // PLL Lock Wait Enable bit (Clock switch to PLL source will wait until the PLL lock signal is valid.)
#pragma config WINDIS = OFF             // Watchdog Timer Window Enable bit (Watchdog Timer in Non-Window mode)
#pragma config FWDTEN = OFF             // Watchdog Timer Enable bit (Watchdog timer enabled/disabled by user software)

// FPOR
#pragma config FPWRT = PWR128           // Power-on Reset Timer Value Select bits (128ms)
#pragma config BOREN = OFF              // Brown-out Reset (BOR) Detection Enable bit (BOR is disabled)
#pragma config ALTI2C1 = OFF            // Alternate I2C pins for I2C1 (SDA1/SCK1 pins are selected as the I/O pins for I2C1)
#pragma config ALTI2C2 = OFF            // Alternate I2C pins for I2C2 (SDA2/SCK2 pins are selected as the I/O pins for I2C2)

// FICD
#pragma config ICS = PGD2               // ICD Communication Channel Select bits (Communicate on PGEC2 and PGED2)
#pragma config RSTPRI = PF              // Reset Target Vector Select bit (Device will obtain reset instruction from Primary flash)
#pragma config JTAGEN = OFF             // JTAG Enable bit (JTAG is disabled)

// FAS
#pragma config AWRP = OFF               // Auxiliary Segment Write-protect bit (Auxiliary program memory is not write-protected)
#pragma config APL = OFF                // Auxiliary Segment Code-protect bit (Aux Flash Code protect is disabled)
#pragma config APLK = OFF               // Auxiliary Segment Key bits (Aux Flash Write Protection and Code Protection is Disabled)

/*
 * 
 */
int main(int argc, char** argv) {
    ANSELB = 0x0000;
//    CNPDB = 0xffff;
    TRISE  = 0xFF00;
    ANSELE = 0x0000;
//    CNPDE = 0xffff;
    TRISDbits.TRISD11  = 1; //R/W
    LATDbits.LATD11 = 0;
    
    TRISDbits.TRISD0 = 0;   //clk
    PLLFBDbits.PLLDIV = 80; //max. 140Mhz
    
    while(1)
    {
        unsigned int i;
        
        while((READ_PMP()) != 150); //pockej dokud není r/w 1
        
            WRITE_PMP(0b01010101);
   
            nastaveni = READ_PMP();
            nastaveni2 = READ_PMP();
            
            WRITE_PMP(96); //poľadavek na nastaveni shift
            DRUH = READ_PMP();
            
        if((nastaveni == 0) && (nastaveni2 > 4))
        {
                 if (OSCCONbits.COSC!= 0b011)
                {
                    // Initiate Clock Switch to 
                    PLLFBDbits.PLLDIV = 32; //4x 
                    __builtin_write_OSCCONH(0x03);
                    __builtin_write_OSCCONL(OSCCON | 0x01);
                    // Wait for Clock switch to occur
                    while (OSCCONbits.COSC!= 0b011);
                         // Wait for PLL to lock
                    while (OSCCONbits.LOCK!= 1);
                 }
        }
        else 
        {
            if (OSCCONbits.COSC!= 0b010)
            {
                // Initiate Clock Switch to 
                __builtin_write_OSCCONH(0x02);
                __builtin_write_OSCCONL(OSCCON | 0x01);
                // Wait for Clock switch to occur
                while (OSCCONbits.COSC!= 0b010);
            }
        }    

//        for(i=0;i<200;i++);          
        
        if (RUN==4 || (RUN==1 &&  STOP==0))
            read_AD();
         
        // Initiate Clock Switch to FRC oscillator with PLL (NOSC=0b001)
        PLLFBDbits.PLLDIV = 80; //max. 140Mhz
        __builtin_write_OSCCONH(0x01);
        __builtin_write_OSCCONL(OSCCON | 0x01);
        // Wait for Clock switch to occur
        while (OSCCONbits.COSC!= 0b001);
        // Wait for PLL to lock
        while (OSCCONbits.LOCK!= 1);
        

        for (i=0;i<Pocet_vzorku;i++)
        {
             Data2[i] = (BitReverseTable256[(unsigned char)Data[i]]);
        }
        
        for (i=0;i<Pocet_vzorku;i++)
        {
            if (Data2[i+1] > Data2[i]+15)
            {
              if (Data2[i+1] > Data2[i+2]+15)
              {
                if (Data2[i+3] < Data2[i+2]+15)
                {        
                  Data2[i+1] = Data2[i];
                }
              }
              else if (Data2[i+2] > Data2[i+3]+20)
              {
                  if (Data2[i+5] < Data2[i+4]+15)
                  {
                      Data2[i+1] = Data2[i];
                      Data2[i+2] = Data2[i+1];
                  }
              }
              
            }   
            if (Data2[i+1] < Data2[i]-15)
            {
              if (Data2[i+1] < Data2[i+2]-15)
              {
                if (Data2[i+3] > Data2[i+2]-15)
                {    
                  Data2[i+1] = Data2[i];
                }
              }
             else if (Data2[i+2] < Data2[i+3]-20)
              {
                  if (Data2[i+5] > Data2[i+4]-15)
                  {
                      Data2[i+1] = Data2[i];
                      Data2[i+2] = Data2[i+1];
                  }
              }
            }

        }
        
            if  (nastaveni==32)
            {
                mull=2;
                trig_lim=440;
                trig_start=1014;
            }
            else if (nastaveni==64)
            {
                mull=4;
                trig_lim=880;
                trig_start=814;
            }
            else if (nastaveni==128)
            {
                mull=10;
                trig_lim=414;
                trig_start=2000;
            }
            else
            {
                mull=1;
                trig_lim=220;
                trig_start=2574;
            }
                
        WRITE_PMP(97); //poľadavek na nastaveni urovne trigru
        trig_lvl = READ_PMP();
        
        WRITE_PMP(100); //poľadavek na druh trigru
        trigr(READ_PMP(),trig_lvl);   //trigr
                
        WRITE_PMP(99); //poľadavek na nastaveni run mode
        RUN = READ_PMP();
        
        WRITE_PMP(98); //poľadavek na nastaveni shift
        SHIFT = (char)READ_PMP();
                
        if (DRUH==1)
        {     
           for (i=0;i<Pocet_vzorku;i++)
            {
    //             Data2[i] = c*Data2[i]+ c*Data2[i-1]+ c*Data2[i-2]+ c*Data2[i-3]+c*Data2[i-4];
                   Data2[i] = 0.4*Data2[i]+ 0.2*Data2[i-1]+0.2*Data2[i-2]+0.2*Data2[i-2];
            }
       }        
        if (DRUH==0)
        {    
            if (TRIG == 1)
            {
                WRITE_PMP(0b10101010);

                for(i=0;i<= 202;i++)
                {
                    unsigned int sum;
                    sum = ((i*mull) + TRIG_offset + (int)(SHIFT*20*mull));

                    WRITE_PMP(Data2[sum]);
                }               
                STOP = 1;
                if (RUN == 1)
                {
                    if (RUN != RUN_old)
                        STOP=0;
                }
                RUN_old=RUN;
            }
            else 
             WRITE_PMP(0);
        }
        else if(DRUH==1)
        {
        Soucet=0;
        //efektivní hodnota
        for (i=14;i<Pocet_vzorku;i++)
        {
            buffer =(char)(Data2[i]-128);
            mezihodnota = abs(buffer)*abs(buffer);
            Soucet+=mezihodnota;
        }
        Soucet=Soucet/Pocet_vzorku;
        Soucet=sqrt(Soucet);
    
            WRITE_PMP(95);
            WRITE_PMP((unsigned int)Soucet);
            
            
        //střední hodnota
        Soucet=0;
        
        for (i=14;i<Pocet_vzorku;i++)
        {
            Soucet+=(unsigned char)(Data2[i]);
        }
        Soucet=Soucet/Pocet_vzorku;
       
            WRITE_PMP(94);
            WRITE_PMP((unsigned int)Soucet);    
            
            
        //max hodnota
        Soucet=0;
        OV=0;
        for (i=14;i<Pocet_vzorku;i++)
        {
            
            if((unsigned char)Data2[i] > (unsigned char)Soucet)
            Soucet=(Data2[i]);
        }
        
        if((Soucet-4) < 178)
            OV ++;
        
            WRITE_PMP(93);
            WRITE_PMP((unsigned int)Soucet-4); 
        
        
        //min hodnota
        Soucet=255;
        
        for (i=14;i<Pocet_vzorku;i++)
        {
            if(((unsigned char)Data2[i]) < (unsigned char)Soucet)
            Soucet=Data2[i];
        }
        if(Soucet > 78)
            OV ++;
        
            WRITE_PMP(92);
            WRITE_PMP((unsigned int)Soucet); 
            
        //prepnuti rozsahu
        Soucet=0;
        
        for (i=14;i<Pocet_vzorku;i++)
        {
            
            if((unsigned char)Data2[i] > (unsigned char)250 || Data2[i] == 0)
            Soucet++;
        }
        if (Soucet > (Pocet_vzorku/40))
            SWITCH=1;
        else
            SWITCH=0;
        
        if(OV==2)
        SWITCH+=2;
        
            WRITE_PMP(91);
            WRITE_PMP(SWITCH); 
                
        }
    }
    return (EXIT_SUCCESS);
}

unsigned int reverse(unsigned int o)    //otoci bajt
{
unsigned int c;
    c = (BitReverseTable256[(unsigned char)Data[o]]);
return c;
}


void read_AD(void)
{
    read_AD_ASM(&Data[0]);
}

unsigned int READ_PMP (void)
{    
    unsigned int prom,j;
    TRISE  = 0xFFFF;
    TRISDbits.TRISD11  = 0; //R/W
    for(j=0;j<20;j++);
    LATDbits.LATD11 = 1;  // prepnutí na cteni  
    LATDbits.LATD0 = 0;
    for(j=0;j<20;j++);
    LATDbits.LATD0 = 1; //clk
    for(j=0;j<20;j++);
    LATDbits.LATD0 = 0;
   
    for(j=0;j<300;j++);
    prom = PORTE & 0xff;
    return prom;
}   
    
void  WRITE_PMP (unsigned int prom)
{    
    unsigned int j;
    TRISE  = 0xFF00;
    LATDbits.LATD11 = 0; //prepnuti na zapis
    LATE = prom;
    for(j=0;j<200;j++);
    LATDbits.LATD0 = 0;
    for(j=0;j<20;j++);
    LATDbits.LATD0 = 1;
    for(j=0;j<20;j++);
    LATDbits.LATD0 = 0;
    for(j=0;j<3000;j++);
}

void trigr (unsigned int druh,unsigned char hodnota )
{
    unsigned int j;
    
    if (druh == 4)
    {
      for(j=trig_lim;j<(Pocet_vzorku-trig_start);j++) 
      {
        if (Data2[j] == hodnota || (Data2[j] < hodnota && Data2[j+1] > hodnota))
        {
            if (((Data2[j-3] + Data2[j-2]+ Data2[j-1])/3) < Data2[j])
            {    
                if(Data2[j] < ((Data2[j+3] + Data2[j+2]+ Data2[j+1])/3))
                {
                    TRIG_offset = j-10;
                    TRIG = 1;
                    break;
                }
            }
            else
                continue;
        }
        else
            TRIG = 0;
      }
    }
    else if (druh == 2)
    {
      for(j=trig_lim;j<(Pocet_vzorku-trig_start);j++) 
      {
        if (Data2[j] == hodnota|| (Data2[j] > hodnota && Data2[j+1] < hodnota))
        {
            if (((Data2[j-3] + Data2[j-2]+ Data2[j-1])/3) > Data2[j])
            {    
                if(Data2[j] > ((Data2[j+3] + Data2[j+2]+ Data2[j+1])/3))
                {
                    TRIG_offset = j-10;
                    TRIG = 1;
                    break;
                }
            }
            else
                continue;
        }
        else
            TRIG = 0;
      }
  }
    else if (druh == 1)
    {
        unsigned int max = 0;
        for (j = trig_lim; j < (Pocet_vzorku-trig_start); j++)
        {
          if (Data2[j] > Data2[max])
          max = j;
        }
        TRIG_offset = max-10;
        TRIG = 1;
    }
    else if (druh == 8)
    {
       TRIG = 1;
       TRIG_offset = 2564;
    }
    else
    {
       TRIG = 1;
       TRIG_offset = 2564;
    }
}