Rename the V2Protocol command handlers in the AVRISP project in preperation of XMEGA...
[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_SignOn();
51 break;
52 case CMD_SET_PARAMETER:
53 case CMD_GET_PARAMETER:
54 V2Protocol_GetSetParam(V2Command);
55 break;
56 case CMD_LOAD_ADDRESS:
57 V2Protocol_LoadAddress();
58 break;
59 case CMD_RESET_PROTECTION:
60 V2Protocol_ResetProtection();
61 break;
62 case CMD_ENTER_PROGMODE_ISP:
63 V2Protocol_ISP_EnterISPMode();
64 break;
65 case CMD_LEAVE_PROGMODE_ISP:
66 V2Protocol_ISP_LeaveISPMode();
67 break;
68 case CMD_PROGRAM_FLASH_ISP:
69 case CMD_PROGRAM_EEPROM_ISP:
70 V2Protocol_ISP_ProgramMemory(V2Command);
71 break;
72 case CMD_READ_FLASH_ISP:
73 case CMD_READ_EEPROM_ISP:
74 V2Protocol_ISP_ReadMemory(V2Command);
75 break;
76 case CMD_CHIP_ERASE_ISP:
77 V2Protocol_ISP_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_ISP_ReadFuseLockSigOSCCAL(V2Command);
84 break;
85 case CMD_PROGRAM_FUSE_ISP:
86 case CMD_PROGRAM_LOCK_ISP:
87 V2Protocol_ISP_WriteFuseLock(V2Command);
88 break;
89 case CMD_SPI_MULTI:
90 V2Protocol_ISP_SPIMulti();
91 break;
92 default:
93 V2Protocol_UnknownCommand(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_UnknownCommand(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_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_RESET_PROTECTION command, currently implemented as a dummy ACK function
137 * as no ISP short-circuit protection is currently implemented.
138 */
139 static void V2Protocol_ResetProtection(void)
140 {
141 Endpoint_ClearOUT();
142 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
143
144 Endpoint_Write_Byte(CMD_RESET_PROTECTION);
145 Endpoint_Write_Byte(STATUS_CMD_OK);
146 Endpoint_ClearIN();
147 }
148
149
150 /** Handler for the CMD_SET_PARAMETER and CMD_GET_PARAMETER commands from the host, setting or
151 * getting a device parameter's value from the parameter table.
152 *
153 * \param[in] V2Command Issued V2 Protocol command byte from the host
154 */
155 static void V2Protocol_GetSetParam(uint8_t V2Command)
156 {
157 uint8_t ParamID = Endpoint_Read_Byte();
158 uint8_t ParamValue;
159
160 if (V2Command == CMD_SET_PARAMETER)
161 ParamValue = Endpoint_Read_Byte();
162
163 Endpoint_ClearOUT();
164 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
165
166 Endpoint_Write_Byte(V2Command);
167
168 uint8_t ParamPrivs = V2Params_GetParameterPrivileges(ParamID);
169
170 if ((V2Command == CMD_SET_PARAMETER) && (ParamPrivs & PARAM_PRIV_WRITE))
171 {
172 Endpoint_Write_Byte(STATUS_CMD_OK);
173 V2Params_SetParameterValue(ParamID, ParamValue);
174 }
175 else if ((V2Command == CMD_GET_PARAMETER) && (ParamPrivs & PARAM_PRIV_READ))
176 {
177 Endpoint_Write_Byte(STATUS_CMD_OK);
178 Endpoint_Write_Byte(V2Params_GetParameterValue(ParamID));
179 }
180 else
181 {
182 Endpoint_Write_Byte(STATUS_CMD_FAILED);
183 }
184
185 Endpoint_ClearIN();
186 }
187
188 /** Handler for the CMD_LOAD_ADDRESS command, loading the given device address into a
189 * global storage variable for later use, and issuing LOAD EXTENDED ADDRESS commands
190 * to the attached device as required.
191 */
192 static void V2Protocol_LoadAddress(void)
193 {
194 Endpoint_Read_Stream_BE(&CurrentAddress, sizeof(CurrentAddress));
195
196 Endpoint_ClearOUT();
197 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
198
199 if (CurrentAddress & (1UL << 31))
200 V2Protocol_LoadExtendedAddress();
201
202 Endpoint_Write_Byte(CMD_LOAD_ADDRESS);
203 Endpoint_Write_Byte(STATUS_CMD_OK);
204 Endpoint_ClearIN();
205 }
206
207 /** Handler for the CMD_ENTER_PROGMODE_ISP command, which attempts to enter programming mode on
208 * the attached device, returning success or failure back to the host.
209 */
210 static void V2Protocol_ISP_EnterISPMode(void)
211 {
212 struct
213 {
214 uint8_t TimeoutMS;
215 uint8_t PinStabDelayMS;
216 uint8_t ExecutionDelayMS;
217 uint8_t SynchLoops;
218 uint8_t ByteDelay;
219 uint8_t PollValue;
220 uint8_t PollIndex;
221 uint8_t EnterProgBytes[4];
222 } Enter_ISP_Params;
223
224 Endpoint_Read_Stream_LE(&Enter_ISP_Params, sizeof(Enter_ISP_Params));
225
226 Endpoint_ClearOUT();
227 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
228
229 uint8_t ResponseStatus = STATUS_CMD_FAILED;
230
231 CurrentAddress = 0;
232
233 V2Protocol_DelayMS(Enter_ISP_Params.ExecutionDelayMS);
234 SPI_Init(V2Protocol_GetSPIPrescalerMask() | SPI_SCK_LEAD_RISING | SPI_SAMPLE_LEADING | SPI_MODE_MASTER);
235
236 while (Enter_ISP_Params.SynchLoops-- && (ResponseStatus == STATUS_CMD_FAILED))
237 {
238 uint8_t ResponseBytes[4];
239
240 V2Protocol_ChangeTargetResetLine(true);
241 V2Protocol_DelayMS(Enter_ISP_Params.PinStabDelayMS);
242
243 for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++)
244 {
245 V2Protocol_DelayMS(Enter_ISP_Params.ByteDelay);
246 ResponseBytes[RByte] = SPI_TransferByte(Enter_ISP_Params.EnterProgBytes[RByte]);
247 }
248
249 /* Check if polling disabled, or if the polled value matches the expected value */
250 if (!(Enter_ISP_Params.PollIndex) || (ResponseBytes[Enter_ISP_Params.PollIndex - 1] == Enter_ISP_Params.PollValue))
251 {
252 ResponseStatus = STATUS_CMD_OK;
253 }
254 else
255 {
256 V2Protocol_ChangeTargetResetLine(false);
257 V2Protocol_DelayMS(Enter_ISP_Params.PinStabDelayMS);
258 }
259 }
260
261 Endpoint_Write_Byte(CMD_ENTER_PROGMODE_ISP);
262 Endpoint_Write_Byte(ResponseStatus);
263 Endpoint_ClearIN();
264 }
265
266 /** Handler for the CMD_LEAVE_ISP command, which releases the target from programming mode. */
267 static void V2Protocol_ISP_LeaveISPMode(void)
268 {
269 struct
270 {
271 uint8_t PreDelayMS;
272 uint8_t PostDelayMS;
273 } Leave_ISP_Params;
274
275 Endpoint_Read_Stream_LE(&Leave_ISP_Params, sizeof(Leave_ISP_Params));
276
277 Endpoint_ClearOUT();
278 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
279
280 V2Protocol_DelayMS(Leave_ISP_Params.PreDelayMS);
281 V2Protocol_ChangeTargetResetLine(false);
282 SPI_ShutDown();
283 V2Protocol_DelayMS(Leave_ISP_Params.PostDelayMS);
284
285 Endpoint_Write_Byte(CMD_LEAVE_PROGMODE_ISP);
286 Endpoint_Write_Byte(STATUS_CMD_OK);
287 Endpoint_ClearIN();
288 }
289
290 /** Handler for the CMD_PROGRAM_FLASH_ISP and CMD_PROGRAM_EEPROM_ISP commands, writing out bytes,
291 * words or pages of data to the attached device.
292 *
293 * \param[in] V2Command Issued V2 Protocol command byte from the host
294 */
295 static void V2Protocol_ISP_ProgramMemory(uint8_t V2Command)
296 {
297 struct
298 {
299 uint16_t BytesToWrite;
300 uint8_t ProgrammingMode;
301 uint8_t DelayMS;
302 uint8_t ProgrammingCommands[3];
303 uint8_t PollValue1;
304 uint8_t PollValue2;
305 uint8_t ProgData[256]; // Note, the Jungo driver has a very short ACK timeout period, need to buffer the
306 } Write_Memory_Params; // whole page and ACK the packet as fast as possible to prevent it from aborting
307
308 Endpoint_Read_Stream_LE(&Write_Memory_Params, sizeof(Write_Memory_Params) - sizeof(Write_Memory_Params.ProgData));
309 Write_Memory_Params.BytesToWrite = SwapEndian_16(Write_Memory_Params.BytesToWrite);
310
311 if (Write_Memory_Params.BytesToWrite > sizeof(Write_Memory_Params.ProgData))
312 {
313 Endpoint_ClearOUT();
314 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
315
316 Endpoint_Write_Byte(V2Command);
317 Endpoint_Write_Byte(STATUS_CMD_FAILED);
318 Endpoint_ClearIN();
319 return;
320 }
321
322 Endpoint_Read_Stream_LE(&Write_Memory_Params.ProgData, Write_Memory_Params.BytesToWrite);
323
324 Endpoint_ClearOUT();
325 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
326
327 uint8_t ProgrammingStatus = STATUS_CMD_OK;
328 uint16_t PollAddress = 0;
329 uint8_t PollValue = (V2Command == CMD_PROGRAM_FLASH_ISP) ? Write_Memory_Params.PollValue1 :
330 Write_Memory_Params.PollValue2;
331 uint8_t* NextWriteByte = Write_Memory_Params.ProgData;
332
333 if (Write_Memory_Params.ProgrammingMode & PROG_MODE_PAGED_WRITES_MASK)
334 {
335 uint16_t StartAddress = (CurrentAddress & 0xFFFF);
336
337 /* Paged mode memory programming */
338 for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++)
339 {
340 bool IsOddByte = (CurrentByte & 0x01);
341 uint8_t ByteToWrite = *(NextWriteByte++);
342
343 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
344 Write_Memory_Params.ProgrammingCommands[0] |= READ_WRITE_HIGH_BYTE_MASK;
345 else
346 Write_Memory_Params.ProgrammingCommands[0] &= ~READ_WRITE_HIGH_BYTE_MASK;
347
348 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[0]);
349 SPI_SendByte(CurrentAddress >> 8);
350 SPI_SendByte(CurrentAddress & 0xFF);
351 SPI_SendByte(ByteToWrite);
352
353 if (!(PollAddress) && (ByteToWrite != PollValue))
354 {
355 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
356 Write_Memory_Params.ProgrammingCommands[2] |= READ_WRITE_HIGH_BYTE_MASK;
357
358 PollAddress = (CurrentAddress & 0xFFFF);
359 }
360
361 if (IsOddByte || (V2Command == CMD_PROGRAM_EEPROM_ISP))
362 CurrentAddress++;
363 }
364
365 /* If the current page must be committed, send the PROGRAM PAGE command to the target */
366 if (Write_Memory_Params.ProgrammingMode & PROG_MODE_COMMIT_PAGE_MASK)
367 {
368 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[1]);
369 SPI_SendByte(StartAddress >> 8);
370 SPI_SendByte(StartAddress & 0xFF);
371 SPI_SendByte(0x00);
372
373 /* Check if polling is possible, if not switch to timed delay mode */
374 if (!(PollAddress))
375 {
376 Write_Memory_Params.ProgrammingMode &= ~PROG_MODE_PAGED_VALUE_MASK;
377 Write_Memory_Params.ProgrammingMode |= PROG_MODE_PAGED_TIMEDELAY_MASK;
378 }
379
380 ProgrammingStatus = V2Protocol_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue,
381 Write_Memory_Params.DelayMS, Write_Memory_Params.ProgrammingCommands[2]);
382 }
383 }
384 else
385 {
386 /* Word/byte mode memory programming */
387 for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++)
388 {
389 bool IsOddByte = (CurrentByte & 0x01);
390 uint8_t ByteToWrite = *(NextWriteByte++);
391
392 if (IsOddByte && (V2Command == CMD_READ_FLASH_ISP))
393 Write_Memory_Params.ProgrammingCommands[0] |= READ_WRITE_HIGH_BYTE_MASK;
394 else
395 Write_Memory_Params.ProgrammingCommands[0] &= ~READ_WRITE_HIGH_BYTE_MASK;
396
397 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[0]);
398 SPI_SendByte(CurrentAddress >> 8);
399 SPI_SendByte(CurrentAddress & 0xFF);
400 SPI_SendByte(ByteToWrite);
401
402 if (ByteToWrite != PollValue)
403 {
404 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
405 Write_Memory_Params.ProgrammingCommands[2] |= READ_WRITE_HIGH_BYTE_MASK;
406
407 PollAddress = (CurrentAddress & 0xFFFF);
408 }
409
410 if (IsOddByte || (V2Command == CMD_PROGRAM_EEPROM_ISP))
411 CurrentAddress++;
412
413 ProgrammingStatus = V2Protocol_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue,
414 Write_Memory_Params.DelayMS, Write_Memory_Params.ProgrammingCommands[2]);
415
416 if (ProgrammingStatus != STATUS_CMD_OK)
417 break;
418 }
419 }
420
421 Endpoint_Write_Byte(V2Command);
422 Endpoint_Write_Byte(ProgrammingStatus);
423 Endpoint_ClearIN();
424 }
425
426 /** Handler for the CMD_READ_FLASH_ISP and CMD_READ_EEPROM_ISP commands, reading in bytes,
427 * words or pages of data from the attached device.
428 *
429 * \param[in] V2Command Issued V2 Protocol command byte from the host
430 */
431 static void V2Protocol_ISP_ReadMemory(uint8_t V2Command)
432 {
433 struct
434 {
435 uint16_t BytesToRead;
436 uint8_t ReadMemoryCommand;
437 } Read_Memory_Params;
438
439 Endpoint_Read_Stream_LE(&Read_Memory_Params, sizeof(Read_Memory_Params));
440 Read_Memory_Params.BytesToRead = SwapEndian_16(Read_Memory_Params.BytesToRead);
441
442 Endpoint_ClearOUT();
443 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
444
445 Endpoint_Write_Byte(V2Command);
446 Endpoint_Write_Byte(STATUS_CMD_OK);
447
448 for (uint16_t CurrentByte = 0; CurrentByte < Read_Memory_Params.BytesToRead; CurrentByte++)
449 {
450 bool IsOddByte = (CurrentByte & 0x01);
451
452 if (IsOddByte && (V2Command == CMD_READ_FLASH_ISP))
453 Read_Memory_Params.ReadMemoryCommand |= READ_WRITE_HIGH_BYTE_MASK;
454 else
455 Read_Memory_Params.ReadMemoryCommand &= ~READ_WRITE_HIGH_BYTE_MASK;
456
457 SPI_SendByte(Read_Memory_Params.ReadMemoryCommand);
458 SPI_SendByte(CurrentAddress >> 8);
459 SPI_SendByte(CurrentAddress & 0xFF);
460 Endpoint_Write_Byte(SPI_ReceiveByte());
461
462 /* Check if the endpoint bank is currently full */
463 if (!(Endpoint_IsReadWriteAllowed()))
464 {
465 Endpoint_ClearIN();
466 Endpoint_WaitUntilReady();
467 }
468
469 if ((IsOddByte && (V2Command == CMD_READ_FLASH_ISP)) || (V2Command == CMD_READ_EEPROM_ISP))
470 CurrentAddress++;
471 }
472
473 Endpoint_Write_Byte(STATUS_CMD_OK);
474
475 bool IsEndpointFull = !(Endpoint_IsReadWriteAllowed());
476 Endpoint_ClearIN();
477
478 /* Ensure last packet is a short packet to terminate the transfer */
479 if (IsEndpointFull)
480 {
481 Endpoint_WaitUntilReady();
482 Endpoint_ClearIN();
483 Endpoint_WaitUntilReady();
484 }
485 }
486
487 /** Handler for the CMD_CHI_ERASE_ISP command, clearing the target's FLASH memory. */
488 static void V2Protocol_ISP_ChipErase(void)
489 {
490 struct
491 {
492 uint8_t EraseDelayMS;
493 uint8_t PollMethod;
494 uint8_t EraseCommandBytes[4];
495 } Erase_Chip_Params;
496
497 Endpoint_Read_Stream_LE(&Erase_Chip_Params, sizeof(Erase_Chip_Params));
498
499 Endpoint_ClearOUT();
500 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
501
502 uint8_t ResponseStatus = STATUS_CMD_OK;
503
504 for (uint8_t SByte = 0; SByte < sizeof(Erase_Chip_Params.EraseCommandBytes); SByte++)
505 SPI_SendByte(Erase_Chip_Params.EraseCommandBytes[SByte]);
506
507 if (!(Erase_Chip_Params.PollMethod))
508 V2Protocol_DelayMS(Erase_Chip_Params.EraseDelayMS);
509 else
510 ResponseStatus = V2Protocol_WaitWhileTargetBusy();
511
512 Endpoint_Write_Byte(CMD_CHIP_ERASE_ISP);
513 Endpoint_Write_Byte(ResponseStatus);
514 Endpoint_ClearIN();
515 }
516
517 /** Handler for the CMD_READ_FUSE_ISP, CMD_READ_LOCK_ISP, CMD_READ_SIGNATURE_ISP and CMD_READ_OSCCAL commands,
518 * reading the requested configuration byte from the device.
519 *
520 * \param[in] V2Command Issued V2 Protocol command byte from the host
521 */
522 static void V2Protocol_ISP_ReadFuseLockSigOSCCAL(uint8_t V2Command)
523 {
524 struct
525 {
526 uint8_t RetByte;
527 uint8_t ReadCommandBytes[4];
528 } Read_FuseLockSigOSCCAL_Params;
529
530 Endpoint_Read_Stream_LE(&Read_FuseLockSigOSCCAL_Params, sizeof(Read_FuseLockSigOSCCAL_Params));
531
532 Endpoint_ClearOUT();
533 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
534
535 uint8_t ResponseBytes[4];
536
537 for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++)
538 ResponseBytes[RByte] = SPI_TransferByte(Read_FuseLockSigOSCCAL_Params.ReadCommandBytes[RByte]);
539
540 Endpoint_Write_Byte(V2Command);
541 Endpoint_Write_Byte(STATUS_CMD_OK);
542 Endpoint_Write_Byte(ResponseBytes[Read_FuseLockSigOSCCAL_Params.RetByte - 1]);
543 Endpoint_Write_Byte(STATUS_CMD_OK);
544 Endpoint_ClearIN();
545 }
546
547 /** Handler for the CMD_WRITE_FUSE_ISP and CMD_WRITE_LOCK_ISP commands, writing the requested configuration
548 * byte to the device.
549 *
550 * \param[in] V2Command Issued V2 Protocol command byte from the host
551 */
552 static void V2Protocol_ISP_WriteFuseLock(uint8_t V2Command)
553 {
554 struct
555 {
556 uint8_t WriteCommandBytes[4];
557 } Write_FuseLockSig_Params;
558
559 Endpoint_Read_Stream_LE(&Write_FuseLockSig_Params, sizeof(Write_FuseLockSig_Params));
560
561 Endpoint_ClearOUT();
562 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
563
564 for (uint8_t SByte = 0; SByte < sizeof(Write_FuseLockSig_Params.WriteCommandBytes); SByte++)
565 SPI_SendByte(Write_FuseLockSig_Params.WriteCommandBytes[SByte]);
566
567 Endpoint_Write_Byte(V2Command);
568 Endpoint_Write_Byte(STATUS_CMD_OK);
569 Endpoint_Write_Byte(STATUS_CMD_OK);
570 Endpoint_ClearIN();
571 }
572
573 /** Handler for the CMD_SPI_MULTI command, writing and reading arbitrary SPI data to and from the attached device. */
574 static void V2Protocol_ISP_SPIMulti(void)
575 {
576 struct
577 {
578 uint8_t TxBytes;
579 uint8_t RxBytes;
580 uint8_t RxStartAddr;
581 uint8_t TxData[255];
582 } SPI_Multi_Params;
583
584 Endpoint_Read_Stream_LE(&SPI_Multi_Params, sizeof(SPI_Multi_Params) - sizeof(SPI_Multi_Params.TxData));
585 Endpoint_Read_Stream_LE(&SPI_Multi_Params.TxData, SPI_Multi_Params.TxBytes);
586
587 Endpoint_ClearOUT();
588 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
589
590 Endpoint_Write_Byte(CMD_SPI_MULTI);
591 Endpoint_Write_Byte(STATUS_CMD_OK);
592
593 uint8_t CurrTxPos = 0;
594 uint8_t CurrRxPos = 0;
595
596 /* Write out bytes to transmit until the start of the bytes to receive is met */
597 while (CurrTxPos < SPI_Multi_Params.RxStartAddr)
598 {
599 if (CurrTxPos < SPI_Multi_Params.TxBytes)
600 SPI_SendByte(SPI_Multi_Params.TxData[CurrTxPos]);
601 else
602 SPI_SendByte(0);
603
604 CurrTxPos++;
605 }
606
607 /* Transmit remaining bytes with padding as needed, read in response bytes */
608 while (CurrRxPos < SPI_Multi_Params.RxBytes)
609 {
610 if (CurrTxPos < SPI_Multi_Params.TxBytes)
611 Endpoint_Write_Byte(SPI_TransferByte(SPI_Multi_Params.TxData[CurrTxPos++]));
612 else
613 Endpoint_Write_Byte(SPI_ReceiveByte());
614
615 CurrRxPos++;
616 }
617
618 Endpoint_Write_Byte(STATUS_CMD_OK);
619 Endpoint_ClearIN();
620 }