Recent

Author Topic: Serial port, bluetooth devices  (Read 8526 times)

mmikac

  • New Member
  • *
  • Posts: 26
Serial port, bluetooth devices
« on: July 09, 2010, 07:55:40 am »
Does anyone know where (registry perhaps) or how can I find list of currently available bluetooth devices?

My problem is following. I have to print to serial port (bluetooth SPP device, e.g. COM6).
It works fine if device is connected when I start my application, but for all other cases I cannot continue printing:
- if I "accidentaly" power off the device, I don't know how to get response and be informed of new device status (I can get exception, but not immediatelly after power off of the device)
- if I power on the device again, I cannot successfully connect to it (even though it is paired with winCE device, setup as default outgoing SPP etc.)

So, basically what I need is some kind of discovery whether certain device is present and ready or not.
(I tried simple file and stream access to COM port, tried miniComm library as someone suggested, but with no success. In all cases I can print when device is ready in moment I enter my app, but after first power off I cannot get it back without leaving app and entering again - I don't connect on device in onCreate or similar but rather on every print try, so that this issue is quite frustrating - initially I wanted to connect once and repeat connect if neccessary - it is faster, but I can't make it work)

iMan Biglari

  • New member
  • *
  • Posts: 5
Re: Serial port, bluetooth devices
« Reply #1 on: May 06, 2013, 02:45:22 pm »
You can use this code to list all available COM ports in Windows Mobile and add them to a ComboBox:

var
  SL: TStringList;
  i: integer;
  s: string;
begin
  with TRegistry.Create do
    try
      RootKey := HKEY_LOCAL_MACHINE;
      if OpenKeyReadOnly('\Drivers\Active\') then
      begin
        SL := TStringList.Create;
        try
          GetKeyNames(SL);
          for i := 0 to SL.Count - 1 do
          begin
            if OpenKeyReadOnly('\Drivers\Active\' + SL) then
            begin
              s := Trim(ReadString('Name'));
              if Copy(s, 1, 3) = 'COM' then
                cbPort.Items.Add(s);
              CloseKey;
            end;
          end;
        finally
          SL.Free;
        end;
      end;
    finally
      Free;
    end;
end;


And you can use this code to get friendly description of every com port (e.g. bluetooth, GPS, etc.):

procedure TdlgConfig.cbPortChange(Sender: TObject);
var
  SL: TStringList;
  i: integer;
begin
  with TRegistry.Create do
    try
      RootKey := HKEY_LOCAL_MACHINE;
      if OpenKeyReadOnly('\Drivers\Active\') then
      begin
        SL := TStringList.Create;
        try
          GetKeyNames(SL);
          for i := 0 to SL.Count - 1 do
          begin
            if OpenKeyReadOnly('\Drivers\Active\' + SL) then
            begin
              if Trim(ReadString('Name')) = cbPort.Text then
                if OpenKeyReadOnly('\' + ReadString('Key')) then
                begin
                  mmDescription.Text := ReadString('FriendlyName');
                  Break;
                end;
              CloseKey;
            end;
          end;
        finally
          SL.Free;
        end;
      end;
    finally
      Free;
    end;
end;
There is no worse death than that of hope

djucius

  • Newbie
  • Posts: 1
Re: Serial port, bluetooth devices
« Reply #2 on: October 27, 2013, 04:14:12 pm »
Currently available bluetooth devices are not listed. You must find them:  :)
Code: [Select]
type
   TBtDevices = class
   public
      FBtDevList :TList;
   public
      constructor Create; // Create FBtDevList.
      destructor  Destroy; override; // Clear and destroy FBtDevList.
   public
      function    Search   :Boolean;
   end;

type
   TBtAddrInfo = record
      Name           :String;
      BtSockAddr     :SOCKADDR_BTH;
   end;
   PBtAddrInfo = ^TBtAddrInfo;


function TBtDevices.Search :Boolean;
type
   TCSAddrInfoArray = array[0..1024]of CSADDR_INFO;
   PCSAddrInfoArray = ^TCSAddrInfoArray;
const
   BTH_SDP_VERSION    = 1;
   C_WSA_QUE_SET_SIZE = sizeof({$IFDEF UNICODE}TWSAQuerySetW{$ELSE}TWSAQuerySetA{$ENDIF});
   C_SIZEOF_TWSADATA  = sizeof( TWSAData );
var
   VPWsaData         :PWSAData;
   VPWsaQue          :PWSAQuerySet absolute VPWsaData;
   VPWsaQueResSet    :PWSAQuerySet absolute VPWsaData;
   VSockAddrInfo     :PBtAddrInfo;
   VFooRez           :NativeInt;
   VHServiceLookup   :THandle;
   VLength           :DWORD;
   I                 :Int;
   VWsaStartuped     :Boolean;
begin
   Result            := False;
   VWsaStartuped     := False;
   VPWsaData         := nil;
   VPWsaQue          := nil;
   VPWsaQueResSet    := nil;
   VFooRez           := NO_ERROR;
   VHServiceLookup   := 0;

   // Before search clear system errors.
   Windows.SetLastError    ( NO_ERROR );
   WinSock2.WSASetLastError( NO_ERROR );

   try
      System.Getmem     ( VPWsaData, C_SIZEOF_TWSADATA );
      Windows.ZeroMemory( VPWsaData, C_SIZEOF_TWSADATA );

      VFooRez:= WSAStartup(
            WINSOCK_VERSION,
            VPWsaData^
      );
      System.FreeMem( VPWsaData );
      VPWsaData:= nil;

      if( VFooRez <> NO_ERROR )then begin
         // Log error...
         Exit;
      end;


      System.GetMem     ( VPWsaQue, C_WSA_QUE_SET_SIZE );
      Windows.ZeroMemory( VPWsaQue, C_WSA_QUE_SET_SIZE );
      VPWsaQue^.dwSize      := C_WSA_QUE_SET_SIZE;
      VPWsaQue^.dwNameSpace := NS_BTH;
      VPWsaQue^.lpcsaBuffer := nil;

      VFooRez:= WSALookupServiceBeginW(
            VPWsaQue,
            LUP_CONTAINERS,
            @VHServiceLookup
      );
      System.FreeMem( VPWsaQue );
      VPWsaQue:= nil;

      if( VFooRez <> NO_ERROR )then begin
         // Log error...
         Exit;
      end;


      // Now retrieve the results. Each call to WSALookupServiceNext returns one
      // result set. The following code
      // that terminates when WSALookupServiceNext returns SOCKET_ERROR and
      // WSAGetLastError returns WSA_E_NO_MORE.
      //
      // Note that the ResultSet record is actually variable length. Therefore
      // we allocate a buffer and let ResultSet point to that buffer. We quess
      // that 1024 bytes will be sufficient for most ResultSets.
      VLength := 2048; // 1024
      VPWsaQueResSet:= AllocMem( VLength );
      Windows.ZeroMemory( VPWsaQueResSet, VLength );
      VPWsaQueResSet^.dwSize      := VLength;
      VPWsaQueResSet^.dwNameSpace := NS_BTH;
      VPWsaQueResSet^.lpBlob      := nil;

      VFooRez:= NO_ERROR;
      // Here we clear previous BlueTooth devices list.
      self.FBtDevList.Clear;

      while( VFooRez = NO_ERROR )do begin
         VFooRez:= WSALookupServiceNextW(
               VHServiceLookup,
               ( LUP_RETURN_NAME or LUP_RETURN_ADDR ),
               VLength,
               VPWsaQueResSet
         );

         if(
               ( VFooRez = SOCKET_ERROR )and( WSAGetLastError() = WSAEFAULT )
         )then begin
            // Our 2048 bytes wasn't enough, allocate a larger buffer and try
            // again. This time the function should succeed because the
            // function told us what size the buffer has to be (through the
            // VLength parameter).

            ReallocMem( VPWsaQueResSet, VLength );
            Windows.ZeroMemory( VPWsaQueResSet, VLength );
            VPWsaQueResSet^.dwSize      := VLength;
            VPWsaQueResSet^.dwNameSpace := NS_BTH;
            VPWsaQueResSet^.lpBlob      := nil;

            VFooRez:= WSALookupServiceNextW(
                  VHServiceLookup,
                  0,
                  VLength,
                  VPWsaQueResSet
            );
         end;

         if VFooRez = SOCKET_ERROR then begin
            if( WSAGetLastError() <> WSA_E_NO_MORE )then begin
               // Log error...
               WSALookupServiceEnd( VHServiceLookup );
               VHServiceLookup:= 0;
               System.FreeMem( VPWsaQueResSet );
               VPWsaQueResSet:= nil;
               Exit;
            end;

            Break;
         end;

         // Success. Now loop through all the addresses and add them to the list.
         for I:= 0 to VPWsaQueResSet^.dwNumberOfCsAddrs - 1 do begin
            if PCSAddrInfoArray( VPWsaQueResSet^.lpcsaBuffer )^[I].RemoteAddr.lpSockaddr <> nil then begin
               New( VSockAddrInfo );

               VSockAddrInfo^.Name:= UStr(
                     VPWsaQueResSet^.lpszServiceInstanceName
               );
               VSockAddrInfo^.BtSockAddr := PSOCKADDR_BTH( PCSAddrInfoArray(
                     VPWsaQueResSet^.lpcsaBuffer )^[I].RemoteAddr.lpSockaddr )^;

               self.FBtDevList.Add( VSockAddrInfo );
               VSockAddrInfo:= nil;
            end;
         end;
      end;
   finally
      if( VHServiceLookup <> 0 )then
         WSALookupServiceEnd( VHServiceLookup );

      if( VPWsaQueResSet <> nil )then
         System.FreeMem( VPWsaQueResSet );

      if( VWsaStartuped )then
         WSACleanup;

      Result:= self.FBtDevList.Count > 0;
   end;
end;


If you opened COM port:

Quote
- if I "accidentaly" power off the device, I don't know how to get response and be informed of new device status

If it remote BT device then you get COM error or error in writing to it. So close COM and search again. If it your PPC (pocket pc)
device was powered off then you can write application status to registry or somewhere else and then check when app starting
or doing some other action.

Quote
- if I power on the device again, I cannot successfully connect to it
.
Search BT devices, if needed close previous COM port and reopen it.


Quote
initially I wanted to connect once and repeat connect if neccessary - it is faster, but I can't make it work
Connection to device is only opening COM port, close com port and you disconnect from device.

Device pairing needed only one time for pin entering. If pin changes unpair devices and pair with new pin.
 8-)

Code: [Select]
// This is a reminder to myself  :)