unit Unit1;

interface

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

type
    MessageStatus = class(TObject)
        private
            m_Msg : TPCANMsg;
            m_TimeStamp : TPCANTimestamp;
            m_oldTimeStamp : TPCANTimestamp;
            m_iIndex : integer;
            m_Count : integer;
            m_bShowPeriod : boolean;
            m_bWasChanged : boolean;

            function GetMsgTypeString : AnsiString;
            function GetIdString : AnsiString;
            function GetDataString : AnsiString;
            function GetTimeString : AnsiString;

            procedure SetShowingPeriod(value : boolean);

        public
            constructor Create(canMsg : TPCANMsg; canTimestamp : TPCANTimestamp; listIndex : Integer);
            procedure Update(canMsg : TPCANMsg ; canTimestamp : TPCANTimestamp);

            property CANMsg : TPCANMsg read  m_Msg;
            property Timestamp : TPCANTimestamp read m_TimeStamp;
            property Position : Integer read m_iIndex;
            property TypeString : AnsiString read GetMsgTypeString;
            property IdString : AnsiString read GetIdString;
            property DataString : AnsiString read GetDataString;
            property Count : Integer read m_Count;
            property ShowingPeriod : boolean read m_bShowPeriod write SetShowingPeriod;
            property MarkedAsUpdated : boolean read m_bWasChanged write m_bWasChanged;
            property TimeString : AnsiString read GetTimeString;
    end;

  TForm1 = class(TForm)
    GroupBox1: TGroupBox;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    cbbChannel: TComboBox;
    btnHwRefresh: TButton;
    cbbBaudrates: TComboBox;
    cbbHwType: TComboBox;
    cbbIO: TComboBox;
    cbbInterrupt: TComboBox;
    btnInit: TButton;
    btnRelease: TButton;
    GroupBox2: TGroupBox;
    Label6: TLabel;
    Label7: TLabel;
    chbFilterExt: TCheckBox;
    rdbFilterOpen: TRadioButton;
    rdbFilterClose: TRadioButton;
    rdbFilterCustom: TRadioButton;
    txtIdFrom: TEdit;
    txtIdTo: TEdit;
    btnFilterApply: TButton;
    btnFilterQuery: TButton;
    GroupBox3: TGroupBox;
    Label8: TLabel;
    Label9: TLabel;
    Label10: TLabel;
    btnParameterSet: TButton;
    btnParameterGet: TButton;
    cbbParameter: TComboBox;
    rdbParamActive: TRadioButton;
    rdbParamInactive: TRadioButton;
    txtDeviceId: TEdit;
    GroupBox4: TGroupBox;
    rdbTimer: TRadioButton;
    rdbEvent: TRadioButton;
    rdbManual: TRadioButton;
    chbShowPeriod: TCheckBox;
    btnRead: TButton;
    btnMsgClear: TButton;
    lstMessages: TListView;
    GroupBox5: TGroupBox;
    Label11: TLabel;
    Label12: TLabel;
    Label13: TLabel;
    txtID: TEdit;
    chbExtended: TCheckBox;
    txtLength: TEdit;
    nudLength: TUpDown;
    chbRemote: TCheckBox;
    txtData0: TEdit;
    txtData1: TEdit;
    txtData2: TEdit;
    txtData3: TEdit;
    txtData4: TEdit;
    txtData5: TEdit;
    txtData6: TEdit;
    txtData7: TEdit;
    btnWrite: TButton;
    GroupBox6: TGroupBox;
    lbxInfo: TListBox;
    btnGetVersions: TButton;
    btnInfoClear: TButton;
    btnReset: TButton;
    btnStatus: TButton;
    tmrRead: TTimer;
    tmrDisplay: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure cbbChannelChange(Sender: TObject);
    procedure cbbBaudratesChange(Sender: TObject);
    procedure cbbHwTypeChange(Sender: TObject);
    procedure cbbParameterChange(Sender: TObject);
    procedure btnHwRefreshClick(Sender: TObject);
    procedure btnInitClick(Sender: TObject);
    procedure btnReleaseClick(Sender: TObject);
    procedure btnFilterApplyClick(Sender: TObject);
    procedure btnFilterQueryClick(Sender: TObject);
    procedure btnParameterSetClick(Sender: TObject);
    procedure btnParameterGetClick(Sender: TObject);
    procedure btnReadClick(Sender: TObject);
    procedure btnMsgClearClick(Sender: TObject);
    procedure btnWriteClick(Sender: TObject);
    procedure btnGetVersionsClick(Sender: TObject);
    procedure btnInfoClearClick(Sender: TObject);
    procedure btnStatusClick(Sender: TObject);
    procedure btnResetClick(Sender: TObject);
    procedure chbFilterExtClick(Sender: TObject);
    procedure chbExtendedClick(Sender: TObject);
    procedure tmrReadTimer(Sender: TObject);
    procedure rdbTimerClick(Sender: TObject);
    procedure nudLengthClick(Sender: TObject; Button: TUDBtnType);
    procedure txtIDExit(Sender: TObject);
    procedure txtIdFromExit(Sender: TObject);
    procedure txtIdFromKeyPress(Sender: TObject; var Key: Char);
    procedure txtDeviceIdKeyPress(Sender: TObject; var Key: Char);
    procedure txtDeviceIdExit(Sender: TObject);
    procedure txtData0Exit(Sender: TObject);
    procedure chbShowPeriodClick(Sender: TObject);
    procedure tmrDisplayTimer(Sender: TObject);

  private
    //
    m_PcanHandle : TPCANHandle;
    m_Baudrate : TPCANBaudrate;
    m_HwType : TPCANType;
    m_ActiveReadingMode : Integer;
    m_LastMsgsList : TList;
    m_hEvent : THandle;
    m_hThread : THandle;
    m_objpCS: TCriticalSection;

    m_HandlesArray : array[0..26] of TPCANHandle;
    procedure InitializeProtection();
    procedure FinalizeProtection();

  public
    procedure InitializeControls();
    procedure FillComboBoxData();
    procedure ConfigureLogFile();
    procedure SetConnectionStatus(bConnected : boolean);
    procedure IncludeTextMessage(strMsg: AnsiString);

    procedure InsertMsgEntry(NewMsg : TPCANMsg; timeStamp: TPCANTimestamp);
    procedure DisplayMessages();
    procedure ReadMessage();
    procedure ProcessMessage(theMsg : TPCANMsg; itsTimeStamp : TPCANTimestamp);
    procedure ReadingModeChanged();

    function CANReadThreadFunc() : LongWord;

    function FormatChannelName(handle : TPCANHandle) : AnsiString;
    function GetTPCANHandleName(handle : TPCANHandle) : AnsiString;
    function GetFormatedError(error: TPCANStatus) : AnsiString;
    function GetFilterStatus(var status: Integer) : boolean;

  end;

var
  Form1: TForm1;

implementation

{ MessageStatus }

constructor MessageStatus.Create(canMsg: TPCANMsg; canTimestamp: TPCANTimestamp;
  listIndex: Integer);
begin
    m_Msg := canMsg;
    m_TimeStamp := canTimestamp;
    m_oldTimeStamp := canTimestamp;
    m_iIndex := listIndex;
    m_Count := 1;
    m_bShowPeriod := true;
    m_bWasChanged := false;
end;

procedure MessageStatus.Update(canMsg: TPCANMsg; canTimestamp: TPCANTimestamp);
begin
    m_Msg := canMsg;
    m_oldTimeStamp := m_TimeStamp;
    m_TimeStamp := canTimestamp;
    m_bWasChanged := true;
    m_Count := m_Count + 1;
end;

function MessageStatus.GetDataString: AnsiString;
var
    strTemp : AnsiString;
    I : integer;
begin
    strTemp := '';

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

function MessageStatus.GetIdString: AnsiString;
begin
    // We format the ID of the message and show it
    //
    if((Byte(m_Msg.MSGTYPE) AND Byte(PCAN_MESSAGE_EXTENDED)) <> 0)then
        Result := IntToHex(m_Msg.ID,8) + 'h'
    else
        Result := IntToHex(m_Msg.ID,3) + 'h';
end;

function MessageStatus.GetMsgTypeString: AnsiString;
var
    strTemp : AnsiString;
begin

    strTemp := '';

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

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

    result := strTemp;
end;

function MessageStatus.GetTimeString: AnsiString;
var
    fTime : double;
begin
    fTime := m_TimeStamp.millis + (m_TimeStamp.micros / 1000.0);
    if m_bShowPeriod then
        fTime := fTime - (m_oldTimeStamp.millis + (m_oldTimeStamp.micros / 1000.0));
    Result := Format('%.1f',[fTime]);
end;

procedure MessageStatus.SetShowingPeriod(value: boolean);
begin
    if m_bShowPeriod xor value then
    begin
        m_bShowPeriod := value;
        m_bWasChanged := true;
    end;
end;

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
	// Initialize all
	//
	InitializeControls();
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
	// Release Hardware if needed
	//
	if(btnRelease.Enabled) then
		btnRelease.Click;

	// Close the event
    //
	CloseHandle(m_hEvent);

    try
        m_objpCS.Enter;

        while(m_LastMsgsList.Count > 0) do
        begin
            MessageStatus(m_LastMsgsList.First()).Free;
            m_LastMsgsList.Delete(0);
        end;
        m_LastMsgsList.Free;
    finally
        m_objpCS.Leave;
    end;

    FinalizeProtection();
end;

procedure TForm1.InitializeControls;
begin
	// Initialize the Critical Section
	//
    InitializeProtection();

	// Creates an array with all possible PCAN-Channels
	//
	m_HandlesArray[0] := TPCANBAsic.PCAN_ISABUS1;
	m_HandlesArray[1] := TPCANBAsic.PCAN_ISABUS2;
	m_HandlesArray[2] := TPCANBAsic.PCAN_ISABUS3;
	m_HandlesArray[3] := TPCANBAsic.PCAN_ISABUS4;
	m_HandlesArray[4] := TPCANBAsic.PCAN_ISABUS5;
	m_HandlesArray[5] := TPCANBAsic.PCAN_ISABUS6;
	m_HandlesArray[6] := TPCANBAsic.PCAN_ISABUS7;
	m_HandlesArray[7] := TPCANBAsic.PCAN_ISABUS8;
	m_HandlesArray[8] := TPCANBAsic.PCAN_DNGBUS1;
	m_HandlesArray[9] := TPCANBAsic.PCAN_PCIBUS1;
	m_HandlesArray[10] := TPCANBAsic.PCAN_PCIBUS2;
	m_HandlesArray[11] := TPCANBAsic.PCAN_PCIBUS3;
	m_HandlesArray[12] := TPCANBAsic.PCAN_PCIBUS4;
	m_HandlesArray[13] := TPCANBAsic.PCAN_PCIBUS5;
	m_HandlesArray[14] := TPCANBAsic.PCAN_PCIBUS6;
	m_HandlesArray[15] := TPCANBAsic.PCAN_PCIBUS7;
	m_HandlesArray[16] := TPCANBAsic.PCAN_PCIBUS8;
	m_HandlesArray[17] := TPCANBAsic.PCAN_USBBUS1;
	m_HandlesArray[18] := TPCANBAsic.PCAN_USBBUS2;
	m_HandlesArray[19] := TPCANBAsic.PCAN_USBBUS3;
	m_HandlesArray[20] := TPCANBAsic.PCAN_USBBUS4;
	m_HandlesArray[21] := TPCANBAsic.PCAN_USBBUS5;
	m_HandlesArray[22] := TPCANBAsic.PCAN_USBBUS6;
	m_HandlesArray[23] := TPCANBAsic.PCAN_USBBUS7;
	m_HandlesArray[24] := TPCANBAsic.PCAN_USBBUS8;
	m_HandlesArray[25] := TPCANBAsic.PCAN_PCCBUS1;
	m_HandlesArray[26] := TPCANBAsic.PCAN_PCCBUS2;

	// Create a list to store the displayed messages
	//
	m_LastMsgsList := TList.Create;

	// Create Event to use Received-event
	//
	m_hEvent := CreateEvent(nil, False, False, '');

	// Set the Read-thread variable to null
	//
	m_hThread := 0;

	// We set the variable to know which reading mode is
	// currently selected (Timer by default)
	//
	m_ActiveReadingMode := 0;

	// Prepares the PCAN-Basic's debug-Log file
	//
	FillComboBoxData();

	// Init log parameters
	ConfigureLogFile();

	// Set default connection status
	//
	SetConnectionStatus(false);
end;

procedure TForm1.InitializeProtection();
begin
    m_objpCS := TCriticalSection.Create;
end;

procedure TForm1.FinalizeProtection();
begin
    try
        m_objpCS.Free;
        m_objpCS := nil;
    except

    end;
end;

procedure TForm1.FillComboBoxData;
begin
	// Channels will be check
	//
	btnHwRefresh.Click();

	// TPCANBaudrate
	//
	cbbBaudrates.ItemIndex := 2; // 500 K
	cbbBaudratesChange(cbbBaudrates);

	// Hardware Type for no plugAndplay hardware
	//
	cbbHwType.ItemIndex := 0;
	cbbHwTypeChange(cbbHwType);

	// Interrupt for no plugAndplay hardware
	//
	cbbInterrupt.ItemIndex := 0;

	// IO Port for no plugAndplay hardware
	//
	cbbIO.ItemIndex := 0;

	// Parameters for GetValue and SetValue function calls
	//
	cbbParameter.ItemIndex := 0;
	cbbParameterChange(cbbParameter);
end;

procedure TForm1.ConfigureLogFile();
var
    iBuffer : Integer;
begin
	// Sets the mask to catch all events
	//
	iBuffer := TPCANBasic.LOG_FUNCTION_ENTRY OR TPCANBasic.LOG_FUNCTION_LEAVE OR
        TPCANBasic.LOG_FUNCTION_PARAMETERS OR TPCANBasic.LOG_FUNCTION_READ OR
        TPCANBasic.LOG_FUNCTION_WRITE;

	// Configures the log file.
	// NOTE: The Log capability is to be used with the NONEBUS Handle. Other handle than this will
	// cause the function fail.
	//
	TPCANBasic.SetValue(TPCANBasic.PCAN_NONEBUS, PCAN_LOG_CONFIGURE, PLongWord(iBuffer), sizeof(iBuffer));
end;

procedure TForm1.SetConnectionStatus(bConnected : boolean);
begin
	// Buttons
	//
	btnInit.Enabled := NOT bConnected;
	btnHwRefresh.Enabled := NOT bConnected;
	btnRelease.Enabled := bConnected;
	btnFilterApply.Enabled := bConnected;
	btnFilterQuery.Enabled := bConnected;
	btnWrite.Enabled := bConnected;
	btnRead.Enabled := (bConnected AND rdbManual.Checked);
	btnParameterGet.Enabled := bConnected;
	btnParameterSet.Enabled := bConnected;
	btnGetVersions.Enabled := bConnected;
	btnStatus.Enabled := bConnected;
	btnReset.Enabled := bConnected;

	// ComboBoxs
	//
	cbbBaudrates.Enabled := NOT bConnected;
	cbbChannel.Enabled := NOT bConnected;
	cbbHwType.Enabled := NOT bConnected;
	cbbIO.Enabled := NOT bConnected;
	cbbInterrupt.Enabled := NOT bConnected;

	// Hardware configuration and read mode
	//
	if (NOT bConnected) then
		cbbChannelChange(cbbChannel)
	else
		ReadingModeChanged();

    // Display messages in grid
    //
    tmrDisplay.Enabled := bConnected;
end;

procedure TForm1.IncludeTextMessage(strMsg: AnsiString);
begin
	// Inserts a message in the Info box and focuses it
	//
	lbxInfo.Items.Add(strMsg);
	lbxInfo.ItemIndex := lbxInfo.Items.Count-1;
end;

procedure TForm1.InsertMsgEntry(NewMsg : TPCANMsg; timeStamp: TPCANTimestamp);
var
    msgStsCurrentMsg : MessageStatus;
	CurrentItem : TListItem;
begin
	// (Protected environment)
	//
    try
        m_objpCS.Enter;

		// We add this status in the last message list
		//
		msgStsCurrentMsg := MessageStatus.Create(NewMsg, timeStamp, lstMessages.Items.Count);
		m_LastMsgsList.Add(msgStsCurrentMsg);

		// Add the new ListView Item with the Type of the message
		//
		CurrentItem := lstMessages.Items.Add();
		CurrentItem.Caption := msgStsCurrentMsg.TypeString;

		// We set the ID of the message
		//
		CurrentItem.SubItems.Add(msgStsCurrentMsg.IdString);
		// We set the length of the Message
		//
		CurrentItem.SubItems.Add(IntToStr(NewMsg.LEN));
		// We set the data of the message.
		//
		CurrentItem.SubItems.Add(msgStsCurrentMsg.DataString);
		// we set the message count message (this is the First, so count is 1)
		//
		CurrentItem.SubItems.Add(IntToStr(msgStsCurrentMsg.Count));
		// Add timestamp information
		//
		CurrentItem.SubItems.Add(msgStsCurrentMsg.TimeString);
    finally
        m_objpCS.Leave;
    end;
end;

procedure TForm1.DisplayMessages();
var
//	msgStatus : MessageStatusPointer;
    msgStatus : MessageStatus;
    CurrentItem : TListItem;
    I : integer;
begin
    // We search if a message (Same ID and Type) is
    // already received or if this is a new message
	// (in a protected environment)
	//
    try
        m_objpCS.Enter;

        for I := 0 to m_LastMsgsList.Count - 1 do
        begin
            msgStatus := MessageStatus(m_LastMsgsList.Items[I]);
            if msgStatus.MarkedAsUpdated then
            begin
                msgStatus.MarkedAsUpdated := false;
                CurrentItem := lstMessages.Items[msgStatus.Position];

                CurrentItem.SubItems.Strings[1] := IntToStr(msgStatus.CANMsg.LEN);
                CurrentItem.SubItems.Strings[2] := msgStatus.DataString;
                CurrentItem.SubItems.Strings[3] := IntToStr(msgStatus.Count);
                CurrentItem.SubItems.Strings[4] := msgStatus.TimeString;
            end;
        end;
    finally
        m_objpCS.Leave;
    end;
end;

procedure TForm1.ReadMessage();
var
	CANMsg : TPCANMsg;
	CANTimeStamp : TPCANTimestamp;
	stsResult : TPCANStatus;
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 execute the "Read" function of the PCANBasic
		//
		stsResult := TPCANBasic.Read(m_PcanHandle, CANMsg, CANTimeStamp);

		// A message was received
		// We process the message(s)
		//
		if (stsResult = PCAN_ERROR_OK) then
			ProcessMessage(CANMsg, CANTimeStamp)

	until (NOT btnRelease.Enabled OR ((LongWord(stsResult) AND LongWord(PCAN_ERROR_QRCVEMPTY)) <> 0));
end;

procedure TForm1.ProcessMessage(theMsg : TPCANMsg; itsTimeStamp : TPCANTimestamp);
var
//	msg : MessageStatusPointer;
	msg : MessageStatus;
    I : integer;
begin
    // We search if a message (Same ID and Type) is
    // already received or if this is a new message
	// (in a protected environment)
	//
    try
        m_objpCS.Enter;

        for I := 0 to m_LastMsgsList.Count - 1 do
        begin
            msg := MessageStatus(m_LastMsgsList.Items[I]);
            if (msg.CANMsg.ID = theMsg.ID) And (msg.CANMsg.MSGTYPE = theMsg.MSGTYPE) then
             begin
                // Modify the message and exit
                //
                msg.Update(theMsg, itsTimeStamp);
                exit;
             end;
        end;

        // Message not found. It will created
        //
        InsertMsgEntry(theMsg, itsTimeStamp);
    finally
        m_objpCS.Leave;
    end;
end;

function CallCANReadThreadFunc(lpParam : Pointer) : LongWord; stdcall;
begin

	// Call TForm1 Thread member function
	//
	result := Form1.CANReadThreadFunc();
end;

procedure TForm1.ReadingModeChanged();
var
    dwTemp : LongWord;
begin
	if (NOT btnRelease.Enabled) then
		exit;

	case m_ActiveReadingMode of
	    0:
        begin
         	// If active reading mode is By Timer
		    // Terminate Read Thread if it exists
			//
			if(m_hThread <> 0) then
			begin
				TerminateThread(m_hThread, 1000);
				m_hThread := 0;
			end;
			// We start to read
			//
			tmrRead.Enabled := true;
        end;
        1:
        begin
            // If active reading mode is By Event
			// We stop to read from the CAN queue
			//
			tmrRead.Enabled := false;

			// Create Reading Thread ....
			//
			m_hThread := CreateThread(nil, 0, @CallCANReadThreadFunc, self , 0, dwTemp);

			if(m_hThread = 0) then
				MessageBox(0,'Create CANRead-Thread failed','Error!',MB_ICONERROR)
        end
        else
        begin
            // If active reading mode is Manual
			// Terminate Read Thread if it exists
			//
			if(m_hThread <> 0) then
			begin
				TerminateThread(m_hThread, 1000);
				m_hThread := 0;
			end;
			// We enable the button for read
			//
			tmrRead.Enabled := false;
			btnRead.Enabled := (btnRelease.Enabled AND rdbManual.Checked);
        end;
    end;
end;

function TForm1.CANReadThreadFunc() : LongWord;
var
	stsResult : TPCANStatus;
	dwTemp : LongWord;
begin
	// Sets the handle of the Receive-Event.
	//
	stsResult := TPCANBasic.SetValue(m_PcanHandle, PCAN_RECEIVE_EVENT ,PLongWord(@m_hEvent), sizeof(m_hEvent));

	// If it fails, a error message is shown
	//
	if (stsResult <> PCAN_ERROR_OK) then
	begin
		MessageBox(0, PChar(GetFormatedError(stsResult)), 'Error!',MB_ICONERROR);
		result := 1;
        exit;
	end;

	// While this mode is selected
	//
	while(rdbEvent.Checked) do
	begin
		//Wait for CAN Data...
		if (WaitForSingleObject(m_hEvent, INFINITE) = WAIT_OBJECT_0) then
			ReadMessage();
	end;

	// Resets the Event-handle configuration
	//
	dwTemp := 0;
	TPCANBasic.SetValue(m_PcanHandle, PCAN_RECEIVE_EVENT ,PLongWord(@dwTemp), sizeof(dwTemp));

	result := 0;
end;

function TForm1.FormatChannelName(handle : TPCANHandle) : AnsiString;
var
	strName : AnsiString;
    byChannel : byte;
begin
	// Gets the owner device and channel for a
	// PCAN-Basic handle
	//
	byChannel := handle;
	byChannel := byChannel AND $F;

	// Constructs the PCAN-Basic Channel name and return it
	//
	strName := GetTPCANHandleName(handle);
	result := Format('%s %d (%Xh)', [strName, byChannel, handle]);
end;

function TForm1.GetTPCANHandleName(handle : TPCANHandle) : AnsiString;
begin
    if((handle >= TPCANBasic.PCAN_ISABUS1) AND (handle <= TPCANBasic.PCAN_ISABUS8)) then
        result := 'PCAN_ISA'
    else if(handle = TPCANBasic.PCAN_DNGBUS1) then
        result := 'PCAN_DNG'
    else if((handle >= TPCANBasic.PCAN_PCIBUS1) AND (handle <= TPCANBasic.PCAN_PCIBUS8)) then
        result := 'PCAN_PCI'
    else if((handle >= TPCANBasic.PCAN_USBBUS1) AND (handle <= TPCANBasic.PCAN_USBBUS8)) then
        result := 'PCAN_USB'
    else if((handle >= TPCANBasic.PCAN_PCCBUS1) AND (handle <= TPCANBasic.PCAN_PCCBUS2)) then
        result := 'PCAN_PCC'
    else
        result := 'PCAN_NONE';
end;

function TForm1.GetFormatedError(error: TPCANStatus) : AnsiString;
var
	status : TPCANStatus;
	buffer : array[0..255] of Ansichar;
begin
	// Gets the text using the GetErrorText API function
	// If the function success, the translated error is returned. If it fails,
	// a text describing the current error is returned.
	//
	status := TPCANBasic.GetErrorText(error, 0, buffer);
	if(status <> PCAN_ERROR_OK) then
		result := Format('An error ocurred. Error-code''s text (%Xh) couldn''t be retrieved', [Integer(error)])
	else
		result := buffer;
end;

function TForm1.GetFilterStatus(var status: Integer) : boolean;
var
	stsResult : TPCANStatus;
begin
	// Tries to get the status of the filter for the current connected hardware
	//
	stsResult := TPCANBasic.GetValue(m_PcanHandle, PCAN_MESSAGE_FILTER, PLongWord(@status), sizeof(status));

	// If it fails, a error message is shown
	//
	if (stsResult <> PCAN_ERROR_OK) then
	begin
		MessageBox(0, PChar(GetFormatedError(stsResult)), 'Error!',MB_ICONERROR);
		result := false;
	end
    else
    	result := true;
end;

procedure TForm1.tmrDisplayTimer(Sender: TObject);
begin
    DisplayMessages();
end;

procedure TForm1.tmrReadTimer(Sender: TObject);
begin
	ReadMessage();
end;

procedure TForm1.btnHwRefreshClick(Sender: TObject);
var
	iBuffer : Integer;
	stsResult : TPCANStatus;
    I: Integer;
    iCount :Integer;
begin
	// Clears the Channel combioBox and fill it againa with
	// the PCAN-Basic handles for no-Plug&Play hardware and
	// the detected Plug&Play hardware
	//
	cbbChannel.Items.Clear();

    iCount := Trunc((sizeof(m_HandlesArray) /sizeof(TPCANHandle)))-1;

	for i:= 0 To iCount do
	begin
		// Includes all no-Plug&Play Handles
		//
		if (m_HandlesArray[i] <= TPCANBasic.PCAN_DNGBUS1) then
			cbbChannel.Items.Add(FormatChannelName(m_HandlesArray[i]))
		else
		begin
			// Checks for a Plug&Play Handle and, according with the return value, includes it
			// into the list of available hardware channels.
			//
			stsResult := TPCANBasic.GetValue(m_HandlesArray[i], PCAN_CHANNEL_CONDITION, PlongWord(@iBuffer), sizeof(iBuffer));
			if ((stsResult = PCAN_ERROR_OK) AND (iBuffer = TPCANBAsic.PCAN_CHANNEL_AVAILABLE)) then
				cbbChannel.Items.Add(FormatChannelName(m_HandlesArray[i]));
		end;
	end;

	// Select Last One
	//
	cbbChannel.ItemIndex := cbbChannel.Items.Count - 1;
	cbbChannelChange(cbbChannel);
end;

procedure TForm1.btnInitClick(Sender: TObject);
var
	stsResult : TPCANStatus;
	selectedIO : Integer;
	selectedInterrupt : Integer;
begin
	// Parse IO and Interrupt
	//
	selectedIO := StrToInt('0x'+cbbIO.Text);
	selectedInterrupt := StrToInt('0x'+cbbInterrupt.Text);

	// Connects a selected PCAN-Basic channel
	//
	stsResult := TPCANBasic.Initialize(m_PcanHandle, m_Baudrate, m_HwType, selectedIO, selectedInterrupt);

	if (stsResult <> PCAN_ERROR_OK) then
		MessageBox(0, PChar(GetFormatedError(stsResult)), 'Error!',MB_ICONERROR);

	// Sets the connection status of the main-form
	//
	SetConnectionStatus(stsResult = PCAN_ERROR_OK);
end;

procedure TForm1.btnReleaseClick(Sender: TObject);
begin
	// Terminate Read Thread if it exists
	//
	if(m_hThread <> 0) then
	begin
		TerminateThread(m_hThread, 1000);
		m_hThread := 0;
	end;

	// We stop to read from the CAN queue
	//
	tmrRead.Enabled := false;

	// Releases a current connected PCAN-Basic channel
	//
	TPCANBasic.Uninitialize(m_PcanHandle);

	// Sets the connection status of the main-form
	//
	SetConnectionStatus(false);
end;

procedure TForm1.btnFilterApplyClick(Sender: TObject);
var
	iBuffer : Integer;
	info : AnsiString;
	stsResult : TPCANStatus;
begin
	// Gets the current status of the message filter
	//
	if (Not GetFilterStatus(iBuffer)) then
		exit;

	// Configures the message filter for a custom range of messages
	//
	if (rdbFilterCustom.Checked) then
	begin
		// The filter must be first closed in order to customize it
		//
		if (iBuffer <> TPCANBasic.PCAN_FILTER_OPEN) then
		begin
			// Sets the custom filter
			//
            if(chbFilterExt.Checked) then
    			stsResult := TPCANBasic.FilterMessages(m_PcanHandle, StrToInt('0x'+txtIdFrom.Text), StrToInt('0x'+txtIdTo.Text), PCAN_MODE_EXTENDED)
            else
                stsResult := TPCANBasic.FilterMessages(m_PcanHandle, StrToInt('0x'+txtIdFrom.Text), StrToInt('0x'+txtIdTo.Text), PCAN_MODE_STANDARD);
			// If success, an information message is written, if it is not, an error message is shown
			//
			if (stsResult = PCAN_ERROR_OK) then
			begin
				info := Format('The filter was customized. IDs from {0x%s} to {0x%s} will be received', [txtIdFrom.Text,txtIdTo.Text]);
				IncludeTextMessage(info);
			end
			else
				MessageBox(0, PChar(GetFormatedError(stsResult)), 'Error!',MB_ICONERROR);
		end
		else
			MessageBox(0, 'The filter must be closed first in order to be able to customize it', 'Attention!',MB_ICONWARNING);

		exit;
	end;

	// The filter will be full opened or complete closed
	//
	if (rdbFilterClose.Checked) then
		iBuffer := TPCANBasic.PCAN_FILTER_CLOSE
	else
		iBuffer := TPCANBasic.PCAN_FILTER_OPEN;

	// The filter is configured
	//
	stsResult := TPCANBasic.SetValue(m_PcanHandle, PCAN_MESSAGE_FILTER, PLongWord(@iBuffer), sizeof(iBuffer));

	// If success, an information message is written, if it is not, an error message is shown
	//
	if (stsResult = PCAN_ERROR_OK) then
	begin

        if(rdbFilterClose.Checked) then
    		IncludeTextMessage('The filter was successfully closed.')
        else
    		IncludeTextMessage('The filter was successfully opened.');
	end
	else
		MessageBox(0, PChar(GetFormatedError(stsResult)), 'Error!',MB_ICONERROR);
end;

procedure TForm1.btnFilterQueryClick(Sender: TObject);
var
	iBuffer : Integer;
begin
	// Queries the current status of the message filter
	//
	if (GetFilterStatus(iBuffer)) then
        // The filter is closed
        //
        if (iBuffer = TPCANBasic.PCAN_FILTER_CLOSE) then
            IncludeTextMessage('The Status of the filter is: closed.')
        // The filter is fully opened
        //
        else if (iBuffer = TPCANBasic.PCAN_FILTER_OPEN) then
            IncludeTextMessage('The Status of the filter is: full opened.')
        // The filter is customized
        //
        else if (iBuffer = TPCANBasic.PCAN_FILTER_CUSTOM) then
            IncludeTextMessage('The Status of the filter is: customized.')
        // The status of the filter is undefined. (Should never happen)
        //
        else
            IncludeTextMessage('The Status of the filter is: Invalid.');
end;

procedure TForm1.btnParameterSetClick(Sender: TObject);
var
	stsResult : TPCANStatus;
	iBuffer : Integer;
	info : AnsiString;
	szDirectory : array[0..MAX_PATH] of char;
begin
	// Sets a PCAN-Basic parameter value
	//
	case cbbParameter.ItemIndex of
		// The Device-Number of an USB channel will be set
		//
	    0:
        begin
    		iBuffer := StrToInt(txtDeviceId.Text);
	    	stsResult := TPCANBasic.SetValue(m_PcanHandle, PCAN_DEVICE_NUMBER, PLongWord(@iBuffer), sizeof(iBuffer));
		    if(stsResult = PCAN_ERROR_OK) then
			    IncludeTextMessage('The desired Device-Number was successfully configured');
		end;

		// The 5 Volt Power feature of a PC-card or USB will be set
		//
	    1:
        begin
            if(rdbParamActive.Checked) then
                iBuffer := TPCANBasic.PCAN_PARAMETER_ON
            else
                iBuffer := TPCANBasic.PCAN_PARAMETER_OFF;

            stsResult := TPCANBasic.SetValue(m_PcanHandle, PCAN_5VOLTS_POWER, PLongWord(@iBuffer), sizeof(iBuffer));
            if(stsResult = PCAN_ERROR_OK) then
            begin
                if(iBuffer = TPCANBasic.PCAN_PARAMETER_ON) then
                    IncludeTextMessage('The USB/PC-Card 5 power was successfully activated')
                else
                    IncludeTextMessage('The USB/PC-Card 5 power was successfully deactivated');
            end;
        end;

		// The feature for automatic reset on BUS-OFF will be set
		//
	    2:
        begin
            if(rdbParamActive.Checked) then
                iBuffer := TPCANBasic.PCAN_PARAMETER_ON
            else
                iBuffer := TPCANBasic.PCAN_PARAMETER_OFF;
            stsResult := TPCANBasic.SetValue(m_PcanHandle, PCAN_BUSOFF_AUTORESET, PLongWord(@iBuffer), sizeof(iBuffer));
            if(stsResult = PCAN_ERROR_OK) then
            begin
                if(iBuffer = TPCANBasic.PCAN_PARAMETER_ON) then
                    IncludeTextMessage('The automatic-reset on BUS-OFF was successfully activated')
                else
                    IncludeTextMessage('The automatic-reset on BUS-OFF was successfully deactivated')
            end;
		end;

		// The CAN option "Listen Only" will be set
		//
	    3:
        begin
            if(rdbParamActive.Checked) then
                iBuffer := TPCANBasic.PCAN_PARAMETER_ON
            else
                iBuffer := TPCANBasic.PCAN_PARAMETER_OFF;
            stsResult := TPCANBasic.SetValue(m_PcanHandle, PCAN_LISTEN_ONLY, PLongWord(@iBuffer), sizeof(iBuffer));
            if(stsResult = PCAN_ERROR_OK) then
            begin
                if(iBuffer = TPCANBasic.PCAN_PARAMETER_ON) then
                    IncludeTextMessage('The CAN-option Listen-Only was successfully activated')
                else
                    IncludeTextMessage('The CAN-option Listen-Only was successfully deactivated');
            end;
		end;

		// The feature for logging debug-information will be set
		//
	    4:
        begin
            if(rdbParamActive.Checked) then
                iBuffer :=  TPCANBasic.PCAN_PARAMETER_ON
            else
                iBuffer :=  TPCANBasic.PCAN_PARAMETER_OFF;
            stsResult := TPCANBasic.SetValue(TPCANbasic.PCAN_NONEBUS, PCAN_LOG_STATUS, PLongWord(@iBuffer), sizeof(iBuffer));
            if(stsResult = PCAN_ERROR_OK) then
            begin
                if(iBuffer = TPCANBasic.PCAN_PARAMETER_ON) then
                    IncludeTextMessage('The feature for logging debug information was successfully activated')
                else
                    IncludeTextMessage('The feature for logging debug information was successfully deactivated');
                GetCurrentDirectory(sizeof(szDirectory) - 1, szDirectory);
                info := Format('Log file folder: %s', [szDirectory]);
                IncludeTextMessage(info);
            end;
		end;

		// The current parameter is invalid
		//
	    else
        begin
	    	MessageBox(0, 'Wrong parameter code.', 'Error!',MB_ICONERROR);
		    exit;
        end;
	end;

	// If the function fail, an error message is shown
	//
	if(stsResult <> PCAN_ERROR_OK) then
		MessageBox(NULL, PChar(GetFormatedError(stsResult)), 'Error!',MB_ICONERROR);
end;

procedure TForm1.btnParameterGetClick(Sender: TObject);
var
	stsResult : TPCANStatus;
	iBuffer : Integer;
	info : AnsiString;
begin
	// Sets a PCAN-Basic parameter value
	//
	case cbbParameter.ItemIndex of
		// The Device-Number of an USB channel will be get
		//
	    0:
        begin
		    stsResult := TPCANBasic.GetValue(m_PcanHandle, PCAN_DEVICE_NUMBER, PLongWord(@iBuffer), sizeof(iBuffer));
    		if(stsResult = PCAN_ERROR_OK) then
    		begin
    			info := Format('The configured Device-Number is %d', [iBuffer]);
	    		IncludeTextMessage(info);
		    end;
		end;

		// The 5 Volt Power feature of a PC-card or USB will be get
		//
	    1:
        begin
            stsResult := TPCANBasic.GetValue(m_PcanHandle, PCAN_5VOLTS_POWER, PLongWord(@iBuffer), sizeof(iBuffer));
            if(stsResult = PCAN_ERROR_OK) then
            begin
                if(iBuffer = TPCANBasic.PCAN_PARAMETER_ON) then
                    info := 'The 5-Volt Power of the USB/PC-Card is activated'
                else
                    info := 'The 5-Volt Power of the USB/PC-Card is deactivated';
                IncludeTextMessage(info);
            end;
		end;

		// The feature for automatic reset on BUS-OFF will be get
		//
	    2:
        begin
            stsResult := TPCANBasic.GetValue(m_PcanHandle, PCAN_BUSOFF_AUTORESET, PLongWord(@iBuffer), sizeof(iBuffer));
            if(stsResult = PCAN_ERROR_OK) then
            begin
                if(iBuffer = TPCANBasic.PCAN_PARAMETER_ON) then
                    info := 'The automatic-reset on BUS-OFF is activated'
                else
                    info := 'The automatic-reset on BUS-OFF is deactivated';
                IncludeTextMessage(info);
            end;
        end;

		// The CAN option "Listen Only" will be get
		//
	    3:
        begin
            stsResult := TPCANBasic.GetValue(m_PcanHandle, PCAN_LISTEN_ONLY, PLongWord(@iBuffer), sizeof(iBuffer));
            if(stsResult = PCAN_ERROR_OK) then
            begin
                if (iBuffer = TPCANBasic.PCAN_PARAMETER_ON) then
                    info := 'The CAN-option Listen-Only is activated'
                else
                    info := 'The CAN-option Listen-Only is deactivated';
                IncludeTextMessage(info);
            end;
		end;

		// The feature for logging debug-information will be get
		//
	    4:
        begin
            stsResult := TPCANBasic.GetValue(TPCANBasic.PCAN_NONEBUS, PCAN_LOG_STATUS, PLongWord(@iBuffer), sizeof(iBuffer));
            if(stsResult = PCAN_ERROR_OK) then
            begin
                if(iBuffer = TPCANBasic.PCAN_PARAMETER_ON) then
                    info := 'The feature for logging debug information is activated'
                else
                    info := 'The feature for logging debug information is deactivated';
                IncludeTextMessage(info);
            end;
		end;

		// The current parameter is invalid
		//
        else
        begin
            MessageBox(0, 'Wrong parameter code.', 'Error!',MB_ICONERROR);
		    exit;
        end;
	end;

	// If the function fail, an error message is shown
	//
	if(stsResult <> PCAN_ERROR_OK) then
		MessageBox(0, PChar(GetFormatedError(stsResult)), 'Error!',MB_ICONERROR);
end;

procedure TForm1.btnReadClick(Sender: TObject);
var
	CANMsg : TPCANMsg;
	CANTimeStamp : TPCANTimestamp;
	stsResult : TPCANStatus;
begin
	// We execute the "Read" function of the PCANBasic
	//
	stsResult := TPCANBasic.Read(m_PcanHandle, CANMsg, CANTimeStamp);
	if (stsResult = PCAN_ERROR_OK) then
		// We show the received message
		//
		ProcessMessage(CANMsg, CANTimeStamp)
	else
		// If an error occurred, an information message is included
		//
		IncludeTextMessage(GetFormatedError(stsResult));
end;

procedure TForm1.btnMsgClearClick(Sender: TObject);
begin
	// Clear Messages
	//
    try
        m_objpCS.Enter;

        lstMessages.Items.Clear();
        while(m_LastMsgsList.Count > 0) do
        begin
            MessageStatus(m_LastMsgsList.First()).Free;
            m_LastMsgsList.Delete(0);
        end;
    finally
        m_objpCS.Leave;
    end;
end;

procedure TForm1.btnWriteClick(Sender: TObject);
var
	CANMsg : TPCANMsg;
	stsResult : TPCANStatus;
begin
	// We configurate the Message.  The ID (max 0x1FF),
	// Length of the Data, Message Type (Standard in
	// this example) and die data
	//
	CANMsg.ID := StrToInt('0x'+txtID.Text);
	CANMsg.LEN := nudLength.Position;
    if(chbExtended.Checked) then
    	CANMsg.MSGTYPE := PCAN_MESSAGE_EXTENDED
     else
        CANMsg.MSGTYPE := PCAN_MESSAGE_STANDARD;

	// If a remote frame will be sent, the data bytes are not important.
	//
	if (chbRemote.Checked) then
		CANMsg.MSGTYPE := TPCANMessageType(Byte(CANMsg.MSGTYPE) OR Byte(PCAN_MESSAGE_RTR))
	else
	begin
		// We get so much data as the Len of the message
		//
		CANMsg.DATA[0] := StrToInt('0x' + txtData0.Text);
		CANMsg.DATA[1] := StrToInt('0x' + txtData1.Text);
		CANMsg.DATA[2] := StrToInt('0x' + txtData2.Text);
		CANMsg.DATA[3] := StrToInt('0x' + txtData3.Text);
		CANMsg.DATA[4] := StrToInt('0x' + txtData4.Text);
		CANMsg.DATA[5] := StrToInt('0x' + txtData5.Text);
		CANMsg.DATA[6] := StrToInt('0x' + txtData6.Text);
		CANMsg.DATA[7] := StrToInt('0x' + txtData7.Text);
	end;

	// The message is sent to the configured hardware
	//
	stsResult := TPCANBasic.Write(m_PcanHandle, CANMsg);

	// The Hardware was successfully sent
	//
	if (stsResult = PCAN_ERROR_OK) then
		IncludeTextMessage('Message was successfully SENT')
	// An error occurred.  We show the error.
	//
	else
		MessageBox(0, PChar(GetFormatedError(stsResult)), 'Error!',MB_ICONERROR);
end;

procedure TForm1.btnGetVersionsClick(Sender: TObject);
var
	stsResult : TPCANStatus;
	buffer : array[0..255] of AnsiChar;
	info : AnsiString;
	iPos : Integer;
begin
	// We get the vesion of the PCAN-Basic API
	//
	stsResult := TPCANBasic.GetValue(TPCANBAsic.PCAN_NONEBUS, PCAN_API_VERSION, buffer, 256);
	if (stsResult = PCAN_ERROR_OK) then
	begin
		info := Format('API Version: %s', [buffer]);
		IncludeTextMessage(info);
		// We get the driver version of the channel being used
		//
		stsResult := TPCANBasic.GetValue(m_PcanHandle, PCAN_CHANNEL_VERSION, buffer, 256);

		if (stsResult = PCAN_ERROR_OK) then
		begin
			IncludeTextMessage('Channel/Driver Version: ');

			// Because this information contains line control characters (several lines)
			// we split this also in several entries in the Information List-Box
			//
			info := buffer;
			while(info <> '') do
			begin
				iPos := Pos(#$A,info);
				if(iPos = 0) then
					iPos := Length(info);
				IncludeTextMessage('     * ' + Copy(info, 1, iPos));
				Delete(info, 1,iPos);
			end;
		end;
	end;

	// If the function fail, an error message is shown
	//
	if(stsResult <> PCAN_ERROR_OK) then
		MessageBox(0, PChar(GetFormatedError(stsResult)), 'Error!',MB_ICONERROR);
end;

procedure TForm1.btnInfoClearClick(Sender: TObject);
begin
	lbxInfo.Clear();
end;

procedure TForm1.btnStatusClick(Sender: TObject);
var
	status : TPCANStatus;
	errorName : AnsiString;
	info : AnsiString;
begin
	// Gets the current BUS status of a PCAN Channel.
	//
	status := TPCANBasic.GetStatus(m_PcanHandle);

	// Switch On Error Name
	//
	case status of
		PCAN_ERROR_INITIALIZE:
			errorName := 'PCAN_ERROR_INITIALIZE';

		PCAN_ERROR_BUSLIGHT:
			errorName := 'PCAN_ERROR_BUSLIGHT';

		PCAN_ERROR_BUSHEAVY:
			errorName := 'PCAN_ERROR_BUSHEAVY';

		PCAN_ERROR_BUSOFF:
			errorName := 'PCAN_ERROR_BUSOFF';

		PCAN_ERROR_OK:
			errorName := 'PCAN_ERROR_OK';

		else
			errorName := 'See Documentation';
    end;

	// Display Message
	//
	info := Format('Status: %s (%Xh)', [errorName, Integer(status)]);
	IncludeTextMessage(info);
end;

procedure TForm1.btnResetClick(Sender: TObject);
var
	stsResult : TPCANStatus;
begin
	// Resets the receive and transmit queues of a PCAN Channel.
	//
	stsResult := TPCANBasic.Reset(m_PcanHandle);

	// If it fails, a error message is shown
	//
	if (stsResult <> PCAN_ERROR_OK) then
		MessageBox(0, PChar(GetFormatedError(stsResult)), 'Error!',MB_ICONERROR)
	else
		IncludeTextMessage('Receive and transmit queues successfully reset');
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:
            m_Baudrate:= PCAN_BAUD_1M;
        1:
            m_Baudrate:= PCAN_BAUD_800K;
        2:
            m_Baudrate:= PCAN_BAUD_500K;
        3:
            m_Baudrate:= PCAN_BAUD_250K;
        4:
            m_Baudrate:= PCAN_BAUD_125K;
        5:
            m_Baudrate:= PCAN_BAUD_100K;
        6:
            m_Baudrate:= PCAN_BAUD_95K;
        7:
            m_Baudrate:= PCAN_BAUD_83K;
        8:
            m_Baudrate:= PCAN_BAUD_50K;
        9:
            m_Baudrate:= PCAN_BAUD_47K;
        10:
            m_Baudrate:= PCAN_BAUD_33K;
        11:
            m_Baudrate:= PCAN_BAUD_20K;
        12:
            m_Baudrate:= PCAN_BAUD_10K;
        13:
            m_Baudrate:= PCAN_BAUD_5K;
        else
            m_Baudrate:= TPCANBaudrate(0);
    end;
end;

procedure TForm1.cbbChannelChange(Sender: TObject);
var
	bNonPnP : boolean;
	strTemp : AnsiString;
begin
	// Get the handle from the text being shown
	//
	strTemp := cbbChannel.Text;

	strTemp := Copy(strTemp, Pos('(',strTemp) + 1, 2);

	// Determines if the handle belong to a No Plug&Play hardware
	//
	m_PcanHandle := TPCANHandle(StrToInt('0x'+strTemp));
	bNonPnP := m_PcanHandle <= TPCANBasic.PCAN_DNGBUS1;

	// Activates/deactivates configuration controls according with the
	// kind of hardware
	//
	cbbIO.Enabled := bNonPnP;
	cbbInterrupt.Enabled := bNonPnP;
	cbbHwType.Enabled := bNonPnP;
end;

procedure TForm1.cbbHwTypeChange(Sender: TObject);
begin
	Case cbbHwType.ItemIndex of
        0:
		    m_HwType := PCAN_TYPE_ISA;
	    1:
    		m_HwType := PCAN_TYPE_ISA_SJA;
	    2:
	    	m_HwType := PCAN_TYPE_ISA_PHYTEC;
	    3:
    		m_HwType := PCAN_TYPE_DNG;
	    4:
    		m_HwType := PCAN_TYPE_DNG_EPP;
	    5:
    		m_HwType := PCAN_TYPE_DNG_SJA;
	    6:
    		m_HwType := PCAN_TYPE_DNG_SJA_EPP;
    end;
end;

procedure TForm1.cbbParameterChange(Sender: TObject);
begin
	// Activates/deactivates controls according with the selected
	// PCAN-Basic parameter
	//
	rdbParamActive.Enabled := (cbbParameter.ItemIndex <> 0);
	rdbParamInactive.Enabled := rdbParamActive.Enabled;
	txtDeviceId.Enabled := (NOT rdbParamActive.Enabled);
end;

procedure TForm1.chbFilterExtClick(Sender: TObject);
begin
	// Updates the from and To ID-text according with the Message type
	//
	txtIdFromExit(txtIdFrom);
	txtIdFromExit(txtIdTo);
end;

procedure TForm1.chbShowPeriodClick(Sender: TObject);
var
    I : Integer;
    msgStsCurrentMessage : MessageStatus;
begin
    try
        m_objpCS.Enter;

        for I:=0 To m_LastMsgsList.Count-1 do
        begin
            msgStsCurrentMessage := MessageStatus(m_LastMsgsList.Items[I]);
            msgStsCurrentMessage.ShowingPeriod := chbShowPeriod.Checked;
        end;
    finally
        m_objpCS.Leave;
    end;
end;

procedure TForm1.chbExtendedClick(Sender: TObject);
begin
	// Updates the ID-text according with the Message type
	//
	txtIDExit(txtID);
end;

procedure TForm1.rdbTimerClick(Sender: TObject);
var
	radioBtn : TRadioButton;
begin

	radioBtn := Sender as TRadioButton;
	if((radioBtn <> nil) AND Not (radioBtn.Checked)) then
		exit;

	if(radioBtn.Name = 'rdbTimer') then
		m_ActiveReadingMode := 0;
	if(radioBtn.Name = 'rdbEvent') then
		m_ActiveReadingMode := 1;
	if(radioBtn.Name = 'rdbManual') then
		m_ActiveReadingMode := 2;

	ReadingModeChanged();
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.txtIdFromExit(Sender: TObject);
var
	iTempMax, iTempValue : LongWord;
	IdBox : TEdit;
begin
	IdBox := Sender as TEdit;

	// Calculates the text length and Maximum ID value according
	// with the Frame Type
	//
    if(chbFilterExt.Checked) then
    	IdBox.MaxLength := 8
    else
        IdBox.MaxLength := 3;

    if(chbFilterExt.Checked) then
    	iTempMax := $1FFFFFFF
    else
        iTempMax := $7FF;

	// Adjusts the ID value to refresh
	//
	iTempValue := StrToInt('0x' + IdBox.Text);
	if(iTempValue < iTempMax) then
		iTempMax := iTempValue;

	// Refreshes the ID value
	//
	IdBox.Text := IntToHex(Integer(iTempMax),IdBox.MaxLength);
end;

procedure TForm1.txtIdFromKeyPress(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.txtDeviceIdExit(Sender: TObject);
var
	iTemp : Int64;
begin

	// Checks the range of the given device ID
	//
	iTemp := StrToInt64(txtDeviceId.Text);
	if(iTemp > 4294967295) then
		txtDeviceId.Text := FloatToStr(4294967295);
end;

procedure TForm1.txtDeviceIdKeyPress(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;

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

procedure TForm1.txtIDExit(Sender: TObject);
var
	iTempMax, iTempValue : LongWord;
begin
	// Calculates the text length and Maximum ID value according
	// with the Frame Type
	//
    if(chbExtended.Checked) then
    	txtID.MaxLength := 8
    else
        txtID.MaxLength := 3;

    if(chbExtended.Checked) then
    	iTempMax := $1FFFFFFF
    else
        iTempMax := $7FF;

	// Adjusts the ID value to refresh
	//
	iTempValue := StrToInt('0x' + txtID.Text);
	if(iTempValue < iTempMax) then
		iTempMax := iTempValue;

	// Refreshes the ID value
	//
	txtID.Text := IntToHex(Integer(iTempMax),txtID.MaxLength);
end;

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

end.
