mirror of https://github.com/FOME-Tech/openblt.git
424 lines
14 KiB
Plaintext
424 lines
14 KiB
Plaintext
unit XcpTransport;
|
|
//***************************************************************************************
|
|
// Description: XCP transport layer for CAN.
|
|
// File Name: XcpTransport.pas
|
|
//
|
|
//---------------------------------------------------------------------------------------
|
|
// C O P Y R I G H T
|
|
//---------------------------------------------------------------------------------------
|
|
// Copyright (c) 2017 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 have received a copy of the GNU General Public License along with OpenBLT. It
|
|
// should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
|
|
//
|
|
//***************************************************************************************
|
|
interface
|
|
|
|
|
|
//***************************************************************************************
|
|
// Includes
|
|
//***************************************************************************************
|
|
uses
|
|
Windows, Messages, SysUtils, Classes, Forms, IniFiles, canlib;
|
|
|
|
|
|
//***************************************************************************************
|
|
// Global Constants
|
|
//***************************************************************************************
|
|
// a CAN message can only have up to 8 bytes
|
|
const kMaxPacketSize = 8;
|
|
|
|
|
|
//***************************************************************************************
|
|
// Type Definitions
|
|
//***************************************************************************************
|
|
type
|
|
TKvaserHardware = ( KVASER_LEAFLIGHT_V2 = $01 );
|
|
|
|
TXcpTransport = class(TObject)
|
|
private
|
|
packetTxId : LongWord;
|
|
packetRxId : LongWord;
|
|
extendedId : Boolean;
|
|
kvaserHandle : canHandle;
|
|
canHardware : TKvaserHardware; { KVASER_xxx }
|
|
canChannel : Word; { currently supported is 1..1 }
|
|
canBaudrate : LongWord; { in bits/sec }
|
|
connected : Boolean;
|
|
public
|
|
packetData : array[0..kMaxPacketSize-1] of Byte;
|
|
packetLen : Word;
|
|
constructor Create;
|
|
procedure Configure(iniFile : string);
|
|
function Connect: Boolean;
|
|
function SendPacket(timeOutms: LongWord): Boolean;
|
|
function IsComError: 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;
|
|
|
|
// reset the packet ids
|
|
packetTxId := 0;
|
|
packetRxId := 0;
|
|
// use standard id's by default
|
|
extendedId := false;
|
|
// reset packet length
|
|
packetLen := 0;
|
|
// disconnected by default
|
|
connected := false;
|
|
// invalidate the handle
|
|
kvaserHandle := canINVALID_HANDLE;
|
|
// initialize the library
|
|
canInitializeLibrary;
|
|
end; //*** end of Create ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: Destroy
|
|
// PARAMETER: none
|
|
// RETURN VALUE: none
|
|
// DESCRIPTION: Class destructor
|
|
//
|
|
//***************************************************************************************
|
|
destructor TXcpTransport.Destroy;
|
|
begin
|
|
// unload the library
|
|
canUnloadLibrary;
|
|
// 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;
|
|
baudrateIdx : Integer;
|
|
const
|
|
baudrateLookupTable : array[0..7] of LongWord =
|
|
(
|
|
// list baudrates in the same order as they appear in the combobox on the settings
|
|
// form. this way the combobox's ItemIndex property can be used as an indexer to this
|
|
// array.
|
|
1000000, 500000, 250000, 125000, 100000, 83333, 50000, 10000
|
|
);
|
|
begin
|
|
// read XCP configuration from INI
|
|
if FileExists(iniFile) then
|
|
begin
|
|
// create ini file object
|
|
settingsIni := TIniFile.Create(iniFile);
|
|
|
|
// set hardware configuration
|
|
case settingsIni.ReadInteger('can', 'hardware', 0) of
|
|
0: canHardware := KVASER_LEAFLIGHT_V2;
|
|
else
|
|
canHardware := KVASER_LEAFLIGHT_V2;
|
|
end;
|
|
// set channel configuration
|
|
canChannel := settingsIni.ReadInteger('can', 'channel', 0) + 1;
|
|
// set baudrate configuration
|
|
baudrateIdx := settingsIni.ReadInteger('can', 'baudrate', 1);
|
|
canBaudrate := 500000;
|
|
if (baudrateIdx >= 0) and (baudrateIdx < Length(baudrateLookupTable)) then
|
|
canBaudrate := baudrateLookupTable[baudrateIdx];
|
|
// set message configuration
|
|
packetTxId := settingsIni.ReadInteger('can', 'txid', $667);
|
|
packetRxId := settingsIni.ReadInteger('can', 'rxid', $7e1);
|
|
extendedId := settingsIni.ReadBool('can', 'extended', false);
|
|
|
|
// release ini file object
|
|
settingsIni.Free;
|
|
end;
|
|
end; //*** end of Configure ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: Connect
|
|
// PARAMETER: none
|
|
// RETURN VALUE: True if successful, False otherwise.
|
|
// DESCRIPTION: Connects the transport layer device.
|
|
//
|
|
//***************************************************************************************
|
|
function TXcpTransport.Connect: Boolean;
|
|
var
|
|
openFlags: Integer;
|
|
frequency: Integer;
|
|
begin
|
|
// init result value
|
|
result := false;
|
|
|
|
// disconnect first if still connected
|
|
if connected then
|
|
Disconnect;
|
|
|
|
// the current version only supports the leaf light v2
|
|
if canHardware = KVASER_LEAFLIGHT_V2 then
|
|
begin
|
|
// open the CAN channel if valid
|
|
if canChannel > 0 then
|
|
begin
|
|
// set the open flags
|
|
openFlags := canOPEN_REQUIRE_INIT_ACCESS;
|
|
if extendedId then
|
|
begin
|
|
openFlags := openFlags or canOPEN_REQUIRE_EXTENDED;
|
|
end;
|
|
kvaserHandle := canOpenChannel(canChannel - 1, openFlags);
|
|
// only continue if the channel was opened and the handle is not valid
|
|
if kvaserHandle >= 0 then
|
|
begin
|
|
case canBaudrate of
|
|
1000000: frequency := canBITRATE_1M;
|
|
500000: frequency := canBITRATE_500K;
|
|
250000: frequency := canBITRATE_250K;
|
|
125000: frequency := canBITRATE_125K;
|
|
100000: frequency := canBITRATE_100K;
|
|
83333: frequency := canBITRATE_83K;
|
|
50000: frequency := canBITRATE_50K;
|
|
10000: frequency := canBITRATE_10K;
|
|
else
|
|
frequency := canBITRATE_500K;
|
|
end;
|
|
// configure the baudrate
|
|
if canSetBusParams(kvaserHandle, frequency, 0, 0, 0, 0, 0) = canOK then
|
|
begin
|
|
// configure output control to the default normal mode
|
|
if canSetBusOutputControl(kvaserHandle, canDRIVER_NORMAL) = canOK then
|
|
begin
|
|
// go on the bus
|
|
if canBusOn(kvaserHandle) = canOK then
|
|
begin
|
|
// connection was established
|
|
connected := true;
|
|
result := true;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end; //*** end of Connect ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: IsComError
|
|
// PARAMETER: none
|
|
// RETURN VALUE: True if in error state, False otherwise.
|
|
// DESCRIPTION: Determines if the communication interface is in an error state.
|
|
//
|
|
//***************************************************************************************
|
|
function TXcpTransport.IsComError: Boolean;
|
|
var
|
|
statusFlags: Cardinal;
|
|
begin
|
|
// init result to no error.
|
|
result := false;
|
|
|
|
// do not check if the handle is invalid
|
|
if kvaserHandle <= canINVALID_HANDLE then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
// check for bus off error or error passive if connected
|
|
if connected then
|
|
begin
|
|
if canReadStatus(kvaserHandle, statusFlags) = canOK then
|
|
begin
|
|
// check for bus off or error passive bits
|
|
if (statusFlags and (canSTAT_BUS_OFF or canSTAT_ERROR_PASSIVE)) > 0 then
|
|
begin
|
|
result := true;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
// could not read the status which is also an indicator that something is wrong
|
|
result := true
|
|
end;
|
|
end;
|
|
end; //*** end of IsComError ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// 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
|
|
responseReceived: Boolean;
|
|
timeoutTime: DWORD;
|
|
txId: LongInt;
|
|
txData: array[0..kMaxPacketSize-1] of Byte;
|
|
txFlags: Cardinal;
|
|
rxId: LongInt;
|
|
rxData: array[0..kMaxPacketSize-1] of Byte;
|
|
rxFlags: Cardinal;
|
|
rxLen: Cardinal;
|
|
rxTime: Cardinal;
|
|
byteIdx: Byte;
|
|
status: canStatus;
|
|
idTypeOk: Boolean;
|
|
begin
|
|
// initialize the result value
|
|
result := false;
|
|
|
|
// do not send data when the packet length is invalid or when not connected
|
|
// to the CAN hardware
|
|
if (packetLen > kMaxPacketSize) or (not connected) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
// do not send if the handle is invalid
|
|
if kvaserHandle <= canINVALID_HANDLE then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
// prepare the packet for transmission in a CAN message
|
|
txId := packetTxId;
|
|
for byteIdx := 0 to (packetLen - 1) do
|
|
begin
|
|
txData[byteIdx] := packetData[byteIdx];
|
|
end;
|
|
if extendedId then
|
|
txFlags := canMSG_EXT
|
|
else
|
|
txFlags := canMSG_STD;
|
|
|
|
// submit the packet for transmission via the CAN bus
|
|
if canWrite(kvaserHandle, txId, @txData[0], packetLen, txFlags) <> canOK then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
// reset flag and set the reception timeout time
|
|
responseReceived := false;
|
|
timeoutTime := GetTickCount + timeOutms;
|
|
|
|
// attempt to receive the packet response within the timeout time
|
|
repeat
|
|
// prepare message reception
|
|
rxId := packetRxId;
|
|
// attempt to read the packet response from the reception queue
|
|
status := canReadSpecificSkip(kvaserHandle, rxId, @rxData[0], rxLen, rxFlags, rxTime);
|
|
// check if an error was detected
|
|
if (status <> canOK) and (status <> canERR_NOMSG) then
|
|
begin
|
|
// error detected. stop loop.
|
|
Break;
|
|
end;
|
|
// no error, now check if a message was actually received
|
|
if status = canOK then
|
|
begin
|
|
// a message with the identifier of the response packet was received. now check
|
|
// that the identifier type also matches
|
|
idTypeOk := false;
|
|
if extendedId then
|
|
begin
|
|
if (rxFlags and canMSG_EXT) > 0 then
|
|
idTypeOk := true;
|
|
end
|
|
else
|
|
begin
|
|
if (rxFlags and canMSG_STD) > 0 then
|
|
idTypeOk := true;
|
|
end;
|
|
if idTypeOk then
|
|
begin
|
|
// response received. set flag
|
|
responseReceived := true;
|
|
end;
|
|
end;
|
|
// give the application a chance to use the processor
|
|
Application.ProcessMessages;
|
|
until (GetTickCount > timeoutTime) or (responseReceived);
|
|
|
|
// check if the response was correctly received
|
|
if responseReceived then
|
|
begin
|
|
// copy the received response packet
|
|
packetLen := rxLen;
|
|
for byteIdx := 0 to (packetLen - 1) do
|
|
begin
|
|
packetData[byteIdx] := rxData[byteIdx];
|
|
end;
|
|
// success
|
|
result := true;
|
|
end;
|
|
end; //*** end of SendPacket ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: Disconnect
|
|
// PARAMETER: none
|
|
// RETURN VALUE: none
|
|
// DESCRIPTION: Disconnects the transport layer device.
|
|
//
|
|
//***************************************************************************************
|
|
procedure TXcpTransport.Disconnect;
|
|
begin
|
|
// disconnect CAN interface if connected
|
|
if connected then
|
|
begin
|
|
// only disconnect if the handle is valid
|
|
if kvaserHandle > canINVALID_HANDLE then
|
|
begin
|
|
// take the channel from the bus
|
|
canBusOff(kvaserHandle);
|
|
// close the channel
|
|
canClose(kvaserHandle);
|
|
end;
|
|
end;
|
|
kvaserHandle := canINVALID_HANDLE;
|
|
connected := false;
|
|
end; //*** end of Disconnect ***
|
|
|
|
end.
|
|
//******************************** end of XcpTransport.pas ******************************
|
|
|