/*@!Encoding:1252*/
includes
{
  #include "CommonConst.CIN"
}

variables
{
  byte sAutoStart = 0; // > 0 if auto start of the server is enabled
  char sLwATableFile[100] = "ClientLwATable.txt";
  int  sFreezedHearbeatCounter = -1;

  int sNumOfReqForTestlabCertToIgnore;
  int sNumOfReqForManufactCertToIgnore;
  int sNumOfReqForManufactSeriesCertToIgnore;
  int sNumOfReqForDeviceCertToIgnore;
}

on start
{
  sysSetVariableInt(sysvar::TIMClient::svStart, 0);
  @sysvar::TIMClient::svTIMClientFreezeState = 0;

  Iso11783IL_SetVerbosity(cVerbosityErrorsAndWarnings);
  Iso11783IL_TIMSetProperty("enableDemoMode", @svDemoModeActive);
}

on sysvar sysvar::ISO11783::TIMClient::ILState
{
  if (sAutoStart && @this == 2) //Online
  {
    Iso11783IL_TIMConnectToServer(TIMServer);
  }
}

on sysvar sysvar::TIMClient::svStart
{
  if(@this > 0)
  {
    StartClient();
  }
  else
  {
    StopClient();
  }
}

on sysvar sysvar::TIMClient::svReconnectClientToServer
{
  if(@this > 0)
  {
    ReconnectClientToServer();
  }
}

on sysvar sysvar::TIMClient::svRestartAuthentication
{
  if(@this > 0)
  {
    Iso11783IL_TIMRestartAuthentication(TIMServer);
  }
}

on sysvar sysvar::TIMClient::svOperatorEnable
{
  if(@this > 0)
  {
    Iso11783IL_TIMOperatorEnable(TIMServer);
  }
}

on sysvar sysvar::TIMClient::svStoreLwAKeyTable
{
  if(@this > 0)
  {
    Iso11783IL_TIMSaveLwATable(sLwATableFile);
  }
}

on sysvar sysvar::TIMClient::svClearLwAKeyTable
{
  if(@this > 0)
  {
    Iso11783IL_TIMClearLwATable();
    Iso11783IL_TIMSaveLwATable(sLwATableFile);
  }
}

on sysvar sysvar::TIMClient::svContinue
{
  if(@this > 0)
  {
    Iso11783IL_TIMContinueConnection(TIMServer);
  } 
}

on sysvar sysvar::TIMClient::svContinueAndFreeze
{
  if(@this > 0)
  {
    Iso11783IL_TIMContinueConnection(TIMServer);
  } 
  
  // set new freeze state if state has been changed
  if (@sysvar::TIMClient::svTIMClientFreezeState > 0)
  {
    Iso11783IL_TIMFreezeConnection(TIMServer, @sysvar::TIMClient::svTIMClientFreezeState);
  }
}

on sysvar sysvar::TIMClient::svDisableNameCheck
{
  UpdateDeactivatedCertificateChecks();
}

on sysvar sysvar::TIMClient::svDisableICCCheck
{
  UpdateDeactivatedCertificateChecks();
}

on sysvar sysvar::TIMClient::svDisableFctCapibilitiesCheck
{
  UpdateDeactivatedCertificateChecks();
}

on sysvar sysvar::TIMClient::svDisableCRLCheck
{
  UpdateDeactivatedCertificateChecks();
}

on sysvar sysvar::TIMClient::svAuxValve1
{
  SetCurrentAuxValue1();
}

on sysvar sysvar::TIMClient::svRearPTO
{
  SetCurrentRearPTO();
}

on sysvar sysvar::TIMClient::svVehicleSpeed
{
  SetCurrentVehicleSpeed();
}

on sysvar sysvar::TIMClient::svAssignFctAuxValue1
{
  if (@this)
  {
    Iso11783IL_TIMAssignFunction(cAuxValve01, TIMServer);   
  }
}

on sysvar sysvar::TIMClient::svUnassignFctAuxValue1
{
  if (@this)
  {
    Iso11783IL_TIMUnassignFunction(cAuxValve01);       
  }
}

on sysvar sysvar::TIMClient::svReleaseFctAuxValue1
{
  if (@this)
  {
    Iso11783IL_TIMFunctionRequest(cAuxValve01, cReleasedControlRequestingOperator);   
  }
}

on sysvar sysvar::TIMClient::svAssignFctRearPTO
{
  if (@this)
  {
    Iso11783IL_TIMAssignFunction(cRearPTO, TIMServer);   
  }
}

on sysvar sysvar::TIMClient::svUnassignFctRearPTO
{
  if (@this)
  {
    Iso11783IL_TIMUnassignFunction(cRearPTO);       
  }
}

on sysvar sysvar::TIMClient::svReleaseFctRearPTO
{
  if (@this)
  {
    Iso11783IL_TIMFunctionRequest(cRearPTO, cReleasedControlRequestingOperator);   
  }
}

on sysvar sysvar::TIMClient::svAssignFctVehicleSpeed
{
  if (@this)
  {
    Iso11783IL_TIMAssignFunction(cVehicleSpeed, TIMServer);   
  }
}

on sysvar sysvar::TIMClient::svUnassignFctVehicleSpeed
{
  if (@this)
  {
    Iso11783IL_TIMUnassignFunction(cVehicleSpeed);       
  }
}


on sysvar sysvar::TIMClient::svReleaseFctVehicleSpeed
{
  if (@this)
  {
    Iso11783IL_TIMFunctionRequest(cVehicleSpeed, cReleasedControlRequestingOperator);   
  }
}

on sysvar sysvar::TIMClient::svAssignFctRearHitch
{
  if (@this)
  {
    Iso11783IL_TIMAssignFunction(cRearHitch, TIMServer);   
  }
}

void StartClient()
{
  sNumOfReqForTestlabCertToIgnore        = @TIMClient::svNumOfIgnRqstForTestlab;
  sNumOfReqForManufactCertToIgnore       = @TIMClient::svNumOfIgnRqstForManufact;  
  sNumOfReqForManufactSeriesCertToIgnore = @TIMClient::svNumOfIgnRqstForManufactSeries;  
  sNumOfReqForDeviceCertToIgnore         = @TIMClient::svNumOfIgnRqstForDevice;  

  DefaultPreparationSequence_Client();
  
  Iso11783IL_TIMConnectSysVarToState(TIMServer, "TIMClient::svTIMClientState");

  Iso11783IL_TIMLoadLwATable(sLwATableFile);
  
  
  if(@sysvar::TIMClient::svTIMClientFreezeState > 0)
  {
    Iso11783IL_TIMFreezeConnection(TIMServer, @sysvar::TIMClient::svTIMClientFreezeState);
  }
  
  Iso11783IL_TIMConnectToServer(TIMServer);
}

void ReconnectClientToServer()
{ 
  SetRequiredFunctionFacilities();
  
  Iso11783IL_TIMConnectToServer(TIMServer);
}

void StopClient()
{
  Iso11783IL_TIMDisconnectFromServer(TIMServer, 1);  
}

void DefaultPreparationSequence_Client()
{
  char buf[100], version[100];
  long value, implementedVersion;
  
  UpdateDeactivatedCertificateChecks();

  Iso11783IL_TIMSetProperty("useRequestCounter", @sysvar::TIMClient::svUseRequestCounter);

  value = sysGetVariableInt(sysvar::TIMClient::svMinimumVersion);
  Iso11783IL_TIMSetProperty("minimumVersion", value);
  implementedVersion = sysGetVariableInt(sysvar::TIMClient::svImplementedVersion);
  Iso11783IL_TIMSetProperty("implementedVersion", implementedVersion);
  if (implementedVersion <= 1)
  {
    if (@TIMClient::svRequiredFctVehicleSpeedChangeOfDirection == 1)
    {
      Write("TIM Client: Because implemented version is <= 1, the facility 'Vehicle change of direction' is disabled");
      @TIMClient::svRequiredFctVehicleSpeedChangeOfDirection = 0;
    }
  }
  //Set product identification
  sysGetVariableString(sysvar::TIMClient::svProductIdentification, buf, elcount(buf));
  Iso11783IL_TIMSetProductIdentification(buf);

  //Set compliance information
  Iso11783IL_TIMSetComplianceCertification(@TIMClient::svCCITestProtocolPublicationYear, @TIMClient::svCCITestProtocolRevision, @TIMClient::svCCILaboratoryType, @TIMClient::svCCILaboratoryID, @TIMClient::svCCIReferenceNumber);
  
  // Set sequence of requested certficates
  if (Iso11783IL_TIMSetCertificateSequence(@TIMClient::svCertificateType1, @TIMClient::svCertificateType2, @TIMClient::svCertificateType3, @TIMClient::svCertificateType4) != 0)
  {
    Write("TIM Client: Failed to set certificate sequence");
  }
  
  //Set required functions
  SetRequiredFunctionFacilities();
  
  // Define which functions have to be assigned to which server
  Iso11783IL_TIMUnAssignFunction(-1);
//   Iso11783IL_TIMAssignFunction(cAuxValve01, TIMServer);
//   Iso11783IL_TIMAssignFunction(cRearPTO, TIMServer);
//   Iso11783IL_TIMAssignFunction(cVehicleSpeed, TIMServer);
   
  // Set root certificates
  Iso11783IL_TIMAddCertificate(cCertificateType_AEFRoot, "Certificates//root_ca.der");
  
  // Set test lab certifiates 
  Iso11783IL_TIMAddCertificate(cCertificateType_Testlab, "Certificates//aef_testlab.der");
  
  // Set manufacturer certificate
  sysGetVariableString(sysvar::TIMClient::svManufacturerCertificate, buf, elcount(buf));
  Iso11783IL_TIMAddCertificate(cCertificateType_Manufacturer, buf);
  
  // Set manufacturer series certificate (if there is one)
  sysGetVariableString(sysvar::TIMClient::svManufacturerSeriesCertificate, buf, elcount(buf));
  if (strncmp(buf, "-", elcount(buf)) == 0)
  {
    Iso11783IL_TIMRemoveCertificate(cCertificateType_ManufacturerSeries);
  }
  else if (strlen(buf) > 0)
  {
    Iso11783IL_TIMAddCertificate(cCertificateType_ManufacturerSeries, buf);
  }
  
  // Set device certificate
  sysGetVariableString(sysvar::TIMClient::svDeviceCertificate, buf, elcount(buf));
  Iso11783IL_TIMAddCertificate(cCertificateType_Device, buf);
  
  // Set server private key
  sysGetVariableString(sysvar::TIMClient::svPrivateKey, buf, elcount(buf));
  Iso11783IL_TIMSetPrivateKey(buf);
  
  // Set CRL Signing
  Iso11783IL_TIMAddCertificate(cCertificateType_CRLSigning, "Certificates//crl_ca.der");
  
  // Set CRL
  Iso11783IL_TIMSetCRL(cCRLType_CRL, "Certificates//crl.der");
  Iso11783IL_TIMSetCRL(cCRLType_CRLSignCA, "Certificates//crl_sub_ca.der");

  // connect system variable to function states
  Iso11783IL_TIMConnectSysVarToFunctionState(cAuxValve01, "TIMClient::svAuxValue1State");
  Iso11783IL_TIMConnectSysVarToFunctionState(cRearPTO, "TIMClient::svRearPTOState");
  Iso11783IL_TIMConnectSysVarToFunctionState(cVehicleSpeed, "TIMClient::svVehicleSpeedState");
}

void SetRequiredFunctionFacilities()
{
  //Set required functions
  Iso11783IL_TIMResetAllRequiredFunctions();
  // Auxiliary Values
  Iso11783IL_TIMSetRequiredFacility("auxiliaryValve1State ", @TIMClient::svRequiredFctAuxiliaryValve1State);
  Iso11783IL_TIMSetRequiredFacility("auxiliaryValve1Flow ",  @TIMClient::svRequiredFctAuxiliaryValve1Flow);
  // Rear PTO
  Iso11783IL_TIMSetRequiredFacility("rearPTODisengagement",             @TIMClient::svRequiredFctRearPTODisengagement);
  Iso11783IL_TIMSetRequiredFacility("rearPTOEngagementCounterClockwise",@TIMClient::svRequiredFctRearPTOEngagementCounterClockwise);
  Iso11783IL_TIMSetRequiredFacility("rearPTOEngagementClockwise",       @TIMClient::svRequiredFctRearPTOEngagementClockwise);
  Iso11783IL_TIMSetRequiredFacility("rearPTOSpeedCounterClockwise",     @TIMClient::svRequiredFctRearPTOSpeedCounterClockwise);
  Iso11783IL_TIMSetRequiredFacility("rearPTOSpeedClockwise",            @TIMClient::svRequiredFctRearPTOSpeedClockwise);
  // Vehicle Speed
  Iso11783IL_TIMSetRequiredFacility("vehicleSpeedForward",            @TIMClient::svRequiredFctVehicleSpeedForward);
  Iso11783IL_TIMSetRequiredFacility("vehicleSpeedReverse",            @TIMClient::svRequiredFctVehicleSpeedReverse);
  Iso11783IL_TIMSetRequiredFacility("vehicleSpeedStartMotion",        @TIMClient::svRequiredFctVehicleSpeedStartMotion);
  Iso11783IL_TIMSetRequiredFacility("vehicleSpeedStopMotion",         @TIMClient::svRequiredFctVehicleSpeedStopMotion);
  Iso11783IL_TIMSetRequiredFacility("vehicleSpeedForwardDirection",   @TIMClient::svRequiredFctVehicleSpeedForwardDirection);
  Iso11783IL_TIMSetRequiredFacility("vehicleSpeedReverseDirection",   @TIMClient::svRequiredFctVehicleSpeedReverseDirection);
  if (@TIMClient::svRequiredFctVehicleSpeedChangeOfDirection)
  {
    Iso11783IL_TIMSetRequiredFacility("vehicleSpeedChangeOfDirection", 1); // call only succeeds if implemented version is > 1  
  }
}

void UpdateDeactivatedCertificateChecks()
{
  long deactivatedChecks;
  
  deactivatedChecks = 0;
  deactivatedChecks |= (@TIMClient::svDisableICCCheck > 0)             ?  0x01 : 0;   
  deactivatedChecks |= (@TIMClient::svDisableNameCheck > 0)            ?  0x02 : 0;   
  deactivatedChecks |= (@TIMClient::svDisableFctCapibilitiesCheck > 0) ?  0x04 : 0;   
  deactivatedChecks |= (@TIMClient::svDisableCRLCheck > 0)             ?  0x08 : 0;   
  
  if (Iso11783IL_TIMSetProperty("deactivateCertificateValidation", deactivatedChecks) != 0)
  {
    write("Failed to set deactivated certificate validations");
  }
}

void SetCurrentAuxValue1()
{
  word rawValue;
  rawValue = (@sysvar::TIMClient::svAuxValve1 + 128.512) * 250;
  if (rawValue >= 0)
  {
    if (Iso11783IL_TIMFunctionRequest(cAuxValve01, rawValue ) != 0)
    {
      write("Failed to set auxiliary value 1 to %f %", @sysvar::TIMClient::svAuxValve1);
    }
  }
}

void SetCurrentRearPTO()
{
  word rawValue;
  rawValue = (@sysvar::TIMClient::svRearPTO + 4016.0) * 8;
  if (rawValue >= 0)
  {
    if (Iso11783IL_TIMFunctionRequest(cRearPTO, rawValue ) != 0)
    {
      write("Failed to set rear PTO to %f 1/min", @sysvar::TIMClient::svRearPTO);
    }
  }
}

void SetCurrentVehicleSpeed()
{
  word rawValue;
  rawValue = (@sysvar::TIMClient::svVehicleSpeed + 32.128) * 1000;
  if (rawValue >= 0)
  {
    if (Iso11783IL_TIMFunctionRequest(cVehicleSpeed, rawValue ) != 0)
    {
      write("Failed to set speed to %f m/s", @sysvar::TIMClient::svVehicleSpeed);
    }
  }
}

void Iso11783IL_TIMOnFunctionStateChanged(dword functionID, dword newState) 
{
  switch (newState)
  {
    case 4: // // Automation Pending
      switch(functionID)
      {
        case cAuxValve01:
          SetCurrentAuxValue1();
          break;
        case cRearPTO:
          SetCurrentRearPTO();
          break;
        case cVehicleSpeed:
          SetCurrentVehicleSpeed();
          break;
        default:
          break;
      }
    default:
      break;
  }
}

long Iso11783IL_OnTxPrepare( pg * txPG )
{ 
  switch( txPG.PGN ) {
  case TIM21.pgn:
    switch (txPG.byte(0))
    {
      case TIMClientStatus_Msg:
        if (sysGetVariableInt(sysvar::TIMClient::svFreezeClientHeartbeatCounter) > 0)
        {
          // if error injection is active we always send the same heartbeat counter
          if (sFreezedHearbeatCounter < 0)
          {
            sFreezedHearbeatCounter =  txPG.byte(1);
          }
          txPG.byte(1) = sFreezedHearbeatCounter;
        }
        else
        {
          // if error injection is deactivated we reset the heartbeat variable  
          sFreezedHearbeatCounter = -1;
        }
        break;
      default:
        break;
    }
    
    break;
  default:
    break;
  }
    
  return 1; // send message
}

long Iso11783IL_OnRxMessage(pg * rxPG)
{
  if((rxPG.pgn == AUTH12.pgn) && (rxPG.byte(0) == 3)) // Client Certificate Request
  {
    switch(rxPG.Byte(4))
    {
      case 1: // testlab
      {
        if(sNumOfReqForTestlabCertToIgnore > 0)
        {
          sNumOfReqForTestlabCertToIgnore--;
          return 0;
        }
        else
        {
          return 1;
        }
      }
      break;

      case 2: // Manufacturer
      {
        if(sNumOfReqForManufactCertToIgnore > 0)
        {
          sNumOfReqForManufactCertToIgnore--;
          return 0;
        }
        else
        {
          return 1;
        }
      }
      break;
      
      case 3: // Manufacturer Series
      {
        if(sNumOfReqForManufactSeriesCertToIgnore > 0)
        {
          sNumOfReqForManufactSeriesCertToIgnore--;
          return 0;
        }
        else
        {
          return 1;
        }
      }
      break;
      
      case 4: // Device
      {
        if(sNumOfReqForDeviceCertToIgnore > 0)
        {
          sNumOfReqForDeviceCertToIgnore--;
          return 0;
        }
        else
        {
          return 1;
        }
      }
      break;
    }
  }
  return 1;
}
