Partial Commit: Move AVRISP project out of the Projects\Incomplete directory.
[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 receieved 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 V2Command Issued V2 Protocol command byte from the host
105 */
106 static void V2Protocol_Command_Unknown(uint8_t V2Command)
107 {
108 /* Discard all incomming 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 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_GetParameterPrivellages(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 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[512];
305 } Write_Memory_Params;
306
307 uint8_t* NextWriteByte = Write_Memory_Params.ProgData;
308
309 Endpoint_Read_Stream_LE(&Write_Memory_Params, sizeof(Write_Memory_Params) - sizeof(Write_Memory_Params.ProgData));
310 Write_Memory_Params.BytesToWrite = SwapEndian_16(Write_Memory_Params.BytesToWrite);
311 Endpoint_Read_Stream_LE(&Write_Memory_Params.ProgData, Write_Memory_Params.BytesToWrite);
312
313 Endpoint_ClearOUT();
314 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
315
316 uint8_t ProgrammingStatus = STATUS_CMD_OK;
317 uint16_t PollAddress = 0;
318 uint8_t PollValue = (V2Command == CMD_PROGRAM_FLASH_ISP) ? Write_Memory_Params.PollValue1 :
319 Write_Memory_Params.PollValue2;
320 if (Write_Memory_Params.ProgrammingMode & PROG_MODE_PAGED_WRITES_MASK)
321 {
322 uint16_t StartAddress = (CurrentAddress & 0xFFFF);
323
324 /* Paged mode memory programming */
325 for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++)
326 {
327 bool IsOddByte = (CurrentByte & 0x01);
328 uint8_t ByteToWrite = *(NextWriteByte++);
329
330 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
331 Write_Memory_Params.ProgrammingCommands[0] |= READ_WRITE_HIGH_BYTE_MASK;
332 else
333 Write_Memory_Params.ProgrammingCommands[0] &= ~READ_WRITE_HIGH_BYTE_MASK;
334
335 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[0]);
336 SPI_SendByte(CurrentAddress >> 8);
337 SPI_SendByte(CurrentAddress & 0xFF);
338 SPI_SendByte(ByteToWrite);
339
340 if (!(PollAddress) && (ByteToWrite != PollValue))
341 {
342 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
343 Write_Memory_Params.ProgrammingCommands[2] |= READ_WRITE_HIGH_BYTE_MASK;
344
345 PollAddress = (CurrentAddress & 0xFFFF);
346 }
347
348 if (IsOddByte || (V2Command == CMD_PROGRAM_EEPROM_ISP))
349 CurrentAddress++;
350 }
351
352 /* If the current page must be committed, send the PROGRAM PAGE command to the target */
353 if (Write_Memory_Params.ProgrammingMode & PROG_MODE_COMMIT_PAGE_MASK)
354 {
355 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[1]);
356 SPI_SendByte(StartAddress >> 8);
357 SPI_SendByte(StartAddress & 0xFF);
358 SPI_SendByte(0x00);
359
360 /* Check if polling is possible, if not switch to timed delay mode */
361 if (!(PollAddress))
362 {
363 Write_Memory_Params.ProgrammingMode &= ~PROG_MODE_PAGED_VALUE_MASK;
364 Write_Memory_Params.ProgrammingMode |= PROG_MODE_PAGED_TIMEDELAY_MASK;
365 }
366
367 ProgrammingStatus = V2Protocol_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue,
368 Write_Memory_Params.DelayMS, Write_Memory_Params.ProgrammingCommands[2]);
369 }
370 }
371 else
372 {
373 /* Word/byte mode memory programming */
374 for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++)
375 {
376 bool IsOddByte = (CurrentByte & 0x01);
377 uint8_t ByteToWrite = *(NextWriteByte++);
378
379 if (IsOddByte && (V2Command == CMD_READ_FLASH_ISP))
380 Write_Memory_Params.ProgrammingCommands[0] |= READ_WRITE_HIGH_BYTE_MASK;
381 else
382 Write_Memory_Params.ProgrammingCommands[0] &= ~READ_WRITE_HIGH_BYTE_MASK;
383
384 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[0]);
385 SPI_SendByte(CurrentAddress >> 8);
386 SPI_SendByte(CurrentAddress & 0xFF);
387 SPI_SendByte(ByteToWrite);
388
389 if (ByteToWrite != PollValue)
390 {
391 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
392 Write_Memory_Params.ProgrammingCommands[2] |= READ_WRITE_HIGH_BYTE_MASK;
393
394 PollAddress = (CurrentAddress & 0xFFFF);
395 }
396
397 if (IsOddByte || (V2Command == CMD_PROGRAM_EEPROM_ISP))
398 CurrentAddress++;
399
400 ProgrammingStatus = V2Protocol_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue,
401 Write_Memory_Params.DelayMS, Write_Memory_Params.ProgrammingCommands[2]);
402
403 if (ProgrammingStatus != STATUS_CMD_OK)
404 break;
405 }
406 }
407
408 Endpoint_Write_Byte(V2Command);
409 Endpoint_Write_Byte(ProgrammingStatus);
410
411 Endpoint_ClearIN();
412 }
413
414 /** Handler for the CMD_READ_FLASH_ISP and CMD_READ_EEPROM_ISP commands, reading in bytes,
415 * words or pages of data from the attached device.
416 *
417 * \param V2Command Issued V2 Protocol command byte from the host
418 */
419 static void V2Protocol_Command_ReadMemory(uint8_t V2Command)
420 {
421 struct
422 {
423 uint16_t BytesToRead;
424 uint8_t ReadMemoryCommand;
425 } Read_Memory_Params;
426
427 Endpoint_Read_Stream_LE(&Read_Memory_Params, sizeof(Read_Memory_Params));
428 Read_Memory_Params.BytesToRead = SwapEndian_16(Read_Memory_Params.BytesToRead);
429
430 Endpoint_ClearOUT();
431 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
432
433 Endpoint_Write_Byte(V2Command);
434 Endpoint_Write_Byte(STATUS_CMD_OK);
435
436 for (uint16_t CurrentByte = 0; CurrentByte < Read_Memory_Params.BytesToRead; CurrentByte++)
437 {
438 bool IsOddByte = (CurrentByte & 0x01);
439
440 if (IsOddByte && (V2Command == CMD_READ_FLASH_ISP))
441 Read_Memory_Params.ReadMemoryCommand |= READ_WRITE_HIGH_BYTE_MASK;
442 else
443 Read_Memory_Params.ReadMemoryCommand &= ~READ_WRITE_HIGH_BYTE_MASK;
444
445 SPI_SendByte(Read_Memory_Params.ReadMemoryCommand);
446 SPI_SendByte(CurrentAddress >> 8);
447 SPI_SendByte(CurrentAddress & 0xFF);
448 Endpoint_Write_Byte(SPI_ReceiveByte());
449
450 /* Check if the endpoint bank is currently full */
451 if (!(Endpoint_IsReadWriteAllowed()))
452 {
453 Endpoint_ClearIN();
454 Endpoint_WaitUntilReady();
455 }
456
457 if ((IsOddByte && (V2Command == CMD_READ_FLASH_ISP)) || (V2Command == CMD_READ_EEPROM_ISP))
458 CurrentAddress++;
459 }
460
461 Endpoint_Write_Byte(STATUS_CMD_OK);
462
463 bool IsEndpointFull = !(Endpoint_IsReadWriteAllowed());
464 Endpoint_ClearIN();
465
466 /* Ensure last packet is a short packet to terminate the transfer */
467 if (IsEndpointFull)
468 {
469 Endpoint_WaitUntilReady();
470 Endpoint_ClearIN();
471 Endpoint_WaitUntilReady();
472 }
473 }
474
475 /** Handler for the CMD_CHI_ERASE_ISP command, clearing the target's FLASH memory. */
476 static void V2Protocol_Command_ChipErase(void)
477 {
478 struct
479 {
480 uint8_t EraseDelayMS;
481 uint8_t PollMethod;
482 uint8_t EraseCommandBytes[4];
483 } Erase_Chip_Params;
484
485 Endpoint_Read_Stream_LE(&Erase_Chip_Params, sizeof(Erase_Chip_Params));
486
487 Endpoint_ClearOUT();
488 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
489
490 uint8_t ResponseStatus = STATUS_CMD_OK;
491
492 for (uint8_t SByte = 0; SByte < sizeof(Erase_Chip_Params.EraseCommandBytes); SByte++)
493 SPI_SendByte(Erase_Chip_Params.EraseCommandBytes[SByte]);
494
495 if (!(Erase_Chip_Params.PollMethod))
496 V2Protocol_DelayMS(Erase_Chip_Params.EraseDelayMS);
497 else
498 ResponseStatus = V2Protocol_WaitWhileTargetBusy();
499
500 Endpoint_Write_Byte(CMD_CHIP_ERASE_ISP);
501 Endpoint_Write_Byte(ResponseStatus);
502 Endpoint_ClearIN();
503 }
504
505 /** Handler for the CMD_READ_FUSE_ISP, CMD_READ_LOCK_ISP, CMD_READ_SIGNATURE_ISP and CMD_READ_OSCCAL commands,
506 * reading the requested configuration byte from the device.
507 *
508 * \param V2Command Issued V2 Protocol command byte from the host
509 */
510 static void V2Protocol_Command_ReadFuseLockSigOSCCAL(uint8_t V2Command)
511 {
512 struct
513 {
514 uint8_t RetByte;
515 uint8_t ReadCommandBytes[4];
516 } Read_FuseLockSigOSCCAL_Params;
517
518 Endpoint_Read_Stream_LE(&Read_FuseLockSigOSCCAL_Params, sizeof(Read_FuseLockSigOSCCAL_Params));
519
520 Endpoint_ClearOUT();
521 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
522
523 uint8_t ResponseBytes[4];
524
525 for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++)
526 ResponseBytes[RByte] = SPI_TransferByte(Read_FuseLockSigOSCCAL_Params.ReadCommandBytes[RByte]);
527
528 Endpoint_Write_Byte(V2Command);
529 Endpoint_Write_Byte(STATUS_CMD_OK);
530 Endpoint_Write_Byte(ResponseBytes[Read_FuseLockSigOSCCAL_Params.RetByte - 1]);
531 Endpoint_Write_Byte(STATUS_CMD_OK);
532 Endpoint_ClearIN();
533 }
534
535 /** Handler for the CMD_WRITE_FUSE_ISP and CMD_WRITE_LOCK_ISP commands, writing the requested configuration
536 * byte to the device.
537 *
538 * \param V2Command Issued V2 Protocol command byte from the host
539 */
540 static void V2Protocol_Command_WriteFuseLock(uint8_t V2Command)
541 {
542 struct
543 {
544 uint8_t WriteCommandBytes[4];
545 } Write_FuseLockSig_Params;
546
547 Endpoint_Read_Stream_LE(&Write_FuseLockSig_Params, sizeof(Write_FuseLockSig_Params));
548
549 Endpoint_ClearOUT();
550 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
551
552 for (uint8_t SByte = 0; SByte < sizeof(Write_FuseLockSig_Params.WriteCommandBytes); SByte++)
553 SPI_SendByte(Write_FuseLockSig_Params.WriteCommandBytes[SByte]);
554
555 Endpoint_Write_Byte(V2Command);
556 Endpoint_Write_Byte(STATUS_CMD_OK);
557 Endpoint_Write_Byte(STATUS_CMD_OK);
558 Endpoint_ClearIN();
559 }
560
561 /** Handler for the CMD_SPI_MULTI command, writing and reading arbitrary SPI data to and from the attached device. */
562 static void V2Protocol_Command_SPIMulti(void)
563 {
564 struct
565 {
566 uint8_t TxBytes;
567 uint8_t RxBytes;
568 uint8_t RxStartAddr;
569 uint8_t TxData[255];
570 } SPI_Multi_Params;
571
572 Endpoint_Read_Stream_LE(&SPI_Multi_Params, sizeof(SPI_Multi_Params) - sizeof(SPI_Multi_Params.TxData));
573 Endpoint_Read_Stream_LE(&SPI_Multi_Params.TxData, SPI_Multi_Params.TxBytes);
574
575 Endpoint_ClearOUT();
576 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
577
578 Endpoint_Write_Byte(CMD_SPI_MULTI);
579 Endpoint_Write_Byte(STATUS_CMD_OK);
580
581 uint8_t CurrTxPos = 0;
582 uint8_t CurrRxPos = 0;
583
584 /* Write out bytes to transmit until the start of the bytes to receive is met */
585 while (CurrTxPos < SPI_Multi_Params.RxStartAddr)
586 {
587 if (CurrTxPos < SPI_Multi_Params.TxBytes)
588 SPI_SendByte(SPI_Multi_Params.TxData[CurrTxPos]);
589 else
590 SPI_SendByte(0);
591
592 CurrTxPos++;
593 }
594
595 /* Transmit remaining bytes with padding as needed, read in response bytes */
596 while (CurrRxPos < SPI_Multi_Params.RxBytes)
597 {
598 if (CurrTxPos < SPI_Multi_Params.TxBytes)
599 Endpoint_Write_Byte(SPI_TransferByte(SPI_Multi_Params.TxData[CurrTxPos++]));
600 else
601 Endpoint_Write_Byte(SPI_ReceiveByte());
602
603 CurrRxPos++;
604 }
605
606 Endpoint_Write_Byte(STATUS_CMD_OK);
607 Endpoint_ClearIN();
608 }