unit XcpTransport;
//***************************************************************************************
//  Description: XCP transport layer for SCI.
//    File Name: XcpTransport.pas
//
//---------------------------------------------------------------------------------------
//                          C O P Y R I G H T
//---------------------------------------------------------------------------------------
//   Copyright (c) 2011 by Feaser    http://www.feaser.com    All rights reserved
//
//   This software has been carefully tested, but is not guaranteed for any particular
// purpose. The author does not offer any warranties and does not guarantee the accuracy,
//   adequacy, or completeness of the software and is not responsible for any errors or
//              omissions or the results obtained from use of the software.
//
//---------------------------------------------------------------------------------------
//                            L I C E N S E
//---------------------------------------------------------------------------------------
// This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with OpenBLT.
// If not, see <http://www.gnu.org/licenses/>.
//
// A special exception to the GPL is included to allow you to distribute a combined work
// that includes OpenBLT without being obliged to provide the source code for any
// proprietary components. The exception text is included at the bottom of the license
// file <license.html>.
//
//***************************************************************************************
interface


//***************************************************************************************
// Includes
//***************************************************************************************
uses
  Windows, Messages, SysUtils, Classes, Forms, CPDrv, IniFiles;


//***************************************************************************************
// Global Constants
//***************************************************************************************
const kMaxPacketSize = 256;


//***************************************************************************************
// Type Definitions
//***************************************************************************************
type
  TXcpTransport = class(TObject)
  private
  public
    packetData   : array[0..kMaxPacketSize-1] of Byte;
    packetLen    : Word;
    sciDriver    : TCommPortDriver;
    constructor Create;
    procedure   Configure(iniFile : string);
    procedure   Connect;
    function    SendPacket(timeOutms: LongWord): Boolean;
    procedure   Disconnect;
    destructor  Destroy; override;
  end;


implementation

//***************************************************************************************
// NAME:           Create
// PARAMETER:      none
// RETURN VALUE:   none
// DESCRIPTION:    Class constructore
//
//***************************************************************************************
constructor TXcpTransport.Create;
begin
  // call inherited constructor
  inherited Create;

  // create a sci driver instance
  sciDriver := TCommPortDriver.Create(nil);

  // init sci settings
  sciDriver.DataBits := db8BITS;
  sciDriver.StopBits := sb1BITS;
  sciDriver.Parity := ptNONE;
  sciDriver.SwFlow := sfNONE;
  sciDriver.PollingDelay := 5;

  // reset packet length
  packetLen := 0;
end; //*** end of Create ***


//***************************************************************************************
// NAME:           Destroy
// PARAMETER:      none
// RETURN VALUE:   none
// DESCRIPTION:    Class destructor
//
//***************************************************************************************
destructor TXcpTransport.Destroy;
begin
  // release sci driver instance
  sciDriver.Free;

  // call inherited destructor
  inherited;
end; //*** end of Destroy ***


//***************************************************************************************
// NAME:           Configure
// PARAMETER:      filename of the INI
// RETURN VALUE:   none
// DESCRIPTION:    Configures both this class from the settings in the INI.
//
//***************************************************************************************
procedure TXcpTransport.Configure(iniFile : string);
var
  settingsIni : TIniFile;
  configIndex : integer;
begin
	// read XCP configuration from INI
  if FileExists(iniFile) then
  begin
    // create ini file object
    settingsIni := TIniFile.Create(iniFile);

    // configure baudrate
    configIndex := settingsIni.ReadInteger('sci', 'baudrate', 6);
    sciDriver.BaudRate := br38400; // init to default value
    case configIndex of
      0 : sciDriver.BaudRate := br1200;
      1 : sciDriver.BaudRate := br2400;
      2 : sciDriver.BaudRate := br4800;
      3 : sciDriver.BaudRate := br9600;
      4 : sciDriver.BaudRate := br14400;
      5 : sciDriver.BaudRate := br19200;
      6 : sciDriver.BaudRate := br38400;
      7 : sciDriver.BaudRate := br56000;
      8 : sciDriver.BaudRate := br57600;
      9 : sciDriver.BaudRate := br115200;
      10: sciDriver.BaudRate := br128000;
      11: sciDriver.BaudRate := br256000;
    end;

    // configure port
    configIndex := settingsIni.ReadInteger('sci', 'port', 0);
    sciDriver.Port := pnCOM1; // init to default value
    case configIndex of
      0 : sciDriver.Port := pnCOM1;
      1 : sciDriver.Port := pnCOM2;
      2 : sciDriver.Port := pnCOM3;
      3 : sciDriver.Port := pnCOM4;
      4 : sciDriver.Port := pnCOM5;
      5 : sciDriver.Port := pnCOM6;
      6 : sciDriver.Port := pnCOM7;
      7 : sciDriver.Port := pnCOM8;
    end;

    // release ini file object
    settingsIni.Free;
  end;
end; //*** end of Configure ***


//***************************************************************************************
// NAME:           Connect
// PARAMETER:      none
// RETURN VALUE:   none
// DESCRIPTION:    Connects the transport layer device.
//
//***************************************************************************************
procedure TXcpTransport.Connect;
begin
  if not sciDriver.Connect then
    Application.MessageBox( 'Could not connect to COM port.',
                            'Error', MB_OK or MB_ICONERROR );
end; //*** end of Connect ***


//***************************************************************************************
// NAME:           SendPacket
// PARAMETER:      the time[ms] allowed for the reponse from the slave to come in.
// RETURN VALUE:   True if response received from slave, False otherwise
// DESCRIPTION:    Sends the XCP packet using the data in 'packetData' and length in
//                 'packetLen' and waits for the response to come in.
//
//***************************************************************************************
function TXcpTransport.SendPacket(timeOutms: LongWord): Boolean;
var
  msgData : array of Byte;
  resLen  : byte;
  cnt     : byte;
  dwEnd   :DWord;
begin
  // init the return value
  result := false;

  // prepare the packet. length goes in the first byte followed by the packet data
  SetLength(msgData, packetLen+1);
  msgData[0] := packetLen;
  for cnt := 0 to packetLen-1 do
  begin
    msgData[cnt+1] := packetData[cnt];
  end;

  // submit the packet transmission request
  if sciDriver.SendData(@msgData[0], packetLen+1) <> (packetLen+1)  then
  begin
    // unable to submit tx request
    Exit;
  end;

  // compute timeout time
  dwEnd := GetTickCount + timeOutms;

  // configure timeout for first byte
  sciDriver.InputTimeout := timeOutms;

  // receive the first byte which holds the packet length
  if sciDriver.ReadByte(resLen) = true then
  begin
    timeOutms := GetTickCount;
    if timeOutms < dwEnd then
    begin
      // configure timeout for remaining bytes
      sciDriver.InputTimeout := dwEnd - timeOutms;
    end
    else
    begin
      Exit; // timed out
    end;

    // receive the actual packet data
    if sciDriver.ReadData(@packetData[0], resLen) = resLen then
    begin
      packetLen := resLen;
      result := true;
    end;
  end;
end; //*** end of SendPacket ***


//***************************************************************************************
// NAME:           Disconnect
// PARAMETER:      none
// RETURN VALUE:   none
// DESCRIPTION:    Disconnects the transport layer device.
//
//***************************************************************************************
procedure TXcpTransport.Disconnect;
begin
  sciDriver.Disconnect;
end; //*** end of Disconnect ***


end.
//******************************** end of XcpTransport.pas ******************************

