The incomplete StandaloneProgrammer project now uses Host and Device Mass storage...
[pub/USBasp.git] / Projects / AVRISP / Lib / V2Protocol.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2009.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, and distribute this software
13 and its documentation for any purpose and without fee is hereby
14 granted, provided that the above copyright notice appear in all
15 copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29 */
30
31 /** \file
32 *
33 * V2Protocol handler, to process V2 Protocol commands used in Atmel programmer devices.
34 */
35
36 #define INCLUDE_FROM_V2PROTOCOL_C
37 #include "V2Protocol.h"
38
39 /** Master V2 Protocol packet handler, for received V2 Protocol packets from a connected host.
40 * This routine decodes the issued command and passes off the handling of the command to the
41 * appropriate function.
42 */
43 void V2Protocol_ProcessCommand(void)
44 {
45 uint8_t V2Command = Endpoint_Read_Byte();
46
47 switch (V2Command)
48 {
49 case CMD_SIGN_ON:
50 V2Protocol_Command_SignOn();
51 break;
52 case CMD_SET_PARAMETER:
53 case CMD_GET_PARAMETER:
54 V2Protocol_Command_GetSetParam(V2Command);
55 break;
56 case CMD_LOAD_ADDRESS:
57 V2Protocol_Command_LoadAddress();
58 break;
59 case CMD_RESET_PROTECTION:
60 V2Protocol_Command_ResetProtection();
61 break;
62 case CMD_ENTER_PROGMODE_ISP:
63 V2Protocol_Command_EnterISPMode();
64 break;
65 case CMD_LEAVE_PROGMODE_ISP:
66 V2Protocol_Command_LeaveISPMode();
67 break;
68 case CMD_PROGRAM_FLASH_ISP:
69 case CMD_PROGRAM_EEPROM_ISP:
70 V2Protocol_Command_ProgramMemory(V2Command);
71 break;
72 case CMD_READ_FLASH_ISP:
73 case CMD_READ_EEPROM_ISP:
74 V2Protocol_Command_ReadMemory(V2Command);
75 break;
76 case CMD_CHIP_ERASE_ISP:
77 V2Protocol_Command_ChipErase();
78 break;
79 case CMD_READ_FUSE_ISP:
80 case CMD_READ_LOCK_ISP:
81 case CMD_READ_SIGNATURE_ISP:
82 case CMD_READ_OSCCAL_ISP:
83 V2Protocol_Command_ReadFuseLockSigOSCCAL(V2Command);
84 break;
85 case CMD_PROGRAM_FUSE_ISP:
86 case CMD_PROGRAM_LOCK_ISP:
87 V2Protocol_Command_WriteFuseLock(V2Command);
88 break;
89 case CMD_SPI_MULTI:
90 V2Protocol_Command_SPIMulti();
91 break;
92 default:
93 V2Protocol_Command_Unknown(V2Command);
94 break;
95 }
96
97 Endpoint_WaitUntilReady();
98 Endpoint_SetEndpointDirection(ENDPOINT_DIR_OUT);
99 }
100
101 /** Handler for unknown V2 protocol commands. This discards all sent data and returns a
102 * STATUS_CMD_UNKNOWN status back to the host.
103 *
104 * \param[in] V2Command Issued V2 Protocol command byte from the host
105 */
106 static void V2Protocol_Command_Unknown(uint8_t V2Command)
107 {
108 /* Discard all incoming data */
109 while (Endpoint_BytesInEndpoint() == AVRISP_DATA_EPSIZE)
110 {
111 Endpoint_ClearOUT();
112 Endpoint_WaitUntilReady();
113 }
114
115 Endpoint_ClearOUT();
116 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
117
118 Endpoint_Write_Byte(V2Command);
119 Endpoint_Write_Byte(STATUS_CMD_UNKNOWN);
120 Endpoint_ClearIN();
121 }
122
123 /** Handler for the CMD_SIGN_ON command, returning the programmer ID string to the host. */
124 static void V2Protocol_Command_SignOn(void)
125 {
126 Endpoint_ClearOUT();
127 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
128
129 Endpoint_Write_Byte(CMD_SIGN_ON);
130 Endpoint_Write_Byte(STATUS_CMD_OK);
131 Endpoint_Write_Byte(sizeof(PROGRAMMER_ID) - 1);
132 Endpoint_Write_Stream_LE(PROGRAMMER_ID, (sizeof(PROGRAMMER_ID) - 1));
133 Endpoint_ClearIN();
134 }
135
136 /** Handler for the CMD_SET_PARAMETER and CMD_GET_PARAMETER commands from the host, setting or
137 * getting a device parameter's value from the parameter table.
138 *
139 * \param[in] V2Command Issued V2 Protocol command byte from the host
140 */
141 static void V2Protocol_Command_GetSetParam(uint8_t V2Command)
142 {
143 uint8_t ParamID = Endpoint_Read_Byte();
144 uint8_t ParamValue;
145
146 if (V2Command == CMD_SET_PARAMETER)
147 ParamValue = Endpoint_Read_Byte();
148
149 Endpoint_ClearOUT();
150 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
151
152 Endpoint_Write_Byte(V2Command);
153
154 uint8_t ParamPrivs = V2Params_GetParameterPrivileges(ParamID);
155
156 if ((V2Command == CMD_SET_PARAMETER) && (ParamPrivs & PARAM_PRIV_WRITE))
157 {
158 Endpoint_Write_Byte(STATUS_CMD_OK);
159 V2Params_SetParameterValue(ParamID, ParamValue);
160 }
161 else if ((V2Command == CMD_GET_PARAMETER) && (ParamPrivs & PARAM_PRIV_READ))
162 {
163 Endpoint_Write_Byte(STATUS_CMD_OK);
164 Endpoint_Write_Byte(V2Params_GetParameterValue(ParamID));
165 }
166 else
167 {
168 Endpoint_Write_Byte(STATUS_CMD_FAILED);
169 }
170
171 Endpoint_ClearIN();
172 }
173
174 /** Handler for the CMD_LOAD_ADDRESS command, loading the given device address into a
175 * global storage variable for later use, and issuing LOAD EXTENDED ADDRESS commands
176 * to the attached device as required.
177 */
178 static void V2Protocol_Command_LoadAddress(void)
179 {
180 Endpoint_Read_Stream_BE(&CurrentAddress, sizeof(CurrentAddress));
181
182 Endpoint_ClearOUT();
183 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
184
185 if (CurrentAddress & (1UL << 31))
186 V2Protocol_LoadExtendedAddress();
187
188 Endpoint_Write_Byte(CMD_LOAD_ADDRESS);
189 Endpoint_Write_Byte(STATUS_CMD_OK);
190 Endpoint_ClearIN();
191 }
192
193 /** Handler for the CMD_RESET_PROTECTION command, currently implemented as a dummy ACK function
194 * as no ISP short-circuit protection is currently implemented.
195 */
196 static void V2Protocol_Command_ResetProtection(void)
197 {
198 Endpoint_ClearOUT();
199 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
200
201 Endpoint_Write_Byte(CMD_RESET_PROTECTION);
202 Endpoint_Write_Byte(STATUS_CMD_OK);
203 Endpoint_ClearIN();
204 }
205
206 /** Handler for the CMD_ENTER_PROGMODE_ISP command, which attempts to enter programming mode on
207 * the attached device, returning success or failure back to the host.
208 */
209 static void V2Protocol_Command_EnterISPMode(void)
210 {
211 struct
212 {
213 uint8_t TimeoutMS;
214 uint8_t PinStabDelayMS;
215 uint8_t ExecutionDelayMS;
216 uint8_t SynchLoops;
217 uint8_t ByteDelay;
218 uint8_t PollValue;
219 uint8_t PollIndex;
220 uint8_t EnterProgBytes[4];
221 } Enter_ISP_Params;
222
223 Endpoint_Read_Stream_LE(&Enter_ISP_Params, sizeof(Enter_ISP_Params));
224
225 Endpoint_ClearOUT();
226 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
227
228 uint8_t ResponseStatus = STATUS_CMD_FAILED;
229
230 CurrentAddress = 0;
231
232 V2Protocol_DelayMS(Enter_ISP_Params.ExecutionDelayMS);
233 SPI_Init(V2Protocol_GetSPIPrescalerMask() | SPI_SCK_LEAD_RISING | SPI_SAMPLE_LEADING | SPI_MODE_MASTER);
234
235 while (Enter_ISP_Params.SynchLoops-- && (ResponseStatus == STATUS_CMD_FAILED))
236 {
237 uint8_t ResponseBytes[4];
238
239 V2Protocol_ChangeTargetResetLine(true);
240 V2Protocol_DelayMS(Enter_ISP_Params.PinStabDelayMS);
241
242 for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++)
243 {
244 V2Protocol_DelayMS(Enter_ISP_Params.ByteDelay);
245 ResponseBytes[RByte] = SPI_TransferByte(Enter_ISP_Params.EnterProgBytes[RByte]);
246 }
247
248 /* Check if polling disabled, or if the polled value matches the expected value */
249 if (!(Enter_ISP_Params.PollIndex) || (ResponseBytes[Enter_ISP_Params.PollIndex - 1] == Enter_ISP_Params.PollValue))
250 {
251 ResponseStatus = STATUS_CMD_OK;
252 }
253 else
254 {
255 V2Protocol_ChangeTargetResetLine(false);
256 V2Protocol_DelayMS(Enter_ISP_Params.PinStabDelayMS);
257 }
258 }
259
260 Endpoint_Write_Byte(CMD_ENTER_PROGMODE_ISP);
261 Endpoint_Write_Byte(ResponseStatus);
262 Endpoint_ClearIN();
263 }
264
265 /** Handler for the CMD_LEAVE_ISP command, which releases the target from programming mode. */
266 static void V2Protocol_Command_LeaveISPMode(void)
267 {
268 struct
269 {
270 uint8_t PreDelayMS;
271 uint8_t PostDelayMS;
272 } Leave_ISP_Params;
273
274 Endpoint_Read_Stream_LE(&Leave_ISP_Params, sizeof(Leave_ISP_Params));
275
276 Endpoint_ClearOUT();
277 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
278
279 V2Protocol_DelayMS(Leave_ISP_Params.PreDelayMS);
280 V2Protocol_ChangeTargetResetLine(false);
281 SPI_ShutDown();
282 V2Protocol_DelayMS(Leave_ISP_Params.PostDelayMS);
283
284 Endpoint_Write_Byte(CMD_LEAVE_PROGMODE_ISP);
285 Endpoint_Write_Byte(STATUS_CMD_OK);
286 Endpoint_ClearIN();
287 }
288
289 /** Handler for the CMD_PROGRAM_FLASH_ISP and CMD_PROGRAM_EEPROM_ISP commands, writing out bytes,
290 * words or pages of data to the attached device.
291 *
292 * \param[in] V2Command Issued V2 Protocol command byte from the host
293 */
294 static void V2Protocol_Command_ProgramMemory(uint8_t V2Command)
295 {
296 struct
297 {
298 uint16_t BytesToWrite;
299 uint8_t ProgrammingMode;
300 uint8_t DelayMS;
301 uint8_t ProgrammingCommands[3];
302 uint8_t PollValue1;
303 uint8_t PollValue2;
304 uint8_t ProgData[256]; // Note, the Jungo driver has a very short ACK timeout period, need to buffer the
305 } Write_Memory_Params; // whole page and ACK the packet as fast as possible to prevent it from aborting
306
307 Endpoint_Read_Stream_LE(&Write_Memory_Params, sizeof(Write_Memory_Params) - sizeof(Write_Memory_Params.ProgData));
308 Write_Memory_Params.BytesToWrite = SwapEndian_16(Write_Memory_Params.BytesToWrite);
309
310 if (Write_Memory_Params.BytesToWrite > sizeof(Write_Memory_Params.ProgData))
311 {
312 Endpoint_ClearOUT();
313 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
314
315 Endpoint_Write_Byte(V2Command);
316 Endpoint_Write_Byte(STATUS_CMD_FAILED);
317 Endpoint_ClearIN();
318 return;
319 }
320
321 Endpoint_Read_Stream_LE(&Write_Memory_Params.ProgData, Write_Memory_Params.BytesToWrite);
322
323 Endpoint_ClearOUT();
324 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
325
326 uint8_t ProgrammingStatus = STATUS_CMD_OK;
327 uint16_t PollAddress = 0;
328 uint8_t PollValue = (V2Command == CMD_PROGRAM_FLASH_ISP) ? Write_Memory_Params.PollValue1 :
329 Write_Memory_Params.PollValue2;
330 uint8_t* NextWriteByte = Write_Memory_Params.ProgData;
331
332 if (Write_Memory_Params.ProgrammingMode & PROG_MODE_PAGED_WRITES_MASK)
333 {
334 uint16_t StartAddress = (CurrentAddress & 0xFFFF);
335
336 /* Paged mode memory programming */
337 for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++)
338 {
339 bool IsOddByte = (CurrentByte & 0x01);
340 uint8_t ByteToWrite = *(NextWriteByte++);
341
342 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
343 Write_Memory_Params.ProgrammingCommands[0] |= READ_WRITE_HIGH_BYTE_MASK;
344 else
345 Write_Memory_Params.ProgrammingCommands[0] &= ~READ_WRITE_HIGH_BYTE_MASK;
346
347 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[0]);
348 SPI_SendByte(CurrentAddress >> 8);
349 SPI_SendByte(CurrentAddress & 0xFF);
350 SPI_SendByte(ByteToWrite);
351
352 if (!(PollAddress) && (ByteToWrite != PollValue))
353 {
354 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
355 Write_Memory_Params.ProgrammingCommands[2] |= READ_WRITE_HIGH_BYTE_MASK;
356
357 PollAddress = (CurrentAddress & 0xFFFF);
358 }
359
360 if (IsOddByte || (V2Command == CMD_PROGRAM_EEPROM_ISP))
361 CurrentAddress++;
362 }
363
364 /* If the current page must be committed, send the PROGRAM PAGE command to the target */
365 if (Write_Memory_Params.ProgrammingMode & PROG_MODE_COMMIT_PAGE_MASK)
366 {
367 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[1]);
368 SPI_SendByte(StartAddress >> 8);
369 SPI_SendByte(StartAddress & 0xFF);
370 SPI_SendByte(0x00);
371
372 /* Check if polling is possible, if not switch to timed delay mode */
373 if (!(PollAddress))
374 {
375 Write_Memory_Params.ProgrammingMode &= ~PROG_MODE_PAGED_VALUE_MASK;
376 Write_Memory_Params.ProgrammingMode |= PROG_MODE_PAGED_TIMEDELAY_MASK;
377 }
378
379 ProgrammingStatus = V2Protocol_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue,
380 Write_Memory_Params.DelayMS, Write_Memory_Params.ProgrammingCommands[2]);
381 }
382 }
383 else
384 {
385 /* Word/byte mode memory programming */
386 for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++)
387 {
388 bool IsOddByte = (CurrentByte & 0x01);
389 uint8_t ByteToWrite = *(NextWriteByte++);
390
391 if (IsOddByte && (V2Command == CMD_READ_FLASH_ISP))
392 Write_Memory_Params.ProgrammingCommands[0] |= READ_WRITE_HIGH_BYTE_MASK;
393 else
394 Write_Memory_Params.ProgrammingCommands[0] &= ~READ_WRITE_HIGH_BYTE_MASK;
395
396 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[0]);
397 SPI_SendByte(CurrentAddress >> 8);
398 SPI_SendByte(CurrentAddress & 0xFF);
399 SPI_SendByte(ByteToWrite);
400
401 if (ByteToWrite != PollValue)
402 {
403 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
404 Write_Memory_Params.ProgrammingCommands[2] |= READ_WRITE_HIGH_BYTE_MASK;
405
406 PollAddress = (CurrentAddress & 0xFFFF);
407 }
408
409 if (IsOddByte || (V2Command == CMD_PROGRAM_EEPROM_ISP))
410 CurrentAddress++;
411
412 ProgrammingStatus = V2Protocol_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue,
413 Write_Memory_Params.DelayMS, Write_Memory_Params.ProgrammingCommands[2]);
414
415 if (ProgrammingStatus != STATUS_CMD_OK)
416 break;
417 }
418 }
419
420 Endpoint_Write_Byte(V2Command);
421 Endpoint_Write_Byte(ProgrammingStatus);
422 Endpoint_ClearIN();
423 }
424
425 /** Handler for the CMD_READ_FLASH_ISP and CMD_READ_EEPROM_ISP commands, reading in bytes,
426 * words or pages of data from the attached device.
427 *
428 * \param[in] V2Command Issued V2 Protocol command byte from the host
429 */
430 static void V2Protocol_Command_ReadMemory(uint8_t V2Command)
431 {
432 struct
433 {
434 uint16_t BytesToRead;
435 uint8_t ReadMemoryCommand;
436 } Read_Memory_Params;
437
438 Endpoint_Read_Stream_LE(&Read_Memory_Params, sizeof(Read_Memory_Params));
439 Read_Memory_Params.BytesToRead = SwapEndian_16(Read_Memory_Params.BytesToRead);
440
441 Endpoint_ClearOUT();
442 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
443
444 Endpoint_Write_Byte(V2Command);
445 Endpoint_Write_Byte(STATUS_CMD_OK);
446
447 for (uint16_t CurrentByte = 0; CurrentByte < Read_Memory_Params.BytesToRead; CurrentByte++)
448 {
449 bool IsOddByte = (CurrentByte & 0x01);
450
451 if (IsOddByte && (V2Command == CMD_READ_FLASH_ISP))
452 Read_Memory_Params.ReadMemoryCommand |= READ_WRITE_HIGH_BYTE_MASK;
453 else
454 Read_Memory_Params.ReadMemoryCommand &= ~READ_WRITE_HIGH_BYTE_MASK;
455
456 SPI_SendByte(Read_Memory_Params.ReadMemoryCommand);
457 SPI_SendByte(CurrentAddress >> 8);
458 SPI_SendByte(CurrentAddress & 0xFF);
459 Endpoint_Write_Byte(SPI_ReceiveByte());
460
461 /* Check if the endpoint bank is currently full */
462 if (!(Endpoint_IsReadWriteAllowed()))
463 {
464 Endpoint_ClearIN();
465 Endpoint_WaitUntilReady();
466 }
467
468 if ((IsOddByte && (V2Command == CMD_READ_FLASH_ISP)) || (V2Command == CMD_READ_EEPROM_ISP))
469 CurrentAddress++;
470 }
471
472 Endpoint_Write_Byte(STATUS_CMD_OK);
473
474 bool IsEndpointFull = !(Endpoint_IsReadWriteAllowed());
475 Endpoint_ClearIN();
476
477 /* Ensure last packet is a short packet to terminate the transfer */
478 if (IsEndpointFull)
479 {
480 Endpoint_WaitUntilReady();
481 Endpoint_ClearIN();
482 Endpoint_WaitUntilReady();
483 }
484 }
485
486 /** Handler for the CMD_CHI_ERASE_ISP command, clearing the target's FLASH memory. */
487 static void V2Protocol_Command_ChipErase(void)
488 {
489 struct
490 {
491 uint8_t EraseDelayMS;
492 uint8_t PollMethod;
493 uint8_t EraseCommandBytes[4];
494 } Erase_Chip_Params;
495
496 Endpoint_Read_Stream_LE(&Erase_Chip_Params, sizeof(Erase_Chip_Params));
497
498 Endpoint_ClearOUT();
499 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
500
501 uint8_t ResponseStatus = STATUS_CMD_OK;
502
503 for (uint8_t SByte = 0; SByte < sizeof(Erase_Chip_Params.EraseCommandBytes); SByte++)
504 SPI_SendByte(Erase_Chip_Params.EraseCommandBytes[SByte]);
505
506 if (!(Erase_Chip_Params.PollMethod))
507 V2Protocol_DelayMS(Erase_Chip_Params.EraseDelayMS);
508 else
509 ResponseStatus = V2Protocol_WaitWhileTargetBusy();
510
511 Endpoint_Write_Byte(CMD_CHIP_ERASE_ISP);
512 Endpoint_Write_Byte(ResponseStatus);
513 Endpoint_ClearIN();
514 }
515
516 /** Handler for the CMD_READ_FUSE_ISP, CMD_READ_LOCK_ISP, CMD_READ_SIGNATURE_ISP and CMD_READ_OSCCAL commands,
517 * reading the requested configuration byte from the device.
518 *
519 * \param[in] V2Command Issued V2 Protocol command byte from the host
520 */
521 static void V2Protocol_Command_ReadFuseLockSigOSCCAL(uint8_t V2Command)
522 {
523 struct
524 {
525 uint8_t RetByte;
526 uint8_t ReadCommandBytes[4];
527 } Read_FuseLockSigOSCCAL_Params;
528
529 Endpoint_Read_Stream_LE(&Read_FuseLockSigOSCCAL_Params, sizeof(Read_FuseLockSigOSCCAL_Params));
530
531 Endpoint_ClearOUT();
532 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
533
534 uint8_t ResponseBytes[4];
535
536 for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++)
537 ResponseBytes[RByte] = SPI_TransferByte(Read_FuseLockSigOSCCAL_Params.ReadCommandBytes[RByte]);
538
539 Endpoint_Write_Byte(V2Command);
540 Endpoint_Write_Byte(STATUS_CMD_OK);
541 Endpoint_Write_Byte(ResponseBytes[Read_FuseLockSigOSCCAL_Params.RetByte - 1]);
542 Endpoint_Write_Byte(STATUS_CMD_OK);
543 Endpoint_ClearIN();
544 }
545
546 /** Handler for the CMD_WRITE_FUSE_ISP and CMD_WRITE_LOCK_ISP commands, writing the requested configuration
547 * byte to the device.
548 *
549 * \param[in] V2Command Issued V2 Protocol command byte from the host
550 */
551 static void V2Protocol_Command_WriteFuseLock(uint8_t V2Command)
552 {
553 struct
554 {
555 uint8_t WriteCommandBytes[4];
556 } Write_FuseLockSig_Params;
557
558 Endpoint_Read_Stream_LE(&Write_FuseLockSig_Params, sizeof(Write_FuseLockSig_Params));
559
560 Endpoint_ClearOUT();
561 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
562
563 for (uint8_t SByte = 0; SByte < sizeof(Write_FuseLockSig_Params.WriteCommandBytes); SByte++)
564 SPI_SendByte(Write_FuseLockSig_Params.WriteCommandBytes[SByte]);
565
566 Endpoint_Write_Byte(V2Command);
567 Endpoint_Write_Byte(STATUS_CMD_OK);
568 Endpoint_Write_Byte(STATUS_CMD_OK);
569 Endpoint_ClearIN();
570 }
571
572 /** Handler for the CMD_SPI_MULTI command, writing and reading arbitrary SPI data to and from the attached device. */
573 static void V2Protocol_Command_SPIMulti(void)
574 {
575 struct
576 {
577 uint8_t TxBytes;
578 uint8_t RxBytes;
579 uint8_t RxStartAddr;
580 uint8_t TxData[255];
581 } SPI_Multi_Params;
582
583 Endpoint_Read_Stream_LE(&SPI_Multi_Params, sizeof(SPI_Multi_Params) - sizeof(SPI_Multi_Params.TxData));
584 Endpoint_Read_Stream_LE(&SPI_Multi_Params.TxData, SPI_Multi_Params.TxBytes);
585
586 Endpoint_ClearOUT();
587 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
588
589 Endpoint_Write_Byte(CMD_SPI_MULTI);
590 Endpoint_Write_Byte(STATUS_CMD_OK);
591
592 uint8_t CurrTxPos = 0;
593 uint8_t CurrRxPos = 0;
594
595 /* Write out bytes to transmit until the start of the bytes to receive is met */
596 while (CurrTxPos < SPI_Multi_Params.RxStartAddr)
597 {
598 if (CurrTxPos < SPI_Multi_Params.TxBytes)
599 SPI_SendByte(SPI_Multi_Params.TxData[CurrTxPos]);
600 else
601 SPI_SendByte(0);
602
603 CurrTxPos++;
604 }
605
606 /* Transmit remaining bytes with padding as needed, read in response bytes */
607 while (CurrRxPos < SPI_Multi_Params.RxBytes)
608 {
609 if (CurrTxPos < SPI_Multi_Params.TxBytes)
610 Endpoint_Write_Byte(SPI_TransferByte(SPI_Multi_Params.TxData[CurrTxPos++]));
611 else
612 Endpoint_Write_Byte(SPI_ReceiveByte());
613
614 CurrRxPos++;
615 }
616
617 Endpoint_Write_Byte(STATUS_CMD_OK);
618 Endpoint_ClearIN();
619 }