/************************************************************************/
/*                                                                      */
/*  FILE        :easyRoof.c                                             */
/*  DATE        :Jan 1, 2007                                            */
/*  DESCRIPTION :Main Program                                           */
/*  CPU TYPE    :R5F21134 (Renesas R8C13)                               */
/*  AUTHOR      :Dirk Siegmund                                          */
/*               www.simpleroof.de                                      */
/*                                                                      */
/*  History                                                             */
/*          : V1.00 03.01.2007   lite version only                      */
/*                                                                      */
/*          : V1.01 13.02.2007   full version                           */
/*                                                                      */
/*          : V1.02 17.02.2007   power down improved                    */
/*                                                                      */
/*          : V1.03 01.03.2007   alarm function alarm_cfg               */
/*                                                                      */
/*          : V1.04 08.03.2007   lock_timeout                           */
/*                               watchdog / window automation           */
/*                                                                      */
/*          : V1.05 15.03.2007   ABS_working detection                  */
/*                                                                      */
/*          : V1.06 20.03.2007   ABS_working collided with unlock       */
/*                               window automation independent from     */
/*                               speed limit                            */
/*                               TOPREL_OUT=1 only Remote               */
/*                                                                      */
/*          : V1.07 26.03.2007   TOPREL_OUT=1 always --> ignition off   */
/*                               lock_timeout error on Door open        */
/*                               Watchdog reset                         */
/*                               EMERGENCY_WAIT =840                    */
/*                               RemoteEMERGENCY_STOP at any remote key */
/*                                                                      */
/*          : V1.08 02.04.2007   set roof_timer on Key detection        */
/*                                                                      */
/*          : V1.09 21.05.2007   no ABS-Detection while remote_action   */
/*                               REMOTE_WAIT after Speed_Edge           */
/*                                                                      */
/*          : V1.10 21.07.2007   new hardware V1.2  unlock   OK         */
/*                               window remote               OK         */
/*                               alarm always activated      OK         */
/*                               Chirp config                OK         */
/*                               power timeout alarm         OK         */
/*                                                                      */
/*          : V1.11 16.10.2007   10x Chirp =memory error                */
/*                               infrared support with automatic        */
/*                               detection                              */
/*                                                                      */
/************************************************************************/

#include "sfr_r813.h"
#include "string.h"

#define REMOTE_DEBUGGER     1   /* only for development */

#define RELOCK              1   /* Lock car after remote roof lowering */

#define ROOF_LOWER_CLICKS   3   /* standard = 3 */
#define ROOF_RAISE_CLICKS   2   /* standard = 2 */

#define WINDOW_LOWER_CLICKS 4   /* standard = 4 */
#define WINDOW_RAISE_CLICKS 3   /* standard = 3 */

/* this is only for version information in compiled code */

typedef struct APPtag{
    unsigned char ID[3];
    unsigned char Name[16];
    unsigned char VerInfo[20];
    unsigned int  Version;
    unsigned int  CRC;
    unsigned char valid;
    unsigned long Start;
}APP;

const APP Application ={{'A','P','F'},
            "EasyRoofSLKR170",
            "V1.11    16.10.2007",
            111,        //Version number
            0x0000,
            0x00,
            0x00C800};

/* declaration of interrupt routines */

#pragma INTERRUPT  timerX_int   /* Declares interrupt handler TIMER X  */
#pragma INTERRUPT  timerC_int   /* Declares interrupt handler TIMER C  */
#pragma INTERRUPT  int0_int     /* Declares interrupt handler INT0     */
#pragma INTERRUPT  int1_int     /* Declares interrupt handler INT1     */
#pragma INTERRUPT  int2_int     /* Declares interrupt handler INT2     */
#pragma INTERRUPT  int3_int     /* Declares interrupt handler INT3     */
#pragma INTERRUPT  key_int      /* Declares interrupt handler KEY      */

/* pin and port definitions */

#define TOPREL_OUT      p0_1        /* output port for hardtop power relay in fuse box */
#define RELABS_OUT      p0_2        /* output port for ABS and speed signal relay on PCB */
#define LAMP_IN         p0_3        /* input port for pilot light in hardtop control knob */
#define ALARM_CFG       p0_4        /* input port for activating the ALARM function */
#define DOOR_CFG        p0_5        /* input port for activating the door contact test  --- don't use it*/
#define UNLOCK_OUT      p0_6        /* output port for unlocking the car */
#define LOCK_OUT        p0_7        /* output port for locking the car */

#define RAISE_OUT       p1_0        /* output port for raising the hardtop */
#define RAISE_OUTdir    pd1_0       /* direction control register */
#define DOOR_IN         p1_1        /* input port from the main control unit for the inner lighting */
#define DOOR_INdir      pd1_1       /* direction control register */
#define RAISE_IN        p1_2        /* input port for raising feedback */
#define RAISE_INdir     pd1_2       /* direction control register */
#define LOWER_IN        p1_3        /* input port for lowering feedback */
#define LOWER_INdir     pd1_3       /* direction control register */

#define SDA             p1_4        /* IIC data port for debug interface */
#define SDAdir          pd1_4       /* direction control register */
#define SCL             p1_5        /* IIC clock port for debug interface */
#define SCLdir          pd1_5       /* direction control register */
#define LOWER_OUT       p1_6        /* output port for lowering the hardtop */
#define LOWER_OUTdir    pd1_6       /* direction control register */
#define ABS_IN          p1_7        /* input port for ABS signal */
#define ABS_INdir       pd1_7       /* direction control register */

#define CHIRP_OUT       p3_0        /* output port for chirp sound and alarm */
#define CHIRP_OUTdir    pd3_0       /* direction control register */
#define ABS_OUT         p3_1        /* output port for original AND simulated ABS signal*/
#define ABS_OUTdir      pd3_1       /* direction control register */
#define UNLOCK_IN       p3_2        /* input port for RF-remote unlock signal*/
#define UNLOCK_INdir    pd3_2       /* direction control register */
#define SPEED_IN        p3_3        /* input port for speed pulse (Tachosignal) */
#define SPEED_INdir     pd3_3       /* direction control register */

#define LOCK_IN         p4_5        /* input port for RF-remote lock signal OR IR-remote lock/unlock*/
#define LOCK_INdir      pd4_5       /* direction control register */

union byte_def Prog_Flags;
#define     ProgFlags       Prog_Flags.byte

#define     Flash           Prog_Flags.bit.b0
#define     AltFlash        Prog_Flags.bit.b1
#define     Refresh         Prog_Flags.bit.b2
#define     Scan            Prog_Flags.bit.b3
#define     LastRaiseState  Prog_Flags.bit.b4
#define     LastLowerState  Prog_Flags.bit.b5
#define     LastLampState   Prog_Flags.bit.b6
#define     ABS_working     Prog_Flags.bit.b7

union byte_def Option_Flags;
#define     OptionFlags     Option_Flags.byte
#define     ChirpActive     Option_Flags.bit.b0
#define     ClickActive     Option_Flags.bit.b1
#define     CarLocked       Option_Flags.bit.b2
#define     AlarmActive     Option_Flags.bit.b3
#define     IRmode          Option_Flags.bit.b4

union byte_def Prog_State;
#define     ProgState       Prog_State.byte

#define     Programming     Prog_State.bit.b0
#define     Remote_avail    Prog_State.bit.b1
#define     ABS_active      Prog_State.bit.b2
#define     Speed_Limiter   Prog_State.bit.b3
#define     Save            Prog_State.bit.b4
#define     Stop            Prog_State.bit.b5
#define     LockState       Prog_State.bit.b6
#define     UnlockState     Prog_State.bit.b7

union byte_def Key_Flags;
#define     KeyFlags        Key_Flags.byte

#define     Edge_Plus       Key_Flags.bit.b0
#define     Edge_Start      Key_Flags.bit.b1
#define     Edge_Minus      Key_Flags.bit.b2
#define     Edge_Prog       Key_Flags.bit.b3
#define     Raise_Edge      Key_Flags.bit.b4
#define     Lower_Edge      Key_Flags.bit.b5
#define     Speed_Edge      Key_Flags.bit.b6

unsigned int  ABS_period= 0x1000;
unsigned int  TimerX    = 0;

unsigned long period=1;
unsigned long periodH=0;
unsigned int  periodL=0;
unsigned long periods[8]={0,0,0,0,0,0,0,0};         /* intial values for the last 8 speed measurements */
unsigned char pcount=0;                             /* measurement counter */

unsigned int  chirp_timer=0;
unsigned int  chirp_pause=0;
unsigned char chirp_count=0;

#define CHIRP_TIME      60          //msec
#define CHIRP_PAUSE     180         //msec
#define ALARM_SOUND     30000       //msec

unsigned int  lock_timer=0;
unsigned char lock_timeout=0;

#define LOCK_TIME_RF    180         //msec
#define LOCK_TIME_IR    150         //msec

#define LOCK_TIMEOUT    60          //x0.5Sec = 30sec

unsigned int  unlock_timer=0;
unsigned int  unlock_pause=0;
unsigned char unlock_pulses=0;

unsigned int  UnlockPulseLength=0;
unsigned int  UnlockPauseLength=0;
unsigned char UnlockPulseCount=0;

unsigned int  LockPulseLength=0;
unsigned int  LockPauseLength=0;

#define MAX_PULSE_LENGTH 20         //x5msec

#define UNLOCK_TIME_RF   30         //msec      repeated 4 times
#define UNLOCK_PAUSE_RF  15         //msec

#define UNLOCK_TIME_IR   15         //msec      repeated 6 times
#define UNLOCK_PAUSE_IR  10         //msec

unsigned char Raise_clicks=0;
unsigned char Lower_clicks=0;
unsigned char Click_timeout=0;

unsigned char LockTiming=0;
unsigned char LockCount=0;

unsigned char UnlockTiming=0;
unsigned char UnlockCount=0;
unsigned char UnlockPackets=0;
unsigned int  UnlockPacketTiming=0;

#define ROOF_IDLE       0
#define ROOF_LOWER      1
#define ROOF_RAISE      2
#define WINDOWS_LOWER   3
#define WINDOWS_RAISE   4

#define ROOF_TIME           35000   //msec
#define WINDOW_UP_TIME       7000   //msec
#define MAX_LAMP_BLINK_TIME  1500   //msec

unsigned char roof_action=ROOF_IDLE;
unsigned int  roof_timer=0;

unsigned int  RemoteTimer=0;
unsigned char RemoteAction=ROOF_IDLE;

#define REMOTE_WAIT          2000   //msec
#define CLICK_WAIT           1200   //msec
#define ALARM_WAIT          10000   //msec

unsigned long KMH=0;

unsigned int  ABS_timeout;
unsigned int  POWER_timeout;
unsigned char Emergency=0;

#define WAIT_ABS 3
#define WAIT_TIL_POWERDOWN  80      //x0.5 seconds
#define EMERGENCY_WAIT     840      //x0.5 seconds

#define CLICK_IDLE      0
#define WINDOW_DOWN     1
#define WINDOW_UP       2
#define SECOND_CLICK    0x80

unsigned int  click_timer=0;
unsigned int  click_pause=0;
unsigned char click_dir=CLICK_IDLE;

#define CLICK_PAUSE_TIME    100 //msec
#define CLICK_DOWN_TIME    6000 //msec
#define CLICK_UP_TIME      7000 //msec
#define CLICK_TIME          150 //msec

unsigned int  DoubleDetect_raise=0;
unsigned int  DoubleDetect_lower=0;

#define DOUBLE_CLICK_THRESHOLD  80  //x5msec

#define DOOR_EDGE_TIME_OPEN    112  //x5msec
#define DOOR_EDGE_TIME_CLOSE   160  //x5msec
#define DOOR_REL_TIME            8  //x5msec

unsigned int Door_open_edge=0;
unsigned int Door_close_edge=DOOR_EDGE_TIME_CLOSE+1;

typedef struct SysVar_Tag
{
  struct APPtag APF;            /* record 1 application information & ID */
  unsigned int SpeedLimit;      /* record 2 memorizes speed limit*/
  unsigned int WindowsUp;       /* record 3 0x01=UpOnRaise 0x02=UpOnLower */
  unsigned int ChirpOnOff;      /* record 6 0x01=UpOnRaise 0x02=UpOnLower */

} SVar;

SVar SysVar;


/**** Proto-type declaration **************************/

void timerX_int(void);
void timerC_int(void);
void int0_int(void);
void int1_int(void);
void int2_int(void);
void int3_int(void);
void key_int(void);

void far main(void);

/***** Include Files **********************************/
#include    "virtEE_Variable.c" /* Virtual EEPROM (variable size records) function definitions */
NV_type EE_data;                /* Need NV_type structure to use  VirtEE API */

#include    "Flash_API.c"       /* Flash subroutines */

#if (REMOTE_DEBUGGER==1)
    #include "remote_debug.c"
#endif


/* --TIMERX-TIMERX-TIMERX-TIMERX-TIMERX-TIMERX------- invoked every 1ms */

void far timerX_int(void)
{
  asm( "\tFSET  I");                            /* Enable all active interrupts */

    TimerX++;

    if (!(ABS_period & 0x1000)) ABS_period++;       /*   */

    if ((TimerX % 5)==1)                        /* every 5ms */
    {
        Scan=1;                                 /* scan debug interface keyboard */
    }

    if ((TimerX % 10)==1)                       /* every 10ms */
    {
        if (LockTiming)
        {
            LockTiming--;
        }
        else LockCount=0;

        if (UnlockTiming)
        {
            UnlockTiming--;
        }
        else
        {
            UnlockCount=0;
            UnlockPulseCount=0;
            if (UnlockPacketTiming)
            {
                UnlockPacketTiming--;
            }
            else UnlockPackets=0;
        }
    }

  if ((TimerX % 100)==1)                        /* every 100ms */
  {
      Refresh=1;                                /* refresh debug interface display */

      if (Click_timeout)                        /* check click timeout */
      {
            if (--Click_timeout==0)             /* reset, if timed out */
            {
                Lower_clicks=0;
                Raise_clicks=0;
            }
      }
  }

  if (SysVar.SpeedLimit>800) SysVar.SpeedLimit=800;     /* safety check --- not more than 80km/h hardtop activation limit */

  if (KMH>=SysVar.SpeedLimit)                           /* check if current speed higher than limit */
  {
        if((TimerX % 24) == 0) ABS_OUT=~ABS_OUT;        /* generate ABS signal ---- 21Hz ABS-Signal ===> ausserhalb erlaubter Bereich  */

        if (Speed_Edge)
        {
            if ((roof_action!=WINDOWS_LOWER) && (roof_action!=WINDOWS_RAISE))
            {
                RAISE_OUT=1;
                LOWER_OUT=1;
            }

            RELABS_OUT=0;

            Speed_Limiter=1;
        }

        Speed_Edge=1;
  }
  else
  {
        if((TimerX % 166) == 0) ABS_OUT=~ABS_OUT;       /* 3Hz ABS-Standsignal ===> innerhalb erlaubter Bereich     */

        if ( !( (RAISE_IN && LOWER_IN && LAMP_IN) || ChirpActive || ClickActive) || (KMH<30) || (RemoteAction!=ROOF_IDLE))
        {
             if ((ABS_working) && (KMH<30) && (RemoteAction==ROOF_IDLE))
                  RELABS_OUT=0;
             else RELABS_OUT=1;
        }
        else RELABS_OUT=0;

        Speed_Limiter=0;

        if (Speed_Edge)
        {
            if (roof_timer)
            {
                if (roof_action==ROOF_RAISE)
                {
                    TOPREL_OUT=1;
                    RAISE_OUT=0;
                    LOWER_OUT=1;
                    RemoteTimer=REMOTE_WAIT;
                }

                if (roof_action==ROOF_LOWER)
                {
                    TOPREL_OUT=1;
                    RAISE_OUT=1;
                    LOWER_OUT=0;
                    RemoteTimer=REMOTE_WAIT;
                }
            }

            Speed_Edge=0;
        }
  }

  if (TimerX >= 500)
  {
      TimerX=0;
      Flash = ~Flash;

      if (ABS_timeout)
      {
          if(!--ABS_timeout)
          {
              ABS_active=0;
              ABS_working=0;
          }
      }

      if (POWER_timeout)
      {
          if(--POWER_timeout==0)
          {
              Stop=1;
          }
          else
          {
              if ((Emergency) && (POWER_timeout<=40))       /* last 20 Seconds */
              chirp_count=1;
          }
      }

      if (lock_timeout)
      {
          if (!--lock_timeout)
          {
                if (IRmode)
                {
                     unlock_timer=LOCK_TIME_RF; /* lock the car */
                     unlock_pulses=0;
                }
                else lock_timer=LOCK_TIME_RF;   /* lock the car */

                CarLocked=1;
                RemoteTimer=ALARM_WAIT;
          }
      }

  }

  if (RemoteTimer)
  {
      if(!--RemoteTimer)
      {
          switch(RemoteAction)
          {
            case ROOF_LOWER:
                RAISE_OUT=1;
                LOWER_OUT=0;
            break;
            case ROOF_RAISE:
                RAISE_OUT=0;
                LOWER_OUT=1;
            break;
          }
      }
  }

  if (roof_timer)
  {
      if ((!Speed_Limiter) || (roof_action==WINDOWS_LOWER) || (roof_action==WINDOWS_RAISE))
      {
          roof_timer--;

          if (!roof_timer)
          {
              TOPREL_OUT=0;
              RAISE_OUT=1;
              LOWER_OUT=1;

              if ((RemoteAction==ROOF_LOWER) && (!ABS_active))
              {
                #if(RELOCK==1)
                  lock_timeout=LOCK_TIMEOUT;
                #endif
                  POWER_timeout= WAIT_TIL_POWERDOWN;
                  Emergency=0;
              }
              else
              if ((RemoteAction==ROOF_RAISE) && (!ABS_active))
              {
                #if(RELOCK==1)
                  lock_timeout=1;
                #endif
                  POWER_timeout= WAIT_TIL_POWERDOWN;
                  Emergency=0;
              }

              RemoteAction=ROOF_IDLE;
              roof_action=ROOF_IDLE;
              Save=1;
          }
      }
  }

/*------------------------------------ creating signal chirp and alarm sound */
  if (chirp_timer)
  {
      ChirpActive=1;

      if (--chirp_timer==0)
      {
          CHIRP_OUT=0;
          chirp_pause=CHIRP_PAUSE;
          AlarmActive=0;
      }
      else CHIRP_OUT=1;
  }
  else
  if (chirp_pause)
  {
      ChirpActive=1;

      if (--chirp_pause) CHIRP_OUT=0;
  }
  else
  if (chirp_count)
  {
      chirp_count--;
      chirp_timer=CHIRP_TIME;
      CHIRP_OUT=1;
  }
  else
  {
      ChirpActive=0;
      CHIRP_OUT=0;
  }

/*------------------- creating signal for unlocking the car and alarm system */
  if (lock_timer)
  {
      lock_timer--;
      LOCK_OUT=0;
  }
  else LOCK_OUT=1;

/*------------------- creating signal for unlocking the car and alarm system */
  if (unlock_timer)
  {
      if (--unlock_timer==0)
      {
          UNLOCK_OUT=1;
          if (IRmode)
               unlock_pause=UNLOCK_PAUSE_IR;
          else unlock_pause=UNLOCK_PAUSE_RF;
      }
      else UNLOCK_OUT=0;
  }
  else
  if (unlock_pause)
  {
      if (--unlock_pause) UNLOCK_OUT=1;
  }
  else
  if (unlock_pulses)
  {
      unlock_pulses--;
      if (IRmode)
           unlock_timer=UNLOCK_TIME_IR;
      else unlock_timer=UNLOCK_TIME_RF;
      UNLOCK_OUT=0;
  }
  else UNLOCK_OUT=1;


/*------------------------------- creating double click function for windows */
  if (click_timer)
  {
      ClickActive=1;

      if (--click_timer==0)
      {
          LOWER_OUT=1;
          RAISE_OUT=1;
          click_pause=CLICK_PAUSE_TIME;

          if (click_dir==CLICK_IDLE)
          {
            #if(RELOCK==1)
              lock_timeout=2;
            #endif
          }
      }
  }
  else
  if (click_pause)
  {
      if (--click_pause==0)
      {
          if ((click_dir==CLICK_IDLE) && (roof_action==ROOF_IDLE) && (RemoteAction==ROOF_IDLE))
          {
            TOPREL_OUT=0;
            ClickActive=0;
          }
      }
  }
  else
  if (click_dir)
  {
      switch(click_dir & 0x7F)
      {
      case WINDOW_DOWN:

            LOWER_OUT=0;

            if (click_dir & SECOND_CLICK)
            {
                click_dir=CLICK_IDLE;
                click_timer=CLICK_DOWN_TIME;
            }
            else
            {
                click_dir |= SECOND_CLICK;
                click_timer=CLICK_TIME;
            }
      break;
      case WINDOW_UP:

            RAISE_OUT=0;

            if (click_dir & SECOND_CLICK)
            {
                click_dir=CLICK_IDLE;
                click_timer=CLICK_UP_TIME;
            }
            else
            {
                click_dir |= SECOND_CLICK;
                click_timer=CLICK_TIME;
            }
      break;
      }
  }
  else ClickActive=0;

  return;
}


void far timerC_int(void)
{
    if (periodH<0xFFFF0000) periodH+=0x00010000;

    return;
}

void far int0_int(void)     // Lock-Signal
{
    asm( "\tFSET    I");    // Enable interrupt

    POWER_timeout= WAIT_TIL_POWERDOWN;
    Emergency=0;
    return;
}

void far int1_int(void)     // ABS-Signal
{
    asm( "\tFSET    I");    // Enable interrupt

    if(ABS_active) lock_timeout=0;  // erst beim zweiten Mal

    ABS_active=1;
    ABS_timeout=WAIT_ABS;

    if (ABS_period<200)
         ABS_working=1;
    else ABS_working=0;

    ABS_period=0;

    POWER_timeout= WAIT_TIL_POWERDOWN;
    Emergency=0;

    return;
}

void far int2_int(void)     // Unlock-Signal
{
    asm( "\tFSET    I");    // Enable interrupt

    POWER_timeout= WAIT_TIL_POWERDOWN;
    Emergency=0;
    return;
}

void far int3_int(void)     // Tacho-Signal
{
    asm( "\tFSET    I");    // Enable interrupt

    // lock_timeout=0;

    periods[pcount]=periodH+tm0;
    pcount=(pcount+1 & 0x07);
    periodH=0;
    tcc00=0;
    tcc00=1;

    return;
}

void far key_int(void)      // Raise/Lower-Signal
{
    asm( "\tFSET    I");    // Enable interrupt

    POWER_timeout= WAIT_TIL_POWERDOWN;
    Emergency=0;
    return;
}


void DefaultSysVar(void)
{
  unsigned int i;

    for(i=0;i<sizeof(SysVar);i++) ((unsigned char far*)&SysVar)[i] = 0x00;

    memcpy((char far*)&SysVar.APF,(char far*)&Application,sizeof(APP));

    SysVar.SpeedLimit=600;
    SysVar.WindowsUp=1;
    SysVar.ChirpOnOff=1;
    roof_action=ROOF_IDLE;
    RemoteAction=ROOF_IDLE;
}

unsigned char Write_SysVar(unsigned char rec)
{
    unsigned char wr = 1;

    switch(rec)
    {
        case 1:
                EE_data.pData = (unsigned int *)&SysVar.APF;
                EE_data.data_size = (sizeof(APP)/2)-1;      /* size in words (-1) */
        break;
        case 2:
                EE_data.pData = (unsigned int *)&SysVar.SpeedLimit;
                EE_data.data_size = 0;
        break;
        case 3:
                EE_data.pData = (unsigned int *)&SysVar.WindowsUp;
                EE_data.data_size = 0;
        break;
        case 4:
                EE_data.pData = (unsigned int *)&roof_action;
                EE_data.data_size = 0;
        break;
        case 5:
                EE_data.pData = (unsigned int *)&RemoteAction;
                EE_data.data_size = 0;
        break;
        case 6:
                EE_data.pData = (unsigned int *)&SysVar.ChirpOnOff;
                EE_data.data_size = 0;
        break;
        default:
                wr = 0;
        break;
    }

    if(wr)
    {
        EE_data.record_label = rec;
        return NV_Write(&EE_data);
    }
    else    return 2;       //Parameter not Valid
}

unsigned char LoadSysVar(void)
{
  int i;
  unsigned int *intptr;

    DefaultSysVar();

    EE_data.record_label = 1;       //read first record
    if (NV_Read(&EE_data) == 0)
    {
        intptr=(unsigned int*)&SysVar.APF;
        for(i=0;i<=EE_data.data_size;i++) *intptr++ = EE_data.pData[i]; //Read APF

    }
    else if (Write_SysVar(1) != 0) goto SyS_WriteErr;

    EE_data.record_label = 2;
    if (NV_Read(&EE_data) == 0)
    {
        SysVar.SpeedLimit=EE_data.pData[0];
    }
    else if (Write_SysVar(2) != 0) goto SyS_WriteErr;

    EE_data.record_label = 3;
    if (NV_Read(&EE_data) == 0)
    {
        SysVar.WindowsUp=EE_data.pData[0];
    }
    else if (Write_SysVar(3) != 0) goto SyS_WriteErr;

    EE_data.record_label = 4;
    if (NV_Read(&EE_data) == 0)
    {
        roof_action=EE_data.pData[0];
    }
    else if (Write_SysVar(4) != 0) goto SyS_WriteErr;

    EE_data.record_label = 5;
    if (NV_Read(&EE_data) == 0)
    {
        RemoteAction=EE_data.pData[0];
    }
    else if (Write_SysVar(5) != 0) goto SyS_WriteErr;

    EE_data.record_label = 6;
    if (NV_Read(&EE_data) == 0)
    {
        SysVar.ChirpOnOff=EE_data.pData[0];
    }
    else if (Write_SysVar(6) != 0) goto SyS_WriteErr;

    return 0;

  SyS_WriteErr:
    return 1;

}


void checkControlButton(void)
{
    if (ChirpActive) return;
    if (ClickActive) return;

    if (!LAMP_IN)
    {
        POWER_timeout= WAIT_TIL_POWERDOWN;  // if roof hangs, no power down
        Emergency=0;

        if (LastLampState)          /* Lamp in hardtop button goes ON (edge detected)*/
        {
            if (!(RAISE_IN || Speed_Limiter))
            {
                TOPREL_OUT=1;
                roof_timer=ROOF_TIME;
                roof_action=ROOF_RAISE;
                Save=1;
            }
            else
            if (!(LOWER_IN || Speed_Limiter))
            {
                TOPREL_OUT=1;
                roof_timer=ROOF_TIME;
                roof_action=ROOF_LOWER;
                Save=1;
            }
        }

        LastLampState=0;

        if ((!RAISE_IN) && (!LOWER_IN))
        {
            RAISE_OUT=1;
            LOWER_OUT=1;
            LastRaiseState=0;
            LastLowerState=0;
            roof_action=ROOF_IDLE;
        }
        else
        {
            if (!RAISE_IN)
            {
                LOWER_OUT=1;

                if (LastRaiseState)
                {
                    if (!Speed_Limiter)
                    {
                        TOPREL_OUT=1;
                        RAISE_OUT=0;
                        roof_action=ROOF_RAISE;
                        if (!roof_timer) roof_timer=ROOF_TIME;
                        Save=1;
                    }

                    LastRaiseState=0;
                }
            }
            else LastRaiseState=1;

            if (!LOWER_IN)
            {
                RAISE_OUT=1;

                if (LastLowerState)
                {
                    if (!Speed_Limiter)
                    {
                        TOPREL_OUT=1;
                        LOWER_OUT=0;
                        roof_action=ROOF_LOWER;
                        if (!roof_timer) roof_timer=ROOF_TIME;
                        Save=1;
                    }

                    LastLowerState=0;
                }
            }
            else LastLowerState=1;

        }
    }
    else
    {
        if (!LastLampState)                 /* Lamp in hardtop button goes off (edge detected)*/
        {

            // check Timer & Speed_limiter
            if (roof_action != ROOF_IDLE)
            {
                if  ((!ClickActive) && (!RemoteTimer) && (!Speed_Limiter) && ((ROOF_TIME-roof_timer)<MAX_LAMP_BLINK_TIME))
                {
                    roof_timer=0;
                    RemoteAction=ROOF_IDLE;
                    roof_action=ROOF_IDLE;
                    RAISE_OUT=1;
                    LOWER_OUT=1;
                    TOPREL_OUT=0;
                    Save=1;
                }
            }

            if ((!ClickActive) && (!RemoteTimer) && (!Speed_Limiter))
            {
                if ((SysVar.WindowsUp & 0x01) && (roof_action==ROOF_RAISE))
                {
                    RAISE_OUT=0;
                    LOWER_OUT=1;
                    roof_timer=WINDOW_UP_TIME;
                }
                else
                if ((SysVar.WindowsUp & 0x02) && (roof_action==ROOF_LOWER))
                {
                    RAISE_OUT=1;
                    LOWER_OUT=0;
                    roof_timer=WINDOW_UP_TIME;
                }
                else
                {
                    TOPREL_OUT=0;
                    RAISE_OUT=1;
                    LOWER_OUT=1;

                    if ((RemoteAction==ROOF_LOWER) && (!ABS_active))
                    {
                      #if(RELOCK==1)
                        lock_timeout=LOCK_TIMEOUT;
                      #endif
                        POWER_timeout= WAIT_TIL_POWERDOWN;
                        Emergency=0;
                    }
                    else
                    if ((RemoteAction==ROOF_RAISE) && (!ABS_active))
                    {
                      #if(RELOCK==1)
                        lock_timeout=1;
                      #endif
                        POWER_timeout= WAIT_TIL_POWERDOWN;
                        Emergency=0;
                    }

                    RemoteAction=ROOF_IDLE;
                    roof_action=ROOF_IDLE;
                    roof_timer=0;
                    Save=1;
                }
            }

            LastLampState=1;
        }

        LastRaiseState=1;
        LastLowerState=1;

        switch(roof_action)
        {
        case ROOF_IDLE:
            /* section for programming via hardtop button */

            if ((!RAISE_IN) && (!ClickActive))  // Raise active - no click in progress
            {
                if (!Raise_Edge)
                {
                    POWER_timeout= WAIT_TIL_POWERDOWN;
                    Emergency=0;

                    Raise_Edge=1;
                    Raise_clicks++;
                    Lower_clicks=0;

                    switch(Raise_clicks)
                    {
                    case 1:
                        Click_timeout=7;
                        DoubleDetect_raise=0;
                    break;
                    case 2:
                        if (Click_timeout)
                        {
                            Click_timeout=7;
                            DoubleDetect_raise=1;
                        }
                        else Raise_clicks=0;
                    break;
                    case 3:
                        if (Click_timeout)      /* toggle window function */
                        {
                            SysVar.WindowsUp = (SysVar.WindowsUp+1) & 0x03;

                            if (!Write_SysVar(3)) chirp_count=(SysVar.WindowsUp & 0x03)+1;  /* save new settings */
                            else chirp_count=10; //Fehler

                            /* 1 chirp/blink == windows stay down on raising and lowering */
                            /* 2 chirp/blink == windows stay up on raising and down on lowering */
                            /* 3 chirp/blink == windows stay down on raising and up on lowering */
                            /* 4 chirp/blink == windows stay up on raising and lowering */
                        }

                        DoubleDetect_raise=0;
                        Raise_clicks=0;
                    break;
                    }
                }
                else
                {
                    if (DoubleDetect_raise)
                    {
                        DoubleDetect_raise++;
                        if (DoubleDetect_raise==DOUBLE_CLICK_THRESHOLD)
                        {
                            DoubleDetect_raise++;
                            RemoteAction=ROOF_IDLE;
                            roof_action=WINDOWS_RAISE;
                            RAISE_OUT=0;
                            LOWER_OUT=1;
                            roof_timer=WINDOW_UP_TIME;
                        }
                    }
                }
            }
            else Raise_Edge=0;

            if ((!LOWER_IN) && (!ClickActive))  // Lower active - no click in progress
            {
                if (!Lower_Edge)
                {
                    POWER_timeout= WAIT_TIL_POWERDOWN;
                    Emergency=0;

                    Lower_Edge=1;
                    Lower_clicks++;
                    Raise_clicks=0;

                    switch(Lower_clicks)
                    {
                    case 1:
                        Click_timeout=7;
                        DoubleDetect_lower=0;
                    break;
                    case 2:
                        if (Click_timeout)
                        {
                            Click_timeout=7;
                            DoubleDetect_lower=1;
                        }
                        else Lower_clicks=0;
                    break;
                    case 3:
                        if (Click_timeout)      /* set new speed limit */
                        {
                            if (ABS_active)
                            {
                                if (KMH>80)
                                {
                                    if (KMH<=800)
                                         SysVar.SpeedLimit=KMH;
                                    else SysVar.SpeedLimit=800;
                                }
                                else SysVar.SpeedLimit=80;

                                if (!Write_SysVar(2)) chirp_count=1;    /* save new settings */
                                else chirp_count=10; //Fehler
                            }
                            else
                            {
                                if (SysVar.ChirpOnOff)
                                {
                                    SysVar.ChirpOnOff=0;
                                    if (!Write_SysVar(6)) chirp_count=2;    /* save new settings */
                                    else chirp_count=10; //Fehler
                                }
                                else
                                {
                                    SysVar.ChirpOnOff=1;
                                    if (!Write_SysVar(6)) chirp_count=5;    /* save new settings */
                                    else chirp_count=10; //Fehler
                                }
                            }
                        }

                        Lower_clicks=0;
                        DoubleDetect_lower=0;
                    break;
                    }
                }
                else
                {
                    if (DoubleDetect_lower)
                    {
                        DoubleDetect_lower++;
                        if (DoubleDetect_lower==DOUBLE_CLICK_THRESHOLD)
                        {
                            DoubleDetect_lower++;
                            RemoteAction=ROOF_IDLE;
                            roof_action=WINDOWS_LOWER;
                            RAISE_OUT=1;
                            LOWER_OUT=0;
                            roof_timer=WINDOW_UP_TIME;
                        }
                    }
                }
            }
            else Lower_Edge=0;

        break;
        case ROOF_RAISE:
        case WINDOWS_RAISE:
            if (!LOWER_IN)  // Lower aktiv
            {
                if (Lower_Edge)     // spikes ausfiltern
                {
                    roof_timer=0;
                    RAISE_OUT=1;
                    LOWER_OUT=1;

                    if (roof_action==ROOF_RAISE)
                    {
                         POWER_timeout= EMERGENCY_WAIT;
                         Emergency=1;
                    }
                    else
                    {
                        POWER_timeout= WAIT_TIL_POWERDOWN;
                        Emergency=0;
                    }

                    RemoteAction=ROOF_IDLE;
                    roof_action=ROOF_IDLE;
                    Save=1;
                }

                Lower_Edge=1;
            }
            else Lower_Edge=0;
        break;
        case ROOF_LOWER:
        case WINDOWS_LOWER:
            if (!RAISE_IN)  // Raise aktiv
            {
                if (!Raise_Edge)    // spikes ausfiltern
                {
                    roof_timer=0;
                    RAISE_OUT=1;
                    LOWER_OUT=1;

                    if (roof_action==ROOF_LOWER)
                    {
                         POWER_timeout= EMERGENCY_WAIT;
                         Emergency=1;
                    }
                    else
                    {
                        POWER_timeout= WAIT_TIL_POWERDOWN;
                        Emergency=0;
                    }

                    RemoteAction=ROOF_IDLE;
                    roof_action=ROOF_IDLE;
                    Save=1;
                }

                Raise_Edge=1;
            }
            else Raise_Edge=0;
        break;
        }
    }
}

void calcSpeed(void)
{
int i;

    period=0;
    for(i=0;i<8;i++)
     period+=periods[i];

    period=period/8;

    if ((period>1) && (periodH<0x01000000))
        KMH=30303030/period;
    else
    {
        KMH=0;
        for(i=0;i<8;i++) periods[i]=0;
    }
}

void checkLocking(void)
{
   /*---------------------------------------
    -  lock/unlock inputs from remote key  -
    ---------------------------------------*/

 if (!lock_timer)       /* not for own lock-signal */
 {
    if (!LOCK_IN)
    {
        if (!LockState)
        {
            LockState=1;
            LockPulseLength=0;
        }
        else // LockState=1
        {
            if (LockPulseLength<MAX_PULSE_LENGTH)
            {
                LockPulseLength++;
            }
        }
    }
    else
    {
        if (LockState)
        {
            // trailing edge
            LockPauseLength=0;
        }
        else
        {
            if (LockPauseLength<MAX_PULSE_LENGTH)
            {
                LockPauseLength++;
            }

            if (LockPauseLength==MAX_PULSE_LENGTH)
            {
                LockPauseLength++;

                if (LockPulseLength==MAX_PULSE_LENGTH) goto IS_LONG_LOCK_PULSE;
            }
        }

        LockState=0;
    }
 }

 if ((!unlock_timer) && (!unlock_pulses))       /* not for own lock-signal */
 {


    if (!UNLOCK_IN)
    {
        if (!UnlockState)
        {
            UnlockState=1;
            UnlockPulseLength=0;
        }
        else // UnlockState=1
        {
            if (UnlockPulseLength<MAX_PULSE_LENGTH)
            {
                UnlockPulseLength++;
            }
        }
    }
    else
    {

        if (UnlockState)
        {
            // trailing edge
            UnlockPauseLength=0;

            if (UnlockPulseLength<(MAX_PULSE_LENGTH/2))
            {
                // is short unlock pulse
                UnlockPulseCount++;
                UnlockTiming=30;
            }
        }
        else
        {
            if (UnlockPauseLength<MAX_PULSE_LENGTH)
            {
                UnlockPauseLength++;
            }

            if (UnlockPauseLength==MAX_PULSE_LENGTH)
            {
                UnlockPauseLength++;

                if (UnlockPulseCount==4)
                {
                    // is RF unlock pulse
                    IRmode=0;
                }
                else
                if (UnlockPulseCount==6)
                {
                    // is IR unlock pulse
                    IRmode=1;
                }

                if (UnlockPulseCount>3) /* four to six pulses received ---> Unlock*/
                {
                    CarLocked=0;

                    chirp_timer=0;
                    AlarmActive=0;
                    chirp_pause=CHIRP_PAUSE;

                    if ((!ABS_active) && (SysVar.ChirpOnOff)) chirp_count=1;

                    UnlockPacketTiming=300;

                    UnlockPackets++;                /* increment packet count */

                    if ( (IRmode && ((UnlockPackets+LockCount)==ROOF_RAISE_CLICKS)) && (!Speed_Limiter) && (!AlarmActive))
                    {
                        /* Remote hardtop raise start */
                        TOPREL_OUT=1;

                        POWER_timeout= WAIT_TIL_POWERDOWN;
                        Emergency=0;

                        RemoteAction=ROOF_RAISE;
                        RemoteTimer=REMOTE_WAIT;
                        Save=1;
                    }
                    else
                    if ( ( (!IRmode && (UnlockPackets==ROOF_LOWER_CLICKS)) ||
                           (IRmode && ((UnlockPackets+LockCount)==ROOF_LOWER_CLICKS)) ) && (!Speed_Limiter) && (!AlarmActive))
                    {
                        /* Remote hardtop lower start */
                        TOPREL_OUT=1;

                        RemoteAction=ROOF_LOWER;
                        RemoteTimer=REMOTE_WAIT;
                        Save=1;
                    }
                    else
                    if ( (!IRmode && (UnlockPackets==WINDOW_LOWER_CLICKS)) && (!ClickActive) && (!AlarmActive))
                    {
                        /* Remote window lower start */
                        TOPREL_OUT=1;
                        click_dir=WINDOW_DOWN;
                        ClickActive=1;
                        click_pause=CLICK_WAIT;

                        RemoteAction=ROOF_IDLE;
                        RemoteTimer=0;
                        UnlockPacketTiming=0;
                        UnlockPackets=0;
                    }
                    else
                    if ((RemoteAction==ROOF_RAISE) || (RemoteAction==ROOF_LOWER))   /* Emergency Stop */
                    {
                        if (RemoteTimer)
                        {
                            POWER_timeout= 1;
                            Emergency=0;
                        }
                        else
                        {
                            POWER_timeout= EMERGENCY_WAIT;
                            Emergency=1;
                        }

                        roof_timer=0;
                        RemoteAction=ROOF_IDLE;
                        roof_action=ROOF_IDLE;
                        RAISE_OUT=1;
                        LOWER_OUT=1;
                        Save=1;
                    }
                }
                else
                if (UnlockPulseLength==MAX_PULSE_LENGTH)
                {
                    // is long lock pulse
IS_LONG_LOCK_PULSE:
                    LockTiming=250;
                    LockCount++;
                    chirp_timer=0;
                    AlarmActive=0;
                    chirp_pause=CHIRP_PAUSE;

                    CarLocked=1;
                    RemoteTimer=ALARM_WAIT;

                    if ((!ABS_active) && (SysVar.ChirpOnOff)) chirp_count=2;

                    if ( ( (!IRmode && (LockCount==ROOF_RAISE_CLICKS)) ||
                           (IRmode && ((UnlockPackets+LockCount)==ROOF_RAISE_CLICKS)) ) && (!Speed_Limiter) && (!AlarmActive))
                    {
                        /* Remote hardtop raise start */
                        TOPREL_OUT=1;

                        if (!IRmode)
                        {
                            unlock_pulses=4;                        /* unlock car alarm */
                            unlock_pause=1000;
                        }

                        POWER_timeout= WAIT_TIL_POWERDOWN;
                        Emergency=0;

                        RemoteAction=ROOF_RAISE;
                        RemoteTimer=REMOTE_WAIT;
                        Save=1;
                    }
                    else
                    if ( (IRmode && ((UnlockPackets+LockCount)==ROOF_LOWER_CLICKS)) && (!Speed_Limiter) && (!AlarmActive))
                    {
                        /* Remote hardtop lower start */
                        TOPREL_OUT=1;

                        RemoteAction=ROOF_LOWER;
                        RemoteTimer=REMOTE_WAIT;
                        Save=1;
                    }
                    else
                    if ((!IRmode && (LockCount==WINDOW_RAISE_CLICKS)) && (!ClickActive) && (!AlarmActive))
                    {
                        /* Remote window lower start */
                        TOPREL_OUT=1;
                        click_dir=WINDOW_UP;
                        ClickActive=1;
                        click_pause=CLICK_WAIT;

                        RemoteAction=ROOF_IDLE;
                        RemoteTimer=0;
                        LockCount=0;
                    }
                    else
                    if ((RemoteAction==ROOF_RAISE) || (RemoteAction==ROOF_LOWER))   /* Emergency Stop */
                    {
                        if (RemoteTimer)
                        {
                            POWER_timeout= 1;
                            Emergency=0;
                        }
                        else
                        {
                            POWER_timeout= EMERGENCY_WAIT;
                            Emergency=1;
                        }

                        roof_timer=0;
                        RemoteAction=ROOF_IDLE;
                        roof_action=ROOF_IDLE;
                        RAISE_OUT=1;
                        LOWER_OUT=1;
                        Save=1;
                    }
                }
            }
        }

        UnlockState=0;
    }
 }
}

void checkDoors(void)
{
    if ((roof_action==ROOF_IDLE) && (RemoteAction==ROOF_IDLE) && (!ClickActive) && (!RemoteTimer))
    {
        if (!DOOR_IN)
        {
            if (Door_open_edge<DOOR_EDGE_TIME_OPEN)
            {
                Door_open_edge++;
            }

            if (Door_open_edge==DOOR_EDGE_TIME_OPEN)
            {
                Door_open_edge++;
                Door_close_edge=0;

                if (CarLocked  && (!AlarmActive))
                {
                    chirp_timer=ALARM_SOUND;
                    AlarmActive=1;
                }
            }
        }
        else
        {

            if (Door_close_edge<DOOR_EDGE_TIME_CLOSE)
            {
                Door_close_edge++;
            }

            if (Door_close_edge==DOOR_EDGE_TIME_CLOSE)
            {
                Door_close_edge++;
                Door_open_edge=0;
            }
        }
    }
}

void StopMode(void)
{
   /*------------------------------------------
    -  Goto Stop mode and wait for interrupt  -
    ------------------------------------------*/
#if (REMOTE_DEBUGGER==1)
    Digit[0] = 0x1F;
    Digit[1] = 0x1F;
    Digit[2] = 0x1F;
    Digit[3] = 0x1F;
    remote_display();       /* remote programmer display off */
#endif

    TOPREL_OUT = 0;
    RELABS_OUT = 0;
    RAISE_OUT  = 1;
    LOWER_OUT  = 1;
    CHIRP_OUT  = 0;
    ABS_OUT    = 1;
    LOCK_OUT   = 1;

    prc0 = 1;               /* Protect off */
    cm10 = 1;               /* All clocks off */
    asm("jmp ?+");          /* Clear queue */
    asm("?:");
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");             /* Program stopped */

   /*------------------------------------------
    -  wait for interrupt  -
    ------------------------------------------*/

    prc0 = 1;               /* Protect off */
    cm15 = 1;               /* XCIN-XCOUT drive capacity select bit : HIGH */
    cm16 = 0;               /* Main clock = No division mode */
    cm17 = 0;
    cm06 = 0;               /* CM16 and CM17 enable */
    prc0 = 0;

}

void main(void)
{

   /*-------------------------------------------------
    -  Change on-chip oscillator clock to Main clock  -
    -------------------------------------------------*/

    prc0 = 1;               /* Protect off */
    cm13 = 1;               /* Xin Xout */
    cm15 = 1;               /* XCIN-XCOUT drive capacity select bit : HIGH */
    cm05 = 0;               /* Xin on */
    cm16 = 0;               /* Main clock = No division mode */
    cm17 = 0;
    cm06 = 0;               /* CM16 and CM17 enable */

    asm("nop");             /* Waiting for stable oscillation */
    asm("nop");
    asm("nop");
    asm("nop");

    ocd2 = 0;               /* Main clock change */
    prc0 = 0;               /* Protect on */

    prc1 = 1;               /* Protect off */
    pm10 = 1;               /* enable data flash area */
    prc1 = 0;               /* Protect on */

    prc2    = 1;            /* Protect off */

    pd0     = 0xC6;         /* port 0 direction */

    TOPREL_OUT      = 0;
    RELABS_OUT      = 0;
    LAMP_IN         = 1;
    ALARM_CFG       = 1;
    DOOR_CFG        = 1;
    UNLOCK_OUT      = 1;
    LOCK_OUT        = 1;

    pu00            = 1;    /* Pull-Up port 0 bits 0..3*/
    pu01            = 1;    /* Pull-Up port 0 bits 4..7*/

    RAISE_OUTdir    = 1;
    RAISE_OUT       = 1;

    DOOR_INdir      = 0;
    DOOR_IN         = 1;

    RAISE_INdir     = 0;
    RAISE_IN        = 1;

    LOWER_INdir     = 0;
    LOWER_IN        = 1;

    SDAdir          = 1;
    SDA             = 1;

    SCLdir          = 1;
    SCL             = 1;

    LOWER_OUTdir    = 1;
    LOWER_OUT       = 1;

    ABS_INdir       = 0;
    ABS_IN          = 1;

    pu02            = 1;    /* Pull-Up port 1 bits 0..3*/
    pu03            = 1;    /* Pull-Up port 1 bits 4..7*/

    drr             = 0x0F;

    CHIRP_OUTdir    = 1;
    CHIRP_OUT       = 0;

    ABS_OUTdir      = 1;
    ABS_OUT         = 1;

    UNLOCK_INdir    = 0;
    UNLOCK_IN       = 1;

    SPEED_INdir     = 0;
    SPEED_IN        = 1;

    pu06            = 1;

    LOCK_INdir      = 0;
    LOCK_IN         = 1;

    pu11            = 1;

    txmr            = 0x00;
    txck0           = 1;
    txck1           = 0;    /* 2.5MHz */

    prex            = 249;  /* Teilerfaktor 1 249+1=250 ==> 2.5MHz --> 100KHz */
    tx              = 9;    /* Teilerfaktor 2 9+1=10    ==> 100KHz --> 1kHz --> 1ms Timer-Interrupt */

    txic            = 3;

    txs             = 1;

    tcc0            = 0x08;
    tcc1            = 0x00;
    tcic            = 0x05;
    int3ic          = 0x05;
    tcc00           = 1;

    int0ic          = 0x02; /* Lock input -- return from stop mode */
    int0pl          = 0;
    int0en          = 1;

    int1ic          = 0x01;

    ProgFlags       = 0x00;
    ProgState       = 0x00;
    KeyFlags        = 0xF0;
    OptionFlags     = 0x00;

#if (REMOTE_DEBUGGER==1)
    Keys            = 0x00;
#endif
    int2ic          = 0x02; /* Unlock input -- return from stop mode */
    r1edg           = 1;

    ki1en           = 1;    /* Enable key interrupt for DOOR_IN -- return from stop mode */
    ki1pl           = 0;    /* Falling edge */

    ki2en           = 1;    /* Enable key interrupt for RAISE_IN -- return from stop mode */
    ki2pl           = 0;    /* Falling edge */

    ki3en           = 1;    /* Enable key interrupt for LOWER_IN -- return from stop mode */
    ki3pl           = 0;    /* Falling edge */

    kupic           = 0x02;

    asm( "\tFSET    I");    /* Enable all active interrupts */

    LoadSysVar();           /* Load sytem variables from flash*/

    wdc7    = 1;
    pm12    = 1;            /* Watchdog Reset */
    wdtr    = 0;
    wdts    = 1;

    if (roof_action==ROOF_RAISE)
    {
        TOPREL_OUT=1;
        RemoteAction=ROOF_RAISE;
        RemoteTimer=REMOTE_WAIT;
    }

    if (roof_action==ROOF_LOWER)
    {
        TOPREL_OUT=1;
        RemoteAction=ROOF_LOWER;
        RemoteTimer=REMOTE_WAIT;
    }

    POWER_timeout= WAIT_TIL_POWERDOWN;
    Emergency=0;

    while(1)                /* repeat endlessly */
    {

        wdtr    = 0;

        if (Scan)
        {
#if (REMOTE_DEBUGGER==1)
            get_keys();             /* only remote I2C-bus */
#endif
            checkControlButton();   /* hardtop control button routine */

            checkLocking();         /* remote key lock/unlock */

            Scan=0;                 /* reset Scan flag */

            checkDoors();
        }

        if (Refresh)
        {
            calcSpeed();            /* calculate current speed from measured periods */

#if (REMOTE_DEBUGGER==1)
            displayData();          /* remote programmer display content */

            remote_display();       /* remote programmer display redraw */
#endif

            Refresh=0;              /* reset Refresh flag*/
        }

#if (REMOTE_DEBUGGER==1)
        if (Keys)                   /* only remote I2C-bus */
        {
            remoteProgrammer();     /* remote programmer key action */
        }
#endif
        if (Save)                   /* Save current action for restart */
        {
            Write_SysVar(4);
            Write_SysVar(5);
            Save=0;
        }

        if (Stop)                   /* power saving mode */
        {
            StopMode();
            Stop=0;
        }

    }
}