TestAndMeasurement.c 13.6 KB
Newer Older
1
2
/*
             LUFA Library
3
     Copyright (C) Dean Camera, 2011.
4
5
              
  dean [at] fourwalledcubicle [dot] com
6
           www.lufa-lib.org
7
8
9
*/

/*
10
  Copyright 2011  Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

  Permission to use, copy, modify, distribute, and sell this 
  software and its documentation for any purpose is hereby granted
  without fee, provided that the above copyright notice appear in 
  all copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting 
  documentation, and that the name of the author not be used in 
  advertising or publicity pertaining to distribution of the 
  software without specific, written prior permission.

  The author disclaim all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

#include "TestAndMeasurement.h"

33
34
35
36
37
38
/** Contains the (usually static) capabilities of the TMC device. This table is requested by the
 *  host upon enumeration to give it information on what features of the Test and Measurement USB
 *  Class the device supports.
 */
TMC_Capabilities_t Capabilities =
	{
39
		.Status     = TMC_STATUS_SUCCESS,
40
41
42
43
44
45
		.TMCVersion = VERSION_BCD(1.00),
		
		.Interface  =
			{
				.ListenOnly             = false,
				.TalkOnly               = false,
46
				.PulseIndicateSupported = false,
47
48
49
50
51
52
53
54
			},

		.Device     =
			{
				.SupportsAbortINOnMatch = false,
			},
	};

55
/** Current TMC control request that is being processed */
56
uint8_t RequestInProgress = 0;
57
58

/** Stream callback abort flag for bulk IN data */
59
bool IsTMCBulkINReset = false;
60
61

/** Stream callback abort flag for bulk OUT data */
62
bool IsTMCBulkOUTReset = false;
63

64
65
/** Last used tag value for data transfers */
uint8_t CurrentTransferTag = 0;
66

67
68
/** Length of last data transfer, for reporting to the host in case an in-progress tranfer is aborted */
uint32_t LastTransferLength = 0;
69

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/** Main program entry point. This routine contains the overall program flow, including initial
 *  setup of all components and the main program loop.
 */
int main(void)
{
	SetupHardware();

	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
	sei();
	
	for (;;)
	{
		TMC_Task();
		USB_USBTask();
	}
}

/** Configures the board hardware and chip peripherals for the demo's functionality. */
void SetupHardware(void)
{
	/* Disable watchdog if enabled by bootloader/fuses */
	MCUSR &= ~(1 << WDRF);
	wdt_disable();

	/* Disable clock division */
	clock_prescale_set(clock_div_1);
	
	/* Hardware Initialization */
	LEDs_Init();
	USB_Init();
}

102
103
104
/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
 *  starts the library USB task to begin the enumeration and USB management process.
 */
105
106
107
108
109
void EVENT_USB_Device_Connect(void)
{
	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
}

110
111
112
/** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
 *  the status LEDs and stops the USB management and CDC management tasks.
 */
113
114
115
116
117
void EVENT_USB_Device_Disconnect(void)
{
	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
}

118
119
120
/** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration
 *  of the USB device after enumeration - the device endpoints are configured and the CDC management task started.
 */
121
122
void EVENT_USB_Device_ConfigurationChanged(void)
{
123
	bool ConfigSuccess = true;
124

125
	/* Setup TMC In, Out and Notification Endpoints */
126
127
	ConfigSuccess &= Endpoint_ConfigureEndpoint(TMC_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
	                                            TMC_IO_EPSIZE, ENDPOINT_BANK_SINGLE);
128
129
130
131
132
133
134
	ConfigSuccess &= Endpoint_ConfigureEndpoint(TMC_IN_EPNUM,  EP_TYPE_BULK, ENDPOINT_DIR_IN,
	                                            TMC_IO_EPSIZE, ENDPOINT_BANK_SINGLE);
	ConfigSuccess &= Endpoint_ConfigureEndpoint(TMC_OUT_EPNUM, EP_TYPE_BULK, ENDPOINT_DIR_OUT,
	                                            TMC_IO_EPSIZE, ENDPOINT_BANK_SINGLE);

	/* Indicate endpoint configuration success or failure */
	LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
135
136
}

137
138
139
/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to
 *  the device from the USB host before passing along unhandled control requests to the library for processing
 *  internally.
140
 */
141
void EVENT_USB_Device_ControlRequest(void)
142
{
143
	uint8_t TMCRequestStatus = TMC_STATUS_SUCCESS;
144

145
	/* Process TMC specific control requests */
146
147
148
149
150
	switch (USB_ControlRequest.bRequest)
	{
		case Req_InitiateAbortBulkOut:
			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT))
			{
151
				/* Check that no split transaction is already in progress and the data transfer tag is valid */
152
				if (RequestInProgress != 0)
153
				{
154
					TMCRequestStatus = TMC_STATUS_SPLIT_IN_PROGRESS;
155
				}
156
				else if (USB_ControlRequest.wValue != CurrentTransferTag)
157
				{
158
					TMCRequestStatus = TMC_STATUS_TRANSFER_NOT_IN_PROGRESS;
159
160
161
162
163
164
165
				}
				else
				{
					/* Indicate that all in-progress/pending data OUT requests should be aborted */
					IsTMCBulkOUTReset = true;
					
					/* Save the split request for later checking when a new request is received */
166
					RequestInProgress = Req_InitiateAbortBulkOut;
167
				}
168
169

				Endpoint_ClearSETUP();
170
				
171
172
173
				/* Write the request response byte */
				Endpoint_Write_Byte(TMCRequestStatus);

174
175
				Endpoint_ClearIN();
				Endpoint_ClearStatusStage();
176
177
178
179
180
181
			}
			
			break;
		case Req_CheckAbortBulkOutStatus:
			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT))
			{
182
				/* Check that an ABORT BULK OUT transaction has been requested and that the request has completed */
183
				if (RequestInProgress != Req_InitiateAbortBulkOut)
184
				  TMCRequestStatus = TMC_STATUS_SPLIT_NOT_IN_PROGRESS;				
185
				else if (IsTMCBulkOUTReset)
186
				  TMCRequestStatus = TMC_STATUS_PENDING;
187
				else
188
189
190
191
				  RequestInProgress = 0;	

				Endpoint_ClearSETUP();
								
192
193
194
				/* Write the request response bytes */
				Endpoint_Write_Byte(TMCRequestStatus);
				Endpoint_Write_Word_LE(0);
195
				Endpoint_Write_DWord_LE(LastTransferLength);
196
197
198

				Endpoint_ClearIN();
				Endpoint_ClearStatusStage();				
199
200
201
202
203
204
			}
			
			break;
		case Req_InitiateAbortBulkIn:
			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT))
			{
205
				/* Check that no split transaction is already in progress and the data transfer tag is valid */
206
				if (RequestInProgress != 0)
207
				{
208
					TMCRequestStatus = TMC_STATUS_SPLIT_IN_PROGRESS;				
209
				}
210
				else if (USB_ControlRequest.wValue != CurrentTransferTag)
211
				{
212
					TMCRequestStatus = TMC_STATUS_TRANSFER_NOT_IN_PROGRESS;
213
214
215
216
				}
				else
				{
					/* Indicate that all in-progress/pending data IN requests should be aborted */
217
					IsTMCBulkINReset = true;
218
219
					
					/* Save the split request for later checking when a new request is received */
220
					RequestInProgress = Req_InitiateAbortBulkIn;
221
				}
222
223

				Endpoint_ClearSETUP();
224
				
225
226
				/* Write the request response bytes */
				Endpoint_Write_Byte(TMCRequestStatus);
227
				Endpoint_Write_Byte(CurrentTransferTag);
228

229
230
				Endpoint_ClearIN();
				Endpoint_ClearStatusStage();
231
232
233
234
235
236
			}
			
			break;
		case Req_CheckAbortBulkInStatus:
			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT))
			{
237
				/* Check that an ABORT BULK IN transaction has been requested and that the request has completed */
238
				if (RequestInProgress != Req_InitiateAbortBulkIn)
239
				  TMCRequestStatus = TMC_STATUS_SPLIT_NOT_IN_PROGRESS;
240
				else if (IsTMCBulkINReset)
241
				  TMCRequestStatus = TMC_STATUS_PENDING;
242
				else
243
				  RequestInProgress = 0;
244
245
246

				Endpoint_ClearSETUP();
								
247
248
249
				/* Write the request response bytes */
				Endpoint_Write_Byte(TMCRequestStatus);
				Endpoint_Write_Word_LE(0);
250
				Endpoint_Write_DWord_LE(LastTransferLength);
251
252

				Endpoint_ClearIN();
253
				Endpoint_ClearStatusStage();
254
255
256
257
258
259
			}
			
			break;
		case Req_InitiateClear:
			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
			{
260
				/* Check that no split transaction is already in progress */
261
				if (RequestInProgress != 0)
262
				{
263
					Endpoint_Write_Byte(TMC_STATUS_SPLIT_IN_PROGRESS);				
264
265
266
267
268
269
270
271
				}
				else
				{
					/* Indicate that all in-progress/pending data IN and OUT requests should be aborted */
					IsTMCBulkINReset  = true;
					IsTMCBulkOUTReset = true;
					
					/* Save the split request for later checking when a new request is received */
272
					RequestInProgress = Req_InitiateClear;
273
				}
274
275

				Endpoint_ClearSETUP();
276
				
277
278
279
				/* Write the request response byte */
				Endpoint_Write_Byte(TMCRequestStatus);

280
281
				Endpoint_ClearIN();
				Endpoint_ClearStatusStage();
282
283
284
285
286
287
			}
			
			break;
		case Req_CheckClearStatus:
			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
			{
288
				/* Check that a CLEAR transaction has been requested and that the request has completed */
289
				if (RequestInProgress != Req_InitiateClear)
290
				  TMCRequestStatus = TMC_STATUS_SPLIT_NOT_IN_PROGRESS;				
291
				else if (IsTMCBulkINReset || IsTMCBulkOUTReset)
292
				  TMCRequestStatus = TMC_STATUS_PENDING;
293
				else
294
				  RequestInProgress = 0;
295
296
297

				Endpoint_ClearSETUP();

298
299
300
				/* Write the request response bytes */
				Endpoint_Write_Byte(TMCRequestStatus);
				Endpoint_Write_Byte(0);
301
302
303
				
				Endpoint_ClearIN();
				Endpoint_ClearStatusStage();				
304
305
306
307
308
309
			}
			
			break;
		case Req_GetCapabilities:
			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
			{
310
311
312
				Endpoint_ClearSETUP();
					
				/* Write the device capabilities to the control endpoint */
313
				Endpoint_Write_Control_Stream_LE(&Capabilities, sizeof(TMC_Capabilities_t));				
314
				Endpoint_ClearOUT();
315
316
317
318
319
			}
			
			break;
	}
}
320
321

/** Function to manage TMC data transmission and reception to and from the host. */
322
323
324
325
326
void TMC_Task(void)
{
	/* Device must be connected and configured for the task to run */
	if (USB_DeviceState != DEVICE_STATE_Configured)
	  return;
327
	
328
	TMC_MessageHeader_t MessageHeader;
329
	uint16_t            BytesTransferred;
330
	
331
	/* Try to read in a TMC message from the interface, process if one is available */
332
	if (ReadTMCHeader(&MessageHeader))
333
	{
334
335
		/* Indicate busy */
		LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
336
		
337
338
339
		switch (MessageHeader.MessageID)
		{
			case TMC_MESSAGEID_DEV_DEP_MSG_OUT:
340
341
342
343
344
345
346
347
348
				BytesTransferred = 0;
				while (Endpoint_Discard_Stream(MessageHeader.TransferSize, &BytesTransferred) ==
				       ENDPOINT_RWSTREAM_IncompleteTransfer)
				{
					if (IsTMCBulkOUTReset)
					  break;
				}
				LastTransferLength = BytesTransferred;
				
349
				Endpoint_ClearOUT();
350
351
				break;
			case TMC_MESSAGEID_DEV_DEP_MSG_IN:
352
				Endpoint_ClearOUT();
353

354
				MessageHeader.TransferSize = 3;
355
				MessageHeader.MessageIDSpecific.DeviceOUT.LastMessageTransaction = true;
356
				WriteTMCHeader(&MessageHeader);
357

358
359
360
361
362
363
364
365
366
				BytesTransferred = 0;
				while (Endpoint_Write_Stream_LE("TMC", MessageHeader.TransferSize, &BytesTransferred) ==
				       ENDPOINT_RWSTREAM_IncompleteTransfer)
				{
					if (IsTMCBulkINReset)
					  break;
				}
				LastTransferLength = BytesTransferred;

367
				Endpoint_ClearIN();
368
369
370
				break;
			default:
				Endpoint_StallTransaction();
371
372
				break;
		}
373
374

		LEDs_SetAllLEDs(LEDMASK_USB_READY);
375
	}
376
377
378
379
	
	/* All pending data has been processed - reset the data abort flags */
	IsTMCBulkINReset  = false;
	IsTMCBulkOUTReset = false;
380
}
381

382
383
384
385
386
387
/** Attempts to read in the TMC message header from the TMC interface.
 *
 *  \param[out] MessageHeader  Pointer to a location where the read header (if any) should be stored
 *
 *  \return Boolean true if a header was read, false otherwise
 */
388
389
bool ReadTMCHeader(TMC_MessageHeader_t* const MessageHeader)
{
390
391
	uint16_t BytesTransferred;

392
393
394
395
396
397
398
399
	/* Select the Data Out endpoint */
	Endpoint_SelectEndpoint(TMC_OUT_EPNUM);
	
	/* Abort if no command has been sent from the host */
	if (!(Endpoint_IsOUTReceived()))
	  return false;
	
	/* Read in the header of the command from the host */
400
401
402
403
404
405
406
	BytesTransferred = 0;
	while (Endpoint_Read_Stream_LE(MessageHeader, sizeof(TMC_MessageHeader_t), &BytesTransferred) ==
	       ENDPOINT_RWSTREAM_IncompleteTransfer)
	{
		if (IsTMCBulkOUTReset)
		  break;
	}
407
408
409
410
411

	/* Store the new command tag value for later use */
	CurrentTransferTag = MessageHeader->Tag;
	
	/* Indicate if the command has been aborted or not */
412
	return !(IsTMCBulkOUTReset);
413
414
415
416
}

bool WriteTMCHeader(TMC_MessageHeader_t* const MessageHeader)
{
417
	uint16_t BytesTransferred;
418
419
420
421
422
423
424
425
426

	/* Set the message tag of the command header */
	MessageHeader->Tag        =  CurrentTransferTag;
	MessageHeader->InverseTag = ~CurrentTransferTag;

	/* Select the Data In endpoint */
	Endpoint_SelectEndpoint(TMC_IN_EPNUM);

	/* Send the command header to the host */
427
428
429
430
431
432
433
	BytesTransferred = 0;
	while (Endpoint_Write_Stream_LE(MessageHeader, sizeof(TMC_MessageHeader_t), &BytesTransferred) ==
	       ENDPOINT_RWSTREAM_IncompleteTransfer)
	{
		if (IsTMCBulkINReset)
		  break;
	}
434
435

	/* Indicate if the command has been aborted or not */
436
	return !(IsTMCBulkINReset);
437
}