unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, ComCtrls, PCANLight;

type
MessageStatuspointer = ^MessageStatus;
MessageStatus = record
    Msg : TPCANMsg;
    iIndex : integer;
end;

  TForm1 = class(TForm)
    GroupBox1: TGroupBox;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    cbbHws: TComboBox;
    btnInfo: TButton;
    btnInit: TButton;
    btnRelease: TButton;
    cbbBaudrates: TComboBox;
    cbbMsgType: TComboBox;
    cbbIO: TComboBox;
    cbbInterrupt: TComboBox;
    GroupBox2: TGroupBox;
    Label6: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    txtID: TEdit;
    nudLength: TUpDown;
    txtLength: TEdit;
    txtData0: TEdit;
    txtData1: TEdit;
    txtData2: TEdit;
    txtData3: TEdit;
    txtData4: TEdit;
    txtData5: TEdit;
    txtData6: TEdit;
    txtData7: TEdit;
    chbExtended: TCheckBox;
    chbRemote: TCheckBox;
    btnWrite: TButton;
    GroupBox3: TGroupBox;
    lstMessages: TListView;
    GroupBox4: TGroupBox;
    txtInfo: TMemo;
    tmrRead: TTimer;
    btnClose: TButton;
    GroupBox5: TGroupBox;
    Label9: TLabel;
    Label10: TLabel;
    rdbStandard: TRadioButton;
    rdbExtended: TRadioButton;
    txtIdFrom: TEdit;
    txtIdTo: TEdit;
    btnSetFilter: TButton;
    btnResetFilter: TButton;
    btnGetDeviceNumber: TButton;
    btnSetDeviceNumber: TButton;
    ediDeviceNumber: TEdit;
    nudDeviceNumber: TUpDown;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure cbbHwsChange(Sender: TObject);
    procedure cbbBaudratesChange(Sender: TObject);
    procedure txtIDKeyPress(Sender: TObject; var Key: Char);
    procedure txtIDExit(Sender: TObject);
    procedure nudLengthClick(Sender: TObject; Button: TUDBtnType);
    procedure txtData0Exit(Sender: TObject);
    procedure chbExtendedClick(Sender: TObject);
    procedure chbRemoteClick(Sender: TObject);
    procedure txtInfoDblClick(Sender: TObject);
    procedure lstMessagesDblClick(Sender: TObject);
    procedure tmrReadTimer(Sender: TObject);
    procedure btnInitClick(Sender: TObject);
    procedure btnInfoClick(Sender: TObject);
    procedure btnReleaseClick(Sender: TObject);
    procedure btnWriteClick(Sender: TObject);
    procedure btnCloseClick(Sender: TObject);
    procedure rdbStandardClick(Sender: TObject);
    procedure txtIdFromExit(Sender: TObject);
    procedure btnSetFilterClick(Sender: TObject);
    procedure btnResetFilterClick(Sender: TObject);
    procedure btnSetDeviceNumberClick(Sender: TObject);
    procedure btnGetDeviceNumberClick(Sender: TObject);
  private
    // Save the current initiated hardware type
    //
    ActiveHardware: HardwareType;

    // CAN messages Array. Store the Message Status for its display
    //
    LastMsgsList : TList;

    procedure ModifyMsgEntry(LastMsg : MessageStatus;NewMsg : TPCANMsg);
    procedure InsertMsgEntry(NewMsg : TPCANMsg);
    procedure ProcessMessage(MyMsg : TPCANMsg);

  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

procedure TForm1.InsertMsgEntry(NewMsg: TPCANMsg);
var
    strNewData,strTemp : string;
    CurrItem : TListItem;
    ToInsert : MessageStatusPointer;
    I : integer;
begin

    strTemp := '';
    strNewData := '';

    // Add the new ListView Item with the Type of the message
    //
    if((NewMsg.MSGTYPE AND Byte(MSGTYPE_EXTENDED)) <> 0)then
        strTemp := 'EXTENDED'
    else
        strTemp := 'STANDARD';

    if((NewMsg.MSGTYPE AND Byte(MSGTYPE_RTR)) = Byte(MSGTYPE_RTR))then
        strTemp := (strTemp + '/RTR');

    CurrItem := lstMessages.Items.Add();
    CurrItem.Caption:= strTemp;

    // We format the ID of the message and show it
    //
    if((NewMsg.MSGTYPE AND Byte(MSGTYPE_EXTENDED)) <> 0)then
        CurrItem.SubItems.Add(IntToHex(NewMsg.ID,8) + 'h')
    else
        CurrItem.SubItems.Add(IntToHex(NewMsg.ID,3) + 'h');

    // We set the length of the Message
    //
    CurrItem.SubItems.Add(IntToStr(NewMsg.LEN));

    // We format the data of the message. Each data is one
    // byte of Hexadecimal data
    //
    if((NewMsg.MSGTYPE AND Byte(MSGTYPE_RTR)) = Byte(MSGTYPE_RTR))then
        strNewData := 'Remote Request'
    else
        for I:=0 To NewMsg.LEN-1 do
            strNewData := (strNewData + IntToHex(NewMsg.DATA[I],2) + ' ');

    CurrItem.SubItems.Add(strNewData);

    // The message is the First, so count is 1
    //
    CurrItem.SubItems.Add('1');

    // We add this status in the last message list
    //
    New(ToInsert);
    ToInsert.Msg := NewMsg;
    ToInsert.iIndex := CurrItem.Index;
    LastMsgsList.Add(ToInsert);
end;

procedure TForm1.ModifyMsgEntry(LastMsg: MessageStatus; NewMsg: TPCANMsg);
var
    strLastData, strNewData : string;
    NewStatus,ToDelete : MessageStatusPointer;
    CurrItem : TListItem;
    I, iLen, iCount : Integer;
begin
    strNewData := '';
    strLastData := '';

    // Values from the last messages
    //
    CurrItem := lstMessages.Items.Item[LastMsg.iIndex];
    iCount := StrToInt(CurrItem.SubItems.Strings[3]);
    strLastData := CurrItem.SubItems.Strings[2];;
    iLen := LastMsg.Msg.LEN;

    // New values
    //
    if((NewMsg.MSGTYPE AND byte(MSGTYPE_RTR)) <> 0)then
        strNewData := 'Remote Request'
    else
        for I:=0 To NewMsg.LEN-1 do
            strNewData := (strNewData + IntToHex(NewMsg.DATA[I],2) + ' ');

    // Count is updated
    //
    iCount := iCount + 1;

    // Set the changes
    //
    if(iLen <> NewMsg.LEN)then
    begin
        iLen := NewMsg.LEN;
        CurrItem.SubItems.Strings[1] := IntToStr(iLen);
    end;

    if(strLastData <> strNewData)then
        CurrItem.SubItems.Strings[2] := strNewData;

    CurrItem.SubItems.Strings[3] := IntToStr(iCount);

    // Save the new Status of the message
    // NOTE: The objects are saved in the same index position which
    // they use in the Listview
    //
    New(NewStatus);
    NewStatus.Msg := NewMsg;
    NewStatus.iIndex := LastMsg.iIndex;

    ToDelete := LastMsgsList.Items[LastMsg.iIndex];
    LastMsgsList.Delete(LastMsg.iIndex);
    Dispose(ToDelete);
    LastMsgsList.Insert(LastMsg.iIndex,NewStatus);
end;

procedure TForm1.ProcessMessage(MyMsg: TPCANMsg);
var
    bFound : boolean;
    CurrMessage : MessageStatusPointer;
    I : Integer;
begin
    bFound := false;
    CurrMessage := nil;

    // We search if a message (Smae ID, Type and same Net) is
    // already received or if this is a new message
    //
    for I:=0 To LastMsgsList.Count-1 do
    begin
        CurrMessage := LastMsgsList.Items[i];
        if(CurrMessage.Msg.ID = MyMsg.ID)then
            if(CurrMessage.Msg.MSGTYPE = MyMsg.MSGTYPE)then
            begin
                bFound := true;
                break;
            end;
    end;

    if(bFound)then
        // Messages of this kind are already received; we make an update
        //
        ModifyMsgEntry(CurrMessage^,MyMsg)
    else
        // Messages of this kind are not received; we make a new entry
        //
        InsertMsgEntry(MyMsg);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
	// We set the variable to know which hardware is
	// currently selected (none!)
	//
    ActiveHardware:= HardwareType(-1);

	// Create a list to store the displayed mesasges
	//
    LastMsgsList := TList.Create;

    // Set the standard values in the interface
    //
    cbbHws.ItemIndex:= 0;
    cbbBaudrates.ItemIndex:= 0;
    cbbIO.ItemIndex:= 18;
    cbbInterrupt.ItemIndex:= 3;
    cbbMsgType.ItemIndex:= 0;

    cbbBaudratesChange(self);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    tmrRead.Enabled:= false;

    if btnRelease.Enabled then
        btnRelease.Click;

    while (LastMsgsList.Count > 0) do
    begin
        Dispose(LastMsgsList.First);
        LastMsgsList.Delete(0);
    end;
    LastMsgsList.Free;
end;

procedure TForm1.cbbHwsChange(Sender: TObject);
var
    bShowIO: Boolean;
    current : HardwareType;
begin

    current := HardwareType(cbbHws.ItemIndex);

    // According with the selection in the Hardware list,
    // we show/hide the input controls for I/O Address and
    // Interrupt. (This parameters are NOT necessary for all
    // hardware types) .
    //
    Case current of
        DNG:
            bShowIO:= true;
        DNP:
            bShowIO:= true;
        ISA_1CH:
            bShowIO:= true;
        ISA_2CH:
            bShowIO:= true;
        else
            bShowIO:= false;
    end;

    cbbIO.Enabled:= bShowIO;
    cbbInterrupt.Enabled:= bShowIO;

	// According with the selection in the Hardware list, we 
	// Enable/Disable the controls for Get/Set the USB device Number.
	//
	btnGetDeviceNumber.Enabled := (current = USB_1CH) Or (current = USB_2CH);
	btnSetDeviceNumber.Enabled := (btnGetDeviceNumber.Enabled);
	nudDeviceNumber.Enabled := (btnGetDeviceNumber.Enabled);
end;

procedure TForm1.cbbBaudratesChange(Sender: TObject);
begin
    // We save the corresponding Baudrate enumeration
    // type value for every selected Baudrate from the
    // list.
    //
    Case cbbBaudrates.ItemIndex Of
        0:
            cbbBaudrates.Tag:= Integer(BAUD_1M);
        1:
            cbbBaudrates.Tag:= Integer(BAUD_500K);
        2:
            cbbBaudrates.Tag:= Integer(BAUD_250K);
        3:
            cbbBaudrates.Tag:= Integer(BAUD_125K);
        4:
            cbbBaudrates.Tag:= Integer(BAUD_100K);
        5:
            cbbBaudrates.Tag:= Integer(BAUD_50K);
        6:
            cbbBaudrates.Tag:= Integer(BAUD_20K);
        7:
            cbbBaudrates.Tag:= Integer(BAUD_10K);
        8:
            cbbBaudrates.Tag:= Integer(BAUD_5K);
        else
            cbbBaudrates.Tag:= 0;
    end;
end;

procedure TForm1.txtIDKeyPress(Sender: TObject; var Key: Char);
begin
    // We convert the Character to its Upper case equivalent
    //
    Key := (UpperCase(Key))[1];

    // The Key is the Delete (Backspace) Key
    //
    if(Ord(Key) = 8)then
        exit;
    // The Key is a number between 0-9
    //
    if((Ord(Key) > 47)AND(Ord(Key) < 58))then
        exit;
    // The Key is a character between A-F
    //
    if((Ord(Key) > 64)AND(Ord(Key) < 71))then
        exit;

    // Is neither a number nor a character between A(a) and F(f)
    //
    Key := #0;
end;

procedure TForm1.txtIDExit(Sender: TObject);
var
    TextLength, MaxValue : Integer;
begin
    // calculate the text length and Maximum ID value according
    // with the Message Type
    //
    if(chbExtended.Checked)then
      TextLength := 8
    else
      TextLength := 3;
    if(chbExtended.Checked)then
      MaxValue := $1FFFFFF
    else
      MaxValue := $7FF;

    // The Textbox for the ID is represented with 3 characters for
    // Standard and 8 characters for extended messages.
    // Therefore if the Length of the text is smaller than TextLength,
    // we add "0"
    //
    while(Length(txtID.Text) <> TextLength)do
        txtID.Text := ('0' + txtID.Text);

    // Because in this example will be sent only Standard messages
    // we check that the ID is not bigger than 0x7FF
    //
    if(StrToInt('$' + txtID.Text) > MaxValue)then
        txtID.Text := IntToHex(MaxValue,TextLength);
end;

procedure TForm1.nudLengthClick(Sender: TObject; Button: TUDBtnType);
var
    CurrentTextBox : TEdit;
    I : Integer;
begin
    // We enable so much TextBox Data fields as the length of the
    // message will be, that is the value of the UpDown control
    //
    for I:=0 to 7 do
    begin
        CurrentTextBox := TEdit(FindComponent('txtData'+IntToStr(I)));
        if(I < nudLength.Position)then
          CurrentTextBox.Enabled := true
        else
          CurrentTextBox.Enabled := false;
    end;
end;

procedure TForm1.txtData0Exit(Sender: TObject);
var
  CurrentEdit : TEdit;
begin
    if(String(Sender.ClassName) = 'TEdit')then
    begin
        CurrentEdit := TEdit(Sender);
        while(Length(CurrentEdit.Text) <> 2)do
            CurrentEdit.Text := ('0' + CurrentEdit.Text);
    end;
end;

procedure TForm1.chbExtendedClick(Sender: TObject);
var
    iTemp : Integer;
begin
    if(chbExtended.Checked)then
      txtID.MaxLength := 8
    else
      txtID.MaxLength := 3;

    // the only way that the text length can be bigger als MaxLength
    // is when the change is from Extended to Standard message Type.
    // We have to handle this and set an ID not bigger than the Maximum
    // ID value for a Standard Message (0x7FF)
    //
    if(Length(txtID.Text) > txtID.MaxLength)then
    begin
        iTemp := StrToInt('$' + txtID.Text);
        if(iTemp < $7FF)then
          txtID.Text := IntToHex(iTemp,3)
         else
           txtID.Text := '7FF';
    end;

    txtIDExit(txtID);
end;

procedure TForm1.chbRemoteClick(Sender: TObject);
var
    CurrentTextBox : TEdit;
    I : Integer;
begin
    // We enable so much TextBox Data fields as the length of the
    // message will be, that is the value of the UpDown control.
    //
    for I:=0 To 7 do
    begin
        CurrentTextBox := TEdit(FindComponent('txtData' + IntToStr(I)));
        CurrentTextBox.Visible := Not chbRemote.Checked;
    end;
end;

procedure TForm1.txtInfoDblClick(Sender: TObject);
begin
    // We clear the Information edit box
    //
    txtInfo.Text:= '';
end;

procedure TForm1.lstMessagesDblClick(Sender: TObject);
begin
    lstMessages.Items.Clear();
    while(LastMsgsList.Count >0)do
    begin
        Dispose(LastMsgsList.First);
        LastMsgsList.Delete(0);
    end;
end;

procedure TForm1.tmrReadTimer(Sender: TObject);
var
    MyMsg : TPCANMsg;
    Res: CANResult;
begin
    // We read at least one time the queue looking for messages.
    // If a message is found, we look again trying to find more.
    // If the queue is empty or an error occurr, we get out from
    // the dowhile statement.
    //
    repeat
        // We read the queue looking for messages.
        //
        Res:= CANLight.Read(ActiveHardware,MyMsg);

        // A message was received
        // We process the message(s)
        //
        if Res = ERR_OK then
            ProcessMessage(MyMsg);
    until ((DWORD(Res) AND DWORD(ERR_QRCVEMPTY)) = DWORD(ERR_QRCVEMPTY));
end;

procedure TForm1.btnInfoClick(Sender: TObject);
var
    strInfo: string;
    Res: CANResult;
    I: Integer;
begin
    I:= 1;
    // We execute the "VersionInfo" function of the PCANLight
    // using as parameter the Hardware type and a string
    // variable to get the info.
    //
    Res:= CANLight.VersionInfo(HardwareType(cbbHws.ItemIndex),strInfo);
    while I < Length(strInfo) do
    begin
        if IsDelimiter(#10,strInfo,I) then
        begin
            Delete(strInfo,I,1);
            Insert(#13#10,strInfo,I);
            i:= I + 2;
        end
        else
            I:= I + 1;
    end;

    // The function was successfully executed
    //
    if Res = ERR_OK then
        // We show the Version Information
        //
        txtInfo.Text:= strInfo
        // An error occurred.  We show the error.
        //
    else
        txtInfo.Text:= 'Error Number: ' + IntToHex(Integer(Res),4) + 'h';
end;
procedure TForm1.btnInitClick(Sender: TObject);
var
    Res: CANResult;
begin
    // According with the active parameters/hardware, we
    // use one of the two possible "Init" PCANLight functions.
    // One is for Plug And Play hardware, and the other for
    // Not P&P.
    //
    if cbbIO.Enabled then
        // Not P&P Hardware
        //
        Res:= CANLight.Init(HardwareType(cbbHws.ItemIndex),
            Baudrates(cbbBaudrates.Tag),
            FramesType(cbbMsgType.ItemIndex),
            StrToInt('$' + cbbIO.Text),
            StrToInt(cbbInterrupt.Text))
    else
        // P&P Hardware
        //
        Res:= CANLight.Init(HardwareType(cbbHws.ItemIndex),
            Baudrates(cbbBaudrates.Tag),
            FramesType(cbbMsgType.ItemIndex));

    // The Hardware was successfully initiated
    //
    if Res = ERR_OK then
    begin
        // We save the hardware type which is currently
        // initiated
        //
        ActiveHardware:= HardwareType(cbbHws.ItemIndex);

        // We start to read from the CAN Queue
        //
        tmrRead.Enabled:= true;

        // We show the information of the configured
        // and initiated hardware
        //
        btnWrite.Enabled:= true;
        btnRelease.Enabled:= true;
        btnSetFilter.Enabled := true;
        btnResetFilter.Enabled := true;
        btnInit.Enabled:= false;
        txtInfo.Text:= 'Active Hardware: ' + cbbHws.Text;
        txtInfo.Text:= txtInfo.Text + #13#10 + 'Baud Rate: ' + cbbBaudrates.Text;
        txtInfo.Text:= txtInfo.Text + #13#10 + 'Frame Type: ' + cbbMsgType.Text;
        // If was a no P&P Hardware, we show additional information
        //
        if cbbIO.Enabled then
        begin
            txtInfo.Text:= txtInfo.Text + #13#10 + 'I/O Addr.: ' + cbbIO.Text + 'h';
            txtInfo.Text:= txtInfo.Text + #13#19 + 'Interrupt: ' + cbbInterrupt.Text;
        end;
    end
    // An error occurred.  We show the error.
    //
    else
        txtInfo.Text:= 'Error Number: ' + IntToHex(Integer(Res),4) + 'h';
end;

procedure TForm1.btnReleaseClick(Sender: TObject);
var
    Res: CANResult;
begin
    // We stopt to read from tehe CAN Queue
    //
    tmrRead.Enabled:= false;

    // We close the active hardware using the
    // "Close" function of the PCANLight using
    // as parameter the Hardware type.
    //
    Res:= CANLight.Close(ActiveHardware);

    // The Hardware was successfully closed
    //
    if Res = ERR_OK then
        txtInfo.Text:= 'Hardware was successfully Released.' + #13#10
    // An error occurred.  We show the error.
    //
    else
        txtInfo.Text:= 'Error Number: ' + IntToHex(Integer(Res),4) + 'h';

    // We set the varibale of active hardware to None
    // and activate/deactivate the corresponding buttons
    //
    ActiveHardware:= HardwareType(-1);
    btnInit.Enabled:= true;
    btnWrite.Enabled:= false;
    btnRelease.Enabled:= false;
    btnSetFilter.Enabled := false;
    btnResetFilter.Enabled := false;
end;

procedure TForm1.btnWriteClick(Sender: TObject);
var
    MsgToSend : TPCANMsg;
    CurrentTextBox : TEdit;
    I : Integer;
    Res: CANResult;
begin
    // We configurate the Message.  The ID (max 0x1FF),
    // Length of the Data, Message Type (Standard in
    // this example) and die data
    //
    MsgToSend.ID := StrToInt('$' + txtID.Text);
    MsgToSend.LEN := nudLength.Position;

    if(chbExtended.Checked)then
      MsgToSend.MSGTYPE := Byte(MSGTYPE_EXTENDED)
    else
      MsgToSend.MSGTYPE := Byte(MSGTYPE_STANDARD);

    if(chbRemote.Checked)then
      MsgToSend.MSGTYPE := Byte(MsgToSend.MSGTYPE) OR Byte(MSGTYPE_RTR)
    else
      // We get so much data as the Len of the message
      //
      for I:=0 To MsgToSend.LEN-1 do
      begin
        CurrentTextBox := TEdit(FindComponent('txtData'+IntToStr(I)));
        MsgToSend.DATA[i] := StrToInt('$' + CurrentTextBox.Text);
      end;


    Res := CANLight.Write(ActiveHardware,MsgToSend);

    // The Hardware was successfully sent
    //
    if Res = ERR_OK then
        txtInfo.Text:= 'Message was successfully SENT.'+#13#10
    // An error occurred.  We show the error.
    //
    else
        txtInfo.Text:= 'Error Number: ' + IntToHex(Integer(Res),4) + 'h';
end;

procedure TForm1.btnCloseClick(Sender: TObject);
begin
    // We terminate the application
    //
    Close;
end;

procedure TForm1.rdbStandardClick(Sender: TObject);
var
    uiTemp : integer;
begin
    if (rdbExtended.Checked) then
        txtIdFrom.MaxLength := 8
    else
        txtIdFrom.MaxLength := 3;

    txtIdTo.MaxLength := txtIdFrom.MaxLength;

    // the only way that the text length can be bigger als MaxLength
    // is when the change is from Extended to Standard message Type.
    // We have to handle this and set an ID not bigger than the Maximum
    // ID value for a Standard Message (0x7FF)
    //
    if (Length(txtIdFrom.Text) > txtIdFrom.MaxLength) then
    begin
        uiTemp :=  StrToInt('0x' + txtIdFrom.Text);
        if (uiTemp < $7FF) then
            txtIdFrom.Text := IntToHex(uiTemp,3)
        else
            txtIdFrom.Text := '7FF';
    end;
    if (Length(txtIdTo.Text) > txtIdTo.MaxLength) then
    begin
        uiTemp := StrToInt('0x' + txtIdTo.Text);
        if(uiTemp < $7FF) then
            txtIdTo.Text := IntToHex(uiTemp,3)
        else
            txtIdTo.Text := '7FF';
    end;
end;

procedure TForm1.txtIdFromExit(Sender: TObject);
var
    TextLength, MaxValue : integer;
    IdBox : TEdit;
begin
    IdBox := TEdit(Sender);

    // calculate the text length and Maximum ID value according
    // with the Message Type
    //
    if (rdbExtended.Checked) then
    begin
        TextLength := 8;
        MaxValue := $1FFFFFFF;
    end
    else
    begin
        TextLength := 3;
        MaxValue := $7FF;
    end;


    // The Textbox for the ID is represented with 3 characters for
    // Standard and 8 characters for extended messages.
    // Therefore if the Length of the text is smaller than TextLength,
    // we add "0"
    //
    while(Length(IdBox.Text) <> TextLength) do
        IdBox.Text := ('0' + IdBox.Text);

    // Because in this example will be sent only Standard messages
    // we check that the ID is not bigger than 0x7FF
    //
    if (StrToInt('$' + IdBox.Text) > MaxValue) then
        IdBox.Text := IntToHex(MaxValue,TextLength);
end;

procedure TForm1.btnSetFilterClick(Sender: TObject);
var
    FromID, ToID : LongWord;
    Res : CANResult;
begin
    // The range IDs is read
    //
    FromID := StrToInt('$' + txtIdFrom.Text);
    ToID := StrToInt('$' + txtIdTo.Text);

    // The desired Filter is set on the configured Hardware
    //
    if (rdbStandard.Checked) then
        Res := CANLight.MsgFilter(ActiveHardware,FromID,ToID,MSGTYPE_STANDARD)
    else
        Res := CANLight.MsgFilter(ActiveHardware,FromID,ToID,MSGTYPE_EXTENDED);

    // The Filter was successfully set
    //
    if(Res = ERR_OK)then
        txtInfo.Text := 'Filter was successfully SET.'+#13#10
        // An error occurred.  We show the error.
        //
    else
        txtInfo.Text := 'Error Number: ' + IntToHex(Integer(Res),4) + 'h';
end;

procedure TForm1.btnResetFilterClick(Sender: TObject);
var
    Res : CANResult;
begin
    // The current Filter on the configured Hardware is reset
    //
    Res := CANLight.ResetFilter(ActiveHardware);

    // The Filter was successfully reset
    //
    if (Res = ERR_OK) then
        txtInfo.Text := 'Filter was successfully RESET.' + #13#10
    // An error occurred.  We show the error.
    //
    else
        txtInfo.Text := 'Error Number: ' + IntToHex(Integer(Res),4) + 'h';
end;

procedure TForm1.btnGetDeviceNumberClick(Sender: TObject);
var
    i : longint;
    Res : CANResult;
begin
	// The USB Device Number will asked
	//
	Res := CANLight.GetUSBDeviceNr(HardwareType(cbbHws.ItemIndex), i);

	// The Device number was got successfully
	//
	if(Res = ERR_OK) then
		txtInfo.Text := 'USB Device Number is: ' +  IntToStr(i) + #13#10
		// An error occurred.  We show the error.
		//
	else
		txtInfo.Text := 'Error Number: 0x' + IntToHex(Integer(Res),4);
end;

procedure TForm1.btnSetDeviceNumberClick(Sender: TObject);
var
	Res : CANResult;
begin
	// The USB Device Number will set
	//
	Res := CANLight.SetUSBDeviceNr(HardwareType(cbbHws.ItemIndex), nudDeviceNumber.Position);

	// The Device number was set successfully
	//
	if(Res = ERR_OK) then
		txtInfo.Text  := 'USB Device Number was set'
		// An error occurred.  We show the error.
		//
	else
		txtInfo.Text := 'Set USB Device Number failed: 0x' + IntToHex(Integer(Res),4);
end;

end.
