mirror of https://github.com/FOME-Tech/openblt.git
548 lines
20 KiB
Plaintext
548 lines
20 KiB
Plaintext
unit PCANdrvD;
|
|
//***************************************************************************************
|
|
// Project Name: TPCanDriver component for Borland Delphi
|
|
// Description: Encapsulates PCAN's Light driver into a VCL component for PCANUSB 1CH.
|
|
// File Name: PCANdrvD.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, Graphics, Controls, Forms, Dialogs, Pcan_usb;
|
|
|
|
|
|
//***************************************************************************************
|
|
// Type Definitions
|
|
//***************************************************************************************
|
|
type
|
|
TPCanChannel = ( pcanchannel0 );
|
|
TPCanHardware = ( PCAN_USB1CH );
|
|
TPCanDirection = ( PcanTx, PCanRx );
|
|
TPCanMessage = packed record
|
|
id : LongInt;
|
|
dlc : Byte;
|
|
data : array [0..7] of Byte;
|
|
time : LongInt;
|
|
ext : Boolean;
|
|
end;
|
|
|
|
type
|
|
TPCanMessageEvent = procedure( Sender: TObject; Direction: TPCanDirection; Message: TPCanMessage ) of object;
|
|
|
|
type
|
|
TPCanEventThread = class(TThread)
|
|
private
|
|
{ Private declarations }
|
|
FMethod: TThreadMethod;
|
|
protected
|
|
procedure Execute; override;
|
|
public
|
|
property Method : TThreadMethod read FMethod write FMethod;
|
|
end;
|
|
|
|
type
|
|
TPCanDriver = class(TComponent)
|
|
private
|
|
{ Private declarations }
|
|
FCanEventThread: TPCanEventThread;
|
|
FThreadRunning : boolean;
|
|
FCanConnected : boolean;
|
|
FStartTickCnt : DWORD;
|
|
function IsThreadRunning: boolean;
|
|
procedure ProcessReception;
|
|
protected
|
|
{ Protected declarations }
|
|
FBaudRate : LongInt;
|
|
FChannel : TPCanChannel;
|
|
FHardware : TPCanHardware;
|
|
FPriority : TThreadPriority;
|
|
FExtendedId : Boolean;
|
|
FOnMessage : TPCanMessageEvent;
|
|
procedure SetBaudRate( Value: LongInt );
|
|
procedure SetChannel( Value: TPCanChannel );
|
|
procedure SetHardware( Value: TPCanHardware );
|
|
procedure SetPriority( Value: TThreadPriority );
|
|
procedure SetExtendedId( Value: Boolean );
|
|
public
|
|
{ Public declarations }
|
|
constructor Create( AOwner: TComponent ); override;
|
|
destructor Destroy; override;
|
|
function Connect: boolean; virtual;
|
|
procedure Disconnect; virtual;
|
|
function Transmit( Message: TPCanMessage): boolean; virtual;
|
|
function IsConnected: boolean; virtual;
|
|
published
|
|
{ Published declarations }
|
|
property BaudRate : LongInt read FBaudRate write SetBaudRate default 500000;
|
|
property Channel : TPCanChannel read FChannel write SetChannel default pcanchannel0;
|
|
property Hardware : TPCanHardware read FHardware write SetHardware default PCAN_USB1CH;
|
|
property Priority : TThreadPriority read FPriority write SetPriority default tpNormal;
|
|
property ExtendedId : Boolean read FExtendedId write SetExtendedId default False;
|
|
property OnMessage : TPCanMessageEvent read FOnMessage write FOnMessage;
|
|
end;
|
|
|
|
|
|
//***************************************************************************************
|
|
// Prototypes
|
|
//***************************************************************************************
|
|
procedure Register;
|
|
|
|
implementation
|
|
//***************************************************************************************
|
|
// NAME: Execute
|
|
// PRECONDITIONS: none
|
|
// PARAMETER: none
|
|
// RETURN VALUE: none
|
|
// DESCRIPTION: Overriden Execute function for the CanEventThread. Calls and synchro-
|
|
// nizes with the TCanDriver.ProcessEvents function.
|
|
//
|
|
//***************************************************************************************
|
|
procedure TPCanEventThread.Execute;
|
|
begin
|
|
while not Terminated do
|
|
begin
|
|
if Assigned(Method) then // make sure TPCanDriver.ProcessEvents is set
|
|
Synchronize(Method); // call and synchronize
|
|
end;
|
|
end; //*** end of Execute ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: Create
|
|
// PRECONDITIONS: none
|
|
// PARAMETER: AOwner : owner of the component
|
|
// RETURN VALUE: none
|
|
// DESCRIPTION: Component constructor. Calls TComponent's constructor and initializes
|
|
// the private property variables to their default values.
|
|
//
|
|
//***************************************************************************************
|
|
constructor TPCanDriver.Create( AOwner: TComponent );
|
|
begin
|
|
// call inherited constructor
|
|
inherited Create( AOwner );
|
|
|
|
// set defaults for internal variables
|
|
FThreadRunning := False;
|
|
FCanConnected := False;
|
|
|
|
// set defaults for properties
|
|
FBaudRate := 500000;
|
|
FChannel := pcanchannel0;
|
|
FHardware := PCAN_USB1CH;
|
|
FPriority := tpNormal;
|
|
FExtendedId := False;
|
|
end; //*** end of Create ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: Destroy
|
|
// PRECONDITIONS: none
|
|
// PARAMETER: none
|
|
// RETURN VALUE: none
|
|
// DESCRIPTION: Component destructor. Calls TComponent's destructor
|
|
//
|
|
//***************************************************************************************
|
|
destructor TPCanDriver.Destroy;
|
|
begin
|
|
Disconnect; // close the port and driver
|
|
inherited Destroy; // call inherited destructor
|
|
end; //*** end of Destroy ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: IsConnected
|
|
// PRECONDITIONS: none
|
|
// PARAMETER: none
|
|
// RETURN VALUE: True or False
|
|
// DESCRIPTION: Determines whether or not the CAN driver is connected and active
|
|
//
|
|
//***************************************************************************************
|
|
function TPCanDriver.IsConnected: boolean;
|
|
begin
|
|
Result := FCanConnected;
|
|
end; //*** end of IsConnected ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: IsThreadRunning
|
|
// PRECONDITIONS: none
|
|
// PARAMETER: none
|
|
// RETURN VALUE: True or False
|
|
// DESCRIPTION: Determines whether or not the CAN event thread is running
|
|
//
|
|
//***************************************************************************************
|
|
function TPCanDriver.IsThreadRunning: boolean;
|
|
begin
|
|
if FThreadRunning = True then
|
|
Result := True
|
|
else
|
|
Result := False;
|
|
end; //*** end of IsThreadRunning ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: SetBaudRate
|
|
// PRECONDITIONS: none
|
|
// PARAMETER: Value : new baudrate value [0 - 1000000 bps]
|
|
// RETURN VALUE: none
|
|
// DESCRIPTION: Configures the baudrate
|
|
//
|
|
// |------------------------------------------------------------------------------------
|
|
// | Update baudrate configuration
|
|
// |------------------------------------------------------------------------------------
|
|
//***************************************************************************************
|
|
procedure TPCanDriver.SetBaudRate( Value: LongInt );
|
|
begin
|
|
FBaudRate := Value; // update property
|
|
end; //*** end of SetBaudRate ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: SetChannel
|
|
// PRECONDITIONS: none
|
|
// PARAMETER: Value : channel0 or channel1
|
|
// RETURN VALUE: none
|
|
// DESCRIPTION: Configures the used CAN channel
|
|
//
|
|
// |------------------------------------------------------------------------------------
|
|
// | Update channel configuration
|
|
// |------------------------------------------------------------------------------------
|
|
//***************************************************************************************
|
|
procedure TPCanDriver.SetChannel( Value: TPCanChannel );
|
|
begin
|
|
FChannel := Value;
|
|
end; //*** end of SetChannel ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: SetHardware
|
|
// PRECONDITIONS: none
|
|
// PARAMETER: Value : type of CAN hardware (Virtual, CANcardXL, etc.)
|
|
// RETURN VALUE: none
|
|
// DESCRIPTION: Configures the used CAN hardware
|
|
//
|
|
// |------------------------------------------------------------------------------------
|
|
// | Update hardware configuration
|
|
// |------------------------------------------------------------------------------------
|
|
//***************************************************************************************
|
|
procedure TPCanDriver.SetHardware( Value: TPCanHardware );
|
|
begin
|
|
FHardware := Value;
|
|
end; //*** end of SetHardware ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: SetPriority
|
|
// PRECONDITIONS: none
|
|
// PARAMETER: Value : thread priority
|
|
// RETURN VALUE: none
|
|
// DESCRIPTION: Configures the priority for the CAN event thread
|
|
//
|
|
// |------------------------------------------------------------------------------------
|
|
// | y\ Is Thread running? /n
|
|
// |------------------------------------------------------------------------------------
|
|
// | Stop Thread |
|
|
// | Update Thread priority | Update Thread priority
|
|
// | Restart Thread |
|
|
// |------------------------------------------------------------------------------------
|
|
//***************************************************************************************
|
|
procedure TPCanDriver.SetPriority( Value: TThreadPriority );
|
|
begin
|
|
if IsThreadRunning then
|
|
begin
|
|
FCanEventThread.Suspend; // suspend the thread
|
|
FPriority := Value; // update the priority
|
|
FCanEventThread.Resume; // resume the thread
|
|
end
|
|
else
|
|
begin
|
|
FPriority := Value; // update the priority
|
|
end;
|
|
end; //*** end of SetPriority ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: SetExtendedId
|
|
// PRECONDITIONS: none
|
|
// PARAMETER: Value : true = support only 29-bit id's, false = support only 11-bit
|
|
// RETURN VALUE: none
|
|
// DESCRIPTION: Configures the support of extended 29-bit identifiers
|
|
//
|
|
// |------------------------------------------------------------------------------------
|
|
// | Update extended id support selection
|
|
// |------------------------------------------------------------------------------------
|
|
//***************************************************************************************
|
|
procedure TPCanDriver.SetExtendedId( Value: Boolean );
|
|
begin
|
|
FExtendedId := Value;
|
|
end; //*** end of SetExtendedId ***/
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: Connect
|
|
// PRECONDITIONS: Disconnected from CAN bus
|
|
// PARAMETER: none
|
|
// RETURN VALUE: True or False for succees or error, respectively
|
|
// DESCRIPTION: Initializes the CAN driver and synchronizes the hardware with the CAN
|
|
// bus.
|
|
//
|
|
//***************************************************************************************
|
|
function TPCanDriver.Connect: boolean;
|
|
var
|
|
Baudcode : Word;
|
|
MsgType : Integer;
|
|
|
|
begin
|
|
Result := False;
|
|
FThreadRunning := False;
|
|
FCanConnected := False;
|
|
|
|
// convert baudrate in bps to supported baudrate code
|
|
Baudcode := CAN_BAUD_500K; // init local
|
|
case FBaudRate of
|
|
5000 : Baudcode := CAN_BAUD_5K;
|
|
10000 : Baudcode := CAN_BAUD_10K;
|
|
20000 : Baudcode := CAN_BAUD_20K;
|
|
33333 : Baudcode := $1D14;
|
|
50000 : Baudcode := CAN_BAUD_50K;
|
|
83333 : Baudcode := $4B14;
|
|
100000 : Baudcode := CAN_BAUD_100K;
|
|
125000 : Baudcode := CAN_BAUD_125K;
|
|
250000 : Baudcode := CAN_BAUD_250K;
|
|
500000 : Baudcode := CAN_BAUD_500K;
|
|
1000000 : Baudcode := CAN_BAUD_1M;
|
|
end;
|
|
|
|
// convert extented id info
|
|
if FExtendedId then
|
|
MsgType := 1
|
|
else
|
|
MsgType := 0;
|
|
|
|
//-------------------------- open the driver ------------------------------------------
|
|
if CAN_Init(Baudcode, MsgType) <> CAN_ERR_OK then Exit;
|
|
|
|
|
|
//-------------------------- open the acceptance filter --------------------------------
|
|
if CAN_ResetFilter <> CAN_ERR_OK then
|
|
begin
|
|
CAN_Close;
|
|
Exit;
|
|
end;
|
|
|
|
if FExtendedId then
|
|
begin
|
|
if CAN_MsgFilter($000, $1FFFFFFF, MSGTYPE_EXTENDED) <> CAN_ERR_OK then
|
|
begin
|
|
CAN_Close;
|
|
Exit;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if CAN_MsgFilter($000, $7FF, MSGTYPE_STANDARD) <> CAN_ERR_OK then
|
|
begin
|
|
CAN_Close;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
//-------------------------- reset message queues -------------------------------------
|
|
if CAN_ResetClient <> CAN_ERR_OK then
|
|
begin
|
|
CAN_Close;
|
|
Exit;
|
|
end;
|
|
|
|
//-------------------------- start CAN event thread -----------------------------------
|
|
FCanEventThread := TPCanEventThread.Create(True); // create and suspend
|
|
FCanEventThread.FreeOnTerminate := True; // auto free on termination
|
|
FCanEventThread.Method := ProcessReception; // set method
|
|
FCanEventThread.Resume; // start
|
|
FThreadRunning := True;
|
|
|
|
|
|
//-------------------------- store start time for time stamps -------------------------
|
|
FStartTickCnt := GetTickCount;
|
|
|
|
//-------------------------- success --------------------------------------------------
|
|
FCanConnected := True;
|
|
Result := True; // successfully initialized the driver
|
|
end; //*** end of Connect ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: Disconnect
|
|
// PRECONDITIONS: none
|
|
// PARAMETER: none
|
|
// RETURN VALUE: none
|
|
// DESCRIPTION: Disconnects the CAN driver
|
|
//
|
|
//***************************************************************************************
|
|
procedure TPCanDriver.Disconnect;
|
|
begin
|
|
if IsConnected = True then // are we connected?
|
|
begin
|
|
FCanConnected := False;
|
|
// close the channel
|
|
CAN_Close;
|
|
end;
|
|
|
|
if IsThreadRunning then
|
|
begin
|
|
FCanEventThread.Terminate; // stop
|
|
FThreadRunning := False;
|
|
end;
|
|
end; //*** end of Disconnect ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: Transmit
|
|
// PRECONDITIONS: Driver initialized using 'Connect'
|
|
// PARAMETER: Message: CAN message that is to be transmitted
|
|
// RETURN VALUE: True or False for succees or error, respectively
|
|
// DESCRIPTION: Transmits a CAN message.
|
|
//
|
|
//***************************************************************************************
|
|
function TPCanDriver.Transmit( Message: TPCanMessage): boolean;
|
|
var
|
|
cnt : Byte;
|
|
msg : TPCANMsg;
|
|
msgcpy : TPCanMessage;
|
|
begin
|
|
// make sure the CAN driver is connected
|
|
if not IsConnected then
|
|
begin
|
|
Result := False; // can't transmit it not connected
|
|
exit; // no need to continue
|
|
end;
|
|
|
|
// set the message identifier
|
|
msg.ID := Message.id;
|
|
if Message.ext then
|
|
msg.MSGTYPE := MSGTYPE_EXTENDED
|
|
else
|
|
msg.MSGTYPE := MSGTYPE_STANDARD;
|
|
|
|
// set the data length
|
|
msg.LEN := Message.dlc;
|
|
|
|
// store the data bytes
|
|
for cnt :=0 to Message.dlc do
|
|
begin
|
|
msg.DATA[cnt] := Message.data[cnt];
|
|
end;
|
|
|
|
// submit the transmit request
|
|
if CAN_Write(msg) <> CAN_ERR_OK then
|
|
begin
|
|
Result := False;
|
|
exit;
|
|
end;
|
|
|
|
//---------------- process transmission confirmation --------------------------
|
|
if Assigned( FOnMessage ) then
|
|
begin
|
|
msgcpy := Message;
|
|
msgcpy.time := GetTickCount - FStartTickCnt;
|
|
FOnMessage( Self, PCanTx, msgcpy ); // call application's event handler
|
|
end;
|
|
|
|
Result := True;
|
|
end; //*** end of Transmit ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: ProcessReception
|
|
// PRECONDITIONS: thread running
|
|
// PARAMETER: none
|
|
// RETURN VALUE: none
|
|
// DESCRIPTION: Called by the CAN event tread. This function traps and processes CAN
|
|
// events for OnMessage.
|
|
//
|
|
//***************************************************************************************
|
|
procedure TPCanDriver.ProcessReception;
|
|
var
|
|
cnt : Byte;
|
|
msg : TPCanMessage;
|
|
msgraw : TPCANMsg;
|
|
begin
|
|
//---------------- process reception indication -------------------------------
|
|
// continue only if a new message is present in the queue
|
|
if CAN_Read(msgraw) <> CAN_ERR_OK then
|
|
Exit;
|
|
|
|
// only process CAN messages and not the status messages
|
|
if (msgraw.MSGTYPE = MSGTYPE_EXTENDED) or (msgraw.MSGTYPE = MSGTYPE_STANDARD) then
|
|
begin
|
|
// copy the message info
|
|
msg.time := GetTickCount - FStartTickCnt;
|
|
msg.id := msgraw.ID;
|
|
msg.dlc := msgraw.LEN;
|
|
// store the data bytes
|
|
for cnt :=0 to msg.dlc do
|
|
begin
|
|
msg.data[cnt] := msgraw.DATA[cnt];
|
|
end;
|
|
|
|
if Assigned( FOnMessage ) then
|
|
begin
|
|
FOnMessage( Self, PCanRx, msg ); // call application's event handler
|
|
end;
|
|
end;
|
|
end; //*** end of ProcessReception ***
|
|
|
|
|
|
//***************************************************************************************
|
|
// NAME: Register
|
|
// PRECONDITIONS: none
|
|
// PARAMETER: none
|
|
// RETURN VALUE: none
|
|
// DESCRIPTION: Registers the TPCanDriver component into Borland Delphi's IDE.
|
|
//
|
|
//***************************************************************************************
|
|
procedure Register;
|
|
begin
|
|
RegisterComponents('Feaser', [TPCanDriver]);
|
|
end; //*** end of Register ***
|
|
|
|
|
|
end.
|
|
//********************************** end of PCANdrvD.pas ********************************
|
|
|
|
|