Skip to content

Commit 7d49b86

Browse files
committed
implement get object, close session
1 parent 4c81899 commit 7d49b86

File tree

3 files changed

+78
-116
lines changed

3 files changed

+78
-116
lines changed

examples/device/mtp/src/mtp_fs_example.c

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ enum {
105105
SUPPORTED_STORAGE_ID = 0x00010001u // physical = 1, logical = 1
106106
};
107107

108+
static bool is_session_opened = false;
108109

109110
//--------------------------------------------------------------------+
110111
// OPERATING STATUS
@@ -160,14 +161,9 @@ unsigned int fs_get_object_count(void) {
160161

161162
int32_t tud_mtp_data_complete_cb(uint8_t idx, mtp_container_header_t* cmd_header, mtp_generic_container_t* resp_block, tusb_xfer_result_t xfer_result, uint32_t xferred_bytes) {
162163
(void) idx;
163-
// switch (cmd_header->code) {
164-
// default: break;
165-
// }
166164
resp_block->len = MTP_CONTAINER_HEADER_LENGTH;
167165
resp_block->code = (xfer_result == XFER_RESULT_SUCCESS) ? MTP_RESP_OK : MTP_RESP_GENERAL_ERROR;
168-
169166
tud_mtp_response_send(resp_block);
170-
171167
return 0;
172168
}
173169

@@ -195,7 +191,24 @@ int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_bl
195191
}
196192

197193
case MTP_OP_OPEN_SESSION:
198-
out_block->code = MTP_RESP_OK;
194+
if (is_session_opened) {
195+
//return MTP_RESP_SESSION_ALREADY_OPEN;
196+
out_block->code = MTP_RESP_SESSION_ALREADY_OPEN;
197+
}else {
198+
out_block->code = MTP_RESP_OK;
199+
}
200+
is_session_opened = true;
201+
tud_mtp_response_send(out_block);
202+
break;
203+
204+
case MTP_OP_CLOSE_SESSION:
205+
if (!is_session_opened) {
206+
// return MTP_RESP_SESSION_NOT_OPEN;
207+
out_block->code = MTP_RESP_SESSION_NOT_OPEN;
208+
} else {
209+
out_block->code = MTP_RESP_OK;
210+
}
211+
is_session_opened = false;
199212
tud_mtp_response_send(out_block);
200213
break;
201214

@@ -272,13 +285,12 @@ int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_bl
272285
}
273286

274287
case MTP_OP_GET_OBJECT_INFO: {
275-
const uint32_t object_handle = cmd_block->data[0];
276-
fs_object_info_t* obj = fs_object_get_from_handle(object_handle);
288+
const uint32_t obj_handle = cmd_block->data[0];
289+
fs_object_info_t* obj = fs_object_get_from_handle(obj_handle);
277290
if (obj == NULL) {
278-
TU_LOG1("ERR: Object with handle %ld does not exist\r\n", object_handle);
279291
return MTP_RESP_INVALID_OBJECT_HANDLE;
280292
}
281-
mtp_object_info_header_t object_info_header = {
293+
mtp_object_info_header_t obj_info_header = {
282294
.storage_id = SUPPORTED_STORAGE_ID,
283295
.object_format = MTP_OBJ_FORMAT_TEXT,
284296
.protection_status = MTP_PROTECTION_STATUS_NO_PROTECTION,
@@ -295,7 +307,7 @@ int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_bl
295307
.association_desc = 0,
296308
.sequence_number = 0
297309
};
298-
mtp_container_add_raw(out_block, &object_info_header, sizeof(object_info_header));
310+
mtp_container_add_raw(out_block, &obj_info_header, sizeof(obj_info_header));
299311
mtp_container_add_cstring(out_block, obj->name);
300312
mtp_container_add_cstring(out_block, obj->created);
301313
mtp_container_add_cstring(out_block, obj->modified);
@@ -305,6 +317,18 @@ int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_bl
305317
break;
306318
}
307319

320+
case MTP_OP_GET_OBJECT: {
321+
const uint32_t obj_handle = cmd_block->data[0];
322+
fs_object_info_t* obj = fs_object_get_from_handle(obj_handle);
323+
if (obj == NULL) {
324+
return MTP_RESP_INVALID_OBJECT_HANDLE;
325+
}
326+
327+
mtp_container_add_raw(out_block, obj->data, obj->size);
328+
tud_mtp_data_send(out_block);
329+
break;
330+
}
331+
308332
default: return MTP_RESP_OPERATION_NOT_SUPPORTED;
309333
}
310334

src/class/mtp/mtp_device.c

Lines changed: 15 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,10 @@ typedef struct {
7979
//--------------------------------------------------------------------+
8080
// Checker
8181
static mtp_phase_type_t mtpd_chk_generic(const char *func_name, const bool err_cd, const uint16_t ret_code, const char *message);
82-
static mtp_phase_type_t mtpd_chk_session_open(const char *func_name);
8382

8483
// MTP commands
8584
static mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp);
8685
static mtp_phase_type_t mtpd_handle_data(void);
87-
static mtp_phase_type_t mtpd_handle_cmd_close_session(void);
88-
static mtp_phase_type_t mtpd_handle_cmd_get_object(void);
89-
static mtp_phase_type_t mtpd_handle_dti_get_object(void);
9086
static mtp_phase_type_t mtpd_handle_cmd_delete_object(void);
9187
static mtp_phase_type_t mtpd_handle_cmd_send_object_info(void);
9288
static mtp_phase_type_t mtpd_handle_dto_send_object_info(void);
@@ -272,6 +268,7 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
272268
break;
273269
}
274270

271+
#if 0
275272
case MTP_PHASE_DATA_IN:
276273
p_mtp->xferred_len += xferred_bytes;
277274
p_mtp->handled_len = p_mtp->xferred_len;
@@ -333,16 +330,17 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
333330
} else if (p_mtp->handled_len == 0) {
334331
// First data block includes container header + container data
335332
TU_ASSERT(usbd_edpt_xfer(rhport, p_mtp->ep_out,
336-
(uint8_t*) p_container + p_mtp->xferred_len,
333+
(uint8_t*) p_container + p_mtp->xferred_len,
337334
(uint16_t)TU_MIN(p_mtp->total_len - p_mtp->xferred_len, CFG_MTP_EP_SIZE)));
338335
} else {
339336
// Successive data block includes only container data
340337
TU_ASSERT(usbd_edpt_xfer(rhport, p_mtp->ep_out,
341-
((uint8_t *)(&p_container->data)) + p_mtp->xferred_len - p_mtp->handled_len,
342-
(uint16_t)TU_MIN(p_mtp->total_len - p_mtp->xferred_len, CFG_MTP_EP_SIZE)));
338+
((uint8_t *)(&p_container->data)) + p_mtp->xferred_len - p_mtp->handled_len,
339+
(uint16_t)TU_MIN(p_mtp->total_len - p_mtp->xferred_len, CFG_MTP_EP_SIZE)));
343340
}
344341
}
345342
break;
343+
#endif
346344

347345
case MTP_PHASE_RESPONSE_QUEUED:
348346
// response phase is complete -> prepare for new command
@@ -391,12 +389,16 @@ mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp) {
391389
TU_LOG_DRV(" MTP command: MTP_OP_GET_DEVICE_INFO\n");
392390
tud_mtp_device_info_t dev_info = {
393391
.standard_version = 100,
394-
.mtp_vendor_extension_id = 0xFFFFFFFFU,
392+
.mtp_vendor_extension_id = 6, // MTP specs say 0xFFFFFFFF but libMTP check for value 6
395393
.mtp_version = 100,
394+
#ifdef CFG_TUD_MTP_DEVICEINFO_EXTENSIONS
396395
.mtp_extensions = {
397396
.count = sizeof(CFG_TUD_MTP_DEVICEINFO_EXTENSIONS),
398397
.utf16 = { 0 }
399398
},
399+
#else
400+
.mtp_extensions = 0,
401+
#endif
400402
.functional_mode = 0x0000,
401403
.supported_operations = {
402404
.count = TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS),
@@ -419,9 +421,11 @@ mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp) {
419421
.arr = { CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS }
420422
}
421423
};
424+
#ifdef CFG_TUD_MTP_DEVICEINFO_EXTENSIONS
422425
for (uint8_t i=0; i < dev_info.mtp_extensions.count; i++) {
423426
dev_info.mtp_extensions.utf16[i] = (uint16_t)CFG_TUD_MTP_DEVICEINFO_EXTENSIONS[i];
424427
}
428+
#endif
425429
p_container->len = MTP_CONTAINER_HEADER_LENGTH + sizeof(tud_mtp_device_info_t);
426430
p_container->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
427431
p_container->code = MTP_OP_GET_DEVICE_INFO;
@@ -437,7 +441,7 @@ mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp) {
437441

438442
case MTP_OP_CLOSE_SESSION:
439443
TU_LOG_DRV(" MTP command: MTP_OP_CLOSE_SESSION\n");
440-
return mtpd_handle_cmd_close_session();
444+
break;
441445

442446
case MTP_OP_GET_STORAGE_IDS:
443447
TU_LOG_DRV(" MTP command: MTP_OP_GET_STORAGE_IDS\n");
@@ -457,7 +461,8 @@ mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp) {
457461

458462
case MTP_OP_GET_OBJECT:
459463
TU_LOG_DRV(" MTP command: MTP_OP_GET_OBJECT\n");
460-
return mtpd_handle_cmd_get_object();
464+
break;
465+
461466
case MTP_OP_DELETE_OBJECT:
462467
TU_LOG_DRV(" MTP command: MTP_OP_DELETE_OBJECT\n");
463468
return mtpd_handle_cmd_delete_object();
@@ -495,9 +500,6 @@ mtp_phase_type_t mtpd_handle_data(void)
495500

496501
switch(p_container->code)
497502
{
498-
case MTP_OP_GET_OBJECT:
499-
TU_LOG_DRV(" MTP command: MTP_OP_GET_OBJECT-DATA_IN\n");
500-
return mtpd_handle_dti_get_object();
501503
case MTP_OP_SEND_OBJECT_INFO:
502504
TU_LOG_DRV(" MTP command: MTP_OP_SEND_OBJECT_INFO-DATA_OUT\n");
503505
return mtpd_handle_dto_send_object_info();
@@ -511,79 +513,6 @@ mtp_phase_type_t mtpd_handle_data(void)
511513
return true;
512514
}
513515

514-
515-
mtp_phase_type_t mtpd_handle_cmd_close_session(void)
516-
{
517-
mtp_generic_container_t* p_container = &_mtpd_epbuf.container;
518-
uint32_t session_id = p_container->data[0];
519-
520-
mtp_response_t res = tud_mtp_storage_close_session(session_id);
521-
522-
_mtpd_itf.session_id = session_id;
523-
524-
p_container->len = MTP_CONTAINER_HEADER_LENGTH;
525-
p_container->type = MTP_CONTAINER_TYPE_RESPONSE_BLOCK;
526-
p_container->code = res;
527-
528-
return MTP_PHASE_RESPONSE;
529-
}
530-
531-
mtp_phase_type_t mtpd_handle_cmd_get_object(void)
532-
{
533-
mtp_generic_container_t* p_container = &_mtpd_epbuf.container;
534-
_mtpd_get_object_handle = p_container->data[0];
535-
536-
// Continue with DATA-IN
537-
return mtpd_handle_dti_get_object();
538-
}
539-
540-
mtp_phase_type_t mtpd_handle_dti_get_object(void)
541-
{
542-
mtp_response_t res;
543-
mtp_phase_type_t phase;
544-
uint32_t file_size = 0;
545-
mtp_generic_container_t* p_container = &_mtpd_epbuf.container;
546-
res = tud_mtp_storage_object_size(_mtpd_get_object_handle, &file_size);
547-
if ((phase = mtpd_chk_generic(__func__, (res != MTP_RESP_OK), res, "")) != MTP_PHASE_NONE) {
548-
return phase;
549-
}
550-
p_container->len = MTP_CONTAINER_HEADER_LENGTH + file_size;
551-
p_container->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
552-
p_container->code = MTP_OP_GET_OBJECT;
553-
554-
uint32_t buffer_size;
555-
uint32_t read_count;
556-
// Data block must be multiple of EP size
557-
if (_mtpd_itf.handled_len == 0)
558-
{
559-
// First data block: include container header
560-
buffer_size = ((MTP_MAX_PACKET_SIZE + MTP_CONTAINER_HEADER_LENGTH) / CFG_MTP_EP_SIZE) * CFG_MTP_EP_SIZE - MTP_CONTAINER_HEADER_LENGTH;
561-
res = tud_mtp_storage_object_read(_mtpd_get_object_handle, (void *)&p_container->data, buffer_size, &read_count);
562-
if ((phase = mtpd_chk_generic(__func__, (res != MTP_RESP_OK), res, "")) != MTP_PHASE_NONE) {
563-
return phase;
564-
}
565-
_mtpd_itf.queued_len = MTP_CONTAINER_HEADER_LENGTH + read_count;
566-
}
567-
else
568-
{
569-
// Successive data block: consider only container data
570-
buffer_size = (MTP_MAX_PACKET_SIZE / CFG_MTP_EP_SIZE) * CFG_MTP_EP_SIZE;
571-
res = tud_mtp_storage_object_read(_mtpd_get_object_handle, (void *)&p_container->data, buffer_size, &read_count);
572-
if ((phase = mtpd_chk_generic(__func__, (res != MTP_RESP_OK), res, "")) != MTP_PHASE_NONE) {
573-
return phase;
574-
}
575-
_mtpd_itf.queued_len = read_count;
576-
}
577-
578-
// File completed
579-
if (read_count < buffer_size)
580-
{
581-
tud_mtp_storage_object_done();
582-
}
583-
584-
return MTP_PHASE_DATA_IN;
585-
}
586-
587516
mtp_phase_type_t mtpd_handle_cmd_delete_object(void)
588517
{
589518
mtp_generic_container_t* p_container = &_mtpd_epbuf.container;
@@ -689,21 +618,6 @@ mtp_phase_type_t mtpd_handle_cmd_format_store(void)
689618
//--------------------------------------------------------------------+
690619
// Checker
691620
//--------------------------------------------------------------------+
692-
mtp_phase_type_t mtpd_chk_session_open(const char *func_name)
693-
{
694-
(void)func_name;
695-
mtp_generic_container_t* p_container = &_mtpd_epbuf.container;
696-
if (_mtpd_itf.session_id == 0)
697-
{
698-
TU_LOG_DRV(" MTP error: %s session not open\n", func_name);
699-
p_container->type = MTP_CONTAINER_TYPE_RESPONSE_BLOCK;
700-
p_container->code = MTP_RESP_SESSION_NOT_OPEN;
701-
p_container->len = MTP_CONTAINER_HEADER_LENGTH;
702-
return MTP_PHASE_RESPONSE;
703-
}
704-
return MTP_PHASE_NONE;
705-
}
706-
707621
mtp_phase_type_t mtpd_chk_generic(const char *func_name, const bool err_cd, const uint16_t ret_code, const char *message)
708622
{
709623
(void)func_name;

src/class/mtp/mtp_device.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ typedef struct {
4444

4545
// Number of supported operations, events, device properties, capture formats, playback formats
4646
// and max number of characters for strings manufacturer, model, device_version, serial_number
47-
#define MTP_DEVICE_INFO_TYPEDEF(_extension_nchars, _op_count, _event_count, _devprop_count, _capture_count, _playback_count) \
47+
#define MTP_DEVICE_INFO_STRUCT(_extension_nchars, _op_count, _event_count, _devprop_count, _capture_count, _playback_count) \
4848
struct TU_ATTR_PACKED { \
4949
uint16_t standard_version; \
5050
uint32_t mtp_vendor_extension_id; \
@@ -59,11 +59,34 @@ typedef struct {
5959
/* string fields will be added using append function */ \
6060
}
6161

62-
typedef MTP_DEVICE_INFO_TYPEDEF(
63-
sizeof(CFG_TUD_MTP_DEVICEINFO_EXTENSIONS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS),
62+
#define MTP_DEVICE_INFO_NO_EXTENSION_STRUCT(_op_count, _event_count, _devprop_count, _capture_count, _playback_count) \
63+
struct TU_ATTR_PACKED { \
64+
uint16_t standard_version; \
65+
uint32_t mtp_vendor_extension_id; \
66+
uint16_t mtp_version; \
67+
uint8_t mtp_extensions; \
68+
uint16_t functional_mode; \
69+
mtp_auint16_t(_op_count) supported_operations; \
70+
mtp_auint16_t(_event_count) supported_events; \
71+
mtp_auint16_t(_devprop_count) supported_device_properties; \
72+
mtp_auint16_t(_capture_count) capture_formats; \
73+
mtp_auint16_t(_playback_count) playback_formats; \
74+
/* string fields will be added using append function */ \
75+
}
76+
77+
#ifdef CFG_TUD_MTP_DEVICEINFO_EXTENSIONS
78+
typedef MTP_DEVICE_INFO_STRUCT(
79+
sizeof(CFG_TUD_MTP_DEVICEINFO_EXTENSIONS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS),
80+
TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES),
81+
TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS)
82+
) tud_mtp_device_info_t;
83+
#else
84+
typedef MTP_DEVICE_INFO_NO_EXTENSION_STRUCT(
85+
TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS),
6486
TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES),
6587
TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS)
6688
) tud_mtp_device_info_t;
89+
#endif
6790

6891
//--------------------------------------------------------------------+
6992
// Application API
@@ -76,7 +99,8 @@ bool tud_mtp_response_send(mtp_generic_container_t* resp_block);
7699
// Application Callbacks
77100
//--------------------------------------------------------------------+
78101

79-
// Invoked when new command is received
102+
// Invoked when new command is received. Application fill the out_block with either DATA or RESPONSE container
103+
// return MTP response code
80104
int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_block, mtp_generic_container_t* out_block);
81105

82106
// Invoked when data phase is complete

0 commit comments

Comments
 (0)