• AVR Freaks

Hot!How to use HID with old C++Builder 4

Author
franckcl
Starting Member
  • Total Posts : 49
  • Reward points : 0
  • Joined: 2004/01/12 10:03:49
  • Location: Paris (France-EU)
  • Status: offline
2009/12/22 02:16:39 (permalink)
0

How to use HID with old C++Builder 4

Hi,
I have an old and big application which has been developped with C++Builder4 which uses RS232 to communicate with a custom device.
I would like to replace the RS232 by USB (PIC18F87J50) and I would like to provide to the user the possibility to upgrade the firmware.
To avoid the installation of a driver, I prefer to use the HID mode.

So I have two questions:
1) Is it possible to do "firmware updating" using HID mode ?
2) Is exists a DLL file to use with my "old" application ? or any other solution ?

Thank you.
Franck
post edited by franckcl - 2009/12/28 09:11:43
#1

6 Replies Related Threads

    DarioG
    Allmächtig.
    • Total Posts : 54081
    • Reward points : 0
    • Joined: 2006/02/25 08:58:22
    • Location: Oesterreich
    • Status: offline
    RE: How to use HID with old C++Builder 4 2009/12/22 14:54:01 (permalink)
    0
    You can use a HID Bootloader to upgrade the HID firmware
    and
    You can use some APIs or DLL to talk to your device: they won't be "exactly" like using a RS232 port, but similar... So, if you can wrap the communication into some block, you'll be fine.

    GENOVA :D :D ! GODO
    #2
    franckcl
    Starting Member
    • Total Posts : 49
    • Reward points : 0
    • Joined: 2004/01/12 10:03:49
    • Location: Paris (France-EU)
    • Status: offline
    RE: How to use HID with old C++Builder 4 2009/12/23 15:50:18 (permalink)
    0
    Thank you Dario but where can I find this DLL ?
    #3
    DarioG
    Allmächtig.
    • Total Posts : 54081
    • Reward points : 0
    • Joined: 2006/02/25 08:58:22
    • Location: Oesterreich
    • Status: offline
    RE: How to use HID with old C++Builder 4 2009/12/23 16:17:12 (permalink)
    0
    If you make up a Generic HID device, you can use C/C++/VB WriteFile and ReadFile to communicate with the device - no other software is needed.
    Or you can use something like MPUSBDLL (I remember its name barely since I used it just once) which is available by Microchip, and described (as much more for USB) at http://lvr.com site.

    GENOVA :D :D ! GODO
    #4
    franckcl
    Starting Member
    • Total Posts : 49
    • Reward points : 0
    • Joined: 2004/01/12 10:03:49
    • Location: Paris (France-EU)
    • Status: offline
    RE: How to use HID with old C++Builder 4 2009/12/28 06:25:49 (permalink)
    0
    Ok, I have found !
    In fact, we don't need to load a special library, just include the following line:
    #include <setupapi.h>
    I enclose an example.

    Also, here is the code of the test program:
    You need to create a form with 3 buttons : BtnConnect, ToggleLedBtn, GetPushbuttonState and a label named StateLabel.
    Here is the source code of the form :
    ----------------------------------------------

    //---------------------------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop

    #include "MainUnit.h"
    #include <setupapi.h>
    #include <alloc.h>
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;

    #define MY_DEVICE_ID "Vid_04d8&Pid_003F"

    HANDLE WriteHandle = INVALID_HANDLE_VALUE;
    HANDLE ReadHandle = INVALID_HANDLE_VALUE;
    GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30};

    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::BtnConnectClick(TObject *Sender)
    {
    GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30};
    HDEVINFO DeviceInfoTable = INVALID_HANDLE_VALUE;
    PSP_DEVICE_INTERFACE_DATA InterfaceDataStructure = new SP_DEVICE_INTERFACE_DATA;
    PSP_DEVICE_INTERFACE_DETAIL_DATA DetailedInterfaceDataStructure = new SP_DEVICE_INTERFACE_DETAIL_DATA;
    SP_DEVINFO_DATA DevInfoData;
    DWORD InterfaceIndex = 0;
    DWORD StatusLastError = 0;
    DWORD dwRegType;
    DWORD dwRegSize;
    DWORD StructureSize = 0;
    PBYTE PropertyValueBuffer;
    bool MatchFound = false;
    DWORD ErrorStatus;
    HDEVINFO hDevInfo;

    String DeviceIDFromRegistry;
    String DeviceIDToFind = MY_DEVICE_ID;

    //First populate a list of plugged in devices (by specifying "DIGCF_PRESENT"), which are of the specified class GUID.
    DeviceInfoTable = SetupDiGetClassDevs(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

    //Now look through the list we just populated. We are trying to see if any of them match our device.
    while(true)
    {
    InterfaceDataStructure->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
    if (SetupDiEnumDeviceInterfaces(DeviceInfoTable, NULL, &InterfaceClassGuid, InterfaceIndex, InterfaceDataStructure))
    {
    ErrorStatus = GetLastError();
    if(ERROR_NO_MORE_ITEMS == ErrorStatus) //Did we reach the end of the list of matching devices in the DeviceInfoTable?
    { //Cound not find the device. Must not have been attached.
    SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need.
    ShowMessage("Erreur: Sortie1");
    return;
    }
    }
    else //Else some other kind of unknown error ocurred...
    {
    ErrorStatus = GetLastError();
    SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need.
    ShowMessage("Erreur: Sortie2");
    return;
    }
    //Now retrieve the hardware ID from the registry. The hardware ID contains the VID and PID, which we will then
    //check to see if it is the correct device or not.

    //Initialize an appropriate SP_DEVINFO_DATA structure. We need this structure for SetupDiGetDeviceRegistryProperty().
    DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    SetupDiEnumDeviceInfo(DeviceInfoTable, InterfaceIndex, &DevInfoData);

    //First query for the size of the hardware ID, so we can know how big a buffer to allocate for the data.
    SetupDiGetDeviceRegistryProperty(DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &dwRegType, NULL, 0, &dwRegSize);

    //Allocate a buffer for the hardware ID.
    PropertyValueBuffer = (BYTE *) malloc (dwRegSize);
    if(PropertyValueBuffer == NULL) //if null, error, couldn't allocate enough memory
    { //Can't really recover from this situation, just exit instead.
    ShowMessage("Allocation PropertyValueBuffer impossible");
    SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need.
    return;
    }
    //Retrieve the hardware IDs for the current device we are looking at. PropertyValueBuffer gets filled with a
    //REG_MULTI_SZ (array of null terminated strings). To find a device, we only care about the very first string in the
    //buffer, which will be the "device ID". The device ID is a string which contains the VID and PID, in the example
    //format "Vid_04d8&Pid_003f".
    SetupDiGetDeviceRegistryProperty(DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &dwRegType, PropertyValueBuffer, dwRegSize, NULL);

    //Now check if the first string in the hardware ID matches the device ID of my USB device.
    DeviceIDFromRegistry = StrPas((char *)PropertyValueBuffer);
    free(PropertyValueBuffer); //No longer need the PropertyValueBuffer, free the memory to prevent potential memory leaks

    //Convert both strings to lower case. This makes the code more robust/portable accross OS Versions
    DeviceIDFromRegistry = DeviceIDFromRegistry.LowerCase();
    DeviceIDToFind = DeviceIDToFind.LowerCase();
    //Now check if the hardware ID we are looking at contains the correct VID/PID
    MatchFound = (DeviceIDFromRegistry.AnsiPos(DeviceIDToFind)>0);
    if(MatchFound == true)
    {
    //Device must have been found. Open read and write handles. In order to do this, we will need the actual device path first.
    //We can get the path by calling SetupDiGetDeviceInterfaceDetail(), however, we have to call this function twice: The first
    //time to get the size of the required structure/buffer to hold the detailed interface data, then a second time to actually
    //get the structure (after we have allocated enough memory for the structure.)
    DetailedInterfaceDataStructure->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
    //First call populates "StructureSize" with the correct value
    SetupDiGetDeviceInterfaceDetail(DeviceInfoTable, InterfaceDataStructure, NULL, NULL, &StructureSize, NULL);
    DetailedInterfaceDataStructure = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(malloc(StructureSize)); //Allocate enough memory
    if(DetailedInterfaceDataStructure == NULL) //if null, error, couldn't allocate enough memory
    { //Can't really recover from this situation, just exit instead.
    SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need.
    return;
    }
    DetailedInterfaceDataStructure->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
    //Now call SetupDiGetDeviceInterfaceDetail() a second time to receive the goods.
    SetupDiGetDeviceInterfaceDetail(DeviceInfoTable, InterfaceDataStructure, DetailedInterfaceDataStructure, StructureSize, NULL, NULL);

    //We now have the proper device path, and we can finally open read and write handles to the device.
    //We store the handles in the global variables "WriteHandle" and "ReadHandle", which we will use later to actually communicate.
    WriteHandle = CreateFile((DetailedInterfaceDataStructure->DevicePath), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);

    ErrorStatus = GetLastError();
    if(ErrorStatus == ERROR_SUCCESS)
    ToggleLedBtn->Enabled = true; //Make button no longer greyed out
    ReadHandle = CreateFile((DetailedInterfaceDataStructure->DevicePath), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
    ErrorStatus = GetLastError();
    if(ErrorStatus == ERROR_SUCCESS)
    {
    GetPushbuttonState->Enabled = true; //Make button no longer greyed out
    StateLabel->Enabled = true; //Make label no longer greyed out
    }
    SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need.
    return;

    }

    InterfaceIndex++;
    //Keep looping until we either find a device with matching VID and PID, or until we run out of items.
    }//end of while(true)
    ShowMessage("Sortie");
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::ToggleLedBtnClick(TObject *Sender)
    {
    DWORD BytesWritten = 0;
    unsigned char OutputPacketBuffer[65]; //Allocate a memory buffer equal to our endpoint size + 1

    OutputPacketBuffer[0] = 0; //The first byte is the "Report ID". This number is used by the USB driver, but does not
    //get tranmitted accross the USB bus. The custom HID class firmware is only configured for
    //one type of report, therefore, we must always initializate this byte to "0" before sending
    //a data packet to the device.

    OutputPacketBuffer[1] = 0x80; //0x80 is the "Toggle LED(s)" command in the firmware
    //For simplicity, we will leave the rest of the buffer uninitialized, but you could put real
    //data in it if you like.

    //The basic Windows I/O functions WriteFile() and ReadFile() can be used to read and write to HID class USB devices.
    //Note that we need the handle which we got earlier when we called CreateFile() (when we hit the connect button).
    //The following function call will send out 64 bytes (starting from OutputPacketBuffer[1]) to the USB device. The data will
    //arrive on the OUT interrupt endpoint.
    WriteFile(WriteHandle, &OutputPacketBuffer, 65, &BytesWritten, 0); //Blocking function, unless an "overlapped" structure is used

    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::GetPushbuttonStateClick(TObject *Sender)
    {
    DWORD BytesWritten = 0;
    DWORD BytesRead = 0;
    unsigned char OutputPacketBuffer[65]; //Allocate a memory buffer equal to our endpoint size + 1
    unsigned char InputPacketBuffer[65]; //Allocate a memory buffer equal to our endpoint size + 1

    InputPacketBuffer[0] = 0; //The first byte is the "Report ID" and does not get transmitted over the USB bus. Always set = 0.
    OutputPacketBuffer[0] = 0; //The first byte is the "Report ID" and does not get transmitted over the USB bus. Always set = 0.

    OutputPacketBuffer[1] = 0x81; //0x81 is the "Get Pushbutton State" command in the firmware
    //For simplicity, we will leave the rest of the buffer uninitialized, but you could put real
    //data in it if you like.

    //The basic Windows I/O functions WriteFile() and ReadFile() can be used to read and write to HID class USB devices
    //(once we have the read and write handles to the device, which are obtained with CreateFile()).

    //To get the pushbutton state, first, we send a packet with our "Get Pushbutton State" command in it.
    //The following call to WriteFile() sends 64 bytes of data to the USB device.
    WriteFile(WriteHandle, &OutputPacketBuffer, 65, &BytesWritten, 0); //Blocking function, unless an "overlapped" structure is used
    //Now get the response packet from the firmware.
    //The following call to ReadFIle() retrieves 64 bytes of data from the USB device.
    ReadFile(ReadHandle, &InputPacketBuffer, 65, &BytesRead, 0); //Blocking function, unless an "overlapped" structure is used

    //InputPacketBuffer[0] is the report ID, which we don't care about.
    //InputPacketBuffer[1] is an echo back of the command.
    //InputPacketBuffer[2] contains the I/O port pin value for the pushbutton.
    if(InputPacketBuffer[2] == 0x01)
    {
    StateLabel->Caption = "State: Not Pressed"; //Update the pushbutton state text label on the form, so the user can see the result
    }
    else //InputPacketBuffer[2] must have been == 0x00 instead
    {
    StateLabel->Caption = "State: Pressed"; //Update the pushbutton state text label on the form, so the user can see the result
    }

    }
    //---------------------------------------------------------------------------

    post edited by franckcl - 2009/12/28 09:10:49
    #5
    DarioG
    Allmächtig.
    • Total Posts : 54081
    • Reward points : 0
    • Joined: 2006/02/25 08:58:22
    • Location: Oesterreich
    • Status: offline
    RE: How to use HID with old C++Builder 4 2009/12/28 11:03:01 (permalink)
    0
    all right then Smile

    GENOVA :D :D ! GODO
    #6
    Viktor
    New Member
    • Total Posts : 25
    • Reward points : 0
    • Joined: 2015/03/11 05:43:44
    • Location: 0
    • Status: offline
    Re: RE: How to use HID with old C++Builder 4 2020/01/23 06:05:33 (permalink)
    0
    Hello.
    Anyone remade a project:
    WinUSB Simple Demo - PC Application - MS VC++ 2005 Express
    (mla\apps\usb\device...) for C++Builder6 ?  Or specify a web-link please.
    error: WinUsb_WritePipe... and WinUsb_ReadPipe...
    post edited by Viktor - 2020/01/23 06:32:33
    #7
    Jump to:
    © 2020 APG vNext Commercial Version 4.5