Jump to content

mikerabat

Members
  • Content Count

    45
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by mikerabat


  1. 40 minutes ago, JoEmbedded said:

    Hello Mike, thank you very much for Your offer. But I think I wait (and hope Embarcadero will migrate to 64-Bit, I started in 1988 with Turbo-C, so no hurry...).

    In the meantime I'll continue my work on the Progressive-Web-APP (still a lot 2do...) Best regards, Jo

    Hey Jo!

     

    Actually there is already a 64bit compiler so.... I don't know what you are waiting for 😉
    anyway.... the probelm is not the compiler but rather the api used aka WinRT and the fixes are

    put in there in Delhi11 . So either update to this version or check the fixes.

    I can remember that I also put them on stackoverflow: https://stackoverflow.com/questions/61890445/delphi-bluetooth-le-heart-rate-profile-access

     


  2. Actually the fix I posted to Embarcadero was exactly that and a few things more. Basically they used

    an outdated API and needed pairing.

    The code there should fix that. Let me know if you can find it - if not let me know. Maybe I can send you the

    fixed Windows BlueTooth LE stuff directly (I guess I may not post stuff here 😉 )

     

    kind regards

      MIke


  3. Strange enough on a second installation (aka our test site) the OnWork property works as expected... uploading around 1MByte per second

    and not waiting at all at the end. It looks like there is some kind of proxy in between that first receives the full message - relays that to the

    actual server - and waits until something comes back... I have though never heard of something like this and they couldn't clarify that either...

    Is there actually some kind of hardware around that could reproduce such a behaviour?

     


  4. Dear all!

     

    Our Software supports new uploading large files (100MB + ) to a server. To get a nice feedback we wanted

    to have some kind of progress telling the user how far we are already with the upload.

    For the upload we use the TidHTTP component + an openssl io handler.

     

    To get the progress working we used the OnWork event that is published by the component.

    While we were using the component for testing in our internal network (which is quite fast) the

    progress seemed ok but when we tested that on a slow network (around 2MBit) we saw that the first 99% were

    very fast (20MB per second +) and then the last bytes "hang" until the full file was transmitted. Basically the

    progress bar showed a progress of 99% for around 4minutes until the file was finally uploaded.

     

    What am I missing here? How can I determine how much data is transmitted to the server?

     

     

    The code involved is:
     

    function CreateLibertyHTTP( method : TIdSSLVersion = sslvTLSv1_2; proxySet : ISuperObject = nil ) : TIdHTTP;
    var sslIOHandler : TIdSSLIOHandlerSocketOpenSSL;
    begin
         Result := TIdHTTP.Create(nil);
         sslIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(Result);
         sslIOHandler.SSLOptions.Method := method;
         
         Result.IOHandler := sslIOHandler;
    
         if (proxySet <> nil) and (proxySet.S['Server'] <> '') then
         begin
              Result.ProxyParams.ProxyServer := proxySet.S['Server'];
              if proxySet.I['Port'] <> 0 then
                 Result.ProxyParams.ProxyPort := proxySet.I['Port'];
              if proxySet.s['Username'] <> '' then
              begin
                   Result.ProxyParams.ProxyUsername := proxySet.s['Username'];
                   Result.ProxyParams.ProxyPassword := proxySet.s['Pwd'];
              end;
              Result.ProxyParams.BasicAuthentication := proxySet.B['BasicAuthentication'];
         end;
    end;
    
    httpReq := CreateLibertyHTTPReq( some params here );
    DL.LLog(dlInfo, 'Liberty upload');
                             libertyParams.Clear;
                             libertyParams.Add('SID=' + SessionId);
                             libertyParams.Add('blockearly=1');
                             libertyParams.Add('csrfToken=' + csrfToken);
    
                             // eg 'http://192.168.0.193:81/tom24x/uploadFile?SID=45784095&blockearly=1'
                             s := httpReq.Post(LibServer+'tom24x/uploadFile', libertyParams, IndyTextEncoding_UTF8);
                             if Pos('error', LowerCase(s)) > 0 then
                                raise Exception.Create('Error initializing upload');
    
                             uplFileResp := SO(s);
    
                             fUploadFileSize:=FileSizeByName(DawFileName);
                             //s:='?SID='+SessionId+'&blockearly=1&overwrite=1';  // overwrite recording in case it's already uploaded
                             Stream := TStringStream.Create('');
                             Params := TIdMultipartFormDataStream.Create;
                             httpReq.OnWork:=LibertyUploadProgress;
                             try
                                Params.AddFile('pdf', DawFileName, 'application/octet-stream');
                                // New in 2.9.3: The Uploadfile issues a token which can be used as session id (one time thing)
                                // so the param does no harm at all.
                                s := LibServer+'rec/UploadRecording.exe?SID=' + uplFileResp.S['session'] + '&blockearly=1&overwrite=1';
                                // e.g. 'http://192.168.0.193:81/rec/UploadRecording.exe?SID=45784095&blockearly=1&overwrite=1'
                                try
                                   httpReq.Post(s, Params, Stream);
                                except
                                      on E: Exception do
                                         raise Exception.Create('Sending DAW file failed: ' + E.Message);
                                end;
                                DL.LLog(dlInfo, 'Liberty says: '+Stream.DataString);

     

    procedure TfrmDBBrowser.LibertyUploadProgress(ASender: TObject; AWorkMode: TWorkMode;
      AWorkCount: Int64);
    function BytesToStr( numBytes : Int64 ) : string;
    begin
         if numBytes > 1000000 then
         begin
              Result := Format('%.2f MB', [numBytes/(1000*1000)]);
         end
         else if numBytes > 10000 then
         begin
              Result := Format('%d kB', [numBytes div 1000]);
         end
         else
             Result := intToStr( numBytes ) + ' B';
    end;
    begin
         if fSxProgress.Cancelled
         then
             Abort
         else
         begin
              // note: the upload file size may be a bit higher than the actual file size due to header overhead
              fSxProgress.lblTopLabel.Caption := fLibertyUplLabel + ' ' + BytesToStr( Min(fUploadFileSize, AWorkCount ) ) + '/' + BytesToStr( fUploadFileSize );
              fSxProgress.lblTopLabel.Update;
              fSxProgress.SetProgress(-1, MulDiv(AWorkCount, 100, fUploadFileSize));
         end;
    end;

     

    kind regards

       Mike

     

     


  5. 17 hours ago, DelphiUdIT said:

    The WIN32 apis for BlueTooth are system based and are present in:

     

     rtl/net/System.Bluetooth

     rtl/net/System.Bluetooth.Components

    That is only the one half of the story. This is the base - in the next abstraction layer Emba decided to go to the different platforms -

    and for windows and Bluetooth LE the last file that actually implements stuff is System.Win.BluetoothWinRT.pas

     

     

    17 hours ago, DelphiUdIT said:

    Some difference with use of BLE is that with Windows the devices must be paired almost one time to be used with BLE. 

    That is also not entierly true. The imlementation from Embarcadero lacks this ability yes - I managed though to extend the WinRT implementation such that this

    is possible too.

    See the attached file on:
    https://quality.embarcadero.com/browse/RSP-21711

     

    hope that helps 😉

    • Like 1

  6. 1 hour ago, DelphiUdIT said:
    I don't know the WinRT API and have never developed a UWP application.
    I would have created an external timer (a normal TTimer) and called the CancelDiscovery function without "touching" the BLE timer.
     
    In normal WIN32 api I do this and I have no problems whatsoever.

    And how do you do that in win32? I wasn't able to find any BT LE classes or functions besides the WinRT stuff that is covered in Delphi.

    Please note that my code here patches the actual TBluetoothLE component that ships with Delphi 10.4.2!

    And yes I use this code in conjunction with a standard VCL app 😉


  7. I ran into the same problem and managed to fix that with an external timer that calls CancelDiscovery. It works but leaves a massive

    memory/thread leak since every time a new discovery is started the timer variable gets overwritten and not freed leaving the pending thread and

    it's resources....

     

    The problem actually is:

    the problem is within the Delphi implementation of the Thread that triggers the CancelDiscovery function.

    In Windows there is a Thread (TWinRTBluetoothLEAdapter.TDiscoverThreadTimer in System.Win.BluetoothWinRT.pas) that

    actually just waits for a specific amount of time and calls the given timer procedure. The problem here is that the

    Timer procedure cleans up the thread (calls .Free) which waits for the end of the Thread -> deadlock.

     

    To circumvent that problem I needed to adjust System.Win.BluetoothWinRT do the following:

     

    Augment the class

    TWinRTBluetoothLEAdapter

    by

     

    private
        const WM_BTLE_CANCELDISCOVERY = $400 + 666; // WM_USER

    ...

    private

      fHDL : HWND;
      procedure BTLETimerHandler( var msg : TMessage );

    protected

      procedure ThrDoCancelDiscovery;

     

    ..

    implementation

     

    procedure TWinRTBluetoothLEAdapter.BTLETimerHandler(var msg: TMessage);
    begin
         if msg.Msg = WM_BTLE_CANCELDISCOVERY then
            DoCancelDiscovery;
    end;

     

    procedure TWinRTBluetoothLEAdapter.ThrDoCancelDiscovery;
    begin
         // just post otherwise the thread hangs!
         PostMessage( fHDL, WM_BTLE_CANCELDISCOVERY, 0, 0);
    end;

     

    constructor TWinRTBluetoothLEAdapter.Create(const AManager: TBluetoothLEManager; const ARadioInfo: TBluetoothRadioInfo);

    begin

      inherited Create(AManager);
      fHDL := AllocateHWnd(BTLETimerHandler);

    ...

    end;

     

    destructor TWinRTBluetoothLEAdapter.Destroy;
    begin
      DeallocateHWnd(fHDL);

    ...

    end;

     

    function TWinRTBluetoothLEAdapter.DoStartDiscovery(Timeout: Cardinal; const AFilterUUIDList: TBluetoothUUIDsList;
      const ABluetoothLEScanFilterList: TBluetoothLEScanFilterList): Boolean;

    begin

    ...

     

    // new code

    if Assigned(fTimerThread) then
      begin
        fTimerThread.Cancel;
        fTimerThread.Free;
      end;

    // changed from DoCancelDiscovery to ThrDoCancelDiscovery

      FTimerThread := TDiscoverThreadTimer.Create(Self, ThrDoCancelDiscovery, Timeout);

    ...

    end;

     

    I guess one could also use TThread.Queue instead of the "complicated" window allocation in the timer and that should do the trick too!


  8. On 6/25/2021 at 9:06 PM, Remy Lebeau said:

    The main problem with TEncoding.GetBytes() is that its 'public' overloads all require the output to be a TBytes array, which you would then have to copy into your record afterwards, eg:

    
    var
      patData : TPatData;
      SurName : String;
      Bytes: TBytes;
    begin
      FillChar(@patData, sizeof(patData), 0);
      SurName := ...;
      Bytes := TEncoding.UTF8.GetBytes(SurName);
      Move(PBytes(Bytes)^, patData.SurName[0], Math.Min(SizeOf(patData.SurName), Length(Bytes)));
      ...
    end;

    The one overload of GetBytes() that would actually let you output directly into your record without using TBytes is declared as 'strict protected', which means you can't use it without involving some hacks, eg:

    
    type
      TEncodingHelper = class(TEncoding)
      public
        function GetBytes(const S: string; Bytes: PBytes; ByteCount: Integer): Integer;
      end;
    
    function TEncodingHelper.GetBytes(const S: string; Bytes: PBytes; ByteCount: Integer): Integer;
    begin
      Result := GetBytes(PChar(S), Length(S), Bytes, ByteCount);
    end;
    
    var
      patData : TPatData;
      SurName : String;
    begin
      FillChar(@patData, sizeof(patData), 0);
      SurName := ...;
      TEncodingHelper(TEncoding.UTF8).GetBytes(S, PByte(@patData.SurName[0]), SizeOf(patData.SurName));
      ...
    end;

    Or:

    
    type
      TEncodingHelper = class helper for TEncoding
      public
        function GetBytes(const S: string; Bytes: PByte; ByteCount: Integer): Integer;
      end;
    
    function TEncodingHelper.GetBytes(const S: string; Bytes: PByte; ByteCount: Integer): Integer;
    begin
      Result := Self.GetBytes(PChar(S), Length(S), Bytes, ByteCount);
    end;
    
    var
      patData : TPatData;
      SurName : String;
    begin
      FillChar(@patData, sizeof(patData), 0);
      SurName := ...;
      TEncoding.UTF8.GetBytes(S, PByte(@patData.SurName[0]), SizeOf(patData.SurName));
      ...
    end;

    The alternative would be to use System.LocaleCharsFromUnicode() instead, eg:

    
    var
      patData : TPatData;
      SurName : String;
    begin
      FillChar(@patData, sizeof(patData), 0);
      SurName := ...;
      LocaleCharsFromUnicode(CP_UTF8, 0, PChar(SurName), Length(SurName), @patData.SurName[0], sizeof(patData.SurName), nil, nil);
      ...
    end;

     

    Thank you very much much for the great insight!


  9. 23 minutes ago, David Heffernan said:
    
    TEncoding.UTF8.GetBytes

    Sorry but can you elaborate that? I actually cannot see how I get there a string converted to a field in the record...

    what am I missing here?


  10. 4 minutes ago, David Heffernan said:
    
    TEncoding.UTF8.GetBytes

     

     

    You don't need to use AnsiString.

    You mean I don't need AnsiCharacters to communicate with a device that only understands Single Byte characters?

     

    So... how is that?

     

    And tell me then how to use GetBytes to fill a structure like:

     

    type

      TPatData = packed record

         SurName : Array[0..31] of AnsiChar;

         FirstName : Array[0..31] of AnsiChar;

      end;

     

    var pat : TPatData;

          formSurName : String;

    begin

            FillChar(pat, sizeof(pat), 0);

           

           // code to be filled here....

     

    end;

     


  11. 16 hours ago, Stefan Glienke said:

    Yes, ditch AnsiString.

    haha...

    I'd love to but I have file and communication structures that need good old ansi strings.

     

    Or do you actually have a better idea than:
    str8 := UTF8String(SurName);
    System.AnsiStrings.StrLCopy(@patData.surname[0],PAnsiChar(str8), length(patData.surname));

     

    to bring a normal delphi string (SurName) to a structure (patData) that contains single byte characters?

     

     

     


  12. Hi!

     

    I'm currently migrating our projects from Delphi2010 to Delphi 10.4. One of my biggest

    changes is actually using StrLCopy and other Ansistring functions that used to be in SysUtils.

    They are now marked as deprecated and moved to System.AnsiStrings so ... I followed the compiler hint.

     

    Now the base problem is that the compiler is confused which function to use so I always prefix the call

    with

    System.AnsiStrings.StrLCopy ...

    which fixed that.

     

    But that looks actually very "ugly" and I have the feeling that this is not the way to go idera ment to go.

     

    Is there a "best" or anticipated way to handle this?

     

    kind regards

      Mike

     


  13. Hi Folks!

     

    I hope anyone can give me some hints on this topic: Firebird Data encryption and encryption of the data sent.

    Especially the "over the line" encryption of data is going to be mandatory for our next projects since there are

    a few attack vectors we didn't really anticapte that this would ever be a problem: an attacker has access to an internal

    network (e.g. a hospital) and reads the communication from between our program and the remote database.

     

    So... data encryption ala SSL, TLS would be a great thing to have. So far the FAQ from firebird only suggest to

    use an SSH tunnel or similar to connect to the database but ... is this feasable or even performant?

    Has anyone any experience with such a problem or is there anything some Delphi components could do?

     

    kind regards

       Mike

     

     


  14. Hey guys!

     

    I wanted to share my matrix library with you

    basically it contains tons of function for matrix manipulation (add, sub, mult, inverse)

    and higher order functions (SVD, CCA, PLS and tons more)

     

    The library is highly optimized (handoptimized assembler, AVX, SSE, FMA support) and can be multithreaded.

     

    Check out the repository on

    https://github.com/mikerabat/mrmath

     

    and check some tiny examples on:

     

    http://www.mrsoft.org/home/downloads.html

     

    hope you have fun with that ;)

     

    kind regards

       Mike

     

    • Like 1
    • Thanks 5
×