unit USBasp_Threads; { This file is part of Nephelae USBasp HID UART. USB HID Read / Write threads. Copyright (C) 2022 - 2025 Dimitrios Chr. Ioannidis. Nephelae - https://www.nephelae.eu https://www.nephelae.eu/ Licensed under the MIT License (MIT). See licence file in root directory. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. } {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, syncobjs, hidapi, SPSCRingBuffer; type { TThreadHID_Base } TThreadHID_Base = class(TThread) protected FThreadEvent: TEvent; FThreadUnpluggedEvent: TEvent; FBuffer: TSPSCRingBuffer; FHIDDevice: PHidDevice; public constructor Create(const AHIDDevice: PHidDevice; const ABuffer: TSPSCRingBuffer; const AThreadEvent: TEvent; const AUnpluggedEvent: TEvent); reintroduce; end; { TThread_HID_Status_Rx } TThread_HID_Status_Rx = class(TThreadHID_Base) protected procedure Execute; override; end; { TThread_HID_Status_Tx } TThread_HID_Status_Tx = class(TThreadHID_Base) protected procedure Execute; override; end; { TThread_HID_UART_Rx } TThread_HID_UART_Rx = class(TThreadHID_Base) procedure Execute; override; end; { TThread_HID_UART_Tx } TThread_HID_UART_Tx = class(TThreadHID_Base) protected procedure Execute; override; end; implementation { TThreadHID_Base } constructor TThreadHID_Base.Create(const AHIDDevice: PHidDevice; const ABuffer: TSPSCRingBuffer; const AThreadEvent: TEvent; const AUnpluggedEvent: TEvent); begin inherited Create(False); FThreadEvent := AThreadEvent; FThreadUnpluggedEvent := AUnpluggedEvent; FBuffer := ABuffer; FHIDDevice := AHIDDevice; end; { TThread_HID_Status_Rx } procedure TThread_HID_Status_Rx.Execute; var USBAspHidPacket: array[0..7] of byte = (0, 0, 0, 0, 0, 0, 0, 0); DataCount: SizeInt = 0; begin repeat DataCount := FHIDDevice^.Read(USBAspHidPacket, 8); if DataCount > 0 then begin FBuffer.Write(USBAspHidPacket, DataCount); FThreadEvent.SetEvent; end; until Terminated; end; { TThread_HID_Status_Tx } procedure TThread_HID_Status_Tx.Execute; var USBAspHidPacket: array[0..8] of byte = (0, 0, 0, 0, 0, 0, 0, 0, 0); DataCount: byte = 0; begin repeat if FBuffer.Empty then FThreadEvent.ResetEvent; FThreadEvent.WaitFor(INFINITE); FillChar(USBAspHidPacket, 8, 0); DataCount := FBuffer.Peek(USBAspHidPacket[1], 8); if DataCount > 0 then begin FHIDDevice^.Write(USBAspHidPacket, 8 + 1); FBuffer.AdvanceReadIdx(DataCount); end; until Terminated; end; { TThread_HID_UART_Rx } procedure TThread_HID_UART_Rx.Execute; var USBAspHidPacket: array[0..7] of byte = (0, 0, 0, 0, 0, 0, 0, 0); SerialDataCount, DataCount: byte; begin repeat DataCount := FHIDDevice^.Read(USBAspHidPacket, 8); if (DataCount > 0) and (USBAspHidPacket[7] > 0) then begin if (USBAspHidPacket[7] > 7) then SerialDataCount := 8 else SerialDataCount := USBAspHidPacket[7]; if FBuffer.Write(USBAspHidPacket, SerialDataCount) <> SerialDataCount then raise TExceptionClass.Create('Buffer OverRun'); FThreadEvent.SetEvent; end; until Terminated; end; { TThread_HID_UART_Tx } procedure TThread_HID_UART_Tx.Execute; var USBAspHidPacket: array[0..8] of byte = (0, 0, 0, 0, 0, 0, 0, 0, 0); SerialCountOrDataByte, DataCount: byte; begin repeat if FBuffer.Empty then FThreadEvent.ResetEvent; FThreadEvent.WaitFor(INFINITE); DataCount := FBuffer.Peek(USBAspHidPacket[1], 8); SerialCountOrDataByte := DataCount; if (SerialCountOrDataByte = 8) and (USBAspHidPacket[8] = 7) then SerialCountOrDataByte := 7 else if SerialCountOrDataByte < 8 then USBAspHidPacket[8] := SerialCountOrDataByte; if DataCount > 0 then begin SerialCountOrDataByte := FHIDDevice^.Write(USBAspHidPacket, 8 + 1); FBuffer.AdvanceReadIdx(DataCount); end; until Terminated; end; end.