/*
  cc1000.cpp
  
  CC1000 Trasmiter for Arduino

  18.02.2016
  by Marcin Stolarski
*/

#include "Arduino.h"
#include "cc1000.h"

//namespace Cc1000Lib {
 
Cc1000::Cc1000(void)
{
	config();
}
 
Cc1000::Cc1000(uint8_t pale, uint8_t pdata, uint8_t pclk, uint8_t dclk, uint8_t dio, uint8_t chpo, uint8_t rfadc)
{
	config(pale, pdata, pclk, dclk, dio, chpo, rfadc);

}

boolean Cc1000::config()
{

Q1_PALE = 54;   // CC1000_PALE, pin 
Q1_PDATA = 55;  // CC1000_PDATA, pin 
Q1_PCLK = 56;   // CC1000_PCLK, pin 
Q1_DCLK = 57;   // CC1000_DCLK, pin 
Q1_DIO = 58;    // CC1000_DIO, pin 
Q1_CHPO = 59;   // CC1000_CHPO, pin 
Q1_RFADC = 62;  // CC1000 RF ADC PORT (ADC(6))

  return true;
}

boolean Cc1000::config(uint8_t pale, uint8_t pdata, uint8_t pclk, uint8_t dclk, uint8_t dio, uint8_t chpo, uint8_t rfadc)
{

Q1_PALE = pale;   // CC1000_PALE, pin 
Q1_PDATA = pdata;  // CC1000_PDATA, pin 
Q1_PCLK = pclk;   // CC1000_PCLK, pin 
Q1_DCLK = dclk;   // CC1000_DCLK, pin 
Q1_DIO = dio;    // CC1000_DIO, pin 
Q1_CHPO = chpo;   // CC1000_CHPO, pin 
Q1_RFADC = rfadc;  // CC1000 RF ADC PORT (ADC(6))

  return true;
}

//------------------------------------------------------------------
uint8_t Cc1000::init(void) {
  
  PortInitCC1000();
  ResetCC1000();
  SetupCC1000PD();
  
  return 1;
}

uint8_t Cc1000::def_init(void) {

//cc1000

//inicjacja cc1000

Serial.write("Initiation CC1000\n");

char cc1000_init_resoult=CC1000_Init ();

if (cc1000_init_resoult==0) Serial.write("Init fail\n");
    else Serial.write("Init OK\n");



Serial.write("FRQ CC1000\n");
//set deviation dev Hz
Serial.write("DEV 600 Hz\n");
set_deviation (600);


//set frequency dev Hz; mod 0-CW, 1-FM, vco 0-AB, 1-A, 2-B
Serial.write("FRQ 432.920.000 MHz\n");
char cc1000_frq_resoult=set_frequency (432920000, 0, true);
if (cc1000_frq_resoult==0) Serial.write("FRQ fail\n");
    else Serial.write("FRQ OK\n");


CC1000_modem ( 600, NRZ); Serial.write("Mode: NRZ\nBitrate: 300 bps\n");
Serial.write("Modem: ");
Serial.print(ReadFromCC1000Register( CC1000_MODEM0), DEC);
Serial.write("\n");

//WriteToCC1000Register( CC1000_PA_POW, 0x01);Serial.write("Power: -30 dBm\n"); //-30dBm
set_power(PA_VALUE_0DBM); Serial.write("Power: 0 dBm\n"); //0dBm
//WriteToCC1000Register( CC1000_PA_POW, PA_VALUE_0DB);Serial.write("Power: 0 dBm\n");  //7.7dBm
Serial.write("Power: ");
Serial.print(ReadFromCC1000Register( CC1000_PA_POW), DEC);
Serial.write("\n");


//WakeUpCC1000ToRX(RX_CURRENT);
//SetupCC1000RX(RX_CURRENT);
//Serial.write("RX MODE\n");

  return 1;
}

//------------------------------------------------------------------

//------------------------------------------------------------------

/****************************************************************************/
/*  This CC1000 uP port init                                                */
/****************************************************************************/
void Cc1000::PortInitCC1000(void)
{



// for output
pinMode(Q1_PDATA, OUTPUT); //PDATA 
pinMode(Q1_PCLK, OUTPUT); //PCLK
pinMode(Q1_PALE, OUTPUT); //PALE
pinMode(Q1_DIO, OUTPUT); //DIO

// for input
pinMode(Q1_CHPO, INPUT_PULLUP); //CHPO
pinMode(Q1_DCLK, INPUT_PULLUP); //DCLK
pinMode(Q1_RFADC, INPUT); //RFADC

//low state on init
digitalWrite(Q1_PDATA, LOW);
digitalWrite(Q1_PCLK, LOW);
digitalWrite(Q1_PALE, LOW);
digitalWrite(Q1_DIO, LOW);

//high state on init
//digitalWrite(Q1_CHPO, HIGH);
//digitalWrite(Q1_DCLK, HIGH);

}


/****************************************************************************/
/*  This routine sends new configuration data to the CC1000                 */
/*  Based on bit bashing (general I/O pin use)                              */
/****************************************************************************/

void Cc1000::ConfigureCC1000(char Count, short Configuration[])
{
  char  BitCounter;
  char  WordCounter;
  short Data;
 
 
   
  //CC1000_Q1_PALE_PORTx|=(1<<Q1_PALE); 
  digitalWrite(Q1_PALE, HIGH);//PALE=1
  
  for (WordCounter=0;WordCounter<Count;WordCounter++)
  {
    Data=Configuration[(unsigned int)WordCounter];
    //CC1000_Q1_PALE_PORTx&=~(1<<Q1_PALE); 
    digitalWrite(Q1_PALE, LOW);// PALE=0
    
    //Send address bits 
    for (BitCounter=0;BitCounter<7;BitCounter++)
    {
      //CC1000_Q1_PCLK_PORTx|=(1<<Q1_PCLK); 
      digitalWrite(Q1_PCLK, HIGH); // PCLK=1
      if ((Data&0x8000)==0) {
        //CC1000_Q1_PDATA_PORTx&=~(1<<Q1_PDATA); 
        digitalWrite(Q1_PDATA, LOW); // PDATA=0
      }
      else {
        //CC1000_Q1_PDATA_PORTx|=(1<<Q1_PDATA);
        digitalWrite(Q1_PDATA, HIGH); // PDATA=1
      }
      Data=Data<<1;
      //CC1000_Q1_PCLK_PORTx&=~(1<<Q1_PCLK); 
      digitalWrite(Q1_PCLK, LOW); //PCLK=0;
    //waitms(100);
  }
    
    // Send read/write bit 
    // Ignore bit in data, always use 1 
    
    //CC1000_Q1_PCLK_PORTx|=(1<<Q1_PCLK); 
    digitalWrite(Q1_PCLK, HIGH); //PCLK=1
    //CC1000_Q1_PDATA_PORTx|=(1<<Q1_PDATA);  
    digitalWrite(Q1_PDATA, HIGH); //PDATA=1
    //CC1000_Q1_PCLK_PORTx&=~(1<<Q1_PCLK);
    digitalWrite(Q1_PCLK, LOW); //PCLK=0
    Data=Data<<1;
    //CC1000_Q1_PCLK_PORTx|=(1<<Q1_PCLK);
    digitalWrite(Q1_PCLK, HIGH); //PCLK=1
    //CC1000_Q1_PALE_PORTx|=(1<<Q1_PALE);
    digitalWrite(Q1_PALE, HIGH); //PALE=1
    
    // Send data bits 
    
    for (BitCounter=0;BitCounter<8;BitCounter++)
    {
      // CC1000_Q1_PCLK_PORTx|=(1<<Q1_PCLK); 
      digitalWrite(Q1_PCLK, HIGH); //PCLK=1
      if ((Data&0x8000)==0) {
        // CC1000_Q1_PDATA_PORTx&=~(1<<Q1_PDATA); 
        digitalWrite(Q1_PDATA, LOW); // PDATA=0
      }
      else {
        // CC1000_Q1_PDATA_PORTx|=(1<<Q1_PDATA);
        digitalWrite(Q1_PDATA, HIGH); // PDATA=1
      }
      Data=Data<<1;
      // CC1000_Q1_PCLK_PORTx&=~(1<<Q1_PCLK);
      digitalWrite(Q1_PCLK, LOW); //PCLK=0
     }
  //CC1000_Q1_PCLK_PORTx|=(1<<Q1_PCLK); 
  digitalWrite(Q1_PCLK, HIGH); //PCLK=1
  }   // Finished with word    
}

/****************************************************************************/
/*  This routine writes to a single CC1000 register                         */
/****************************************************************************/

void Cc1000::WriteToCC1000Register(char addr, char data)
{
  short val;
  
  val=(addr&0x7F)<<9 | (data&0xFF);
  ConfigureCC1000(1,&val);
}

/****************************************************************************/
/*  This routine writes to a single CC1000 register, with data and address  */
/*  given in the same variable                                              */
/****************************************************************************/

void Cc1000::WriteToCC1000RegisterWord(short addranddata)
{
 
  ConfigureCC1000(1,&addranddata);
}

/****************************************************************************/
/*  This routine reads from a single CC1000 register                        */
/****************************************************************************/

char Cc1000::ReadFromCC1000Register(char addr)
{
  char BitCounter;
  char Data;
  char Debug;
  
    
  //CC1000_Q1_PALE_PORTx|=(1<<Q1_PALE); 
  digitalWrite(Q1_PALE, HIGH); //PALE=1
  
  Data=addr<<1;
  //Whay this is there? !!!!
  //CC1000_Q1_PALE_PORTx&=~(1<<Q1_PALE);
  digitalWrite(Q1_PALE, LOW); //PALE=0
    
  /* Send address bits */
 for (BitCounter=0;BitCounter<7;BitCounter++)
  {
    //CC1000_Q1_PCLK_PORTx|=(1<<Q1_PCLK); 
    digitalWrite(Q1_PCLK, HIGH); // PCLK=1
    if ((Data&0x80)==0) {
      //CC1000_Q1_PDATA_PORTx&=~(1<<Q1_PDATA); 
      digitalWrite(Q1_PDATA, LOW); // PDATA=0
    }
    else {
      //CC1000_Q1_PDATA_PORTx|=(1<<Q1_PDATA); 
      digitalWrite(Q1_PDATA, HIGH); // PDATA=1
    }
    Data=Data<<1;
    //CC1000_Q1_PCLK_PORTx&=~(1<<Q1_PCLK); 
    digitalWrite(Q1_PCLK, LOW); //PCLK=0;
  }
  
  /* Send read/write bit */
  /* Ignore bit in data, always use 0 */
 
  //CC1000_Q1_PCLK_PORTx|=(1<<Q1_PCLK); 
  digitalWrite(Q1_PCLK, HIGH); //PCLK=1
  //CC1000_Q1_PDATA_PORTx&=~(1<<Q1_PDATA); 
  digitalWrite(Q1_PDATA, LOW);  //PDATA=0
  //CC1000_Q1_PCLK_PORTx&=~(1<<Q1_PCLK); 
  digitalWrite(Q1_PCLK, LOW); //PCLK=0
 
 
  //CC1000_Q1_PCLK_PORTx|=(1<<Q1_PCLK); 
  digitalWrite(Q1_PCLK, HIGH); //PCLK=1
  //CC1000_Q1_PALE_PORTx|=(1<<Q1_PALE); 
  digitalWrite(Q1_PALE, HIGH); //PALE=1
    
  /* Receive data bits */
  
  //CC1000_Q1_PDATA_PORTx|=(1<<Q1_PDATA); 
  digitalWrite(Q1_PCLK, HIGH); //PDATA=1
   
  //CC1000_Q1_PDATA_DDRx&=~(1<<Q1_PDATA); 
  pinMode(Q1_PDATA, INPUT); /* Set up PDATA as an input */
   
  for (BitCounter=0;BitCounter<8;BitCounter++)
  {
    //CC1000_Q1_PCLK_PORTx&=~(1<<Q1_PCLK); 
    digitalWrite(Q1_PCLK, LOW); //PCLK=0
    Data=Data<<1;
    //Debug=(1<<Q1_PDATA);
     
    //if ((CC1000_Q1_PDATA_PINx&Debug)==0) {
    if (digitalRead(Q1_PDATA)==0) {
      Data&=0xFE;
    } else {
      Data|=0x01;
    }
    //CC1000_Q1_PCLK_PORTx|=(1<<Q1_PCLK); 
    digitalWrite(Q1_PCLK, HIGH); //PCLK=1
  }
  
  
  //CC1000_Q1_PDATA_DDRx|=(1<<Q1_PDATA); 
  pinMode(Q1_PDATA, OUTPUT); /* Set up PDATA as an output again */
  
  return Data;
}
  

/****************************************************************************/
/*  This routine resets the CC1000, clearing all registers.                 */
/****************************************************************************/  

void Cc1000::ResetCC1000(void)
{
  char MainValue;
  
  MainValue=ReadFromCC1000Register(CC1000_MAIN);
  WriteToCC1000Register(CC1000_MAIN,MainValue & 0xFE);         // Reset CC1000
  WriteToCC1000Register(CC1000_MAIN,MainValue | 0x01);         // Bring CC1000 out of reset
}


/****************************************************************************/
/*  This routine calibrates the CC1000                                      */
/*  Returns 0 if calibration fails, non-zero otherwise. Checks the LOCK     */
/*  to check for success.                                                   */
/****************************************************************************/

char Cc1000::CalibrateCC1000(void)
{  
  int TimeOutCounter;

  WriteToCC1000Register(CC1000_PA_POW,0x00); // Turn off PA to avoid spurs
                                             // during calibration in TX mode
  WriteToCC1000Register(CC1000_CAL,0xA6); // Start calibration

  // Wait for calibration complete
  for(TimeOutCounter=CAL_TIMEOUT; ((ReadFromCC1000Register(CC1000_CAL)&0x08)==0)&&(TimeOutCounter>0); TimeOutCounter--);

  // Wait for lock
  for(TimeOutCounter=LOCK_TIMEOUT; ((ReadFromCC1000Register(CC1000_LOCK)&0x01)==0)&&(TimeOutCounter>0); TimeOutCounter--);
  
  WriteToCC1000Register(CC1000_CAL,0x26); /* End calibration */
  WriteToCC1000Register(CC1000_PA_POW,trx_power); /* Restore PA setting */

  return ((ReadFromCC1000Register(CC1000_LOCK)&0x01)==1);
}

void Cc1000::DIO_Port_SetIn(void)
{

/// for input
pinMode(Q1_DIO, INPUT); //DIO

//high state on init
digitalWrite(Q1_DIO, HIGH);
}

void Cc1000::DIO_Port_SetOut(void)
{

// for output
pinMode(Q1_DIO, OUTPUT); //DIO

//low state on init
digitalWrite(Q1_DIO, LOW);
}



/****************************************************************************/
/*  This routine puts the CC1000 into RX mode (from TX). When switching to  */
/*  RX from PD, use WakeupC1000ToRX first                                   */
/****************************************************************************/


char Cc1000::SetupCC1000RX(char RXCurrent)
{
  DIO_Port_SetIn();

//RX
//ext_rxtx_sw(0);
  
  int i;
  char lock_status;

  WriteToCC1000Register(CC1000_MAIN,0x11);    // Switch into RX, switch to freq. reg A
//  WriteToCC1000Register(CC1000_PLL,RX_PLL);   // Use RX refdiv setting
  WriteToCC1000Register(CC1000_CURRENT,RXCurrent); // Program VCO current for RX

  // Wait 250us before monitoring LOCK
  for (i=0;i<0x1000;i++);

  // Wait for lock
  for(i=LOCK_TIMEOUT; ((ReadFromCC1000Register(CC1000_LOCK)&0x01)==0)&&(i>0); i--);

  // If PLL in lock
  if ((ReadFromCC1000Register(CC1000_LOCK)&0x01)==0x01){
    // Indicate PLL in LOCK
    lock_status = LOCK_OK;
  // Else (PLL out of LOCK)
  }else{
    // If recalibration ok
    if(CalibrateCC1000()){
      // Indicate PLL in LOCK
      lock_status = LOCK_RECAL_OK;
    // Else (recalibration failed)
    }else{
      // Reset frequency syncthesizer (ref.: Errata Note 01)
      ResetFreqSynth();
      // Indicate PLL out of LOCK
      lock_status = LOCK_NOK;
    }
  }

  rssi_ready=1;
  // Return LOCK status to application
  return (lock_status);
}

/****************************************************************************/
/*  This routine puts the CC1000 into TX mode (from RX). When switching to  */
/*  TX from PD, use WakeupCC1000ToTX first                                  */
/****************************************************************************/

char Cc1000::SetupCC1000TX(char TXCurrent)
{
  rssi_ready=0;
  DIO_Port_SetOut();

//TX
//ext_rxtx_sw(1);
  
  int i;
  char lock_status;

  WriteToCC1000Register(CC1000_PA_POW,0x00);   // Turn off PA to avoid frequency splatter

  WriteToCC1000Register(CC1000_MAIN,0xE1);    // Switch into TX, switch to freq. reg B
  WriteToCC1000Register(CC1000_PLL,TX_PLL);   // Use TX refdiv setting
  WriteToCC1000Register(CC1000_CURRENT,TXCurrent); // Program VCO current for TX

  // Wait 250us before monitoring LOCK
  for (i=0;i<0x1000;i++);

  // Wait for lock
  for(i=LOCK_TIMEOUT; ((ReadFromCC1000Register(CC1000_LOCK)&0x01)==0)&&(i>0); i--);

  // If PLL in lock
  if ((ReadFromCC1000Register(CC1000_LOCK)&0x01)==0x01){
    // Indicate PLL in LOCK
    lock_status = LOCK_OK;
  // Else (PLL out of LOCK)
  }else{
    // If recalibration ok
    if(CalibrateCC1000()){
      // Indicate PLL in LOCK
      lock_status = LOCK_RECAL_OK;
    // Else (recalibration failed)
    }else{
      // Reset frequency syncthesizer (ref.: Errata Note 01)
      ResetFreqSynth();
      // Indicate PLL out of LOCK
      lock_status = LOCK_NOK;
    }
  }

  // Increase output power
  WriteToCC1000Register(CC1000_PA_POW,trx_power); // Restore PA setting
  
  // Return LOCK status to application
  return (lock_status);
}

char Cc1000::SetupCC1000TX_calibrate(char TXCurrent)
{
  rssi_ready=0;
  DIO_Port_SetOut();

//TX
//ext_rxtx_sw(0);
  
  int i;
  char lock_status;

  WriteToCC1000Register(CC1000_PA_POW,0x00);   // Turn off PA to avoid frequency splatter

  WriteToCC1000Register(CC1000_MAIN,0xE1);    // Switch into TX, switch to freq. reg B
//  WriteToCC1000Register(CC1000_PLL,TX_PLL);   // Use TX refdiv setting
  WriteToCC1000Register(CC1000_CURRENT,TXCurrent); // Program VCO current for TX

  // Wait 250us before monitoring LOCK
  for (i=0;i<0x1000;i++);

  // Wait for lock
  for(i=LOCK_TIMEOUT; ((ReadFromCC1000Register(CC1000_LOCK)&0x01)==0)&&(i>0); i--);

  // If PLL in lock
  if ((ReadFromCC1000Register(CC1000_LOCK)&0x01)==0x01){
    // Indicate PLL in LOCK
    lock_status = LOCK_OK;
  // Else (PLL out of LOCK)
  }else{
    // If recalibration ok
    if(CalibrateCC1000()){
      // Indicate PLL in LOCK
      lock_status = LOCK_RECAL_OK;
    // Else (recalibration failed)
    }else{
      // Reset frequency syncthesizer (ref.: Errata Note 01)
      ResetFreqSynth();
      // Indicate PLL out of LOCK
      lock_status = LOCK_NOK;
    }
  }

  // Increase output power
  WriteToCC1000Register(CC1000_PA_POW,trx_power); // Restore PA setting
  
  // Return LOCK status to application
  return (lock_status);
}

void Cc1000::SetupCC1000PD(void)
{
  rssi_ready=0;

//PD
//ext_rxtx_sw(2);

  WriteToCC1000Register(CC1000_MAIN,0x3F);    // Put CC1000 into power-down
  WriteToCC1000Register(CC1000_PA_POW,0x00);  // Turn off PA to minimise current draw
}

void Cc1000::WakeUpCC1000ToRX(char RXCurrent)
{
//RX
//ext_rxtx_sw(0);


  int i;
  
  
  WriteToCC1000Register(CC1000_MAIN,0x3B);  // Turn on xtal oscillator core
  WriteToCC1000Register(CC1000_CURRENT,RXCurrent); // Program VCO current for RX 
//  WriteToCC1000Register(CC1000_PLL,RX_PLL); // Use RX refdiv setting
  
  // Insert wait routine here, must wait for xtal oscillator to stabilise, 
  // typically takes 2-5ms.
  //for (i=0;i<0x7FFE;i++);
  delay(10); 
  
  WriteToCC1000Register(CC1000_MAIN,0x39);  // Turn on bias generator
  // Wait for 250us, insert wait loop here
  delay(1);
  WriteToCC1000Register(CC1000_MAIN,0x31);  // Turn on frequency synthesiser

  rssi_ready=1;

}
/****************************************************************************/
/*  This routine wakes the CC1000 up from PD mode to TX mode, call          */
/*  SetupCC1000TX after this routine is finished.                           */
/****************************************************************************/


void Cc1000::WakeUpCC1000ToTX(char TXCurrent)
{
  rssi_ready=0;

//TX
//ext_rxtx_sw(1);

  int i;
  
  
  WriteToCC1000Register(CC1000_MAIN,0xFB);  // Turn on xtal oscillator core
  WriteToCC1000Register(CC1000_CURRENT,TXCurrent); // Program VCO current for TX
//  WriteToCC1000Register(CC1000_PLL,TX_PLL); // Use TX refdiv setting
  
  // Insert wait routine here, must wait for xtal oscillator to stabilise, 
  // typically takes 2-5ms. 
  for (i=0;i<0x7FFE;i++);
  
  WriteToCC1000Register(CC1000_MAIN,0xF9);  // Turn on bias generator
  // Wait for 250us, insert wait loop here
  WriteToCC1000Register(CC1000_PA_POW,trx_power); // Turn on PA
  WriteToCC1000Register(CC1000_MAIN,0xF1);  // Turn on frequency synthesiser
}

/****************************************************************************/
/*  This routine locks the averaging filter of the CC1000                   */
/****************************************************************************/

void Cc1000::AverageManualLockCC1000(void)
{
  WriteToCC1000Register(CC1000_MODEM1,0x19);
}

/****************************************************************************/
/*  This routine unlocks the averaging filter of the CC1000                 */
/****************************************************************************/

void Cc1000::AverageFreeRunCC1000(void)
{
  WriteToCC1000Register(CC1000_MODEM1,0x09);
}

/****************************************************************************/
/*  This routine sets up the averaging filter of the CC1000 for automatic   */
/*  lock. This can be used in polled receivers.                             */
/****************************************************************************/

void Cc1000::AverageAutoLockCC1000(void)
{
  WriteToCC1000Register(CC1000_MODEM1,0x01);
}

/****************************************************************************/
/*  This routine reads the current calibration values from the CC1000       */
/****************************************************************************/

void Cc1000::ReadCurrentCalibration(char *val1, char *val2)
{
  *val1=ReadFromCC1000Register(CC1000_TEST0);
  *val2=ReadFromCC1000Register(CC1000_TEST2);
}

/****************************************************************************/
/*  This routine overrides the current calibration of the CC1000            */
/****************************************************************************/

void Cc1000::OverrideCurrentCalibration(char val1, char val2)
{
  WriteToCC1000Register(CC1000_TEST5,(val1&0x0F)|0x10);
  WriteToCC1000Register(CC1000_TEST6,(val2&0x1F)|0x20);
}

/****************************************************************************/
/*  This routine stops override of the CC1000 calibration values            */
/****************************************************************************/

void Cc1000::StopOverridingCalibration(void)
{
  WriteToCC1000Register(CC1000_TEST5,0x00);
  WriteToCC1000Register(CC1000_TEST6,0x00);
}
  

/****************************************************************************/
/*  This CC1000 frequency synthesizer                                       */
/****************************************************************************/

void Cc1000::ResetFreqSynth(void)
{
  char modem1_value;
  modem1_value = ReadFromCC1000Register(CC1000_MODEM1)&~0x01;
  WriteToCC1000Register(CC1000_MODEM1,modem1_value);
  WriteToCC1000Register(CC1000_MODEM1,modem1_value|0x01);
}

void Cc1000::CC1000_FM_direct(char bit) {
  if(bit) {
    //sbi (CC1000_Q1_DIO_PORTx, Q1_DIO);  //DIO=1;
    digitalWrite(Q1_DIO, HIGH);
  } else {
    //cbi (CC1000_Q1_DIO_PORTx, Q1_DIO);  //DIO=0;
    digitalWrite(Q1_DIO, LOW);
  } 
}

void Cc1000::CC1000_send(char bit) {
  if(bit) {
    //sbi (CC1000_Q1_DIO_PORTx, Q1_DIO);  //DIO=1;
    digitalWrite(Q1_DIO, HIGH);
  } else {
    //cbi (CC1000_Q1_DIO_PORTx, Q1_DIO);  //DIO=0;
    digitalWrite(Q1_DIO, LOW);
  } 
//  while((CC1000_Q1_DCLK_PINx & (1<<Q1_DCLK))==0); //wait for clock high state
//  while((CC1000_Q1_DCLK_PINx & (1<<Q1_DCLK))!=0); //wait for clock low state
  while((digitalRead(Q1_DCLK))==0); //wait for clock high state
  while((digitalRead(Q1_DCLK))!=0); //wait for clock low state
}

  
void Cc1000::CC1000_send_byte(char my_byte) {
  unsigned char my_bit=1; //my_bit=00000001b
  while(1) {
    CC1000_send(my_byte & my_bit);
  if(my_bit==128) break; //if(my_bit=10000000b) break;
  my_bit <<= 1; //00000001 -> 00000010 -> ... -> 10000000
  }
}

char Cc1000::CC1000_receive(void) {
  char ret;    
  //while((CC1000_Q1_DCLK_PINx & (1<<Q1_DCLK))==0); //wait for clock high state
  //ret = CC1000_Q1_DIO_PINx  & (1<<Q1_DIO);      //sample the pin state
  //while((CC1000_Q1_DCLK_PINx & (1<<Q1_DCLK))!=0); //wait for clock low state
  while((digitalRead(Q1_DCLK))==0); //wait for clock high state
  ret = digitalRead(Q1_DIO);      //sample the pin state
  while((digitalRead(Q1_DCLK))!=0); //wait for clock low state
  return ret;
}

char Cc1000::CC1000_receive_byte(void) {
  char my_bit=1, my_byte=0, i; //my_byte is used for storing result
  for(i=0;i<8;i++) {
    if(CC1000_receive()) my_byte|=my_bit;
  //if(my_bit==128) break;
  my_bit <<= 1;
  }
 return my_byte;
}

//CC1000 initiation
char Cc1000::CC1000_Init (void) {

PortInitCC1000();
ResetCC1000();

WriteToCC1000Register(CC1000_MAIN, 0x11);
WriteToCC1000Register( CC1000_FREQ_2A, 0x42);
WriteToCC1000Register( CC1000_FREQ_1A, 0x3A);
WriteToCC1000Register( CC1000_FREQ_0A, 0x54);
WriteToCC1000Register( CC1000_FREQ_2B, 0x42);
WriteToCC1000Register( CC1000_FREQ_1B, 0x40);
WriteToCC1000Register( CC1000_FREQ_0B , 0x0D);
WriteToCC1000Register( CC1000_FSEP1, 0x00);
WriteToCC1000Register( CC1000_FSEP0, 0x46);
WriteToCC1000Register( CC1000_CURRENT, 0x44);
WriteToCC1000Register( CC1000_FRONT_END, 0x12);

//-20dBm
WriteToCC1000Register( CC1000_PA_POW, 0x01);
//0dBm
//WriteToCC1000Register( CC1000_PA_POW, 0x0F);
WriteToCC1000Register( CC1000_PLL, 0x48);
WriteToCC1000Register( CC1000_LOCK, 0x10);
WriteToCC1000Register( CC1000_CAL, 0x26);
WriteToCC1000Register( CC1000_MODEM2, 0x8B);
WriteToCC1000Register( CC1000_MODEM1, 0x6F);
WriteToCC1000Register( CC1000_MODEM0, 0x1B);
WriteToCC1000Register( CC1000_MATCH, 0x70);
WriteToCC1000Register( CC1000_FSCTRL, 0x01);
//WriteToCC1000Register( CC1000_FSHAPE7, 0xE1);
//WriteToCC1000Register( CC1000_FSHAPE6, 0xE1);
//WriteToCC1000Register( CC1000_FSHAPE5, 0xE1);
//WriteToCC1000Register( CC1000_FSHAPE4, 0xE1);
//WriteToCC1000Register( CC1000_FSHAPE3, 0xE1);
//WriteToCC1000Register( CC1000_FSHAPE2, 0xE1);
//WriteToCC1000Register( CC1000_FSHAPE1, 0xE1);
//WriteToCC1000Register( CC1000_FSDELAY, 0xE1);
WriteToCC1000Register( CC1000_PRESCALER, 0x00);
WriteToCC1000Register( CC1000_TEST6, 0x10);
WriteToCC1000Register( CC1000_TEST5, 0x08);
WriteToCC1000Register( CC1000_TEST4, 0x3F);
WriteToCC1000Register( CC1000_TEST3, 0x04);
WriteToCC1000Register( CC1000_TEST2, 0x00);
WriteToCC1000Register( CC1000_TEST1, 0x00);
WriteToCC1000Register( CC1000_TEST0, 0x00);

SetupCC1000RX(RX_CURRENT);
char calibrx=CalibrateCC1000();

SetupCC1000TX_calibrate(TX_CURRENT);
char calibtx=CalibrateCC1000();

SetupCC1000PD();
return calibrx||calibtx;

}

//CC1000 initiation
char Cc1000::CC1000_Init_src (void) {

PortInitCC1000();
ResetCC1000();

WriteToCC1000Register(CC1000_MAIN, 0x11);
WriteToCC1000Register( CC1000_FREQ_2A, 0x42);
WriteToCC1000Register( CC1000_FREQ_1A, 0x98);
WriteToCC1000Register( CC1000_FREQ_0A, 0xEB);
WriteToCC1000Register( CC1000_FREQ_2B, 0x42);
WriteToCC1000Register( CC1000_FREQ_1B, 0x9E);
WriteToCC1000Register( CC1000_FREQ_0B , 0xA4);
WriteToCC1000Register( CC1000_FSEP1, 0x00);
WriteToCC1000Register( CC1000_FSEP0, 0x46);
WriteToCC1000Register( CC1000_CURRENT, 0x44);
WriteToCC1000Register( CC1000_FRONT_END, 0x12);

//-20dBm
WriteToCC1000Register( CC1000_PA_POW, 0x01);
//0dBm
//WriteToCC1000Register( CC1000_PA_POW, 0x0F);
WriteToCC1000Register( CC1000_PLL, 0x48);
WriteToCC1000Register( CC1000_LOCK, 0x10);
WriteToCC1000Register( CC1000_CAL, 0x26);
WriteToCC1000Register( CC1000_MODEM2, 0x8B);
WriteToCC1000Register( CC1000_MODEM1, 0x6F);
//2400bps
WriteToCC1000Register( CC1000_MODEM0, 0x2B);
//38.400 kbps
//WriteToCC1000Register( CC1000_MODEM0, 0x54);
//76.800 kbps
//WriteToCC1000Register( CC1000_MODEM0, 0x54);
WriteToCC1000Register( CC1000_MATCH, 0x70);
WriteToCC1000Register( CC1000_FSCTRL, 0x01);
//WriteToCC1000Register( CC1000_FSHAPE7, 0xE1);
//WriteToCC1000Register( CC1000_FSHAPE6, 0xE1);
//WriteToCC1000Register( CC1000_FSHAPE5, 0xE1);
//WriteToCC1000Register( CC1000_FSHAPE4, 0xE1);
//WriteToCC1000Register( CC1000_FSHAPE3, 0xE1);
//WriteToCC1000Register( CC1000_FSHAPE2, 0xE1);
//WriteToCC1000Register( CC1000_FSHAPE1, 0xE1);
//WriteToCC1000Register( CC1000_FSDELAY, 0xE1);
WriteToCC1000Register( CC1000_PRESCALER, 0x00);
WriteToCC1000Register( CC1000_TEST6, 0x10);
WriteToCC1000Register( CC1000_TEST5, 0x08);
WriteToCC1000Register( CC1000_TEST4, 0x25);
WriteToCC1000Register( CC1000_TEST3, 0x04);
WriteToCC1000Register( CC1000_TEST2, 0x00);
WriteToCC1000Register( CC1000_TEST1, 0x00);
WriteToCC1000Register( CC1000_TEST0, 0x00);

SetupCC1000RX(RX_CURRENT);
char calibrx=CalibrateCC1000();

SetupCC1000TX(TX_CURRENT);
char calibtx=CalibrateCC1000();

SetupCC1000PD();
return calibrx||calibtx;

}



char Cc1000::CC1000_RecivePacket(uint8_t n, uint8_t buffer[]) {
  unsigned char rec_b=0, cntr=0, bit_cntr=0;
  uint8_t ni=0;
  
  WakeUpCC1000ToRX(TX_CURRENT);
  SetupCC1000RX(TX_CURRENT);
//  CalibrateCC1000();
//  waits(1);
  
  while(1) {
    //if received bit is the same as last bit - it isn't preamble
    if(LogicEqual(rec_b,CC1000_receive())) { 
    //if this collect more than 10 correct bits of preamble 
    //this can be the end of preamble
      if(cntr>10) break; 
    cntr=0; //start counting again
    if(bit_cntr>200) {
//        n_value=(uint16_t)ADC_convert_10bit(Q1_RFADC);
    return 0; //end condition (timeout)
    }
    } else {
    rec_b=!rec_b; //change rec_b to the oposite
    // if it is correct preamble, in the next step rec_b
      // will be still different form bit from CC1000
    cntr++; //increment the counter of (possible) preamble bits
      //this can be some kind of noise so dont count too much
    if(cntr>30) cntr=30; 
    }
    bit_cntr++; //count this bit
  if(bit_cntr>200) bit_cntr=201; //again - dont count too much
  }
//  ADC_convert_10bit_Start(Q1_RFADC);
  //preamble was correct, receive the first byte
    rec_b = CC1000_receive_byte();
  if(rec_b!=0x23) {
//    n_value=(uint16_t)ADC_convert_10bit(Q1_RFADC);
  return 0; //is this a secret start code?
  }
  while(1) { //if so, try to receive the following transmission
    rec_b = CC1000_receive_byte(); //get one byte
  //if checksum is correct
  if(LogicEqual(checksum(rec_b),CC1000_receive())) { 
    //cli();
      buffer[(int)ni++]=rec_b; //write to the buffer
    //UCSRB|=(1<<UDRIE); //Start transmission
    //sei();
  }  
    //test the following bit to know, if it should continue(1) or stop
  if(!CC1000_receive()) break;
  if(ni>=n) break;
  }
  
//  s_value=(uint16_t)ADC_convert_10bit_End();
//  n_value=(uint16_t)ADC_convert_10bit(Q1_RFADC);
  
  SetupCC1000PD();
return ni;
}


void Cc1000::CC1000_SendPacket(uint8_t n, uint8_t buffer[]) {
  char my_byte;
  uint8_t ni=0;
  
  WakeUpCC1000ToTX(TX_CURRENT);
  SetupCC1000TX(TX_CURRENT);
//  CalibrateCC1000();
//  waits(1);
  
  for(my_byte=0; my_byte<30; my_byte++) { //preamble
    CC1000_send(0);
    CC1000_send(1);
  }
  CC1000_send(1); //start bit
  CC1000_send_byte(0x23); //secret code
  while(1) { //start transmission
    //cli();
    my_byte=buffer[(int)ni++]; //read next character from the buffer
  //sei();
    CC1000_send_byte(my_byte); //send it
  CC1000_send(checksum(my_byte)); //and send its checksum
    if(ni<n) { //is this the end of data in buffer
      CC1000_send(1); //no - send the continuation bit
  } else {
      CC1000_send(0); //yes - send the stop bit...
    break; //..and exit
  }
  }
  SetupCC1000PD();
}

//are a and b in equal logic state
char Cc1000::LogicEqual(char a, char b) { 
  //looks complicated, byt generates fast assembler code
  if(a) {
    if(b) {
    return 1;
  } else {
    return 0;
  }
  } else {
    if(b) {
    return 0;
  } else {
    return 1;
  }
  }
}

char Cc1000::checksum(char data) { //calculate boolean checksum
  char ret=0; //not in loop to make the code faster
  if(data&0x01) ret=~ret;
  if(data&0x02) ret=~ret;
  if(data&0x04) ret=~ret;
  if(data&0x08) ret=~ret;
  if(data&0x10) ret=~ret;
  if(data&0x20) ret=~ret;
  if(data&0x40) ret=~ret;
  if(data&0x80) ret=~ret;
  return ret;
}

uint16_t Cc1000::s_level (void) {
  
  return (((uint32_t)s_value*(uint32_t)5*(uint32_t)CC1000_RF_VREF)/(10*ADC_SIZE) +50);
}

uint16_t Cc1000::n_level (void) {

  return (((uint32_t)n_value*(uint32_t)5*(uint32_t)CC1000_RF_VREF)/(10*ADC_SIZE) +50);
}


/****************************************************************************/
/*  This routine puts the CC1000 into TX_CW mode (from RX). When switching to  */
/*  TX from PD, use WakeupCC1000ToTX first                                  */
/****************************************************************************/

char Cc1000::SetupCC1000TX_CW(char TXCurrent)
{
  rssi_ready=0;

  DIO_Port_SetOut();

//TX
//ext_rxtx_sw(1);
  
  int i;
  char lock_status;

  WriteToCC1000Register(CC1000_PA_POW,0x00);   // Turn off PA to avoid frequency splatter

  //WriteToCC1000Register(CC1000_MAIN,0xE1);    // Switch into TX, switch to freq. reg B
  WriteToCC1000Register(CC1000_MAIN,0xF1);    // Switch into TX, switch to freq. reg B, PA off
//  WriteToCC1000Register(CC1000_PLL,TX_PLL);   // Use TX refdiv setting
  WriteToCC1000Register(CC1000_CURRENT,TXCurrent); // Program VCO current for TX

  // Wait 250us before monitoring LOCK
  for (i=0;i<0x1000;i++);

  // Wait for lock
  for(i=LOCK_TIMEOUT; ((ReadFromCC1000Register(CC1000_LOCK)&0x01)==0)&&(i>0); i--);

  // If PLL in lock
  if ((ReadFromCC1000Register(CC1000_LOCK)&0x01)==0x01){
    // Indicate PLL in LOCK
    lock_status = LOCK_OK;
  // Else (PLL out of LOCK)
  }else{
    // If recalibration ok
    if(CalibrateCC1000()){
      // Indicate PLL in LOCK
      lock_status = LOCK_RECAL_OK;
    // Else (recalibration failed)
    }else{
      // Reset frequency syncthesizer (ref.: Errata Note 01)
      ResetFreqSynth();
      // Indicate PLL out of LOCK
      lock_status = LOCK_NOK;
    }
  }

  

  // Increase output power
  WriteToCC1000Register(CC1000_PA_POW,trx_power); // Restore PA setting
  
  // Return LOCK status to application
  return (lock_status);
}

//CW key 0-off 1-on
void Cc1000::CC1000TX_CW(char in) {
if (in) {
  //ON
  WriteToCC1000Register(CC1000_MAIN,0xE1);    // Switch into TX, switch to freq. reg B
//    CC1000_EPA_pow(1);
  //WriteToCC1000Register( CC1000_PA_POW, 0x50);
  }  else { 
    //OFF
//    CC1000_EPA_pow(0);
  WriteToCC1000Register(CC1000_MAIN,0x79);    // Switch into TX, switch to freq. reg B, PA off
    //WriteToCC1000Register( CC1000_PA_POW, 0x01);
  }
}

//FM modulation 0-15 levels
void Cc1000::CC1000TX_FM(char in) {
  
  
//if (in>7)    sbi (CC1000_Q1_DIO_PORTx, Q1_DIO); //DIO=1;
//    else cbi (CC1000_Q1_DIO_PORTx, Q1_DIO); //DIO=0;

if (in>7)    digitalWrite(Q1_DIO, HIGH); //DIO=1;
    else digitalWrite(Q1_DIO, LOW); //DIO=0;

/*
  uint16_t v_dev; 
  v_dev=(uint16_t)((vco_dev*in/15)/(CC1000_REF/16384));

  
  WriteToCC1000Register(CC1000_FSEP0,(uint8_t)(0x00FF&v_dev));
  v_dev=v_dev>>8;
  WriteToCC1000Register(CC1000_FSEP1,(uint8_t)(0x0007&v_dev));
*/
}

//FM 7kHz modulation 0-15 levels
void Cc1000::CC1000TX_FM7K (uint8_t in) {
  
  static uint8_t PROGMEM sktab[16] = { 0, 5, 9, 14, 19, 23, 28, 33, 37, 42, 47, 51, 56, 61, 65, 70};
/*
    (7000*0/15)/(CC1000_REF/16384), \
    (7000*1/15)/(CC1000_REF/16384), \
    (7000*2/15)/(CC1000_REF/16384), \
    (7000*3/15)/(CC1000_REF/16384), \
    (7000*4/15)/(CC1000_REF/16384), \
    (7000*5/15)/(CC1000_REF/16384), \
    (7000*6/15)/(CC1000_REF/16384), \
    (7000*7/15)/(CC1000_REF/16384), \
    (7000*8/15)/(CC1000_REF/16384), \
    (7000*9/15)/(CC1000_REF/16384), \
    (7000*10/15)/(CC1000_REF/16384), \
    (7000*11/15)/(CC1000_REF/16384), \
    (7000*12/15)/(CC1000_REF/16384), \
    (7000*13/15)/(CC1000_REF/16384), \
    (7000*14/15)/(CC1000_REF/16384), \
    (7000*15/15)/(CC1000_REF/16384)
    }
*/    
//  sbi (CC1000_Q1_DIO_PORTx, Q1_DIO);  //DIO=1;
  digitalWrite(Q1_DIO, HIGH);//DIO=1
  WriteToCC1000Register(CC1000_FSEP0,pgm_read_byte(&sktab[in]));

//if (in>7)    sbi (CC1000_Q1_DIO_PORTx, Q1_DIO); //DIO=1;
//    else cbi (CC1000_Q1_DIO_PORTx, Q1_DIO); //DIO=0;

/*
  uint16_t v_dev; 
  v_dev=(uint16_t)((vco_dev*in/15)/(CC1000_REF/16384));

  
  WriteToCC1000Register(CC1000_FSEP0,(uint8_t)(0x00FF&v_dev));
  v_dev=v_dev>>8;
  WriteToCC1000Register(CC1000_FSEP1,(uint8_t)(0x0007&v_dev));
*/
}

/*
MODEM0 Register (11h) 
REGISTER  NAME  Default  Active  Description 
value 
MODEM0[7] -  - - Not used 
MODEM0[6:4]  BAUDRATE[2:0]  010  -  000 : 0.6 kBaud 
001 : 1.2 kBaud 
010 : 2.4 kBaud 
011 : 4.8 kBaud 
100 : 9.6 kBaud 
101 : 19.2, 38.4 and 76.8 kBaud 
110 : Not used 
111 : Not used 
MODEM0[3:2]  DATA_FORMAT[1:0]  01  -  00 : NRZ operation. 
01 : Manchester operation 
10 : Transparent Asyncronous UART operation 
11 : Not used 
MODEM0[1:0]  XOSC_FREQ[1:0]  00  -  Selection of XTAL frequency range 
00 : 3MHz – 4MHz crystal, 3.6864MHz  
recommended 
Also used for 76.8 kBaud, 14.7456MHz 
01 : 6MHz – 8MHz crystal, 7.3728MHz  
recommended 
Also used for 38.4 kBaud, 14.7456MHz 
10 : 9MHz – 12MHz crystal, 11.0592 MHz  
recommended 
11 : 12MHz – 16MHz crystal, 14.7456MHz  
recommended 
uint8_t CC1000_baudrate (uint32_t br) {
*/

//Baudrate 300-76800, mode (0-NRZ, 1-MANCHESTER, 2-UART)
uint8_t Cc1000::CC1000_modem (uint32_t br, uint8_t mode) {
  
  trx_bitrate = br;
  
  uint8_t reg=ReadFromCC1000Register( CC1000_MODEM0)&0b10000000;
  uint8_t ret=0;

  reg=(reg|(mode<<2));
  reg=(reg|CC1000_XTAL_FR);
  if (mode==1) br*=2;
  
  switch (br) {
    case   600: WriteToCC1000Register( CC1000_MODEM0, reg|0x00);ret=1;break;
    case  1200: WriteToCC1000Register( CC1000_MODEM0, reg|0x10);ret=1;break;
    case  2400: WriteToCC1000Register( CC1000_MODEM0, reg|0x20);ret=1;break;
    case  4800: WriteToCC1000Register( CC1000_MODEM0, reg|0x30);ret=1;break;
    case  9600: WriteToCC1000Register( CC1000_MODEM0, reg|0x40);ret=1;break;
    case 19200: WriteToCC1000Register( CC1000_MODEM0, reg|0x53);ret=1;break;
    case 38400: if (CC1000_XTAL_FR==3) {WriteToCC1000Register( CC1000_MODEM0, reg|0x51);ret=1;} break;
    case 76800: if (CC1000_XTAL_FR==3) {WriteToCC1000Register( CC1000_MODEM0, reg|0x50);ret=1;} break;

  }
  if (br<600) {WriteToCC1000Register( CC1000_MODEM0, reg|0x00);ret=1;}
  
  return ret;
}

//SEND----------------------------------------------------------------------------------------------------

uint8_t Cc1000::send_data(String str)
{
	return send_data((char*)str.c_str());
}

uint8_t Cc1000::send_data(char *data)
{
	switch (modem_mode) {
		case   	RTTY_MODE:	RTTY_addString(data); RTTY_flush(); break;
		default:			break;
	}
 
	return 1;
}
//GET--------------------------------------------------
uint8_t Cc1000::get_modem_mode(void)
{
	return modem_mode;
}

uint8_t Cc1000::get_power(void)
{
	return ReadFromCC1000Register( CC1000_PA_POW);
}

uint32_t Cc1000::get_deviation(void)
{
	return trx_dev;
}

uint32_t Cc1000::get_bitrate(void)
{
	return trx_bitrate;
}
uint32_t Cc1000::get_frequency(void)
{
	return get_frequency(VCO_AB);
}

uint32_t Cc1000::get_frequency(uint8_t vco)
{
	uint32_t vco_frq, frq;
	
	if (vco==VCO_A)
	{
		vco_frq = ((uint32_t)ReadFromCC1000Register( CC1000_FREQ_0A))
		+ ((uint32_t)ReadFromCC1000Register( CC1000_FREQ_1A))*0xFF
		+ ((uint32_t)ReadFromCC1000Register( CC1000_FREQ_2A))*0xFFFF;		

		//frq=(vco_frq+8192)*(CC1000_XTAL/(16384*CC1000_REFDIV))+150000-CC1000_FRQCOR;
		frq=(vco_frq+8192)*(CC1000_XTAL/(16384*CC1000_REFDIV))+0-CC1000_FRQCOR;
	}
	else if (vco==VCO_B||vco==VCO_AB)
	{
		vco_frq = ((uint32_t)ReadFromCC1000Register( CC1000_FREQ_0B))
		+ ((uint32_t)ReadFromCC1000Register( CC1000_FREQ_1B))*0xFF
		+ ((uint32_t)ReadFromCC1000Register( CC1000_FREQ_2B))*0xFFFF;				
	
		//frq=(vco_frq+8192)*(CC1000_XTAL/(16384*CC1000_REFDIV))+150000+trx_dev/2-CC1000_FRQCOR;
		frq=(vco_frq+8192)*(CC1000_XTAL/(16384*CC1000_REFDIV))+0+trx_dev/2-CC1000_FRQCOR;
	}
	//vco_frq_tx = ((frq+CC1000_FRQCOR-150000-trx_dev/2))/(CC1000_XTAL/(CC1000_REFDIV*16384)) - 8192;
	return frq;
}


//SET--------------------------------------------------
char Cc1000::set_trx_mode(char mode)
{
	char output = 0;
	
	switch(mode)
	{
		case RX_MODE:
			WakeUpCC1000ToRX(RX_CURRENT);
			output = SetupCC1000RX(RX_CURRENT);
			break;
		case TX_MODE:
			WakeUpCC1000ToTX(TX_CURRENT);
			output = SetupCC1000TX(TX_CURRENT);
			break;
		case PD_MODE:
			SetupCC1000PD();
			output = 1;
			break;
		default:
			
			break;
	}
	return output;
}

uint8_t Cc1000::set_modem_mode(uint8_t mode) {
	modem_mode = mode;
}

uint8_t Cc1000::set_power(uint8_t pow)
{
	trx_power = pow;
	WriteToCC1000Register( CC1000_PA_POW, pow);
	return 1;
}

uint8_t Cc1000::set_bitrate(uint32_t bitrate)
{
	switch (modem_mode) {
		case   	RTTY_MODE:	CC1000_modem(bitrate, NRZ); break;
		default:			CC1000_modem(bitrate, NRZ); break;
	}
 
	return 1;
}



uint8_t Cc1000::set_deviation (uint32_t dev) {
	return set_deviation(dev, false);
}

//set deviation dev Hz, monitor true/false
uint8_t Cc1000::set_deviation (uint32_t dev, boolean monitor) {
  
  trx_dev=dev;
  
  uint16_t v_dev; 
  //v_dev=(uint16_t)(dev/(CC1000_REF/16384)); //old version
  v_dev=(uint16_t)(dev/(CC1000_XTAL/(CC1000_REFDIV*16384)));
  
  
  
  if (monitor) {
		  
	Serial.write("CC1000_REF: ");
	Serial.print(CC1000_REF, DEC);
	Serial.write("\n");

	Serial.write("DEV: ");
	Serial.print(dev, DEC);
	Serial.write("\n");
	Serial.write("V_DEV: ");
	Serial.print(v_dev, DEC);
	Serial.write("\n");
  }
  
  WriteToCC1000Register(CC1000_FSEP0,(uint8_t)(0x00FF&v_dev));
  v_dev=v_dev>>8;
  WriteToCC1000Register(CC1000_FSEP1,(uint8_t)(0x0007&v_dev));

  if (monitor) {
    Serial.write("FSEP0: ");
	Serial.print(ReadFromCC1000Register( CC1000_FSEP0), HEX);
	Serial.write("\n");

	Serial.write("FSEP1: ");
	Serial.print(ReadFromCC1000Register( CC1000_FSEP1), HEX);
	Serial.write("\n");
  }
  
  return 1;
}

//set frequency value Hz
uint8_t Cc1000::set_frequency (uint32_t frq) {
	
	return set_frequency (frq, 0, false);

}

//set frequency value Hz; vco VCO_AB (RXTX), VCO_A (RX), VCO_B (TX); serial monitor false-off, true-on);
uint8_t Cc1000::set_frequency (uint32_t frq, uint8_t vco, boolean monitor) {

  uint32_t vco_frq_rx, vco_frq_tx;
  
  
  //vco_freq_tx = (frequency+frq_correction - IF_filter (150kHz) - deviation/2)/(Xtal_frequency/(REFDIV*16384)) - 8192
  //vco_frq_rx = ((frq+CC1000_FRQCOR-150000))/(CC1000_XTAL/(CC1000_REFDIV*16384)) - 8192;
  //vco_frq_tx = ((frq+CC1000_FRQCOR-150000-trx_dev/2))/(CC1000_XTAL/(CC1000_REFDIV*16384)) - 8192;
  vco_frq_rx = ((frq+CC1000_FRQCOR-0))/(CC1000_XTAL/(CC1000_REFDIV*16384)) - 8192;
  vco_frq_tx = ((frq+CC1000_FRQCOR-0-trx_dev/2))/(CC1000_XTAL/(CC1000_REFDIV*16384)) - 8192;
  //vco_frq_tx = vco_frq_rx;
   
  //old version of calulations 
  //vco_frq_rx=((((frq+CC1000_FRQCOR)-150000-819200))/(CC1000_REF/16384));
  //vco_frq_tx=((((frq+CC1000_FRQCOR)-150000-819200))/(CC1000_REF/16384));
  //it is for set frq betwenn HI and LOW state
  //  vco_frq_tx=((((frq+CC1000_FRQCOR)-((trx_dev*mod)/2)-819200))/(CC1000_REF/16384));


  WriteToCC1000Register(CC1000_PLL,(uint8_t)(0b01111000&(CC1000_REFDIV<<3)));

  if (monitor){
  
	Serial.write("CC1000_PLL: ");
	Serial.print(ReadFromCC1000Register( CC1000_PLL), DEC);
	Serial.write("\n");
  

	Serial.write("FRQ: ");
	Serial.print(frq, DEC);
	Serial.write("\n");
	Serial.write("VCO: ");
	Serial.print(vco_frq_rx, DEC);
	Serial.write("\n");

	Serial.write("FREQ: ");
  }
  
  if (vco==VCO_A||vco==VCO_AB) { //RX
    WriteToCC1000Register(CC1000_FREQ_0A,(uint8_t)(0x000000FF&vco_frq_rx));
    vco_frq_rx=vco_frq_rx>>8;
    WriteToCC1000Register(CC1000_FREQ_1A,(uint8_t)(0x000000FF&vco_frq_rx));
    vco_frq_rx=vco_frq_rx>>8;
    WriteToCC1000Register(CC1000_FREQ_2A,(uint8_t)(0x000000FF&vco_frq_rx));
  } 
  
  if (vco==VCO_B||vco==VCO_AB) { //TX
    WriteToCC1000Register(CC1000_FREQ_0B,(uint8_t)(0x000000FF&vco_frq_tx));
    vco_frq_tx=vco_frq_tx>>8;
    WriteToCC1000Register(CC1000_FREQ_1B,(uint8_t)(0x000000FF&vco_frq_tx));
    vco_frq_tx=vco_frq_tx>>8;
    WriteToCC1000Register(CC1000_FREQ_2B,(uint8_t)(0x000000FF&vco_frq_tx));
  }
  
  

  if (monitor){

	Serial.write("\n");
  
	Serial.write("FREQA: ");
	Serial.print(ReadFromCC1000Register( CC1000_FREQ_0A), HEX);
	Serial.print(ReadFromCC1000Register( CC1000_FREQ_1A), HEX);
	Serial.print(ReadFromCC1000Register( CC1000_FREQ_2A), HEX);
	Serial.write("\n");
	Serial.write("FREQB: ");
	Serial.print(ReadFromCC1000Register( CC1000_FREQ_0B), HEX);
	Serial.print(ReadFromCC1000Register( CC1000_FREQ_1B), HEX);
	Serial.print(ReadFromCC1000Register( CC1000_FREQ_2B), HEX);
	Serial.write("\n");
  }
  
  SetupCC1000RX(RX_CURRENT);
  char calibrx=CalibrateCC1000();

  SetupCC1000TX(TX_CURRENT);
  char calibtx=CalibrateCC1000();

  SetupCC1000PD();
  return calibrx||calibtx;


  //return 1;
}

//RTTY--------------------------------------------------


void Cc1000::RTTY_flush(void)
{
  set_trx_mode(TX_MODE);
  delay(2000);
//  uint8_t nic=0xff;
//  radio->cc1000->pdataWrite_f(&nic,1);
//  waitms(800);

  CC1000_pdataWrite(RTTY_TXbuffer, RTTY_TXptr);


//  radio->cc1000->pdataWrite_f(&nic,1);
//  waitms(300);
  RTTY_TXptr = 0;
  set_trx_mode(PD_MODE);

}

void Cc1000::CC1000_pdataWrite(uint8_t *buff, uint16_t size)
{
  uint16_t byteNo;
  uint16_t byteNo_size;
  uint8_t bitNo;
  uint8_t clock_div = 1;

  if (size%8>0) byteNo_size = size/8 + 1;
  else byteNo_size = size/8;
  
  for(byteNo=0; byteNo<byteNo_size; byteNo++)
  {
    uint8_t byte = buff[byteNo];

    for(bitNo=0; bitNo<8 && size>0; bitNo++)
    {
      digitalWrite(Q1_DIO, byte & 0x01);
      byte = byte >> 1;
      size--;
      if (trx_bitrate<600) clock_div=600/trx_bitrate;
	  else clock_div = 1;
	  
	  for (;clock_div>0;clock_div--)
	  {
		  while( digitalRead(Q1_DCLK) == 0 ); //wait for rising edge
		  while( digitalRead(Q1_DCLK) != 0 ); //wait for falling edge
		  //delay(1000/300);
	  }
    }
  }
}


void Cc1000::RTTY_addBit(uint8_t bit)
{
  uint8_t bias = RTTY_TXptr % 8;			//number of used bits in last byte of "bits in bytes" array
  uint16_t byteNo =  RTTY_TXptr / 8;		//size of "bits in byte" buffer
  uint8_t byte =  RTTY_TXbuffer[byteNo];	//get last byte of bits in bytes array
  uint8_t mask = ~(0x01 << bias) ;			//create bask for first free bit of "bits in bytes" array
  byte = (byte & mask) | (bit << bias);		//add bite to byte
  RTTY_TXbuffer[byteNo] = byte;				//update last byte of "bits in bytes" array
  RTTY_TXptr++;								//update number of bits in "bits in bytes" array
}

void Cc1000::RTTY_addByte(uint8_t data)
{
  if(RTTY_TXptr + BITS_PER_RTTY_CHAR < RTTY_TXsize*8)
  {
    //Serial.write(data);

    RTTY_addBit(RTTY_START_BIT);

    uint8_t i;
    for(i=0; i<8; i++)
    {
      uint8_t bit = (data >> i) & 0x01;
      RTTY_addBit(bit);
    }

    RTTY_addBit(RTTY_STOP_BIT);
    RTTY_addBit(RTTY_STOP_BIT);
  }
}

void Cc1000::RTTY_addString(char *addr)
{
  register uint8_t c;
  //uint8_t size = 20;
  while ((c=addr[0]))
  //for(;size>0; size--)
  {
    RTTY_addByte(addr[0]);
    addr++;
  }
}

void Cc1000::RTTY_addString_P(const char *addr)
{
  register uint8_t c;

  while ((c=pgm_read_byte(addr++)))
  {
    RTTY_addByte(c);
  }
}

void Cc1000::RTTY_addNulls(uint16_t length)
{
  while(length)
  {
    RTTY_addByte('\0');
    length--;
  }
}


//};//namespace
