/*************************************************************
;*************************************************************
;
;    Source code for P-45AVR receiver (version 0.2)
;
;      http://p-45.narod.ru/
;
;    e-mail:p-45@mail.ru
;
;************************************************************
;
;    compile by avr-gcc with -Os options
;
;************************************************************
;
;    distribute by GPL licence
;
;*************************************************************
;*************************************************************
*/
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

#define F_CPU 4000000UL

#include <avr/delay.h>

#define SetBit(port,bit) port |=  _BV(bit)
#define ClrBit(port,bit) port &= ~_BV(bit)


#define Port4Out(port,bit) port |=  _BV(bit)
#define Port4Inp(port,bit) port &= ~_BV(bit)

#define HiBYTE(w) (uint8_t)((w >> 8) & 0x00ff)
#define LoBYTE(w) (uint8_t)((w >> 0) & 0x00ff)

#define Nop() __asm__ __volatile__ ("nop" ::)

/////////////////////////
// for KS-H-146, KS-H-148

#define CONST__GAINoff 0B10001000
#define CONST__GAINon  0B10001001 // Weak Signal Booster ON
#define CONST__LoBAND  0B00000001
#define CONST__MiBAND  0B00000010
#define CONST__HiBAND  0B00001100

#define RCVPCH1 37300
#define RCVPCH2 10700

#define ADR_EE_RC5    0x01A0
#define ADR_EE_Lo     0x01F8
#define ADR_EE_Hi     0x01FC

#define VolumeMAX 0x70
#define VolumeMIN 0x30

#define LM7001_Port_ini   DDRD
#define LM7001_Port      PORTD
#define LM7001_BitClc      PD3
#define LM7001_BitDat      PD4

#define LM7001_PortEN_ini  DDRB
#define LM7001_PortEN     PORTB
#define LM7001_BitCEN       PB0

#define I2C_Port_ini   DDRC
#define I2C_Port      PORTC
#define I2C_BitClc      PD5
#define I2C_BitDat      PD4

#define LCD_Port_ini   DDRD
#define LCD_Port      PORTD
#define LCD_BitClc      PB7
#define LCD_BitDat      PB5

#define DAC_Port_ini   DDRD
#define DAC_Port      PORTD
#define DAC_BitClc      PD6
#define DAC_BitDat      PD7

#define KBD_Port_ini   DDRB
#define KBD_Port_Inp   PINB
#define KBD_Port      PORTB
#define KBD_BitClc      PB5
#define KBD_BitDat      PB4
#define KBD_BitInp      PB3

#define KBD_0    0
#define KBD_1    1
#define KBD_2    2
#define KBD_3    3
#define KBD_4    4
#define KBD_5    5
#define KBD_6    6
#define KBD_7    7
#define KBD_8    8
#define KBD_9    9
#define KBD_F    10
#define KBD_Clr  11
#define KBD_Pls  12
#define KBD_Mns  13

#define IND_0    12
#define IND_1    11
#define IND_2     2
#define IND_3     3
#define IND_4     9
#define IND_5    10
#define IND_6     4
#define IND_7    15
#define IND_8     8
#define IND_9     5
#define IND_F    13
#define IND_Clr  14
#define IND_Pls   7
#define IND_Mns   6

uint8_t Ind2KBD[16]={    0,    0,KBD_2,  KBD_3,
		     KBD_6,KBD_9,KBD_Mns,KBD_Pls,
		     KBD_8,KBD_4,KBD_5,  KBD_1,
		     KBD_0,KBD_F,KBD_Clr,KBD_7};

#define WFM  0
#define NFM  1
#define  AM  2

enum { UP, DOWN };

enum { RADIO,
       STEP,
       GAIN,
       UAPY,
       FINPUT,
       WR_H_L,
       WR_MEM,
       RC_MEM,
       SCAN_F,
       SCAN_M
     };

#define  NUM_MEM 100

#define  LcdBufLEN 8
#define  InpBufLEN 7

#define  RxInpBufLEN 16

#define  PROMPT "\n>"
#define  ERROR  "\nErr\n>"

volatile uint8_t RcInpBuf[RxInpBufLEN];
volatile uint8_t RxInpBuf[RxInpBufLEN];
volatile uint8_t RxInd = 0;
volatile uint8_t TxInd = 0;
volatile uint8_t RcInd = 0;

volatile uint8_t EchoYes = 1;

volatile uint8_t InpBuf[InpBufLEN];
	 uint8_t cccBuf[8];

volatile uint8_t InpInd;
volatile int8_t  IndMEM = 0;

	 uint8_t Step[8]={5,10,15,20,25,30,50,100};

volatile uint32_t FrcvWork;
volatile uint8_t  FrcvStep = 10;
volatile uint8_t  FindStep =  1;

volatile uint8_t  direction = UP;
volatile uint8_t  Regim;

volatile uint8_t  Modulation;

volatile uint8_t  FlagMute;
volatile uint8_t  FlagSQL = 1;
volatile uint16_t MuteCnt = 0;

volatile uint8_t Pwm1;
volatile uint8_t Pwm2;

#define  MUTE     50

#define  RCV_MAX  855000
#define  RCV_MIN   45000

volatile uint32_t FrcvMax;
volatile uint32_t FrcvMin;

	 uint8_t  FlagScanF = 0;
	 uint8_t  FlagScanM = 0;
	 uint8_t  FlagBegin = 0;

	  int8_t  ScanMBank = 0;
	 uint8_t  FlagBank;


volatile uint16_t FrcvPCH2;
volatile uint8_t  flagBo;

volatile uint8_t  Smeter;


static  void KeyNop  (void);
	void KeyMOD  (void);
	void KeyPlus (void);
	void KeyMinus(void);
	void KeyRADIO(void);
	void KeySTEP (void);
	void KeyGAIN (void);
	void KeyUapy (void);
	void KeyFinp (void);
	void KeySetHi(void);
	void KeySetLo(void);
	void KeyWrMem(void);
	void KeyRcMem(void);
	void KeyScanF(void);
	void KeyScanM(void);

	void Key_0   (void);
	void Key_1   (void);
	void Key_2   (void);
	void Key_3   (void);
	void Key_4   (void);
	void Key_5   (void);
	void Key_6   (void);
	void Key_7   (void);
	void Key_8   (void);
	void Key_9   (void);

void (* SwKey[32])(void) =
     {
	KeyMOD,
	KeySTEP,
	KeyGAIN,
	KeyUapy,
	KeySetHi,
	KeyWrMem,
	KeySetLo,
	KeyScanF,
	KeyRcMem,
	KeyScanM,
	KeyFinp,
	KeyRADIO,
	KeyPlus,
	KeyMinus,
	KeyNop,
	KeyNop,

	Key_0,
	Key_1,
	Key_2,
	Key_3,
	Key_4,
	Key_5,
	Key_6,
	Key_7,
	Key_8,
	Key_9,
	KeyFinp,
	KeyRADIO,
	KeyNop,
	KeyNop,
	KeyNop,
	KeyNop
     };



///////////////////
////// U-apy //////

#define UapyNN  10
#define UapyHi  235
#define UapyLo  210

volatile uint8_t  Uapy = 0xff;
volatile uint8_t  UapyYes = 1;
volatile uint8_t  UapyFlg = 1;
	 uint8_t  UapyCnt;
	 uint16_t SmeterUapy = 0;

volatile uint8_t  TunerGain  = 0;


//////////////////////
//   LCD ALS-318A   //
//////////////////////

volatile uint8_t  LcdWork = 1;
volatile uint8_t  LcdInd  = 0;
volatile uint8_t  LcdBuf [LcdBufLEN];

volatile uint8_t  LcdCnt;
volatile uint8_t  LcdFlg;
volatile uint8_t  LcdBlink;


#define Lcd_Comma 0x04
#define Lcd_P     0x73
#define Lcd_S     0xDA
#define Lcd_T     0xD1
#define Lcd_E     0xD3
#define Lcd_N     0x49
#define Lcd_G     0x9B
#define Lcd_A     0x7B
#define Lcd_B     0xD9
#define Lcd_I     0x28
#define Lcd_F     0x53
#define Lcd_O     0xBB
#define Lcd_U     0xB9
#define Lcd_H     0x79
#define Lcd_L     0x91
#define Lcd_Y     0xF8
#define Lcd_c     0xC1
#define Lcd__     0x80

///////////////////////////
	void    cMEM(void);
	void    wMEM(void);
	uint8_t rMEM(void);

	void ScanerF(void);
	void ScanerM(void);
	void SetMute(void);

	void RsControl  (void);
	void UapyControl(uint8_t level);

	void SetVolume (void);
	void VolumeUp  (void);
	void VolumeDown(void);

	void uart_putstr(char *p);

	void wBufEEPROM(uint16_t addr, uint8_t *buff, uint8_t size);
	void rBufEEPROM(uint16_t addr, uint8_t *buff, uint8_t size);

	uint8_t Joystic(void);

	void SQLup(void);
	void SQLdown(void);

void (* RcCom[4])(void) =
     {
	SQLup,
	SQLdown,
	VolumeUp,
	VolumeDown
     };

/////////////////////////////////////////////////
void SetFmax(void) { FrcvMax = RCV_MAX; return; }
void SetFmin(void) { FrcvMin = RCV_MIN; return; }

//////////////////////////////
void KeyNop(void)  { return; }

//////////////////////////
volatile uint8_t  BeepCnt;
volatile uint8_t  BeepTmr;

#define BEEP_Port_ini   DDRB
#define BEEP_Port      PORTB
#define BEEP_Bit         PB2

#define BEEP_T      25  // ms
#define BEEP_F     900  // Hz

#define BEEP_TMR  (7812/BEEP_F)
#define BEEP_LEN  (255-BEEP_T*15/BEEP_TMR)


//////////////////////////////////////////
void Beep(void) { BeepCnt = BEEP_LEN; return; }

/////////////////
void Beeper(void)
{
   if(++BeepTmr > BEEP_TMR)
   {
	BeepTmr = 0;

     if(BeepCnt)
     {
	if(++BeepCnt & 0x01)
	{
	   SetBit(BEEP_Port,BEEP_Bit);
	}
	else
	   ClrBit(BEEP_Port,BEEP_Bit);
     }
   }
   return;
}

//////////////////
void UapyOut(void)
{
  uint8_t out;
  uint8_t i;

  if(UapyYes)
  {
     UapyYes = 0;

    for(i=0,out=Uapy; i < 8; i++)
    {

      if(out & 0x80)
	 SetBit(DAC_Port,DAC_BitDat);
      else
	 ClrBit(DAC_Port,DAC_BitDat);

	 ClrBit(DAC_Port,DAC_BitClc);
	 SetBit(DAC_Port,DAC_BitClc);

      out <<= 1;
    }
  }
}


///////////////////////////
uint8_t LcdDigit(uint8_t c)
{
  static char LcdDigit[]={
	0b10111011,     // 0
	0b00101000,     // 1
	0b11100011,     // 2
	0b11101010,     // 3
	0b01111000,     // 4
	0b11011010,     // 5
	0b11011011,     // 6
	0b00101010,     // 7
	0b11111011,     // 8
	0b11111010,     // 9
	0b01111011,     // A
	0b11011001,     // B
	0b10010011,     // C
	0b11101001,     // D
	0b11010011,     // E
	0b01010011};    // F

	return(LcdDigit[(c & 0x0F)]);
}

//////////////////////////
uint8_t LcdTab1(uint8_t c)
{
  static char LcdTab1[]={
	0B01100101,
	0B01100111,
	0B01101101,
	0B01101111,
	0B01110101,
	0B01110111,
	0B01111101,
	0B01111111,
	0B11100101,
	0B11100111,
	0B11101101,
	0B11101111,
	0B11110101,
	0B11110111,
	0B11111101,
	0B11111111};

	return(LcdTab1[(c & 0x0F)]);
}

//////////////////////////
uint8_t LcdTab2(uint8_t c)
{
  static char LcdTab2[]={
	0b10111111,
	0b11011111,
	0b11111011,
	0b11111110};

	return(LcdTab2[(c & 0x03)]);
}

////////////////////////////
void LcdOut2(uint8_t LcdOut)
{
  uint8_t i;

    for(i=0; i < 8; i++)
    {

      if(LcdOut & 0x80)
	 SetBit(LCD_Port,LCD_BitDat);
      else
	 ClrBit(LCD_Port,LCD_BitDat);

	 ClrBit(LCD_Port,LCD_BitClc);
	 SetBit(LCD_Port,LCD_BitClc);

      LcdOut <<= 1;
    }
    return;
}

/////////////////
void LcdOut(void)
{
  uint8_t LcdOutH;
  uint8_t LcdOutL;
  uint8_t LcdTmp;

  if(++LcdCnt > 50)
  {
       LcdCnt = 0;
       LcdFlg = (LcdFlg)? 0:1;
  }

  if((LcdBlink << LcdInd) & 0x80)
  {
    LcdTmp = (LcdFlg)? LcdBuf[LcdInd]:0;
  }
  else
    LcdTmp = LcdBuf[LcdInd];

    LcdOutH = LcdTab1(LcdTmp);
    LcdOutL = LcdTab1(LcdTmp>>4);

    if(LcdInd >= 4)
       LcdOutL &= LcdTab2(LcdInd);
    else
       LcdOutH &= LcdTab2(LcdInd);

    UapyOut();

    if(LcdWork)
    {
       LcdOut2(LcdOutH);
       LcdOut2(LcdOutL);

       if(++LcdInd >= LcdBufLEN) LcdInd = 0;
    }
    return;
}


/////////////////////////////
//          KBD            //
/////////////////////////////

volatile uint8_t  KbdInd = 0;
volatile uint8_t  KbdKbd = 0;
volatile uint8_t  KbdYes = 0;
volatile uint8_t  KbdCnt;
volatile uint8_t  KbdOld;

volatile uint8_t  TmrInd;

/////////////////
void KbdWrk(void)
{
  uint8_t i;

    if(KbdCnt < 128)
       KbdCnt++;

    for(i=0; i < 16; i++)
    {
	 ClrBit(KBD_Port,KBD_BitDat);

	 ClrBit(KBD_Port,KBD_BitClc);
	 SetBit(KBD_Port,KBD_BitClc);
    }

    if(bit_is_clear(KBD_Port_Inp,KBD_BitInp))
    {
       for(i=0; i < 16; i++)
       {
	 if(KbdInd == i)
	    ClrBit(KBD_Port,KBD_BitDat);
	 else
	    SetBit(KBD_Port,KBD_BitDat);

	    ClrBit(KBD_Port,KBD_BitClc);
	    SetBit(KBD_Port,KBD_BitClc);
       }
       Nop();
       Nop();
       Nop();

       if(bit_is_clear(KBD_Port_Inp,KBD_BitInp))
       {
	 if(KbdYes && KbdOld == KbdInd)
	 {
	    if( KbdInd == IND_Pls ||
		KbdInd == IND_Mns )
	    {
	      if(KbdCnt > 50)
	      {
		 KbdKbd = Ind2KBD[KbdInd]+1;
	      }
	    }
	 }
	 else
	 {
	    Beep();
	    KbdYes = 1;
	    KbdCnt = 0;
	    KbdOld = KbdInd;
	    KbdKbd = Ind2KBD[KbdInd]+1;
	 }
       }
    }
    else
    {
       KbdYes = 0;
    }

    if(++KbdInd >= 16) KbdInd = 0;
}

////////////////////
uint8_t GetKbd(void)
{
  uint8_t tmp;

      tmp = KbdKbd;

   if(tmp)
   {
      KbdKbd = 0;
   }
   return(tmp);
}

///////////////////////////
//      RC-5 decoder     //
///////////////////////////

#define RC5_Port_ini   DDRD
#define RC5_Port_Inp   PIND
#define RC5_Port      PORTB
#define RC5_BitInp      PD2

volatile uint8_t RC5flg;
volatile uint8_t RC5err;
volatile uint8_t RC5num;
volatile uint8_t RC5cnt;
volatile uint8_t RC5wrk;
volatile uint8_t RC5prg;

volatile uint16_t RC5inp;
volatile uint16_t RC5old;
volatile uint16_t RC5rcv;
volatile uint16_t RC5tmp;

volatile  int8_t RC5cnt0a;
volatile  int8_t RC5cnt1a;
volatile  int8_t RC5cnt0b;
volatile  int8_t RC5cnt1b;

/////////////////////////
//  Interrupt by INT0  //
/////////////////////////
SIGNAL (SIG_INTERRUPT0)
{
   if(!RC5flg)
   {
       RC5flg++;
       RC5cnt = 0;
       RC5rcv = 0;
       RC5num = 0;
       RC5err = 0;
   }
   return;
}

////////////////////
void RC5AskBit(void)
{
  uint8_t a;
  uint8_t b;

     if(++RC5num < 14)
     {
     if(abs(RC5cnt1a-RC5cnt0a) < 2) RC5err++;
     if(abs(RC5cnt1b-RC5cnt0b) < 2) RC5err++;

       a = (RC5cnt1a > RC5cnt0a)? 1:0;
       b = (RC5cnt1b > RC5cnt0b)? 1:0;

       if(a == b) RC5err++;

	RC5rcv <<= 1;
	RC5rcv  |= (a > b)? 1:0;
     }
     else
     {
	if(RC5num > 14)
	{
	   if(!RC5err && RC5rcv & 0x1000)
	   {
	       RC5inp =  RC5rcv;
	   }
	   RC5flg = 0;
	}
     }
     RC5cnt1a =
     RC5cnt0a =
     RC5cnt1b =
     RC5cnt0b = 0;
     return;
}

/////////////////////////////
uint8_t RC5corrector(uint8_t i)
{
  static char corrector[12]={26,26,25,26,
			     26,26,25,26,
			     26,26,25,26};

  return((i > 11)? 26:corrector[i]);
}

//////////////////////
void RC5receiver(void)
{
     if(RC5flg)
     {
	if(RC5cnt > 13)
	{
	   if(bit_is_clear(RC5_Port_Inp,RC5_BitInp))
	   {
		RC5cnt0b++;
	   }
	   else
		RC5cnt1b++;
	}
	else
	{
	   if(bit_is_clear(RC5_Port_Inp,RC5_BitInp))
	   {
		RC5cnt0a++;
	   }
	   else
		RC5cnt1a++;
	}
	if(RC5cnt++ > RC5corrector(RC5num))
	{
	   RC5cnt = 0;
	   RC5AskBit();
	}
     }
     return;
}

////////////////////////
void RC5write(uint8_t c)
{
     if(c < 18)
     {
       if(RC5prg > 3)
       {
	  RC5prg = 0;

	  wBufEEPROM ((uint16_t)(c<<2) + ADR_EE_RC5, (uint8_t *)&RC5old, 2);
	  uart_putstr("\nOK");
       }
     }
     return;
}

////////////////////////////
uint16_t RC5_Kbd(void)
{
  uint8_t i;

     for(i = 0; i < 18; i++)
     {
       rBufEEPROM((uint16_t)(i<<2) + ADR_EE_RC5, (uint8_t *)&RC5tmp, 2);

       if( RC5tmp == (RC5inp & 0x07ff) )
       {
	 if(RC5old != RC5inp || i >= KBD_Pls)
	 {
	    if(i < 14)
	    {
	       Beep();
	       RC5old = RC5inp;  return i+1;
	    }
	    else
	    {
	      (* RcCom[i-14])(); return 0;
	    }
	 }
       }
     }
     return 0;
}

/////////////////////////////
/////////////////////////////
     volatile  int8_t TMRxxx;

void TmrYYY(void)
{
  if(TMRxxx)
  {
       LcdOut();
       KbdWrk();
     TMRxxx = 0;
  }
  return;
}

/////////////////////////
// Interrupt by Timer0 //
/////////////////////////
//
// Start by 64 mks
//
SIGNAL (SIG_OVERFLOW0)
{
  RC5receiver();

  Beeper();
  TmrInd++;

  if(TmrInd == 64)
  {
     TmrInd = 0;
     TMRxxx++;

     if(MuteCnt < MUTE)
	MuteCnt++;
  }
}

////////////////////////////
// Interrupt by Rx RS-232 //
////////////////////////////
SIGNAL (SIG_UART_RECV)
{
  uint8_t tmp;

  if(RxInd < RxInpBufLEN)
  {
     RxInpBuf[RxInd++] = UDR;
  }
  else tmp = UDR;
}

//--------------//
void ioinit (void)
{
    // Init PORTs

    Port4Out(LCD_Port_ini,LCD_BitClc); // LCD clc -> Out
    Port4Out(LCD_Port_ini,LCD_BitDat); // LCD dat -> Out

    Port4Out(DAC_Port_ini,DAC_BitClc); // DAC clc -> Out
    Port4Out(DAC_Port_ini,DAC_BitDat); // DAC dat -> Out

    Port4Out(KBD_Port_ini,KBD_BitClc); // KBD clc -> Out
    Port4Out(KBD_Port_ini,KBD_BitDat); // KBD dat -> Out
    Port4Inp(KBD_Port_ini,KBD_BitInp); // KBD inp -> Input
    SetBit  (KBD_Port,KBD_BitInp);     //     Input (+Ucc --> "1")


    Port4Out(LM7001_PortEN_ini,LM7001_BitCEN);  // Lm7001 Enable

    Port4Out(LM7001_Port_ini,  LM7001_BitClc);  // Lm7001 Clock
    Port4Out(LM7001_Port_ini,  LM7001_BitDat);  // Lm7001 Data

    Port4Out(I2C_Port_ini,I2C_BitClc); // I2C clc -> Out
    Port4Out(I2C_Port_ini,I2C_BitDat); // I2C dat -> Out

    SetBit(I2C_Port,I2C_BitClc);  // Init I2C
    SetBit(I2C_Port,I2C_BitDat);

    // Init ADC

    Port4Inp(DDRC,PC0);
    Port4Inp(DDRC,PC1);
    Port4Inp(DDRC,PC2);
    Port4Inp(DDRC,PC3);

    ADMUX  = 0x00;
    ADCSRA = 0x85; // 1000 0101  ADC on, interrupt disable, MCU clock / 32


    // Init Timer0

    TCCR0  = 0x01;       // Timer0 running on MCU clock / 1
    SetBit(TIMSK,TOIE0); // enable interrupt from Timer0


    // Init Timer1

    Port4Out(DDRB,PB1); // output PWM1 (PB1/OC1A)
    Port4Out(DDRB,PB2); // output PWM2 (PB2/OC1B)  --> Beeper

    TCCR1A = 0B10000001; // Timer1 is 8-bit PWM by OC1A
    TCCR1B = 0B00000001; // Timer1 running on MCU clock / 1

    OCR1A = Pwm1 = VolumeMAX; // set PWM1 value

    /*
    TCCR1A = 0B10100001; // Timer1 is duble 8-bit PWM
    TCCR1B = 0B00000001; // Timer1 running on MCU clock / 1

    OCR1A = Pwm1 = VolumeMAX; // set PWM1 value
    OCR1B = Pwm2 = 200;       // set PWM2 value
    */

    // Init INT0

    Port4Inp(RC5_Port_ini,RC5_BitInp); // RC5 inp -> Input
    SetBit  (RC5_Port,    RC5_BitInp); // RC5 Input (+Ucc --> "1")
		       //         _
    MCUCR = 0x03;      // int0  _|   (rising edge)

    SetBit(GICR,INT0); // enable interrupt from INT 0


    // ### RS-232 ###

    Port4Inp(DDRD,PD0); // RS-232 Rx (Inp)
    Port4Out(DDRD,PD1); // RS-232 Tx (Out)

    UBRRL = (F_CPU / (16 * 9600UL)) - 1;        // Bd 9600
    UCSRB = _BV(TXEN) | _BV(RXEN) | _BV(RXCIE); // Tx,Rx,Rx interrupt enable

    // enable interrupts
       sei ();
       return;
}

/////////////////////
void sleep(int16_t s)
{
  for(s*=5; s > 0; s--)
  {
  TmrYYY();
      _delay_us(200);
    //_delay_ms(1);
  }
}

////////////////////////
void uart_putchar(char c)
{
  if (c == '\n')
     uart_putchar('\r');

  //loop_until_bit_is_set(UCSRA, UDRE);

  while(bit_is_clear(UCSRA, UDRE))
  {
    TmrYYY();
  }
  UDR = c;
  return;
}

////////////////////////
void uart_putstr(char *p)
{
   while(*p)
   {
     uart_putchar(*p++);
   }
   return;
}

////////////////////////

void PutHEX(uint8_t c)
{
  static char hex[16]= {'0','1','2','3','4','5','6','7',
			'8','9','A','B','C','D','E','F'};

// uart_putchar('[');
   uart_putchar(hex[c >>   4]);
   uart_putchar(hex[c & 0x0f]);
// uart_putchar(']');
   return;
}

/////////////////////////////////
char str[8]; // for min size code
/////////////////////////////////
void Rcv2Lcd(void)
{
  char *p;

  uint8_t i;
  uint8_t n;

    p = ultoa(FrcvWork,str,10);
    n = strlen(str);

    for(i=0; i < 6; i++)
    {
      LcdBuf[i+2] &= Lcd_Comma;

      if(n < 6)
      {
	 cccBuf[i]='0'; n++;
      }
      else
      {
	 cccBuf[i]=*p++;
	 LcdBuf[i+2] |= LcdDigit(cccBuf[i]-'0');
      }
    }
    return;
}

////////////////////////////////////
void Int2Lcd(uint16_t c, uint8_t sw)
{
  char *p;

  uint8_t i;
  uint8_t n;

    p = utoa(c,str,10);
    n = strlen(str);

    for(i=0; i < 4; i++)
    {
      LcdBuf[i+sw] &= Lcd_Comma;

      if(n < 4)
      {
	 n++;
      }
      else
      {
	 LcdBuf[i+sw] |= LcdDigit(*p-'0');
	 p++;
      }
    }
    return;
}

//////////////////
void Ind2Lcd(void)
{
  char *p;

  uint8_t i;
  uint8_t n;

    p = utoa(IndMEM,str,10);
    n = strlen(str);

    for(i=0; i < 2; i++)
    {
      LcdBuf[i] &= Lcd_Comma;

      if(n < 2)
      {
	 LcdBuf[i] |= Lcd_O;
	 n++;
      }
      else
      {
	 LcdBuf[i] |= LcdDigit(*p-'0');
	 p++;
      }
    }
    return;
}

////////////////////////////////
//  Analog-Digital Converter  //
////////////////////////////////

#define CH_POROG  0x42
#define CH_SMETR  0x43
#define CH_GND    0x4f

#define CH_VOLUME  0x40
#define CH_JOYSTIC 0x41

//--------------//
uint8_t GetADC (uint8_t chanel)
{
  uint16_t ret;

  ADMUX = chanel;
  _delay_us(200);

  SetBit(ADCSRA,ADSC); // start ADC

  while(bit_is_set(ADCSRA,ADSC))
  {
    TmrYYY();
    // Nop();
  }
  _delay_us(200);

  SetBit(ADCSRA,ADSC); // start ADC

  while(bit_is_set(ADCSRA,ADSC))
  {
    TmrYYY();
    // Nop();
  }
  ret = ADCW;
  return((uint8_t)(ret>>2));
}

/////////////////////////////
void SmeterLcd(uint8_t level)
{
   int8_t i;
  uint8_t f = 0;

     for(i = 7; i >= 0; i--)
     {
	if(level & 0x80) f++;

	      LcdBuf[i] &= ~Lcd_Comma;
	if(f) LcdBuf[i] |=  Lcd_Comma;

	level <<= 1;
     }
     return;
}

////////////////////
void SmeterPrn(void)
{
  char *p;

  uint8_t i;
  uint8_t n;
  uint8_t level = GetADC(CH_SMETR);

    SmeterLcd(level);

    uart_putchar(' ');

    p = utoa(level,str,10);
    n = strlen(str);

    for(i=0; i < 4; i++)
    {
      if(n < 4)
      {
	 uart_putchar('0'); n++;
      }
      else
      {
	 uart_putchar(*p++);
      }
    }
    return;
}


/////////////////////////////////////////
void wEEPROM(uint16_t addr, uint8_t byte)
{
     while(bit_is_set(EECR,EEWE))
     {
       Nop();
     }
     EEAR = addr;
     EEDR = byte;
     cli ();
	 SetBit(EECR,EEMWE);
	 SetBit(EECR,EEWE ); // start write to eeprom
     sei ();
     return;
}

//////////////////////////////
uint8_t rEEPROM(uint16_t addr)
{
     while(bit_is_set(EECR,EEWE))
     {
       Nop();
     }
     EEAR = addr;
     SetBit(EECR,EERE);
     return(EEDR);
}

///////////////////////////////////////////////////////////
void wBufEEPROM(uint16_t addr, uint8_t *buff, uint8_t size)
{
     uint8_t i;

     for(i=0; i < size; i++)
     {
       wEEPROM(addr++,*buff); buff++;
     }
     return;
}

///////////////////////////////////////////////////////////
void rBufEEPROM(uint16_t addr, uint8_t *buff, uint8_t size)
{
     uint8_t i;

     for(i=0; i < size; i++)
     {
	*buff = rEEPROM(addr++);
	 buff++;
     }
     return;
}

/////////////////////////
void SetFwork(uint32_t f)
{
     if( f <=  FrcvMax &&
	 f >=  FrcvMin )
     {
	 FrcvWork = (f/5)*5;
     }
     KeyRADIO();
}

/////////////////////////
void Lm7001Out(uint8_t c)
{
  uint8_t i;

    for(i=0; i < 8; i++)
    {
      if(c & 0x01)
	 SetBit(LM7001_Port,LM7001_BitDat);
      else
	 ClrBit(LM7001_Port,LM7001_BitDat);

	_delay_us(5);
	 SetBit(LM7001_Port,LM7001_BitClc);
	_delay_us(5);
	 ClrBit(LM7001_Port,LM7001_BitClc);

      c >>= 1;
    }
    return;
}

////////////////////
void Lm7001Set(void)
{
  static uint8_t  Mod4Lm7001[3] = {0xE6,0xE4,0xE2};
	 uint16_t fPCH2;

     FrcvPCH2 = (RCVPCH1-RCVPCH2)-(FrcvWork-((FrcvWork/50)*50));
	fPCH2 = FrcvPCH2/5;

     cli ();
     SetBit(LM7001_PortEN,LM7001_BitCEN);

     Lm7001Out(LoBYTE(fPCH2));
     Lm7001Out(HiBYTE(fPCH2));

     flagBo = Mod4Lm7001[Modulation];

	  ///////////////////////////////////////
	  //
	  //  S R2 R2 R0 TB Bo3 Bo2 Bo1
	  //
	  //  R0=0, R1=1, R2=1 --> 5kHz
	  //   S=1  --> FMIN
	  //
	  //      flagBo = 0xE0;  // 5kHz, FMIN
	  //
	  // Bo1  --> 1 - Mute ON 0 - Mute OFF
	  // Bo2  --> 1 - WFM  0 - NFM
	  // Bo3  --> 1 - FM   0 -  AM

     if(FlagMute) { flagBo |= 0x01; }

     Lm7001Out(flagBo);

     ClrBit(LM7001_PortEN,LM7001_BitCEN);
     ClrBit(LM7001_Port,  LM7001_BitDat);
     sei ();
     return;
}

/////////////////
//   I2C BUS   //
/////////////////

// Fix me -> need hardware support i2c bus

///////////////////
void I2CStart(void)
{
     SetBit(I2C_Port,I2C_BitClc);
     SetBit(I2C_Port,I2C_BitDat);

    _delay_us(10);
     ClrBit(I2C_Port,I2C_BitDat);

    _delay_us(10);
     ClrBit(I2C_Port,I2C_BitClc);
}

//////////////////
void I2CStop(void)
{
     ClrBit(I2C_Port,I2C_BitDat);
     SetBit(I2C_Port,I2C_BitClc);

    _delay_us(10);
     SetBit(I2C_Port,I2C_BitDat);
}

//////////////////
void I2CSync(void)
{
    _delay_us(10);
     SetBit(I2C_Port,I2C_BitClc);

    _delay_us(10);
     ClrBit(I2C_Port,I2C_BitClc);
}

//////////////////////////
void I2COutByte(uint8_t c)
{
  uint8_t i;

    for(i=0; i < 8; i++)
    {

      if(c & 0x80)
	 SetBit(I2C_Port,I2C_BitDat);
      else
	 ClrBit(I2C_Port,I2C_BitDat);

	I2CSync();

	c <<= 1;
    }
    I2CSync(); // ASK
    return;
}

////////////////////
void KSH14xPLL(void)
{
  uint32_t fPCH1;
  uint8_t   Band;


     Band = CONST__LoBAND;

     if(FrcvWork > 155000L) Band = CONST__MiBAND;
     if(FrcvWork > 440000L) Band = CONST__HiBAND;


     fPCH1 = (uint16_t)((FrcvWork + RCVPCH1)/50);

     I2CStart();

     I2COutByte(0b11000000);   // Tuner Address
     I2COutByte(HiBYTE(fPCH1));
     I2COutByte(LoBYTE(fPCH1));
     I2COutByte((TunerGain)? CONST__GAINon:CONST__GAINoff);
     I2COutByte(Band);

     I2CStop();
     return;
}

//////////////////
void fWorkPrn(void)
{
  uint8_t i;

     Rcv2Lcd(); sleep(5);

     uart_putstr("\nF ");

     GetADC(CH_SMETR);

     for(i = 0; i < 6; i++)
     {
	uart_putchar(cccBuf[i]);

	if(i == 2)
	      uart_putchar('.');
     }
     SmeterPrn();
     SmeterPrn();
     SmeterPrn();
     return;
}

//////////////////
void SetFrcv(void)
{
     Lm7001Set();
     KSH14xPLL();

     fWorkPrn();
     return;
}


// --------- //
int main (void)
{
  uint8_t key;

    ioinit ();

    SetFmax();
    SetFmin();

    FlagMute = 1;
    Modulation = WFM;
    FrcvWork   = 106600;
    rMEM();              // IndMEM = 0

    KeyRADIO(); sleep(1000);
    RC5wrk = 1;
    Joystic ();


    for (;;)
    {
    TmrYYY();

      RsControl();

      key = GetKbd();

      if(RC5inp)
      {
	if(RC5wrk)
	{
	   key = RC5_Kbd();
	}
	else
	{
	   uart_putstr("RC5:");
	   PutHEX(HiBYTE(RC5inp));
	   PutHEX(LoBYTE(RC5inp));
	   uart_putstr(PROMPT);

	   RC5inp &= 0x07ff;

	   if(RC5inp == RC5old)
	   {
	      RC5prg++;
	   }
	   else
	   {
	      RC5prg = 0;
	      RC5old = RC5inp;
	   }
	}
	RC5inp=0;
      }
      SetVolume();

      if(!key) key = Joystic();

      if(key--)
      {
	(* SwKey[((key) & 0x0f) | ((Regim == FINPUT)? 0x10:0x00)] )();
      }

      if(FlagScanF) ScanerF();
      if(FlagScanM) ScanerM();

      SmeterLcd(Smeter = GetADC(CH_SMETR));


      SetMute();

      UapyControl(Smeter);

    } // for(;;)
}

/////////////////////
void FrcvUpDown(void)
{
    switch(direction)
    {
      case UP:   if(FrcvWork <  FrcvMax)
		 {
		    FrcvWork += FrcvStep;
		 }
		 else
		    direction = DOWN;

		 break;

      case DOWN: if(FrcvWork >  FrcvMin)
		 {
		    FrcvWork -= FrcvStep;
		 }
		 else
		    direction = UP;

		 break;
    }
    return;
}


//////////////////
void KeyPlus(void)
{
   if(Regim == RADIO)
   {
     direction = UP;

     FrcvUpDown();
     SetFrcv();
   }

   if(Regim == WR_MEM || Regim == RC_MEM)
   {
      if(++IndMEM > NUM_MEM-1)
	   IndMEM = 0;
      Ind2Lcd();

      if(Regim == RC_MEM) rMEM();
   }

   if(Regim == SCAN_M && FlagBank == 0)
   {
      if(++ScanMBank > 3)
	   ScanMBank = 0;

      Int2Lcd(ScanMBank,4);
   }
   return;
}

//////////////////
void KeyMinus(void)
{
   if(Regim == RADIO)
   {
     direction = DOWN;

     FrcvUpDown();
     SetFrcv();
   }

   if(Regim == WR_MEM || Regim == RC_MEM)
   {
      if(--IndMEM < 0)
	   IndMEM = NUM_MEM-1;
      Ind2Lcd();

      if(Regim == RC_MEM) rMEM();
   }

   if(Regim == SCAN_M && FlagBank == 0)
   {
      if(--ScanMBank < 0)
	   ScanMBank = 3;

      Int2Lcd(ScanMBank,4);
   }
   return;
}

//////////////////
void KeySTEP(void)
{
     switch(Regim)
     {
       case STEP:  if(++FindStep >= 8)
			FindStep  = 0;
		   FrcvStep = Step[FindStep];
       case RADIO:
		   LcdBuf[0] = Lcd_S;
		   LcdBuf[1] = Lcd_T;
		   LcdBuf[2] = Lcd_E;
		   LcdBuf[3] = Lcd_P;

		   Int2Lcd(FrcvStep,4);

		   Regim = STEP;
     }
     return;
}

//////////////////
void Mod2Lcd(void)
{
  static uint8_t Mod4Lcd[3] = {0xC8,0xC1,0xC9};

  LcdBuf[1] = Mod4Lcd[Modulation];
}

//////////////////
void KeyMOD(void)
{
   if(Regim == RADIO)
   {
     if(++Modulation > AM)
	  Modulation = WFM;

     Mod2Lcd();
     Lm7001Set();
   }
   return;
}

//////////////////
void KeyRADIO(void)
{
     if(Regim == SCAN_F)
     {
	FlagScanF = 0;
	SetFmax();
	SetFmin();
     }
     FlagScanM = 0;
     Regim = RADIO;

     LcdBuf[0] = Lcd_P;
     LcdBlink  = 0;

     Mod2Lcd();
     SetFrcv();
}

/////////////////////////
void Flg2Lcd( uint8_t sw)
{
     if(sw)
     {
       LcdBuf[5] = 0;
       LcdBuf[6] = Lcd_O;
       LcdBuf[7] = Lcd_N;
     }
     else
     {
       LcdBuf[5] = Lcd_O;
       LcdBuf[6] = Lcd_F;
       LcdBuf[7] = Lcd_F;
     }
     return;
}

//////////////////
void KeyGAIN(void)
{
     switch(Regim)
     {
       case GAIN:  TunerGain = (TunerGain)? 0:1;
		   KSH14xPLL();

       case RADIO:
		   LcdBuf[0] = Lcd_G;
		   LcdBuf[1] = Lcd_A;
		   LcdBuf[2] = Lcd_I;
		   LcdBuf[3] = Lcd_N;
		   LcdBuf[4] = 0;

		   Flg2Lcd(TunerGain);

		   Regim = GAIN;
     }
     return;
}

//////////////////
void KeyUapy(void)
{
     switch(Regim)
     {
       case UAPY:  UapyFlg = (UapyFlg)? 0:1;

		   Uapy = 0xff;
		   UapyYes = 1;

       case RADIO:
		   LcdBuf[0] = Lcd_U;
		   LcdBuf[1] = Lcd_A;
		   LcdBuf[2] = Lcd_P;
		   LcdBuf[3] = Lcd_Y;
		   LcdBuf[4] = 0;

		   Flg2Lcd(UapyFlg);

		   Regim = UAPY;
     }
     return;
}

//////////////////
void KeyFinp(void)
{
     switch(Regim)
     {
       case FINPUT:
       case  RADIO:
		    Mod2Lcd();
		    LcdBlink  = 0B00100000;
		    LcdBuf[0] = Lcd_F;
		    LcdBuf[2] = Lcd__;

		    memset((void *)&LcdBuf[3],0,5);

		    InpInd = 0;
		    Regim  = FINPUT;
		    break;

       case  WR_MEM:
		    cMEM();
		    LcdBlink = 0xFF;
		    sleep(2000);
		    LcdBlink = 0xC0;
     }
     return;
}

////////////////////////
void Key_ii( uint8_t c )
{
  uint32_t f;

	LcdBlink >>= 1;

	LcdBuf[InpInd+2] &= Lcd_Comma;
	LcdBuf[InpInd+2] |= LcdDigit(c);;

	InpBuf[InpInd++] = c +'0';
	InpBuf[InpInd  ] = 0;

     if(InpInd >= InpBufLEN-1)
     {
	f = atol((const char *)InpBuf);

	SetFwork(f);
     }
     else
	LcdBuf[InpInd+2] = Lcd__;
}

////////////////
void Key_0(void) { Key_ii(0); return; }
void Key_1(void) { Key_ii(1); return; }
void Key_2(void) { Key_ii(2); return; }
void Key_3(void) { Key_ii(3); return; }
void Key_4(void) { Key_ii(4); return; }
void Key_5(void) { Key_ii(5); return; }
void Key_6(void) { Key_ii(6); return; }
void Key_7(void) { Key_ii(7); return; }
void Key_8(void) { Key_ii(8); return; }
void Key_9(void) { Key_ii(9); return; }

///////////////////////////////////////
void KeySetHL(uint16_t addr, uint8_t c)
{
     switch(Regim)
     {
       case WR_H_L:
		    wBufEEPROM (addr, (uint8_t *)&FrcvWork, 4);

		    LcdBlink  = 0;
		    LcdBuf[0] = c;

		    sleep(2000);
		    KeyRADIO();
		    break;
       case  RADIO:
		    LcdBlink  = 0x80;
		    LcdBuf[0] = c;
		    LcdBuf[1] = 0;

		    Regim  = WR_H_L;
     }
     return;
}

///////////////////
void KeySetHi(void) { KeySetHL(ADR_EE_Hi,Lcd_H); return; }
void KeySetLo(void) { KeySetHL(ADR_EE_Lo,Lcd_L); return; }

/////////////////////////////////////
uint8_t buff[8]; // for min size code
/////////////////////////////////////

////////////////
void wMEM(void)
{
     memcpy(buff,(uint8_t *)&FrcvWork,4);

     buff[3] = Modulation | 0xFC;

     wBufEEPROM (((uint16_t)IndMEM)<<2, buff, 4);
}

//////////////////
uint8_t rMEM(void)
{
     rBufEEPROM (((uint16_t)IndMEM)<<2, buff, 4);

     if((buff[3] & 0x03) != 0x03)
     {
	Modulation = buff[3] & 0x03;

	memcpy((uint8_t *)&FrcvWork,buff,3);
	SetFrcv();
     }
     else
     {
	 memset((void *)&LcdBuf[2],0x40,6);
	 return 1;
     }
     return 0;
}

////////////////
void cMEM(void)
{
     buff[0] =
     buff[1] =
     buff[2] =
     buff[3] = 0xff;

     wBufEEPROM (((uint16_t)IndMEM)<<2, buff, 4);
}

///////////////////
void KeyWrMem(void)
{
     switch(Regim)
     {
       case WR_MEM:
		    wMEM();
		    LcdBlink = 0;

		    sleep(2000);
		    KeyRADIO();
		    break;
       case  RADIO:
		    LcdBlink = 0xC0;
		    Ind2Lcd();

		    Regim  = WR_MEM;
     }
     return;
}

///////////////////
void KeyRcMem(void)
{
     if(Regim == RADIO)
     {
	Regim = RC_MEM;

	Ind2Lcd();
	rMEM();
     }
     return;
}

///////////////////
void KeyScanF(void)
{
     if(Regim == SCAN_F)
     {
	FlagScanF = (FlagScanF)? 0:1;
     }

     if(Regim == RADIO)
     {
	Regim = SCAN_F;

	LcdBuf[0] = 0x3B;  // "POISK"
	Mod2Lcd();

	rBufEEPROM (ADR_EE_Hi, (uint8_t *)&FrcvMax, 4);
	rBufEEPROM (ADR_EE_Lo, (uint8_t *)&FrcvMin, 4);

	if(FrcvMax < FrcvMin)
	{
	  rBufEEPROM (ADR_EE_Lo, (uint8_t *)&FrcvMax, 4);
	  rBufEEPROM (ADR_EE_Hi, (uint8_t *)&FrcvMin, 4);
	}
	if(FrcvMax & 0x80000000) SetFmax();
	if(FrcvMin & 0x80000000) SetFmin();

	if( FrcvWork > FrcvMax ||
	    FrcvWork < FrcvMin || FlagBegin)
	{
	    FrcvWork = FrcvMin;
	    FlagBegin= 0;
	    SetFrcv();
	}
	FlagScanF = 1;
     }
     return;
}

//////////////////
void ScanerF(void)
{
     FrcvUpDown(); SetFrcv();
}

///////////////////
void KeyScanM(void)
{
     if(Regim == SCAN_M)
     {
	if(FlagBank)
	{
	   FlagScanM = (FlagScanM)? 0:1;
	}
	else
	{
	   FlagScanM = 1;
	   FlagBank  = 1;
	}
     }

     if(Regim == RADIO)
     {
	Regim = SCAN_M;

	LcdBuf[0] = Lcd_B;  // B
	LcdBuf[1] = Lcd_A;  // a
	LcdBuf[2] = Lcd_N;  // n
	LcdBuf[3] = Lcd_c;  // c

	Int2Lcd(ScanMBank,4);
	FlagBank = 0;
     }
     return;
}

//////////////////
void ScanerM(void)
{
  static uint8_t ScanMmin[4] = { 1,25,50,75};
  static uint8_t ScanMmax[4] = {24,49,74,99};
  uint8_t IndTmp;

     if( IndMEM < ScanMmin[ScanMBank] ||
	 IndMEM > ScanMmax[ScanMBank] )
	 IndMEM = ScanMmin[ScanMBank];

     IndTmp = IndMEM;

     do
     {
	if(++IndMEM > ScanMmax[ScanMBank])
	{
	     IndMEM = ScanMmin[ScanMBank];
	}

	if(!rMEM())
	{
	   SmeterPrn();
	   SmeterPrn();
	   SmeterPrn();
	   SmeterPrn();
	   SmeterPrn();
	   SmeterPrn();
	   break;
	}

     } while(IndTmp != IndMEM);

     Ind2Lcd();
     return;
}

////////////////////
void RsControl(void)
{
  uint8_t inp;
  uint8_t   i;
  uint32_t  f;

  if(Regim == RADIO || Regim == SCAN_F)
  {
     if(RxInd != TxInd)
     {
	if((inp = RxInpBuf[TxInd++]) != '\n' && EchoYes)
	{
	   uart_putchar(inp);
	}
	//uart_putchar(inp = RxInpBuf[TxInd++]);

	if(RxInd >= RxInpBufLEN)
	{
	   RcInd = 0;
	   RxInd = 0;
	   TxInd = 0;
	   uart_putstr(ERROR);

	   return;
	}
	if(isdigit(inp))
	{
	   RcInpBuf[RcInd++] = inp;
	}

	if(inp == '\r')
	{
	   RcInpBuf[RcInd] = '\0';
	   RcInd = 0;

	   if(Regim == SCAN_F)
	   {
	      RxInpBuf[0] = 0;
	      KeyRADIO();
	   }
	   f = atol((const char *)RcInpBuf);

	   i = (uint8_t)(f & 0x000000FF);

	   // use uint8_t inp like tmp

	   inp = (RxInpBuf[0] == '\n')? 1:0;

	   switch(RxInpBuf[inp])
	   {
	    case '+': KeyPlus (); break;
	    case '-': KeyMinus(); break;

	    case 'M':
		      if((Modulation = i & 0x03) == 3)
			  Modulation = 0;
		      Mod2Lcd();
		      Lm7001Set();
		      break;

	    case 'G': TunerGain = i & 0x01;
		      KSH14xPLL();
		      break;

	    case 'S': FindStep = i & 0x07;
		      FrcvStep = Step[FindStep];
		      break;

	    case 'U': Uapy    = i;
		      UapyYes = 1;
		      break;

	    case 'E': EchoYes = i;
		      break;

	    case 'L':
		      if(i == 2)
		      {
			 FlagSQL = 1;
		      }
		      else
		      {
			 FlagMute = i & 0x01;
			 FlagSQL = 0;
			 Lm7001Set();
		      }
		      break;

	    case 'R': RC5wrk = i & 0x01;
		      break;

	    case 'W': RC5write(i);
		      break;

	    case '.': fWorkPrn();
		      break;

	    case ',': SmeterPrn();
		      SmeterPrn();
		      SmeterPrn();
		      SmeterPrn();
		      SmeterPrn();
		      break;

	    case 'D': if(i)
		      {
			LcdWork = 1;
		      }
		      else
		      {
			LcdWork = 0;
			cli();
			LcdOut2(0);
			LcdOut2(0);
			sei();
		      }
		      break;

	    case 'H': wBufEEPROM (ADR_EE_Hi, (uint8_t *)&f, 4);
		      break;

	    case 'B': wBufEEPROM (ADR_EE_Lo, (uint8_t *)&f, 4);
		      break;


	    case 'F': SetFwork(f);
		      break;

	    case 'P': KeyScanF();
		      break;

	    case 'N': FlagBegin++;
		      KeyScanF();
		      break;
	   }
	   RxInd = 0;
	   TxInd = 0;
	   uart_putstr(PROMPT);
	}
     }
  }
  return;
}

///////////////////////////////
void UapyControl(uint8_t level)
{
   if(UapyFlg)
   {
     SmeterUapy += level;

     if(++UapyCnt >= UapyNN)
     {
	SmeterUapy = SmeterUapy / UapyNN;

	if(SmeterUapy > UapyHi)
	{
	  if(Uapy > 1)
	  {
	     Uapy--; UapyYes++;
	  }
	}
	if(SmeterUapy < UapyLo)
	{
	  if(Uapy < 255)
	  {
	     Uapy++; UapyYes++;
	  }

	}
	SmeterUapy = 0;
	UapyCnt    = 0;
     }
   }
   return;
}

/////////////////////
uint8_t Joystic(void)
{
  static
  uint8_t JoysticOld;
  uint8_t lvl;
  uint8_t ret = 0;

      lvl = GetADC(CH_JOYSTIC);

      if(abs(JoysticOld - lvl) > 9)
      {
	     ret = (JoysticOld > lvl)? KBD_Pls+1:KBD_Mns+1;
	     JoysticOld = lvl;
      }
      return ret;
}


  /////////////////////
  /////////////////////
  volatile uint8_t SQL;

////////////////
void SQLup(void)
{
     if(SQL > 99)
     {
	SQL += 10;

	if(SQL < 10)
	   SQL = 255;
	return;
     }

     if(SQL > 20)
     {
	SQL += 5;
	return;
     }
     SQL++;
}

//////////////////
void SQLdown(void)
{
     if(SQL > 99) { SQL -= 10; return; }
     if(SQL > 25) { SQL -=  5; return; }

     if(SQL)
	SQL--;
}

//////////////////
void SetMute(void)
{
  static
  uint8_t old;
  uint8_t lvl;

     if(FlagSQL == 0)
	return;

      lvl = 255-GetADC(CH_POROG);

      if(old != lvl)
      {
	 SQL = lvl;
	 old = lvl;
      }

      if(Smeter > SQL || SQL == 0)
      {
      // Sound ON

	 FlagScanF = 0;
	 FlagScanM = 0;
	 MuteCnt = 0;

	 if(FlagMute)
	 {
	    FlagMute = 0;
	    Lm7001Set();
	 }
      }
      else
      {
      // Sound Off

	 if(MuteCnt >= MUTE)
	 {
	    if(!FlagMute)
	    {
		FlagMute = 1;
		Lm7001Set();
	    }
	 }
      }
      return;
}

///////////////////
void VolumeUp(void)
{
   if(Pwm1 > VolumeMIN)
   {
     OCR1A = Pwm1--;
   }
   return;
}

/////////////////////
void VolumeDown(void)
{
   if(Pwm1 < VolumeMAX)
   {
     OCR1A = Pwm1++;
   }
   return;
}

////////////////////
void SetVolume(void)
{
  static
  uint8_t VolumeOld;
  uint8_t lvl;
  uint8_t tmp;

      lvl = 255-GetADC(CH_VOLUME);

      if(abs(VolumeOld - lvl) > 2)
      {
	     VolumeOld = lvl;

	     if((tmp = VolumeMAX - (lvl/3)) < VolumeMIN)
		 tmp = VolumeMIN;

// uart_putchar('{');
//             PutHEX(tmp);
// uart_putchar('}');

	     OCR1A = Pwm1 = tmp;
      }
      return;
}


