Jump to content

Marus

Members
  • Content Count

    9
  • Joined

  • Last visited

Community Reputation

0 Neutral
  1. Marus

    Virtual Serial Port on USB, not working.

    I failed to install AsyncPro... But I managed to install @aehimself's ComPort component and it's working. It seems that I can read the output of the Raspberry Pico and send commands to it. Thanks a lot !
  2. Marus

    Virtual Serial Port on USB, not working.

    Because I don't know any... I found just one but it's not working... Ok, I will give it a try to Async Pro. Thanks !
  3. Hi ! I want to send data from a Raspberry Pi Pico to my laptop, on USB. The Pico is seen in Windows as a virtual serial port (COM3). I tested the Pico with Putty and indeed it sends data and Putty receive it and display it. So, the Pico side is working. Now, to read the data from COM port in my app, I use the Windows dedicated APIs. I open the port withe CreateFile and read with ReadFile. See the code below. The problem is that I don't receive anything and the code is stuck at WaitForMultipleObjects call. What could be wrong ? Problem code: procedure TCommThread.Execute; var WaitHands: array[0..1] of THandle; EvOvLap: TOverLapped64; HasEvents: THandle; Dummy: DWORD; begin EndReq:= CreateEvent(nil, True, False, nil); HasEvents:= CreateEvent(nil, True, False, nil); try FillChar(EvOvLap, SizeOf(EvOvLap), 0); EvOvLap.hEvent:= HasEvents; WaitHands[0]:= EndReq; WaitHands[1]:= HasEvents; repeat if WaitCommEvent(hCom, EventsMask, @EvOvLap) then HandleEvents else begin if GetLastError <> ERROR_IO_PENDING then Exit; if WaitForMultipleObjects(2, @WaitHands, False, INFINITE) = WAIT_OBJECT_0 + 1 then begin if not GetOverlappedResult(hCom, EvOvLap, Dummy, True) then Exit; HandleEvents; end; end; until Terminated; finally CloseHandle(EvOvLap.hEvent); CloseHandle(EndReq); end; end; All COM port component code: TCommThread = class(TThread) private type TDefaultSet = record BaudRate: DWORD; ByteSize: Byte; Parity: TParity; StopBits: TStopBit; end; private DCB: TDCB; EndReq: THandle; RXOvLap, TXOvLap: TOverLapped64; EventsMask: DWORD; Default: TDefaultSet; RX_BuffSize: Cardinal; procedure LoadSettings; protected hCom: THandle; FLineEvent: TLineEventNotify; ErrorMask: DWORD; procedure Execute; override; procedure HandleEvents; procedure DoReceive; public FOnReceive: TReceiveNotify; constructor Create; destructor Destroy; override; function OpenPort(APort: String): Boolean; function ClosePort: Boolean; procedure SetCommParams(ABaudRate: DWORD; AByteSize: Byte = 0; NStopBits: TStopBit = sbDefault; AParity: TParity = ptDefault); function HandleValid: Boolean; function WriteComm(var Buff; ByteCount: Integer): DWORD; procedure SignalTerminate; procedure ClearComm; end; constructor TCommThread.Create; begin inherited Create(True); // create suspended Priority:= tpHigher; FreeOnTerminate:= False; hCom:= INVALID_HANDLE_VALUE; FillChar(RXOvLap, SizeOf(RXOvLap), 0); RXOvLap.hEvent:= CreateEvent(nil, True, False, nil); SetCommParams(9600, 8, sbOne, ptNone); end; destructor TCommThread.Destroy; begin ClosePort; CloseHandle(RXOvLap.hEvent); end; procedure TCommThread.SetCommParams(ABaudRate: DWORD; AByteSize: Byte = 0; NStopBits: TStopBit = sbDefault; AParity: TParity = ptDefault); begin with Default do begin BaudRate:= ABaudRate; if AByteSize <> 0 then ByteSize:= AByteSize; if NStopBits <> sbDefault then StopBits:= NStopBits; if AParity <> ptDefault then Parity:= AParity; end; LoadSettings; end; procedure TCommThread.LoadSettings; begin if not HandleValid then Exit; GetCommState(hCom, DCB); with DCB do begin BaudRate:= Default.BaudRate; ByteSize:= Default.ByteSize; Parity := DWORD(Default.Parity); StopBits:= DWORD(Default.StopBits); Flags:= 1; end; SetCommState(hCom, DCB); end; function TCommThread.HandleValid: Boolean; begin Result:= hCom <> INVALID_HANDLE_VALUE; end; function TCommThread.OpenPort(APort: String): Boolean; begin Result:= False; if HandleValid then Exit; hCom:= CreateFile(PChar('\\.\'+APort), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); if not HandleValid then Exit; try SetUpComm(hCom, 4096, 4096); LoadSettings; SetCommMask(hCom, EV_RXCHAR or EV_ERR); ClearComm; Start; Result:= True; except CloseHandle(hCom); hCom:= INVALID_HANDLE_VALUE; end; end; function TCommThread.ClosePort: Boolean; begin Result:= True; if not HandleValid then Exit; SignalTerminate; WaitFor; CloseHandle(hCom); end; procedure TCommTHread.ClearComm; begin PurgeComm(hCom, PURGE_RXCLEAR or PURGE_TXCLEAR or PURGE_RXABORT or PURGE_TXABORT); end; procedure TCommThread.DoReceive; { synchronize } begin if Assigned(FOnReceive) then FOnReceive(RX_BuffSize); end; procedure TCommThread.HandleEvents; var ComStat: TComStat; begin ClearCommError(hCom, ErrorMask, @ComStat); // do we have an error ? if ErrorMask > 0 then begin {handle error} end; // anything received ? if (EventsMask and EV_RXCHAR) > 0 then begin RX_BuffSize:= ComStat.cbInQue; Synchronize(DoReceive); //EventsMask:= EventsMask and not EV_RXCHAR; end; end; procedure TCommThread.SignalTerminate; begin FOnReceive:= nil; // kill callbacks... Terminate; // signal thread to terminate SetEvent(EndReq); end; procedure TCommThread.Execute; var WaitHands: array[0..1] of THandle; EvOvLap: TOverLapped64; HasEvents: THandle; Dummy: DWORD; begin EndReq:= CreateEvent(nil, True, False, nil); HasEvents:= CreateEvent(nil, True, False, nil); try FillChar(EvOvLap, SizeOf(EvOvLap), 0); EvOvLap.hEvent:= HasEvents; WaitHands[0]:= EndReq; WaitHands[1]:= HasEvents; repeat if WaitCommEvent(hCom, EventsMask, @EvOvLap) then HandleEvents else begin if GetLastError <> ERROR_IO_PENDING then Exit; if WaitForMultipleObjects(2, @WaitHands, False, INFINITE) = WAIT_OBJECT_0 + 1 then begin if not GetOverlappedResult(hCom, EvOvLap, Dummy, True) then Exit; HandleEvents; end; end; until Terminated; finally CloseHandle(EvOvLap.hEvent); CloseHandle(EndReq); end; end; function TCommThread.ReadComm(var Buff; BytesToRead: DWORD): Boolean; var bRead: DWORD; begin Result:= True; if BytesToRead > 0 then begin ReadFile(hCom, Buff, BytesToRead, nil, @RXOvLap); if not GetOverlappedResult(hCom, RXOvLap, bRead, True) or (bRead <> BytesToRead) then Result:= False; end end;
  4. The string is a file path that is provided by the code (scanning directories, it's a backup app), so it cannot be verry long. Yes, I have it in a variable ready for posting. The data is not critical, it just show in the main form the file that is processed. If there is not enough memory or encounter other unrecoverable errors (because there are many reasons to fail) the thread stops and return the error. The idea was for the worker thread not to wait for the message to be processed and to continue its work. That's why I wanted to use PostMessage. As otherwise, there would have been no problem with SendMessage...
  5. Ok, I understand... Doing what I want will complicate things more that a `try - except` block. I don't want to build another memory manager just to allocate a string variable, so I think I will use `try New() / Dispose() except`. I built a complex function using mainly APIs that do not raise exceptions, and my code is free of "try"s. And adding one just for allocating a variable it ruins my art. I read once in Delphi documentation that "try"s must be used only they are really neede, because of performance impact, and since then I try to avoid them. Indeed, the X behind the Y problem is like this: I want to send a message, from worker thread to the main thread queue, with a string in it. Because the message will be sent using PostMessage, which is asynchronous, I cannot send the string pointer (like in SendMessage), because this is not thread safe. So I need to allocate a string variable just for this message only, then assign the value and send the message with the string pointer. The main thread will receive the message, reads the string, and Dispose the pointer. * By the way, Dalija, you are one of the most beautiful being I ever seen ! And that's not a compliment, it's a fact. I've known you for a long time from StackOverflow. You have helped me many times there too. I have wondered many times who is hiding behind that profile picture, and now after seeing the video on your website... it was wow ! You are a verry special person with something that shines from within... Sorry, I couldn't help myself.
  6. If memory allocation fails it can return a "nil" pointer... All Windows APIs returns a False boolean when they fail. Why memory allocation cannot work the same ?
  7. I need a safe way to allocate memory for a string variable, without getting exceptions. I don't want to use "try-except" blocks and neither the function that do this, use them internaly. I need a speed optimised method. If there are errors it can return a nil pointer. I checked the GetMem, AllocMem, GetMemory... and they all say that raise exceptions. Although I looked to the GetMemory code but I didn't see any code that raise exceptions.
  8. @dummzeuch And if the directory I scan has 5000 files, it will make a snapshot of all of them at start ? I think it will take a lot of time and FindNextFile will not make sense anymore. @FPiette You are right ! But when I open the file at backup time and I got an error, I must report it in the log, but the files deleted by the user are not considered errors. I forgot to mention that my app is not the one who create or delete the files, the app is running in the background and it can happen that the user of the system do this. I would have liked to read one file at a time, then copy it, and then move on to the next one, because if I read the entire list of files and then start copying them, during this time, some files may be deleted...
  9. Hi ! I try to make a backup application... and I use FindFirstFile & FindNextFile Windows APIs to scan the directories. I need a strategy on how to make the scanning if the files are created or deleted in this time. It is difficult for me to create one because I don't understand how this APIs work... I made a test. I created 5 files in a folder and then I started scanning with FindFirstFile. Then I deleted the last 4 of them and continue to enumerate with FindNextFile, which, instead of ending the search with "no more files", because they were deleted, FindNextFile, always returns one file from the deleted ones, as if nothing had happened. It's as if they were cached since the execution of FindFirstFile... I'm really lost here. How would you do ?
×