StillImage.c 13.7 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
  Permission to use, copy, modify, distribute, and sell this
13
  software and its documentation for any purpose is hereby granted
14
  without fee, provided that the above copyright notice appear in
15
  all copies and that both that the copyright notice and this
16
17
18
  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
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  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.
*/

#define  __INCLUDE_FROM_USB_DRIVER
#include "../../HighLevel/USBMode.h"
#if defined(USB_CAN_BE_HOST)

#define  __INCLUDE_FROM_SI_DRIVER
36
#define  __INCLUDE_FROM_STILLIMAGE_HOST_C
37
38
#include "StillImage.h"

39
40
uint8_t SI_Host_ConfigurePipes(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
                               uint16_t ConfigDescriptorSize,
41
                               void* ConfigDescriptorData)
42
{
43
44
45
46
	USB_Descriptor_Endpoint_t*  DataINEndpoint      = NULL;
	USB_Descriptor_Endpoint_t*  DataOUTEndpoint     = NULL;
	USB_Descriptor_Endpoint_t*  EventsEndpoint      = NULL;
	USB_Descriptor_Interface_t* StillImageInterface = NULL;
47

48
	memset(&SIInterfaceInfo->State, 0x00, sizeof(SIInterfaceInfo->State));
49

50
	if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
51
	  return SI_ENUMERROR_InvalidConfigDescriptor;
52
53

	while (!(DataINEndpoint) || !(DataOUTEndpoint))
54
	{
55
56
		if (!(StillImageInterface) ||
		    USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
57
		                              DCOMP_SI_Host_NextSIInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
58
		{
59
			if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
Dean Camera's avatar
Dean Camera committed
60
			                              DCOMP_SI_Host_NextSIInterface) != DESCRIPTOR_SEARCH_COMP_Found)
61
			{
62
				return SI_ENUMERROR_NoCompatibleInterfaceFound;
63
			}
64

65
			StillImageInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
66

67
68
69
			DataINEndpoint  = NULL;
			DataOUTEndpoint = NULL;
			EventsEndpoint  = NULL;
70
71
72
73
74
75
76
77
78
79
80
81

			continue;
		}

		USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);

		if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
		{
			if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
			  EventsEndpoint = EndpointData;
			else
			  DataINEndpoint = EndpointData;
82
83
84
		}
		else
		{
85
86
87
			DataOUTEndpoint = EndpointData;
		}
	}
88

89
90
	for (uint8_t PipeNum = 1; PipeNum < PIPE_TOTAL_PIPES; PipeNum++)
	{
91
92
93
94
95
96
97
		uint16_t Size;
		uint8_t  Type;
		uint8_t  Token;
		uint8_t  EndpointAddress;
		uint8_t  InterruptPeriod;
		bool     DoubleBanked;

98
99
		if (PipeNum == SIInterfaceInfo->Config.DataINPipeNumber)
		{
100
101
102
103
104
105
			Size            = DataINEndpoint->EndpointSize;
			EndpointAddress = DataINEndpoint->EndpointAddress;
			Token           = PIPE_TOKEN_IN;
			Type            = EP_TYPE_BULK;
			DoubleBanked    = SIInterfaceInfo->Config.DataINPipeDoubleBank;
			InterruptPeriod = 0;
106

107
108
109
110
			SIInterfaceInfo->State.DataINPipeSize = DataINEndpoint->EndpointSize;
		}
		else if (PipeNum == SIInterfaceInfo->Config.DataOUTPipeNumber)
		{
111
112
113
114
115
116
			Size            = DataOUTEndpoint->EndpointSize;
			EndpointAddress = DataOUTEndpoint->EndpointAddress;
			Token           = PIPE_TOKEN_OUT;
			Type            = EP_TYPE_BULK;
			DoubleBanked    = SIInterfaceInfo->Config.DataOUTPipeDoubleBank;
			InterruptPeriod = 0;
117

118
			SIInterfaceInfo->State.DataOUTPipeSize = DataOUTEndpoint->EndpointSize;
119
		}
120
121
		else if (PipeNum == SIInterfaceInfo->Config.EventsPipeNumber)
		{
122
123
124
125
126
127
			Size            = EventsEndpoint->EndpointSize;
			EndpointAddress = EventsEndpoint->EndpointAddress;
			Token           = PIPE_TOKEN_IN;
			Type            = EP_TYPE_INTERRUPT;
			DoubleBanked    = SIInterfaceInfo->Config.EventsPipeDoubleBank;
			InterruptPeriod = EventsEndpoint->PollingIntervalMS;
128

129
130
			SIInterfaceInfo->State.EventsPipeSize = EventsEndpoint->EndpointSize;
		}
131
132
133
134
135
136
137
138
139
140
141
142
143
		else
		{
			continue;
		}
		
		if (!(Pipe_ConfigurePipe(PipeNum, Type, Token, EndpointAddress, Size,
		                         DoubleBanked ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE)))
		{
			return SI_ENUMERROR_PipeConfigurationFailed;
		}
		
		if (InterruptPeriod)
		  Pipe_SetInterruptPeriod(InterruptPeriod);
144
145
	}

146
	SIInterfaceInfo->State.InterfaceNumber = StillImageInterface->InterfaceNumber;
147
	SIInterfaceInfo->State.IsActive = true;
148

149
150
151
	return SI_ENUMERROR_NoError;
}

152
uint8_t DCOMP_SI_Host_NextSIInterface(void* const CurrentDescriptor)
153
{
154
155
156
	USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);

	if (Header->Type == DTYPE_Interface)
157
	{
158
		USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
159

160
161
162
		if ((Interface->Class    == SI_CSCP_StillImageClass)    &&
		    (Interface->SubClass == SI_CSCP_StillImageSubclass) &&
		    (Interface->Protocol == SI_CSCP_BulkOnlyProtocol))
163
164
165
166
		{
			return DESCRIPTOR_SEARCH_Found;
		}
	}
167

168
169
170
	return DESCRIPTOR_SEARCH_NotFound;
}

171
uint8_t DCOMP_SI_Host_NextSIInterfaceEndpoint(void* const CurrentDescriptor)
172
{
173
174
175
	USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);

	if (Header->Type == DTYPE_Endpoint)
176
	{
177
		USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
178

179
		uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
180
181

		if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
182
		    (!(Pipe_IsEndpointBound(Endpoint->EndpointAddress))))
183
184
185
186
		{
			return DESCRIPTOR_SEARCH_Found;
		}
	}
187
	else if (Header->Type == DTYPE_Interface)
188
189
190
191
192
193
194
	{
		return DESCRIPTOR_SEARCH_Fail;
	}

	return DESCRIPTOR_SEARCH_NotFound;
}

195
uint8_t SI_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
196
                                PIMA_Container_t* const PIMAHeader)
197
198
{
	uint8_t ErrorCode;
199

200
201
202
203
204
205
206
207
208
	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
	  return PIPE_RWSTREAM_DeviceDisconnected;

	if (SIInterfaceInfo->State.IsSessionOpen)
	  PIMAHeader->TransactionID = SIInterfaceInfo->State.TransactionID++;

	Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
	Pipe_Unfreeze();

209
	if ((ErrorCode = Pipe_Write_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NULL)) != PIPE_RWSTREAM_NoError)
210
	  return ErrorCode;
211

212
213
214
215
	uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0));

	if (ParamBytes)
	{
216
		if ((ErrorCode = Pipe_Write_Stream_LE(&PIMAHeader->Params, ParamBytes, NULL)) != PIPE_RWSTREAM_NoError)
217
218
		  return ErrorCode;
	}
219

Dean Camera's avatar
Dean Camera committed
220
	Pipe_ClearOUT();
221
	Pipe_Freeze();
222

223
224
225
	return PIPE_RWSTREAM_NoError;
}

226
uint8_t SI_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
227
                                   PIMA_Container_t* const PIMAHeader)
228
{
229
	uint16_t TimeoutMSRem        = SI_COMMAND_DATA_TIMEOUT_MS;
230
	uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber();
231
232
233
234
235
236

	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
	  return PIPE_RWSTREAM_DeviceDisconnected;

	Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
	Pipe_Unfreeze();
237

238
	while (!(Pipe_IsINReceived()))
239
	{
240
		uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber();
241

242
		if (CurrentFrameNumber != PreviousFrameNumber)
243
		{
244
			PreviousFrameNumber = CurrentFrameNumber;
245

246
247
			if (!(TimeoutMSRem--))
			  return PIPE_RWSTREAM_Timeout;
248
		}
249

250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
		Pipe_Freeze();
		Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
		Pipe_Unfreeze();

		if (Pipe_IsStalled())
		{
			USB_Host_ClearPipeStall(SIInterfaceInfo->Config.DataOUTPipeNumber);
			return PIPE_RWSTREAM_PipeStalled;
		}

		Pipe_Freeze();
		Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
		Pipe_Unfreeze();

		if (Pipe_IsStalled())
		{
			USB_Host_ClearPipeStall(SIInterfaceInfo->Config.DataINPipeNumber);
			return PIPE_RWSTREAM_PipeStalled;
		}
269

270
271
272
		if (USB_HostState == HOST_STATE_Unattached)
		  return PIPE_RWSTREAM_DeviceDisconnected;
	}
273

274
	Pipe_Read_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NULL);
275

276
	if (PIMAHeader->Type == PIMA_CONTAINER_ResponseBlock)
277
278
279
280
	{
		uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0));

		if (ParamBytes)
281
		  Pipe_Read_Stream_LE(&PIMAHeader->Params, ParamBytes, NULL);
282

283
284
		Pipe_ClearIN();
	}
285

286
	Pipe_Freeze();
287

288
289
290
	return PIPE_RWSTREAM_NoError;
}

291
292
293
uint8_t SI_Host_SendData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
                         void* Buffer,
                         const uint16_t Bytes)
294
295
296
297
298
299
300
301
{
	uint8_t ErrorCode;

	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
	  return PIPE_RWSTREAM_DeviceDisconnected;

	Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
	Pipe_Unfreeze();
302

303
	ErrorCode = Pipe_Write_Stream_LE(Buffer, Bytes, NULL);
304
305
306

	Pipe_ClearOUT();
	Pipe_Freeze();
307

308
309
310
	return ErrorCode;
}

311
312
313
uint8_t SI_Host_ReadData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
                         void* Buffer,
                         const uint16_t Bytes)
314
315
316
317
318
319
320
321
322
{
	uint8_t ErrorCode;

	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
	  return PIPE_RWSTREAM_DeviceDisconnected;

	Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
	Pipe_Unfreeze();

323
	ErrorCode = Pipe_Read_Stream_LE(Buffer, Bytes, NULL);
324
325

	Pipe_Freeze();
326

327
328
329
	return ErrorCode;
}

330
bool SI_Host_IsEventReceived(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
331
332
333
334
335
336
337
338
{
	bool IsEventReceived = false;

	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
	  return false;

	Pipe_SelectPipe(SIInterfaceInfo->Config.EventsPipeNumber);
	Pipe_Unfreeze();
339

340
341
	if (Pipe_BytesInPipe())
	  IsEventReceived = true;
342

343
	Pipe_Freeze();
344

345
346
347
	return IsEventReceived;
}

348
uint8_t SI_Host_ReceiveEventHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
349
                                   PIMA_Container_t* const PIMAHeader)
350
351
352
353
354
355
356
357
{
	uint8_t ErrorCode;

	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
	  return PIPE_RWSTREAM_DeviceDisconnected;

	Pipe_SelectPipe(SIInterfaceInfo->Config.EventsPipeNumber);
	Pipe_Unfreeze();
358

359
	ErrorCode = Pipe_Read_Stream_LE(PIMAHeader, sizeof(PIMA_Container_t), NULL);
360

361
362
	Pipe_ClearIN();
	Pipe_Freeze();
363

364
365
366
	return ErrorCode;
}

367
uint8_t SI_Host_OpenSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
368
369
{
	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
370
	  return PIPE_RWSTREAM_DeviceDisconnected;
371
372
373
374
375
376

	uint8_t ErrorCode;

	SIInterfaceInfo->State.TransactionID = 0;
	SIInterfaceInfo->State.IsSessionOpen = false;

377
	PIMA_Container_t PIMABlock = (PIMA_Container_t)
378
379
		{
			.DataLength    = PIMA_COMMAND_SIZE(1),
380
			.Type          = PIMA_CONTAINER_CommandBlock,
381
382
383
			.Code          = 0x1002,
			.Params        = {1},
		};
384

385
	if ((ErrorCode = SI_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
386
	  return ErrorCode;
387

388
	if ((ErrorCode = SI_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
389
	  return ErrorCode;
390

391
	if ((PIMABlock.Type != PIMA_CONTAINER_ResponseBlock) || (PIMABlock.Code != 0x2001))
392
	  return SI_ERROR_LOGICAL_CMD_FAILED;
393

394
395
396
397
398
	SIInterfaceInfo->State.IsSessionOpen = true;

	return PIPE_RWSTREAM_NoError;
}

399
uint8_t SI_Host_CloseSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
400
401
{
	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
402
	  return PIPE_RWSTREAM_DeviceDisconnected;
403
404
405

	uint8_t ErrorCode;

406
	PIMA_Container_t PIMABlock = (PIMA_Container_t)
407
408
		{
			.DataLength    = PIMA_COMMAND_SIZE(1),
409
			.Type          = PIMA_CONTAINER_CommandBlock,
410
411
412
			.Code          = 0x1003,
			.Params        = {1},
		};
413

414
	if ((ErrorCode = SI_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
415
	  return ErrorCode;
416

417
	if ((ErrorCode = SI_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
418
419
420
421
	  return ErrorCode;

	SIInterfaceInfo->State.IsSessionOpen = false;

422
	if ((PIMABlock.Type != PIMA_CONTAINER_ResponseBlock) || (PIMABlock.Code != 0x2001))
423
424
425
426
427
	  return SI_ERROR_LOGICAL_CMD_FAILED;

	return PIPE_RWSTREAM_NoError;
}

428
429
430
431
uint8_t SI_Host_SendCommand(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
                            const uint16_t Operation,
                            const uint8_t TotalParams,
                            uint32_t* const Params)
432
433
{
	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
434
	  return PIPE_RWSTREAM_DeviceDisconnected;
435
436
437

	uint8_t ErrorCode;

438
	PIMA_Container_t PIMABlock = (PIMA_Container_t)
439
440
		{
			.DataLength    = PIMA_COMMAND_SIZE(TotalParams),
441
			.Type          = PIMA_CONTAINER_CommandBlock,
442
443
			.Code          = Operation,
		};
444

445
	memcpy(&PIMABlock.Params, Params, sizeof(uint32_t) * TotalParams);
446

447
	if ((ErrorCode = SI_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
448
449
450
451
452
	  return ErrorCode;

	return PIPE_RWSTREAM_NoError;
}

453
uint8_t SI_Host_ReceiveResponse(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
454
455
{
	uint8_t ErrorCode;
456
	PIMA_Container_t PIMABlock;
457
458

	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
459
	  return PIPE_RWSTREAM_DeviceDisconnected;
460

461
	if ((ErrorCode = SI_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
462
463
	  return ErrorCode;

464
	if ((PIMABlock.Type != PIMA_CONTAINER_ResponseBlock) || (PIMABlock.Code != 0x2001))
465
	  return SI_ERROR_LOGICAL_CMD_FAILED;
466

467
468
469
470
	return PIPE_RWSTREAM_NoError;
}

#endif
471