1
0

usbasp.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. unit USBasp;
  2. {
  3. This file is part of Nephelae's Object Pascal FPUSBasp.
  4. USBasp Class.
  5. Copyright (C) 2025 Dimitrios Chr. Ioannidis.
  6. Nephelae - https://www.nephelae.eu
  7. https://www.nephelae.eu/
  8. Licensed under the MIT License (MIT).
  9. See licence file in root directory.
  10. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
  11. ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  12. TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  13. PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
  14. SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
  15. ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  16. ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  18. OTHER DEALINGS IN THE SOFTWARE.
  19. }
  20. {$mode objfpc}{$H+}
  21. interface
  22. uses
  23. Classes, SysUtils, syncobjs, hidapi,
  24. SPSCRingBuffer;
  25. const
  26. // USBasp UART Extension
  27. // https://github.com/dioannidis/usbasp/blob/master/firmware/usbasp.h
  28. USBASP_UART_PARITY_MASK = %11;
  29. USBASP_UART_PARITY_NONE = %00;
  30. USBASP_UART_PARITY_EVEN = %01;
  31. USBASP_UART_PARITY_ODD = %10;
  32. USBASP_UART_STOP_MASK = %100;
  33. USBASP_UART_STOP_1BIT = %000;
  34. USBASP_UART_STOP_2BIT = %100;
  35. USBASP_UART_BYTES_MASK = %111000;
  36. USBASP_UART_BYTES_5B = %000000;
  37. USBASP_UART_BYTES_6B = %001000;
  38. USBASP_UART_BYTES_7B = %010000;
  39. USBASP_UART_BYTES_8B = %011000;
  40. USBASP_UART_BYTES_9B = %100000;
  41. TUARTBaudRate: array[0..13] of integer =
  42. (300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 31250,
  43. 38400, 57600, 74880, 115200);
  44. TUARTDataBits: array[0..4] of integer =
  45. (USBASP_UART_BYTES_5B, USBASP_UART_BYTES_6B, USBASP_UART_BYTES_7B,
  46. USBASP_UART_BYTES_8B, USBASP_UART_BYTES_9B);
  47. TUARTParity: array[0..2] of integer =
  48. (USBASP_UART_PARITY_NONE, USBASP_UART_PARITY_EVEN, USBASP_UART_PARITY_ODD);
  49. TUARTStopBit: array[0..1] of integer = (USBASP_UART_STOP_1BIT, USBASP_UART_STOP_2BIT);
  50. type
  51. TUARTReceive = procedure(Sender: TObject; ASerialData: TByteArray;
  52. ASerialDataLength: SizeInt) of object;
  53. TStatusChange = procedure(Sender: TObject) of object;
  54. { TUSBasp }
  55. TUSBasp = class(TObject)
  56. private
  57. FUART_HIDDevice, FSTATUS_HIDDevice: PHidDevice;
  58. FUART_HIDDevicePath, FSTATUS_HIDDevicePath, FSerial, FManufacturer,
  59. FProductName, FHidApiVersionString: unicodestring;
  60. FConnected, FHasHIDUart, FHasStatus, FHasPDI, FHasTPI, FHasSNWrite,
  61. FUARTOpened: boolean;
  62. FCrystalOSC: integer;
  63. FHIDError: string;
  64. FUART_RxBuffer, FUART_TxBuffer, FStatus_RxBuffer: TSPSCRingBuffer;
  65. FUART_RxEvent, FUART_StartRxEvent, FUART_TxEvent, FSTATUS_RxEvent,
  66. FSTATUS_StartRxEvent: TEvent;
  67. FUART_RxThread, FUART_TxThread, FSTATUS_RxThread, FThreadSync: TThread;
  68. FOnUARTReceive: TUARTReceive;
  69. FOnStatusChange: TStatusChange;
  70. function HIDEnumerate(const ASerialNumber: string = ''): boolean;
  71. procedure SetOnStatusChange(AValue: TStatusChange);
  72. procedure SetOnUARTReceive(AValue: TUARTReceive);
  73. protected
  74. procedure DoUARTReceive;
  75. procedure DoStatusChange;
  76. public
  77. constructor Create;
  78. destructor Destroy; override;
  79. function Connect(const ASerialNumber: string = ''): boolean;
  80. function Disconnect: boolean;
  81. function UARTOpen(const ABaudRate, ADataBits, AParity, AStopBits: integer): boolean;
  82. function UARTClose: boolean;
  83. function ChangeSerialNumber(const ASerialNumber: string): boolean;
  84. property Connected: boolean read FConnected;
  85. property UARTOpened: boolean read FUARTOpened;
  86. property HidApiVersion: unicodestring read FHidApiVersionString;
  87. property OnUARTReceive: TUARTReceive read FOnUARTReceive write SetOnUARTReceive;
  88. property OnStatusChange: TStatusChange read FOnStatusChange write SetOnStatusChange;
  89. end;
  90. var
  91. UART_IO_Lock: TCriticalSection;
  92. STATUS_IO_Lock: TCriticalSection;
  93. implementation
  94. const
  95. USBASP_SHARED_VID = $16C0;
  96. USBASP_SHARED_PID = $05DC;
  97. USBASP_FUNC_GETCAPABILITIES = 127;
  98. USBASP_CAP_0_TPI = 1;
  99. USBASP_CAP_PDI = 16;
  100. USBASP_CAP_2_SNHIDUPDATE = 32;
  101. USBASP_CAP_6_UART = 64;
  102. USBASP_CAP_7_HID_UART = 128;
  103. USBASP_NO_CAPS = (-4);
  104. USBASP_CAP_12MHZ_CLOCK = 0;
  105. USBASP_CAP_16MHZ_CLOCK = 1;
  106. USBASP_CAP_18MHZ_CLOCK = 2;
  107. USBASP_CAP_20MHZ_CLOCK = 3;
  108. PROG_STATE_IDLE = 0;
  109. PROG_STATE_WRITEFLASH = 1;
  110. PROG_STATE_READFLASH = 2;
  111. PROG_STATE_READEEPROM = 3;
  112. PROG_STATE_WRITEEEPROM = 4;
  113. PROG_STATE_TPI_READ = 5;
  114. PROG_STATE_TPI_WRITE = 6;
  115. PROG_STATE_SET_REPORT = 7;
  116. UART_STATE_ENABLED = 16;
  117. UART_STATE_DISABLED = 0;
  118. type
  119. THIDPacket_Rx = array[0..7] of byte;
  120. THIDPacket_Tx = array[0..8] of byte;
  121. { TThreadHID }
  122. TThreadHID = class(TThread)
  123. protected
  124. FUSBasp: TUSBasp;
  125. FHIDIOLock: TCriticalSection;
  126. public
  127. constructor Create(const AUSBasp: TUSBasp; const AHIDIOLock: TCriticalSection);
  128. reintroduce;
  129. end;
  130. { THIDStatus_Rx }
  131. THIDStatus_Rx = class(TThreadHID)
  132. protected
  133. procedure Execute; override;
  134. end;
  135. { THIDUART_Rx }
  136. THIDUART_Rx = class(TThreadHID)
  137. procedure Execute; override;
  138. end;
  139. { THIDUART_Tx }
  140. THIDUART_Tx = class(TThreadHID)
  141. protected
  142. procedure Execute; override;
  143. end;
  144. { TThreadHID }
  145. constructor TThreadHID.Create(const AUSBasp: TUSBasp;
  146. const AHIDIOLock: TCriticalSection);
  147. begin
  148. FUSBasp := AUSBasp;
  149. FHIDIOLock := AHIDIOLock;
  150. inherited Create(False);
  151. end;
  152. { THIDStatus_Rx }
  153. procedure THIDStatus_Rx.Execute;
  154. var
  155. HidPacket, PrevHidPacket: THIDPacket_Rx;
  156. DataCount: SizeInt = 0;
  157. function HIDPacketEqual(constref AHIDPacket, APrevHIDPacket:
  158. THIDPacket_Rx): boolean;
  159. var
  160. Idx: byte;
  161. begin
  162. Result := True;
  163. for idx := Low(AHidPacket) to High(AHIDPacket) do
  164. if APrevHIDPacket[Idx] <> AHIDPacket[Idx] then
  165. begin
  166. Result := False;
  167. Break;
  168. end;
  169. end;
  170. begin
  171. FillChar(HIDPacket, High(THIDPacket_Rx) + 1, 0);
  172. PrevHidPacket := HidPacket;
  173. repeat
  174. FUSBasp.FSTATUS_StartRxEvent.WaitFor(INFINITE);
  175. FHIDIOLock.Acquire;
  176. try
  177. if Assigned(FUSBasp.FSTATUS_HIDDevice) then
  178. DataCount := FUSBasp.FSTATUS_HIDDevice^.ReadTimeout(HIDPacket,
  179. High(HIDPacket) + 1, 5)
  180. else
  181. DataCount := 0;
  182. finally
  183. FHIDIOLock.Release;
  184. end;
  185. if (DataCount > 0) and (not HIDPacketEqual(HIDPacket, PrevHidPacket)) then
  186. begin
  187. PrevHidPacket := HidPacket;
  188. FUSBasp.FStatus_RxBuffer.Write(HIDPacket, DataCount);
  189. FUSBasp.FSTATUS_RxEvent.SetEvent;
  190. end;
  191. until Terminated;
  192. end;
  193. { THIDUART_Rx }
  194. procedure THIDUART_Rx.Execute;
  195. var
  196. HIDPacket: THIDPacket_Rx;
  197. SerialDataCount, DataCount: byte;
  198. begin
  199. FillChar(HIDPacket, High(THIDPacket_Rx) + 1, 0);
  200. repeat
  201. FUSBasp.FUART_StartRxEvent.WaitFor(INFINITE);
  202. FHIDIOLock.Acquire;
  203. try
  204. if Assigned(FUSBasp.FUART_HIDDevice) then
  205. DataCount := FUSBasp.FUART_HIDDevice^.ReadTimeout(HIDPacket,
  206. High(THIDPacket_Rx) + 1, 5)
  207. else
  208. DataCount := 0;
  209. finally
  210. FHIDIOLock.Release;
  211. end;
  212. if (DataCount > 0) and (HIDPacket[7] > 0) then
  213. begin
  214. if (HIDPacket[7] > 7) then
  215. SerialDataCount := 8
  216. else
  217. SerialDataCount := HIDPacket[7];
  218. if FUSBasp.FUART_RxBuffer.Write(HIDPacket, SerialDataCount) <>
  219. SerialDataCount then
  220. raise TExceptionClass.Create('Receive Buffer OverRun');
  221. FUSBasp.FUART_RxEvent.SetEvent;
  222. end;
  223. until Terminated;
  224. end;
  225. { THIDUART_Tx }
  226. procedure THIDUART_Tx.Execute;
  227. var
  228. HIDPacket: THIDPacket_Tx;
  229. SerialCountOrDataByte, DataCount: byte;
  230. begin
  231. FillChar(HIDPacket, High(HIDPacket) + 1, 0);
  232. repeat
  233. if FUSBAsp.FUART_TxBuffer.Empty then
  234. FUSBasp.FUART_TxEvent.ResetEvent;
  235. FUSBasp.FUART_TxEvent.WaitFor(INFINITE);
  236. DataCount := FUSBAsp.FUART_TxBuffer.Peek(HIDPacket[1], 8);
  237. SerialCountOrDataByte := DataCount;
  238. if (SerialCountOrDataByte = 8) and (HIDPacket[8] = 7) then
  239. SerialCountOrDataByte := 7
  240. else
  241. if SerialCountOrDataByte < 8 then
  242. HIDPacket[8] := SerialCountOrDataByte;
  243. if DataCount > 0 then
  244. begin
  245. FHIDIOLock.Acquire;
  246. try
  247. if Assigned(FUSBasp.FUART_HIDDevice) then
  248. SerialCountOrDataByte :=
  249. FUSBasp.FUART_HIDDevice^.Write(HIDPacket, High(HIDPacket) + 1);
  250. finally
  251. FHIDIOLock.Release;
  252. end;
  253. FUSBAsp.FUART_TxBuffer.AdvanceReadIdx(DataCount);
  254. end;
  255. until Terminated;
  256. end;
  257. type
  258. { TThreadSync }
  259. TThreadSync = class(TThread)
  260. private
  261. FUSBasp: TUSBasp;
  262. protected
  263. procedure Execute; override;
  264. public
  265. constructor Create(const AUSBasp: TUSBasp); reintroduce;
  266. end;
  267. procedure TThreadSync.Execute;
  268. begin
  269. repeat
  270. if FUSBasp.FUART_RxEvent.WaitFor(3) = wrSignaled then
  271. Synchronize(@FUSBasp.DoUARTReceive);
  272. if FUSBasp.FSTATUS_RxEvent.WaitFor(3) = wrSignaled then
  273. Synchronize(@FUSBasp.DoStatusChange);
  274. until Terminated;
  275. end;
  276. constructor TThreadSync.Create(const AUSBasp: TUSBasp);
  277. begin
  278. FUSBasp := AUSBasp;
  279. inherited Create(False);
  280. end;
  281. { TUSBasp }
  282. constructor TUSBasp.Create;
  283. begin
  284. FConnected := False;
  285. FUARTOpened := False;
  286. FSerial := '';
  287. FUART_RxBuffer := TSPSCRingBuffer.Create(8192);
  288. FUART_TxBuffer := TSPSCRingBuffer.Create(8192);
  289. FStatus_RxBuffer := TSPSCRingBuffer.Create(8);
  290. Randomize;
  291. FUART_StartRxEvent := TEvent.Create(nil, True, False, 'STARTUARTRX' +
  292. IntToStr(Random(999)));
  293. FUART_RxEvent := TEvent.Create(nil, False, False, 'UARTRX' + IntToStr(Random(999)));
  294. FUART_TxEvent := TEvent.Create(nil, True, False, 'UARTTX' + IntToStr(Random(999)));
  295. FSTATUS_RxEvent := TEvent.Create(nil, False, False, 'STATUSRX' +
  296. IntToStr(Random(999)));
  297. FSTATUS_StartRxEvent := TEvent.Create(nil, True, False, 'STARTSTATUSRX' +
  298. IntToStr(Random(999)));
  299. FThreadSync := TThreadSync.Create(Self);
  300. FUART_RxThread := THIDUART_Rx.Create(Self, UART_IO_Lock);
  301. FUART_TxThread := THIDUART_Tx.Create(Self, UART_IO_Lock);
  302. FSTATUS_RxThread := THIDStatus_Rx.Create(Self, STATUS_IO_Lock);
  303. end;
  304. destructor TUSBasp.Destroy;
  305. begin
  306. Disconnect;
  307. FThreadSync.Terminate;
  308. FThreadSync.WaitFor;
  309. FreeAndNil(FThreadSync);
  310. FUART_RxThread.Terminate;
  311. FUART_StartRxEvent.SetEvent;
  312. FUART_RxThread.WaitFor;
  313. FreeAndNil(FUART_RxThread);
  314. FUART_TxThread.Terminate;
  315. FUART_TxEvent.SetEvent;
  316. FUART_TxThread.WaitFor;
  317. FreeAndNil(FUART_TxThread);
  318. FSTATUS_RxThread.Terminate;
  319. FSTATUS_StartRxEvent.SetEvent;
  320. FSTATUS_RxThread.WaitFor;
  321. FreeAndNil(FSTATUS_RxThread);
  322. FreeAndNil(FUART_RxBuffer);
  323. FreeAndNil(FUART_TxBuffer);
  324. FreeAndNil(FStatus_RxBuffer);
  325. FreeAndNil(FUART_RxEvent);
  326. FreeAndNil(FUART_TxEvent);
  327. FreeAndNil(FSTATUS_RxEvent);
  328. FreeAndNil(FUART_StartRxEvent);
  329. FreeAndNil(FSTATUS_StartRxEvent);
  330. inherited Destroy;
  331. end;
  332. function TUSBasp.Connect(const ASerialNumber: string = ''): boolean;
  333. begin
  334. if not FConnected then
  335. begin
  336. HidInit();
  337. if not HIDEnumerate(ASerialNumber) then
  338. Exit;
  339. FUART_HIDDevice := THidDevice.OpenPath(FUART_HIDDevicePath);
  340. FHIDError := THIDDevice.GetNullError(FUART_HIDDevice);
  341. if (FHIDError <> 'Success') then
  342. Exit;
  343. FUART_HIDDevice^.SetNonBlocking(1);
  344. if FHasStatus then
  345. begin
  346. FSTATUS_HIDDevice := THidDevice.OpenPath(FSTATUS_HIDDevicePath);
  347. FHIDError := THIDDevice.GetNullError(FSTATUS_HIDDevice);
  348. if (FHIDError = 'Success') then
  349. begin
  350. FSTATUS_HIDDevice^.SetNonBlocking(1);
  351. FSTATUS_StartRxEvent.SetEvent;
  352. end;
  353. end;
  354. FConnected := True;
  355. end;
  356. Result := FConnected;
  357. end;
  358. function TUSBasp.Disconnect: boolean;
  359. begin
  360. if FConnected then
  361. begin
  362. if FUARTOpened then
  363. begin
  364. UARTClose;
  365. Sleep(100);
  366. end;
  367. UART_IO_Lock.Acquire;
  368. try
  369. FUART_HIDDevice^.Close;
  370. FUART_HIDDevice := nil;
  371. finally
  372. UART_IO_Lock.Release;
  373. end;
  374. if FHasStatus then
  375. begin
  376. STATUS_IO_Lock.Acquire;
  377. try
  378. FSTATUS_HIDDevice^.Close;
  379. FSTATUS_HIDDevice := nil;
  380. FSTATUS_StartRxEvent.ResetEvent;
  381. finally
  382. STATUS_IO_Lock.Release;
  383. end;
  384. end;
  385. FConnected := False;
  386. HidExit;
  387. end;
  388. Result := not FConnected;
  389. end;
  390. function TUSBasp.UARTOpen(const ABaudRate, ADataBits, AParity,
  391. AStopBits: integer): boolean;
  392. var
  393. HIDPacket: THIDPacket_Tx;
  394. Prescaler: word;
  395. Rslt: SizeInt;
  396. begin
  397. if FConnected and not FUARTOpened then
  398. begin
  399. Prescaler := FCrystalOsc div 8 div ABaudRate - 1;
  400. Fillchar(HIDPacket, High(HIDPacket) + 1, 0);
  401. HIDPacket[0] := 0;
  402. HIDPacket[1] := lo(Prescaler);
  403. HIDPacket[2] := hi(Prescaler);
  404. HIDPacket[3] := ADataBits or AStopBits or AParity;
  405. UART_IO_Lock.Acquire;
  406. try
  407. Rslt := FUART_HIDDevice^.SendFeatureReport(HIDPacket, High(HIDPacket) + 1);
  408. FUART_StartRxEvent.SetEvent;
  409. finally
  410. UART_IO_Lock.Release;
  411. end;
  412. if Rslt > 0 then
  413. FUARTOpened := True;
  414. end;
  415. Result := FUARTOpened;
  416. end;
  417. function TUSBasp.UARTClose: boolean;
  418. var
  419. HIDPacket: THIDPacket_Tx;
  420. Rslt: SizeInt;
  421. begin
  422. if FConnected and FUARTOpened then
  423. begin
  424. Fillchar(HIDPacket, High(HIDPacket) + 1, 0);
  425. HIDPacket[0] := 0;
  426. HIDPacket[1] := 0;
  427. HIDPacket[2] := 0;
  428. HIDPacket[3] := 0;
  429. HIDPacket[4] := 0;
  430. UART_IO_Lock.Acquire;
  431. try
  432. Rslt := FUART_HIDDevice^.SendFeatureReport(HIDPacket, High(HIDPacket) + 1);
  433. FUART_StartRxEvent.ResetEvent;
  434. finally
  435. UART_IO_Lock.Release;
  436. end;
  437. if Rslt > 0 then
  438. FUARTOpened := False;
  439. end;
  440. Result := not FUARTOpened;
  441. end;
  442. function TUSBasp.HIDEnumerate(const ASerialNumber: string): boolean;
  443. var
  444. HidItemRoot, HidItem: PHidDeviceInfo;
  445. HIDDevice: PHidDevice;
  446. HIDDeviceMatch: boolean;
  447. FeatureReportBuffer: THIDPacket_Rx;
  448. begin
  449. Result := False;
  450. FUART_HIDDevice := nil;
  451. FSTATUS_HIDDevice := nil;
  452. FUART_HIDDevicePath := '';
  453. FSTATUS_HIDDevicePath := '';
  454. FHasStatus := False;
  455. try
  456. HidItemRoot := THidDeviceInfo.Enumerate(USBASP_SHARED_VID, USBASP_SHARED_PID);
  457. HidItem := HidItemRoot;
  458. while Assigned(HidItem) do
  459. begin
  460. HIDDeviceMatch := True;
  461. if ASerialNumber <> '' then
  462. if ASerialNumber <> PCWCharToUnicodeString(HidItem^.SerialNumber) then
  463. HIDDeviceMatch := False;
  464. if HIDDeviceMatch then
  465. case HidItem^.InterfaceNumber of
  466. 1: begin
  467. FUART_HIDDevicePath := HidItem^.Path;
  468. Result := True;
  469. end;
  470. 2: begin
  471. FSTATUS_HIDDevicePath := HidItem^.Path;
  472. FHasStatus := True;
  473. end;
  474. end;
  475. HidItem := HidItem^.Next;
  476. end;
  477. finally
  478. HidItemRoot^.Free;
  479. end;
  480. if Result then
  481. begin
  482. HIDDevice := THidDevice.OpenPath(FUART_HIDDevicePath);
  483. FSerial := HIDDevice^.GetSerialNumberString;
  484. FManufacturer := HIDDevice^.GetManufacturerString;
  485. FProductName := HIDDevice^.GetProductString;
  486. if HIDDevice^.GetFeatureReport(FeatureReportBuffer, 8 + 1) > 0 then
  487. begin
  488. case FeatureReportBuffer[6] of
  489. USBASP_CAP_12MHZ_CLOCK: FCrystalOsc := 12000000;
  490. USBASP_CAP_16MHZ_CLOCK: FCrystalOsc := 16000000;
  491. USBASP_CAP_18MHZ_CLOCK: FCrystalOsc := 18000000;
  492. USBASP_CAP_20MHZ_CLOCK: FCrystalOsc := 20000000;
  493. end;
  494. FHasHIDUart := (FeatureReportBuffer[5] and USBASP_CAP_7_HID_UART) =
  495. USBASP_CAP_7_HID_UART;
  496. FHasPDI := (FeatureReportBuffer[5] and USBASP_CAP_PDI) = USBASP_CAP_PDI;
  497. FHasTPI := (FeatureReportBuffer[5] and USBASP_CAP_0_TPI) = USBASP_CAP_0_TPI;
  498. FHasSNWrite := (FeatureReportBuffer[5] and USBASP_CAP_2_SNHIDUPDATE) =
  499. USBASP_CAP_2_SNHIDUPDATE;
  500. end;
  501. HIDDevice^.Close;
  502. HIDDevice := nil;
  503. end;
  504. end;
  505. procedure TUSBasp.DoUARTReceive;
  506. var
  507. SerialData: TByteArray;
  508. SerialDataLength, CRIdx: SizeInt;
  509. begin
  510. repeat
  511. SerialDataLength := FUART_RxBuffer.Peek(SerialData, FUART_RxBuffer.Size);
  512. CRIdx := IndexByte(SerialData, SerialDataLength, Ord(#10));
  513. if (CRIdx > 0) and (SerialData[CRIdx - 1] = Ord(#13)) then
  514. FUART_RxBuffer.AdvanceReadIdx(CRIdx + 1);
  515. if Assigned(FOnUARTReceive) and (CRIdx - 1 > 0) then
  516. FOnUARTReceive(Self, SerialData, CRIdx - 1);
  517. until CRIdx = -1;
  518. //SerialDataLength := FUART_RxBuffer.Read(SerialData, FUART_RxBuffer.Size);
  519. //if Assigned(FOnUARTReceive) then
  520. // FOnUARTReceive(Self, SerialData, SerialDataLength);
  521. end;
  522. procedure TUSBasp.SetOnUARTReceive(AValue: TUARTReceive);
  523. begin
  524. if FOnUARTReceive = AValue then Exit;
  525. FOnUARTReceive := AValue;
  526. end;
  527. procedure TUSBasp.DoStatusChange;
  528. var
  529. StatusBuffer: TByteArray;
  530. begin
  531. FStatus_RxBuffer.Read(StatusBuffer, FStatus_RxBuffer.Size);
  532. if Assigned(FOnStatusChange) then
  533. FOnStatusChange(Self);
  534. end;
  535. procedure TUSBasp.SetOnStatusChange(AValue: TStatusChange);
  536. begin
  537. if FOnStatusChange = AValue then Exit;
  538. FOnStatusChange := AValue;
  539. end;
  540. function TUSBasp.ChangeSerialNumber(const ASerialNumber: string): boolean;
  541. var
  542. Buffer: THIDPacket_Rx;
  543. ErrorCode: integer;
  544. SerNumValue: word;
  545. begin
  546. Result := False;
  547. if FConnected and not FUARTOpened then
  548. begin
  549. Val(ASerialNumber, SerNumValue, ErrorCode);
  550. Buffer[0] := 0;
  551. Buffer[1] := lo(SerNumValue);
  552. Buffer[2] := Hi(SerNumValue);
  553. Buffer[4] := 1;
  554. FUART_HIDDevice^.SendFeatureReport(Buffer, 8 + 1);
  555. FHIDError := THidDevice.GetNullError();
  556. //Result := FUART_HIDDevice^.GetError = 'Success';
  557. end;
  558. end;
  559. initialization
  560. UART_IO_Lock := TCriticalSection.Create;
  561. STATUS_IO_Lock := TCriticalSection.Create;
  562. finalization
  563. UART_IO_Lock.Free;
  564. STATUS_IO_Lock.Free;
  565. end.