///////////////////////////////////////////////////////////////////////////////
//  Based on:
//  PCAN_ISA.pas
//  PCAN_2ISA.pas
//  PCAN_PCI.pas
//  PCAN_2PCI.pas
//  PCAN_PCC.pas
//  PCAN_2PCC.pas
//  PCAN_DNG.pas
//  PCAN_DNP.pas
//  PCAN_USB.pas
//  PCAN_2USB.pas
//
//  Version 1.3
//
//  ~~~~~~~~~~~~
//
//  Idea:
//
//  ~~~~~~~~~~
//
//  PCANLight is a Unit in charge of make the managing of the different PCAN Hardware using the
//  PCANLight Dlls: pcan_isa,pcan_2isa,pcan_pci,pcan_2pci,pcan_pcc,pcan_2pcc,pcan_dng,pcan_dnp,
//  pcan_usb, pcan_2usb
//
//  In order  to offer  a simple  interface, some constant valuest were converted  to enumerate
//  types.  The class CANLight  make use of all Dlls and gives  an unique interface for all the
//  hardware types.  In this way, in this high level,  will  exists  only  one  occurrence of each
//  PCANLIGHT function.
//
//  ~~~~~~~~~~~~
//
//  PCAN-Light -API
//
//  ~~~~~~~~~~~~
//
//   Init() (Two versions, for P&P and Non P&P)
//   Close() 
//   Status()
//   Write() 
//   Read()  
//   VersionInfo() 
//   SpecialFunktion()
//   GetDLL2_Version()
//   ResetClient()
//   MsgFilter()
//   ResetFilter()
//   SetUSBDeviceNr()
//   GetUSBDeviceNr()
//
//  ------------------------------------------------------------------
//
//  Autor  : Keneth Wagner
//  Language: Pascal OO (Delphi)
//  Modified: Wagner - 13.08.2008
//
//  ------------------------------------------------------------------
//  Copyright (C) 2006-2008  PEAK-System Technik GmbH, Darmstadt
//
unit PCANLight;

interface

uses
    SysUtils, Dialogs, WinTypes, WinProcs, Math;

Type
// A CAN Message
//
TPCANMsg = record
    ID: LongWord;       // 11/29 Bit-Kennung
    MSGTYPE: Byte;      // Bits aus MSGTYPE_*
    LEN: Byte;          // Anzahl der gueltigen Daten-Bytes (1..8)
    DATA: array[0..7] of Byte;    // Daten-Bytes 0..7
end;

// Kind of Frame - Message Type
//
FramesType = (
    INIT_TYPE_ST	= $00,	//Standart Frame
    INIT_TYPE_EX	= $01	//Extended Frame
);

// Maximal values for the ID of a CAN Message
//
MaxIDValues = (
    MAX_STANDARD_ID	= $7FF,
    MAX_EXTENDED_ID	= $1FFFFFFF
);

// Kind of CAN Message
//
MsgTypes = (
    MSGTYPE_STANDARD	= $00,		// Standard Frame (11 bit ID)
    MSGTYPE_RTR			= $01,		// Remote request
    MSGTYPE_EXTENDED	= $02,		// CAN 2.0 B Frame (29 Bit ID)
    MSGTYPE_STATUS		= $80		// Status Message
);

// PCAN Hardware enumeration
//
Hardware =
(
    HW_INTERN          = 0,
    HW_ISA             = 1,
    HW_DONGLE	       = 2,	//82C200 version
    HW_DONGLE_EPP	   = 3,	//82C200 version
    HW_PHYT_ISA        = 4,
    HW_DONGLE_SJA      = 5,
    HW_DONGLE_SJA_EPP  = 6,
    HW_DONGLE_PRO      = 7,
    HW_DONGLE_PRO_EPP  = 8,
    HW_ISA_SJA         = 9
);

// Hardware type corresponding to the different PCAN Light Dlls
//
HardwareType = (
    ISA_1CH	= 0,		// ISA 1 Channel
	ISA_2CH = 1,		// ISA 2 Channels
	PCI_1CH = 2,		// PCI 1 Channel
	PCI_2CH = 3,		// PCI 2 Channels
	PCC_1CH = 4,		// PCC 1 Channel
	PCC_2CH = 5,		// PCC 2 Channels
	USB_1CH	= 6,		// USB 1st Channel
    USB_2CH = 7,        // USB 2nd Channel
	DNP		= 8,		// DONGLE PRO
	DNG		= 9		// DONGLE
);

// CAN Baudrates
//
Baudrates = (
    BAUD_1M		= $0014,  //   1 MBit/s
    BAUD_500K	= $001C,  // 500 kBit/s
    BAUD_250K	= $011C,  // 250 kBit/s
    BAUD_125K	= $031C,  // 125 kBit/s
    BAUD_100K	= $432F,  // 100 kBit/s
    BAUD_50K	= $472F,  //  50 kBit/s
    BAUD_20K	= $532F,  //  20 kBit/s
    BAUD_10K	= $672F,  //  10 kBit/s
    BAUD_5K		= $7F7F  //   5 kBit/s
);

// CAN Error and status values
//
CANResult = (
    ERR_OK				= $0000,   // No error
    ERR_XMTFULL			= $0001,   // Send buffer of the Controller ist full
    ERR_OVERRUN			= $0002,   // CAN-Controller was read to late
    ERR_BUSLIGHT		= $0004,   // Bus error: an Error count reached the limit
    ERR_BUSHEAVY		= $0008,   // Bus error: an Error count reached the limit
    ERR_BUSOFF			= $0010,   // Bus error: CAN_Controller went to 'Bus-Off'
    ERR_QRCVEMPTY		= $0020,   // RcvQueue is empty
    ERR_QOVERRUN		= $0040,   // RcvQueue was read to late
    ERR_QXMTFULL		= $0080,   // Send queue is full
    ERR_REGTEST			= $0100,   // RegisterTest of the 82C200/SJA1000 failed
    ERR_NOVXD			= $0200,   // Problem with Localization of the VxD
    ERR_ILLHW			= $1400,   // Invalid Hardware handle
    ERR_RESOURCE		= $2000,   // Not generatably Resource (FIFO, Client, Timeout)
    ERR_PARMTYP			= $4000,   // Parameter not permitted
    ERR_PARMVAL			= $8000,   // Invalid Parameter value
    ERRMASK_ILLHANDLE	= $1C00,   // Mask for all Handle errors    
    ERR_ANYBUSERR		= LongWord(ERR_BUSLIGHT) OR LongWord(ERR_BUSHEAVY) OR LongWord(ERR_BUSOFF), // All others error status <> 0 please ask by PEAK ......intern Driver errors.....
    ERR_NO_DLL			= $7FFFFFFF// A Dll could not be loaded or a function was not found into the Dll
);

// Function pointers to load PCANLight functions
//
InitPAP = function (BR: Word; FT: Integer): LongWord; stdcall;                          // init Plug And Play
InitNPAP = function (BR: Word; FT: Integer;
                     HW: Integer; IOP: LongWord; Itr: Word): LongWord; stdcall;         // init Non Plug And Play
C_S_RC_RF = function (): LongWord; stdcall;                                             // Close,Status,ResetClient,ResetFilter
ReadWrite = function (var Msg: TPCANMsg): LongWord; stdcall;                            // CAN_Read CAN_Write
USBSDevNr = function (DN: Longint): LongWord; stdcall;                                  // SetUSBDeviceNumber
USBGDevNr = function (var DN: Longint): LongWord; stdcall;                              // GetUSBDeviceNumber
MessageFilter = function (FI, TI : LongWord; TY: Integer): LongWord; stdcall;           // Set MsgFilter
GetInfo = function (lpszTextBuff: PChar) : LongWord; stdcall;                           // GetDllVersion, VersionInfo
spcFunct = function (DC: LongWord; CN: Integer): LongWord; stdcall;                     // SpecialFunktion

CANLight = Class
    Private
        Class function GetDllHandle(HWType: HardwareType): THandle;

    Public
        Class function Init(HWType: HardwareType ; BTR0BTR1: Baudrates; MsgType: FramesType): CANResult; Overload;
        Class function Init(HWType: HardwareType; BTR0BTR1 : Baudrates; MsgType: FramesType; IO_Port: LongWord; Interrupt: Word): CANResult; Overload;
        Class function Close(HWType: HardwareType): CANResult;
        Class function Status(HWType: HardwareType): CANResult;
        Class function Write(HWType: HardwareType; var MsgToSend: TPCANMsg): CANResult;
        Class function Read(HWType: HardwareType; var MsgToSend: TPCANMsg): CANResult;
        Class function VersionInfo(HWType: HardwareType;var strInfo: string): CANResult;
        Class function SpecialFunktion(HWType: HardwareType; DistributorCode: LongWord; CodeNumber: Integer): CANResult;
        Class function GetDLL2_Version(var Version: string): CANResult;
        Class function ResetClient(HWType: HardwareType): CANResult;
        Class function MsgFilter(HWType: HardwareType; FromId, ToId: LongWord; MsgType: MsgTypes): CANResult;
        Class function ResetFilter(HWType: HardwareType): CANResult;
        Class function SetUSBDeviceNr(HWType: HardwareType; DeviceNumber: Longint): CANResult;
        Class function GetUSBDeviceNr(HWType: HardwareType; var DeviceNumber: Longint): CANResult;
end;

implementation

{ CANLight }


// This Help function intent to load the requested PCANLight Dll
// using first the GetModuleHandle Win32 API function, in order to
// prevent the multiple attachment of a library to the Application.
// If the library is not attached, will be done with the Win32 Api
// LoadLibrary function.
//
Class function CANLight.GetDllHandle(HWType: HardwareType): THandle;
var
    CANLightDll: THandle;
begin
    Case HWType Of
        ISA_1CH:
        begin
            CANLightDll:= GetModuleHandle('PCAN_ISA');
            if CANLightDll = 0 then
                Result:= LoadLibrary('PCAN_ISA')
            else
                Result:= CANLightDll;
        end;
        ISA_2CH:
        begin
            CANLightDll:= GetModuleHandle('PCAN_2ISA');
            if CANLightDll = 0 then
                Result:= LoadLibrary('PCAN_2ISA')
            else
                Result:= CANLightDll;
        end;
        PCI_1CH:
        begin
            CANLightDll:= GetModuleHandle('PCAN_PCI');
            if CANLightDll = 0 then
                Result:= LoadLibrary('PCAN_PCI')
            else
                Result:= CANLightDll;
        end;
        PCI_2CH:
        begin
            CANLightDll:= GetModuleHandle('PCAN_2PCI');
            if CANLightDll = 0 then
                Result:= LoadLibrary('PCAN_2PCI')
            else
                Result:= CANLightDll;
        end;
        PCC_1CH:
        begin
            CANLightDll:= GetModuleHandle('PCAN_PCC');
            if CANLightDll = 0 then
                Result:= LoadLibrary('PCAN_PCC')
            else
                Result:= CANLightDll;
        end;
        PCC_2CH:
        begin
            CANLightDll:= GetModuleHandle('PCAN_2PCC');
            if CANLightDll = 0 then
                Result:= LoadLibrary('PCAN_2PCC')
            else
                Result:= CANLightDll;
        end;
        USB_1CH:
        begin
            CANLightDll:= GetModuleHandle('PCAN_USB');
            if CANLightDll = 0 then
                Result:= LoadLibrary('PCAN_USB')
            else
                Result:= CANLightDll;
        end;
        USB_2CH:
        begin
            CANLightDll:= GetModuleHandle('PCAN_2USB');
            if CANLightDll = 0 then
                Result:= LoadLibrary('PCAN_2USB')
            else
                Result:= CANLightDll;
        end;
        DNP:
        begin
            CANLightDll:= GetModuleHandle('PCAN_DNP');
            if CANLightDll = 0 then
                Result:= LoadLibrary('PCAN_DNP')
            else
                Result:= CANLightDll;
        end;
        DNG:
        begin
            CANLightDll:= GetModuleHandle('PCAN_DNG');
            if CANLightDll = 0 then
                Result:= LoadLibrary('PCAN_DNG')
            else
                Result:= CANLightDll;
        end
    // Hardware is not valid for this function
    //
    else
        Result:= 0;
    end;
end;

// PCANLight Init function for non Plug and Play Hardware.
// This function make the following:
//		- Activate a Hardware
//		- Make a Register Test of 82C200/SJA1000
//		- Allocate a Send buffer and a Hardware handle
//		- Programs the configuration of the transmit/receive driver
//		- Set the Baudrate register
//		- Set the Controller in RESET condition
//
// "HWType" = Which hardware should be initialized
// "BTR0BTR1" = BTR0-BTR1 baudrate register
// "MsgType" = If the frame type is standard or extended
// "IO_Port" = Input/output Port Address of the hardware
// "Interrupt" = Interrupt number
// RETURN = A CANResult value - Error/status of the hardware after execute the function
//
Class function CANLight.Init(HWType: HardwareType; BTR0BTR1: Baudrates;
  MsgType: FramesType; IO_Port: LongWord; Interrupt: Word): CANResult;
var
    CANLightDll : THandle;
    PCLight_Init: InitNPAP;
    HWToInit: Hardware;
    FunctionName: string;
begin
    CANLightDll:= GetDllHandle(HWType);

    Case HWType Of
        ISA_1CH:
        begin
            FunctionName:= 'CAN_Init';
            HWToInit:= HW_ISA_SJA;
        end;
        ISA_2CH:
        begin
            FunctionName:= 'CAN2_Init';
            HWToInit:= HW_ISA_SJA;
        end;
        DNG:
        begin
            FunctionName:= 'CAN_Init';
            HWToInit:= HW_DONGLE_SJA;
        end;
        DNP:
        begin
            FunctionName:= 'CAN_Init';
            HWToInit:= HW_DONGLE_PRO;
        end
        else
        begin
            Result:= ERR_ILLHW;
            Exit;
        end;
    end;

    if CANLightDll <> 0 then
    begin
        @PCLight_Init:= GetProcAddress(CANLightDll,PChar(FunctionName));
        if @PCLight_Init <> nil then
        begin
            Result:= CANResult(PCLight_Init(Word(BTR0BTR1),integer(MsgType),Integer(HWToInit),IO_Port,Word(Interrupt)));
            Exit;
        end;
    end;
    // Error: Dll does not exists or the Init function is not available
    //
    ShowMessage('Error: "DLL could not be loaded!"');
    Result:= ERR_NO_DLL;
end;

// PCANLight Init function for Plug and Play Hardware.
// This function make the following:
//		- Activate a Hardware
//		- Make a Register Test of 82C200/SJA1000
//		- Allocate a Send buffer and a Hardware handle
//		- Programs the configuration of the transmit/receive driver
//		- Set the Baudrate register
//		- Set the Controller in RESET condition
//
// "HWType" = Which hardware should be initialized
// "BTR0BTR1" = BTR0-BTR1 baudrate register
// "MsgType" = If the frame type is standard or extended
// RETURN = A CANResult value - Error/status of the hardware after execute the function
//
Class function CANLight.Init(HWType: HardwareType; BTR0BTR1: Baudrates;
  MsgType: FramesType): CANResult;
var
    CANLightDll : THandle;
    PCLight_Init: InitPAP;
    FunctionName: string;
begin
    // Hardware is not valid for this function
    //
    if ((HWType <> PCI_1CH) AND (HWType <> PCI_2CH) AND (HWType <> PCC_1CH) AND (HWType <> PCC_2CH) AND (HWType <> USB_1CH) AND (HWType <> USB_2CH)) then
    begin
        Result:= ERR_ILLHW;
        Exit;
    end;

    CANLightDll:= GetDllHandle(HWType);

    if (HWType = PCI_2CH) OR (HWType = PCC_2CH) OR (HWType = USB_2CH) then
        FunctionName:= 'CAN2_Init'
    else
        FunctionName:= 'CAN_Init';

    if CANLightDll <> 0 then
    begin
        @PCLight_Init:= GetProcAddress(CANLightDll,PChar(FunctionName));
        if(@PCLight_Init <> nil) then
        begin
            Result:= CANResult(PCLight_Init(Word(BTR0BTR1),Integer(MsgType)));
            Exit;
        end;
    end;

    // Error: Dll does not exists or the Init function is not available
    //
    ShowMessage('Error: "DLL could not be loaded!"');
    Result:= ERR_NO_DLL;
end;      

// PCANLight Close function.
// This function terminate and release all resources and the configured hardware:
//
// "HWType" = Which hardware should be finished
// RETURN = A CANResult value - Error/status of the hardware after execute the function
//
Class function CANLight.Close(HWType: HardwareType): CANResult;
var
    CANLightDll : THandle;
    PCLight_Close: C_S_RC_RF;
    FunctionName: string;
begin
    CANLightDll:= GetDllHandle(HWType);

    if (HWType = ISA_2CH) OR (HWType = PCI_2CH) OR (HWType = PCC_2CH) OR (HWType = USB_2CH) then
        FunctionName:= 'CAN2_Close'
    else
        FunctionName:= 'CAN_Close';

    if CANLightDll <> 0 then
    begin
        @PCLight_Close:= GetProcAddress(CANLightDll,PChar(FunctionName));
        if(@PCLight_Close <> nil) then
        begin
            Result:= CANResult(PCLight_Close);
            Exit;
        end;
    end;

    // Error: Dll does not exists or the Init function is not available
    //
    ShowMessage('Error: "DLL could not be loaded!"');
    Result:= ERR_NO_DLL;
end;

// PCANLight Status Function
// This function request the current status of the hardware (b.e. BUS-OFF)
//
// "HWType" = Which hardware should be asked for it Status
// RETURN = A CANResult value - Error/status of the hardware after execute the function
//
Class function CANLight.Status(HWType: HardwareType): CANResult;
var
    CANLightDll : THandle;
    PCLight_Status: C_S_RC_RF;
    FunctionName: string;
begin
    CANLightDll:= GetDllHandle(HWType);

    if (HWType = ISA_2CH) OR (HWType = PCI_2CH) OR (HWType = PCC_2CH) OR (HWType = USB_2CH) then
        FunctionName:= 'CAN2_Status'
    else
        FunctionName:= 'CAN_Status';

    if CANLightDll <> 0 then
    begin
        @PCLight_Status:= GetProcAddress(CANLightDll,PChar(FunctionName));
        if(@PCLight_Status <> nil) then
        begin
            Result:= CANResult(PCLight_Status);
            Exit;
        end;
    end;

    // Error: Dll does not exists or the Init function is not available
    //
    ShowMessage('Error: "DLL could not be loaded!"');
    Result:= ERR_NO_DLL;
end;


// PCANLight Write function
// This function Place a CAN message into the Transmit Queue of the CAN Hardware
//
// "HWType" = In which hardware should be written the CAN Message
// "MsgToSend" = The TPCANMsg message to be written
// RETURN = A CANResult value - Error/status of the hardware after execute the function
//
Class function CANLight.Write(HWType: HardwareType;
  var MsgToSend: TPCANMsg): CANResult;
var
    CANLightDll : THandle;
    PCLight_Write: ReadWrite;
    FunctionName: string;
begin
    CANLightDll:= GetDllHandle(HWType);

    if (HWType = ISA_2CH) OR (HWType = PCI_2CH) OR (HWType = PCC_2CH) OR (HWType = USB_2CH) then
        FunctionName:= 'CAN2_Write'
    else
        FunctionName:= 'CAN_Write';

    if CANLightDll <> 0 then
    begin
        @PCLight_Write:= GetProcAddress(CANLightDll,PChar(FunctionName));
        if(@PCLight_Write <> nil) then
        begin
            Result:= CANResult(PCLight_Write(MsgToSend));
            Exit;
        end;
    end;

    // Error: Dll does not exists or the Init function is not available
    //
    ShowMessage('Error: "DLL could not be loaded!"');
    Result:= ERR_NO_DLL;
end;

// PCANLight Read function
// This function get the next message or the next error from the Receive Queue of
// the CAN Hardware.
// REMARK:
//		- Check always the type of the received Message (MSGTYPE_STANDARD,MSGTYPE_RTR,
//		  MSGTYPE_EXTENDED,MSGTYPE_STATUS)
//		- The function will return ERR_OK always that you receive a CAN message successfully
//		  although if the messages is a MSGTYPE_STATUS message.
//		- When a MSGTYPE_STATUS mesasge is got, the ID and Length information of the message
//		  will be treated as indefined values. Actually information of the received message
//		  should be interpreted using the first 4 data bytes as follow:
//			*	Data0	Data1	Data2	Data3	Kind of Error
//				0x00	0x00	0x00	0x02	CAN_ERR_OVERRUN		0x0002	CAN Controller was read to late
//				0x00	0x00	0x00	0x04	CAN_ERR_BUSLIGHT	0x0004  Bus Error: An error counter limit reached (96)
//				0x00	0x00	0x00	0x08	CAN_ERR_BUSHEAVY	0x0008	Bus Error: An error counter limit reached (128)
//				0x00	0x00	0x00	0x10	CAN_ERR_BUSOFF		0x0010	Bus Error: Can Controller went "Bus-Off"
//		- If a CAN_ERR_BUSOFF status message is received, the CAN Controller must to be
//		  initialized again using the Init() function.  Otherwise, will be not possible
//		  to send/receive more messages.
//
// "HWType" = From which hardware should be read a CAN Message
// "Msg" = The TPCANMsg structure to store the CAN message
// RETURN = A CANResult value - Error/status of the hardware after execute the function
//
Class function CANLight.Read(HWType: HardwareType;
  var MsgToSend: TPCANMsg): CANResult;
var
    CANLightDll : THandle;
    PCLight_Read: ReadWrite;
    FunctionName: string;
begin
    CANLightDll:= GetDllHandle(HWType);

    if (HWType = ISA_2CH) OR (HWType = PCI_2CH) OR (HWType = PCC_2CH) OR (HWType = USB_2CH) then
        FunctionName:= 'CAN2_Read'
    else
        FunctionName:= 'CAN_Read';

    if CANLightDll <> 0 then
    begin
        @PCLight_Read:= GetProcAddress(CANLightDll,PChar(FunctionName));
        if(@PCLight_Read <> nil) then
        begin
            Result:= CANResult(PCLight_Read(MsgToSend));
            Exit;
        end;
    end;

    // Error: Dll does not exists or the Init function is not available
    //
    ShowMessage('Error: "DLL could not be loaded!"');
    Result:= ERR_NO_DLL;
end;

// PCANLight VersionInfo function
// This function get the Version and copyright of the hardware as text
// (max. 255 characters)
//
// "HWType"  = Which hardware should be asked for its Version information
// "strInfo" = String variable to return the hardware information
// RETURN = A CANResult value - Error/status of the hardware after execute the function
//
Class function CANLight.VersionInfo(HWType: HardwareType;
  var strInfo: string): CANResult;
var
    CANLightDll : THandle;
    PCLight_VersionInfo: GetInfo;
    FunctionName: string;
    ToRead: array [0..254] of Char;
begin
    ToRead:= '';

    CANLightDll:= GetDllHandle(HWType);

    if (HWType = ISA_2CH) OR (HWType = PCI_2CH) OR (HWType = PCC_2CH) OR (HWType = USB_2CH) then
        FunctionName:= 'CAN2_VersionInfo'
    else
        FunctionName:= 'CAN_VersionInfo';

    if CANLightDll <> 0 then
    begin
        @PCLight_VersionInfo:= GetProcAddress(CANLightDll,PChar(FunctionName));
        if(@PCLight_VersionInfo <> nil) then
        begin
            Result:= CANResult(PCLight_VersionInfo(ToRead));
            strInfo:= String(ToRead);
            Exit;
        end;
    end;

    // Error: Dll does not exists or the Init function is not available
    //
    ShowMessage('Error: "DLL could not be loaded!"');
    Result:= ERR_NO_DLL;
end;

// PCANLight SpecialFunktion function
// This function is an special function to be used "ONLY" for distributors
//
// "HWType" = Hardware within use this special function
// "DistributorCode" = Distributor Identification number
// "CodeNumber" = Number code
// RETURN = Literal Numeric value of the CANResult: 1 if the given parameters
// and the parameters in the hardware agree, 0 otherwise
//
Class function CANLight.SpecialFunktion(HWType: HardwareType;
  DistributorCode: LongWord; CodeNumber: Integer): CANResult;
var
    CANLightDll : THandle;
    PCLight_SpecialFunktion: spcFunct;
begin
    if (HWType <> PCI_1CH) AND (HWType <> PCC_1CH) AND (HWType <> USB_1CH) AND (HWType <> USB_2CH) AND (HWType <> DNG) then
    begin
        Result:= ERR_ILLHW;
        Exit;
    end;

    CANLightDll:= GetDllHandle(HWType);

    if CANLightDll <> 0 then
    begin
        @PCLight_SpecialFunktion:= GetProcAddress(CANLightDll,'CAN_SpecialFunktion');
        if(@PCLight_SpecialFunktion <> nil) then
        begin
            Result:= CANResult(PCLight_SpecialFunktion(DistributorCode,CodeNumber));
            Exit;
        end;
    end;

    // Error: Dll does not exists or the Init function is not available
    //
    ShowMessage('Error: "DLL could not be loaded!"');
    Result:= ERR_NO_DLL;
end;

// PCANLight GetDLL2_Version function
// This function work only for the PCI 2 Channels hardware. It is used to get
// the Version and copyright of the DLL as text (max. 255 characters)
//
// "Version" = String variable to return the hardware information
// RETURN = Literal Numeric value of the CANResult: 0xFFFFFFFF if the
// variable is not valid, otherwise is OK
//
Class function CANLight.GetDLL2_Version(var Version: string): CANResult;
var
    CANLightDll : THandle;
    PCLight_GetDLL2_Version: GetInfo;
    ToRead: Array [0..254] of Char;
begin
    ToRead:= '';
    CANLightDll:= GetDllHandle(PCI_2CH);

    if CANLightDll <> 0 then
    begin
        @PCLight_GetDLL2_Version:= GetProcAddress(CANLightDll,'GetDLL2_Version');
        if(@PCLight_GetDLL2_Version <> nil) then
        begin
            Result:= CANResult(PCLight_GetDLL2_Version(ToRead));
            Version:= ToRead;
            Exit;
        end;
    end;

    // Error: Dll does not exists or the Init function is not available
    //
    ShowMessage('Error: "DLL could not be loaded!"');
    Result:= ERR_NO_DLL;
end;

// PCANLight ResetClient function
// This function delete the both queues (Transmit,Receive) of the CAN Controller
// using a RESET
//
// "HWType" = Hardware to reset
// RETURN = A CANResult value - Error/status of the hardware after execute the function
//
Class function CANLight.ResetClient(HWType: HardwareType): CANResult;
var
    CANLightDll : THandle;
    PCLight_ResetClient: C_S_RC_RF;
    FunctionName: string;
begin
    CANLightDll:= GetDllHandle(HWType);

    if (HWType = ISA_2CH) OR (HWType = PCI_2CH) OR (HWType = PCC_2CH) OR (HWType = USB_2CH) then
        FunctionName:= 'CAN2_ResetClient'
    else
        FunctionName:= 'CAN_ResetClient';

    if CANLightDll <> 0 then
    begin
        @PCLight_ResetClient:= GetProcAddress(CANLightDll,PChar(FunctionName));
        if(@PCLight_ResetClient <> nil) then
        begin
            Result:= CANResult(PCLight_ResetClient);
            Exit;
        end;
    end;

    // Error: Dll does not exists or the Init function is not available
    //
    ShowMessage('Error: "DLL could not be loaded!"');
    Result:= ERR_NO_DLL;
end;

// PCANLigth MsgFilter function
// This function set the receive message filter of the CAN Controller.
// REMARK:
//		- A quick register of all messages is possible using the parameters From and To as 0
//		- Every call of this function maybe cause an extention of the receive filter of the
//		  CAN controller, which one can go briefly to RESET
//		- New in Ver 2.x:
//			* Standard frames will be put it down in the acc_mask/code as Bits 28..13
//			* Hardware driver for 82C200 must to be moved to Bits 10..0 again!
//	WARNING:
//		It is not guaranteed to receive ONLY the registered messages.
//
// "HWType" = Hardware which applay the filter to
// "From" = First/Start Message ID - It muss be smaller than the "To" parameter
// "To" = Last/Finish Message ID - It muss be bigger than the "From" parameter
// "MsgType" = Kind of Frame - Standard or Extended
// RETURN = A CANResult value - Error/status of the hardware after execute the function
//
Class function CANLight.MsgFilter(HWType: HardwareType; FromId, ToId: LongWord;
  MsgType: MsgTypes): CANResult;
var
    CANLightDll : THandle;
    PCLight_MsgFilter: MessageFilter;
    FunctionName: string;
begin
    CANLightDll:= GetDllHandle(HWType);

    if (HWType = ISA_2CH) OR (HWType = PCI_2CH) OR (HWType = PCC_2CH) OR (HWType = USB_2CH) then
        FunctionName:= 'CAN2_MsgFilter'
    else
        FunctionName:= 'CAN_MsgFilter';

    if CANLightDll <> 0 then
    begin
        @PCLight_MsgFilter:= GetProcAddress(CANLightDll,PChar(FunctionName));
        if(@PCLight_MsgFilter <> nil) then
        begin
            Result:= CANResult(PCLight_MsgFilter(FromId,ToId,Integer(MsgType)));
            Exit;
        end;
    end;

    // Error: Dll does not exists or the Init function is not available
    //
    ShowMessage('Error: "DLL could not be loaded!"');
    Result:= ERR_NO_DLL;
end;

// PCANLigth ResetFilter function
// This function close completely the Message Filter of the Hardware.
// They will be no more messages received.
//
// "HWType" = Hardware to reset its filter
// RETURN = A CANResult value - Error/status of the hardware after execute the function</returns>
//
Class function CANLight.ResetFilter(HWType: HardwareType): CANResult;
var
    CANLightDll : THandle;
    PCLight_ResetFilter: C_S_RC_RF;
    FunctionName: string;
begin
    CANLightDll:= GetDllHandle(HWType);

    if (HWType = ISA_2CH) OR (HWType = PCI_2CH) OR (HWType = PCC_2CH) OR (HWType = USB_2CH) then
        FunctionName:= 'CAN2_ResetFilter'
    else
        FunctionName:= 'CAN_ResetFilter';

    if CANLightDll <> 0 then
    begin
        @PCLight_ResetFilter:= GetProcAddress(CANLightDll,PChar(FunctionName));
        if(@PCLight_ResetFilter <> nil) then
        begin
            Result:= CANResult(PCLight_ResetFilter);
            Exit;
        end;
    end;

    // Error: Dll does not exists or the Init function is not available
    //
    ShowMessage('Error: "DLL could not be loaded!"');
    Result:= ERR_NO_DLL;
end;

// PCANLight SetUSBDeviceNr function
// This function set an identification number to the USB CAN hardware
//
// "DeviceNumber" = Value to be set as Device Number
// RETURN = A CANResult value - Error/status of the hardware after execute the function
//
Class function CANLight.SetUSBDeviceNr(HWType: HardwareType; DeviceNumber: Integer): CANResult;
var
    CANLightDll : THandle;
    PCLight_SetUSBDeviceNr: USBSDevNr;
    FunctionName: string;    
begin
    case HWType of
        USB_1CH: 
        begin
        CANLightDll:= GetDllHandle(USB_1CH);
        FunctionName:= 'SetUSBDeviceNr'
        end;
        USB_2CH: 
        begin
        CANLightDll:= GetDllHandle(USB_2CH);
        FunctionName:= 'SetUSB2DeviceNr'
        end
    else
        begin
        Result := ERR_ILLHW;
        exit;
        end;
    end;

    if CANLightDll <> 0 then
    begin
        @PCLight_SetUSBDeviceNr:= GetProcAddress(CANLightDll,PChar(FunctionName));
        if(@PCLight_SetUSBDeviceNr <> nil) then
        begin
            Result:= CANResult(PCLight_SetUSBDeviceNr(DeviceNumber));
            Exit;
        end;
    end;

    // Error: Dll does not exists or the Init function is not available
    //
    ShowMessage('Error: "DLL could not be loaded!"');
    Result:= ERR_NO_DLL;
end;

// PCANLight GetUSBDeviceNr function
// This function read the device number of a USB CAN Hardware
//
// "DeviceNumber" = Variable to return the Device Number value
// RETURN = A CANResult value - Error/status of the hardware after execute the function
//
Class function CANLight.GetUSBDeviceNr(HWType: HardwareType; var DeviceNumber: Integer): CANResult;
var
    CANLightDll : THandle;
    PCLight_GetUSBDeviceNr: USBGDevNr;
    FunctionName: string;    
begin
    case HWType of
        USB_1CH: 
        begin
        CANLightDll:= GetDllHandle(USB_1CH);
        FunctionName:= 'GetUSBDeviceNr'        
        end;
        USB_2CH: 
        begin
        CANLightDll:= GetDllHandle(USB_2CH);
        FunctionName:= 'GetUSB2DeviceNr'        
        end
    else
        begin
        Result := ERR_ILLHW;
        exit;
        end;
    end;

    if CANLightDll <> 0 then
    begin
        @PCLight_GetUSBDeviceNr:= GetProcAddress(CANLightDll,PChar(FunctionName));
        if(@PCLight_GetUSBDeviceNr <> nil) then
        begin
            Result:= CANResult(PCLight_GetUSBDeviceNr(DeviceNumber));
            Exit;
        end;
    end;

    // Error: Dll does not exists or the Init function is not available
    //
    ShowMessage('Error: "DLL could not be loaded!"');
    Result:= ERR_NO_DLL;
end;


end.
