refactor API

This commit is contained in:
hathach
2025-09-23 15:23:16 +07:00
parent 1ab45bc525
commit 3c39f60f63
6 changed files with 179 additions and 153 deletions

View File

@ -164,90 +164,87 @@ uint32_t fs_get_object_count(void) {
return count;
}
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) {
(void) idx;
(void) cmd_header;
resp_block->len = MTP_CONTAINER_HEADER_LENGTH;
resp_block->code = (xfer_result == XFER_RESULT_SUCCESS) ? MTP_RESP_OK : MTP_RESP_GENERAL_ERROR;
tud_mtp_response_send(resp_block);
int32_t tud_mtp_data_complete_cb(tud_mtp_cb_data_t* cb_data) {
mtp_container_info_t* reply = &cb_data->reply;
reply->header->len = sizeof(mtp_container_header_t);
reply->header->code = (cb_data->xfer_result == XFER_RESULT_SUCCESS) ? MTP_RESP_OK : MTP_RESP_GENERAL_ERROR;
tud_mtp_response_send(reply);
return 0;
}
int32_t tud_mtp_response_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) {
(void) idx;
(void) cmd_header;
(void) resp_block;
(void) xfer_result;
(void) xferred_bytes;
int32_t tud_mtp_response_complete_cb(tud_mtp_cb_data_t* cb_data) {
(void) cb_data;
return 0; // nothing to do
}
int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_block, mtp_generic_container_t* out_block) {
(void)idx;
switch (cmd_block->code) {
int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t* cb_data) {
const mtp_container_command_t* command = cb_data->command;
mtp_container_info_t* reply = &cb_data->reply;
switch (command->header.code) {
case MTP_OP_GET_DEVICE_INFO: {
// Device info is already prepared up to playback formats. Application only need to add string fields
mtp_container_add_cstring(out_block, DEV_INFO_MANUFACTURER);
mtp_container_add_cstring(out_block, DEV_INFO_MODEL);
mtp_container_add_cstring(out_block, DEV_INFO_VERSION);
mtp_container_add_cstring(out_block, DEV_INFO_SERIAL);
mtp_container_add_cstring(&cb_data->reply, DEV_INFO_MANUFACTURER);
mtp_container_add_cstring(&cb_data->reply, DEV_INFO_MODEL);
mtp_container_add_cstring(&cb_data->reply, DEV_INFO_VERSION);
mtp_container_add_cstring(&cb_data->reply, DEV_INFO_SERIAL);
tud_mtp_data_send(out_block);
tud_mtp_data_send(&cb_data->reply);
break;
}
case MTP_OP_OPEN_SESSION:
if (is_session_opened) {
//return MTP_RESP_SESSION_ALREADY_OPEN;
out_block->code = MTP_RESP_SESSION_ALREADY_OPEN;
reply->header->code = MTP_RESP_SESSION_ALREADY_OPEN;
}else {
out_block->code = MTP_RESP_OK;
reply->header->code = MTP_RESP_OK;
}
is_session_opened = true;
tud_mtp_response_send(out_block);
tud_mtp_response_send(&cb_data->reply);
break;
case MTP_OP_CLOSE_SESSION:
if (!is_session_opened) {
// return MTP_RESP_SESSION_NOT_OPEN;
out_block->code = MTP_RESP_SESSION_NOT_OPEN;
reply->header->code = MTP_RESP_SESSION_NOT_OPEN;
} else {
out_block->code = MTP_RESP_OK;
reply->header->code = MTP_RESP_OK;
}
is_session_opened = false;
tud_mtp_response_send(out_block);
tud_mtp_response_send(&cb_data->reply);
break;
case MTP_OP_GET_STORAGE_IDS: {
uint32_t storage_ids [] = { SUPPORTED_STORAGE_ID }; // physical = 1, logical = 1
mtp_container_add_auint32(out_block, 1, storage_ids);
tud_mtp_data_send(out_block);
mtp_container_add_auint32(&cb_data->reply, 1, storage_ids);
tud_mtp_data_send(&cb_data->reply);
break;
}
case MTP_OP_GET_STORAGE_INFO: {
TU_VERIFY(SUPPORTED_STORAGE_ID == cmd_block->data[0], -1);
uint32_t storage_id = command->params[0];
TU_VERIFY(SUPPORTED_STORAGE_ID == storage_id, -1);
// update storage info with current free space
storage_info.free_space_in_objects = FS_MAX_FILE_COUNT - fs_get_object_count();
storage_info.free_space_in_bytes = FS_MAX_CAPACITY_BYTES-fs_buf_head;
mtp_container_add_raw(out_block, &storage_info, sizeof(storage_info));
tud_mtp_data_send(out_block);
mtp_container_add_raw(&cb_data->reply, &storage_info, sizeof(storage_info));
tud_mtp_data_send(&cb_data->reply);
break;
}
case MTP_OP_GET_DEVICE_PROP_DESC: {
const uint16_t dev_prop_code = (uint16_t) cmd_block->data[0];
const uint16_t dev_prop_code = (uint16_t) command->params[0];
mtp_device_prop_desc_header_t device_prop_header;
device_prop_header.device_property_code = dev_prop_code;
switch (dev_prop_code) {
case MTP_DEV_PROP_DEVICE_FRIENDLY_NAME:
device_prop_header.datatype = MTP_DATA_TYPE_STR;
device_prop_header.get_set = MTP_MODE_GET;
mtp_container_add_raw(out_block, &device_prop_header, sizeof(device_prop_header));
mtp_container_add_cstring(out_block, DEV_PROP_FRIENDLY_NAME); // factory
mtp_container_add_cstring(out_block, DEV_PROP_FRIENDLY_NAME); // current
mtp_container_add_uint8(out_block, 0); // no form
tud_mtp_data_send(out_block);
mtp_container_add_raw(&cb_data->reply, &device_prop_header, sizeof(device_prop_header));
mtp_container_add_cstring(&cb_data->reply, DEV_PROP_FRIENDLY_NAME); // factory
mtp_container_add_cstring(&cb_data->reply, DEV_PROP_FRIENDLY_NAME); // current
mtp_container_add_uint8(&cb_data->reply, 0); // no form
tud_mtp_data_send(&cb_data->reply);
break;
default: return MTP_RESP_PARAMETER_NOT_SUPPORTED;
@ -256,11 +253,11 @@ int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_bl
}
case MTP_OP_GET_DEVICE_PROP_VALUE: {
const uint16_t dev_prop_code = (uint16_t) cmd_block->data[0];
const uint16_t dev_prop_code = (uint16_t) command->params[0];
switch (dev_prop_code) {
case MTP_DEV_PROP_DEVICE_FRIENDLY_NAME:
mtp_container_add_cstring(out_block, DEV_PROP_FRIENDLY_NAME);
tud_mtp_data_send(out_block);
mtp_container_add_cstring(&cb_data->reply, DEV_PROP_FRIENDLY_NAME);
tud_mtp_data_send(&cb_data->reply);
break;
default: return MTP_RESP_PARAMETER_NOT_SUPPORTED;
@ -269,10 +266,10 @@ int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_bl
}
case MTP_OP_GET_OBJECT_HANDLES: {
const uint32_t storage_id = cmd_block->data[0];
const uint32_t obj_format = cmd_block->data[1]; // optional
const uint32_t storage_id = command->params[0];
const uint32_t obj_format = command->params[1]; // optional
(void) obj_format;
const uint32_t parent_handle = cmd_block->data[2]; // folder handle, 0xFFFFFFFF is root
const uint32_t parent_handle = command->params[2]; // folder handle, 0xFFFFFFFF is root
if (storage_id != 0xFFFFFFFF && storage_id != SUPPORTED_STORAGE_ID) {
return MTP_RESP_INVALID_STORAGE_ID;
}
@ -286,13 +283,13 @@ int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_bl
handles[count++] = i + 1; // handle is index + 1
}
}
mtp_container_add_auint32(out_block, count, handles);
tud_mtp_data_send(out_block);
mtp_container_add_auint32(&cb_data->reply, count, handles);
tud_mtp_data_send(&cb_data->reply);
break;
}
case MTP_OP_GET_OBJECT_INFO: {
const uint32_t obj_handle = cmd_block->data[0];
const uint32_t obj_handle = command->params[0];
fs_object_info_t* obj = fs_get_object(obj_handle);
if (obj == NULL) {
return MTP_RESP_INVALID_OBJECT_HANDLE;
@ -314,25 +311,25 @@ int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_bl
.association_desc = 0,
.sequence_number = 0
};
mtp_container_add_raw(out_block, &obj_info_header, sizeof(obj_info_header));
mtp_container_add_cstring(out_block, obj->name);
mtp_container_add_cstring(out_block, FS_FIXED_DATETIME);
mtp_container_add_cstring(out_block, FS_FIXED_DATETIME);
mtp_container_add_cstring(out_block, ""); // keywords, not used
mtp_container_add_raw(&cb_data->reply, &obj_info_header, sizeof(obj_info_header));
mtp_container_add_cstring(&cb_data->reply, obj->name);
mtp_container_add_cstring(&cb_data->reply, FS_FIXED_DATETIME);
mtp_container_add_cstring(&cb_data->reply, FS_FIXED_DATETIME);
mtp_container_add_cstring(&cb_data->reply, ""); // keywords, not used
tud_mtp_data_send(out_block);
tud_mtp_data_send(&cb_data->reply);
break;
}
case MTP_OP_GET_OBJECT: {
const uint32_t obj_handle = cmd_block->data[0];
const uint32_t obj_handle = command->params[0];
fs_object_info_t* obj = fs_get_object(obj_handle);
if (obj == NULL) {
return MTP_RESP_INVALID_OBJECT_HANDLE;
}
mtp_container_add_raw(out_block, obj->data, obj->size);
tud_mtp_data_send(out_block);
mtp_container_add_raw(&cb_data->reply, obj->data, obj->size);
tud_mtp_data_send(&cb_data->reply);
break;
}

View File

@ -92,9 +92,7 @@
//------------- CLASS -------------//
#define CFG_TUD_MTP 1
#define CFG_MTP_EP_SIZE 64
#define CFG_MTP_EVT_EP_SIZE 64
#define CFG_MTP_EVT_INTERVAL 100
#define CFG_TUD_MTP_EP_BUFSIZE 512
//------------- MTP device info -------------//
#define CFG_TUD_MTP_DEVICEINFO_EXTENSIONS "microsoft.com: 1.0; "

View File

@ -109,18 +109,16 @@ enum
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MTP_DESC_LEN)
uint8_t const desc_fs_configuration[] =
{
uint8_t const desc_fs_configuration[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
TUD_MTP_DESCRIPTOR(ITF_NUM_MTP, 4, EPNUM_MTP_EVT, CFG_MTP_EVT_EP_SIZE, CFG_MTP_EVT_INTERVAL, EPNUM_MTP_OUT, EPNUM_MTP_IN, CFG_MTP_EP_SIZE),
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
TUD_MTP_DESCRIPTOR(ITF_NUM_MTP, 4, EPNUM_MTP_EVT, 64, 1, EPNUM_MTP_OUT, EPNUM_MTP_IN, 64),
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
{
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
return desc_fs_configuration;
}

View File

@ -658,7 +658,6 @@ typedef enum {
// Data structures
//--------------------------------------------------------------------+
#define MTP_CONTAINER_HEADER_LENGTH 12
#define MTP_MAX_PACKET_SIZE 512
typedef struct TU_ATTR_PACKED {
@ -669,14 +668,33 @@ typedef struct TU_ATTR_PACKED {
} mtp_container_header_t;
TU_VERIFY_STATIC(sizeof(mtp_container_header_t) == 12, "size is not correct");
typedef struct TU_ATTR_PACKED {
mtp_container_header_t header;
uint32_t params[5];
} mtp_container_command_t;
TU_VERIFY_STATIC(sizeof(mtp_container_command_t) == 32, "size is not correct");
// PTP/MTP Generic container
typedef struct TU_ATTR_PACKED {
uint32_t len;
uint16_t type;
uint16_t code;
uint32_t transaction_id;
uint32_t data[MTP_MAX_PACKET_SIZE / sizeof(uint32_t)];
// union {
uint32_t data[(CFG_TUD_MTP_EP_BUFSIZE - sizeof(mtp_container_header_t)) / sizeof(uint32_t)];
// uint8_t data[CFG_TUD_MTP_EP_BUFSIZE - sizeof(mtp_container_header_t)];
// };
} mtp_generic_container_t;
TU_VERIFY_STATIC(sizeof(mtp_generic_container_t) == CFG_TUD_MTP_EP_BUFSIZE, "size is not correct");
typedef struct {
mtp_container_header_t* header;
union {
uint8_t* payload;
uint16_t* payload16;
uint32_t* payload32;
};
} mtp_container_info_t;
#define mtp_string_t(_nchars) \
struct TU_ATTR_PACKED { \
@ -690,12 +708,10 @@ typedef struct TU_ATTR_PACKED {
_type arr[_count];\
}
#define mtp_aint8_t(_count) mtp_array_t(int8_t, _count)
#define mtp_auint16_t(_count) mtp_array_t(uint16_t, _count)
typedef struct TU_ATTR_PACKED {
uint8_t count;
uint16_t utf16[];
} mtp_flexible_string_t;
#define mtp_auint32_t(_count) mtp_array_t(uint32_t, _count)
#define mtp_auint64_t(_count) mtp_array_t(uint64_t, _count)
typedef union TU_ATTR_PACKED {
struct {
@ -775,95 +791,100 @@ typedef struct TU_ATTR_PACKED {
} mtp_basic_object_info_t;
//--------------------------------------------------------------------+
// Generic Container function
// Container helper function
// return number of bytes added
//--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_raw(mtp_generic_container_t* p_container, const void* data, uint32_t len) {
TU_ASSERT(p_container->len + len < sizeof(mtp_generic_container_t), 0);
memcpy((uint8_t*) p_container + p_container->len, data, len);
p_container->len += len;
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_raw(mtp_container_info_t* p_container, const void* data, uint32_t len) {
TU_ASSERT(p_container->header->len + len < sizeof(mtp_generic_container_t), 0);
uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t);
memcpy(buf, data, len);
p_container->header->len += len;
return len;
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_array(mtp_generic_container_t* p_container, uint8_t scalar_size, uint32_t count, const void* data) {
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_array(mtp_container_info_t* p_container, uint8_t scalar_size, uint32_t count, const void* data) {
const uint32_t added_len = 4 + count * scalar_size;
TU_ASSERT(p_container->len + added_len < sizeof(mtp_generic_container_t), 0);
uint8_t* container8 = (uint8_t*)p_container;
TU_ASSERT(p_container->header->len + added_len < sizeof(mtp_generic_container_t), 0);
uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t);
tu_unaligned_write32(container8 + p_container->len, count);
p_container->len += 4;
tu_unaligned_write32(buf, count);
p_container->header->len += 4;
buf += 4;
memcpy(container8 + p_container->len, data, count * scalar_size);
p_container->len += count * scalar_size;
memcpy(buf, data, count * scalar_size);
p_container->header->len += count * scalar_size;
return added_len;
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_string(mtp_generic_container_t* p_container, uint8_t count, uint16_t* utf16) {
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_string(mtp_container_info_t* p_container, uint8_t count, uint16_t* utf16) {
const uint32_t added_len = 1 + 2 * count;
TU_ASSERT(p_container->len + added_len < sizeof(mtp_generic_container_t), 0);
uint8_t* container8 = (uint8_t*) p_container;
TU_ASSERT(p_container->header->len + added_len < sizeof(mtp_generic_container_t), 0);
uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t);
container8[p_container->len] = count;
p_container->len++;
*buf++ = count;
p_container->header->len++;
memcpy(container8 + p_container->len, utf16, 2 * count);
p_container->len += 2 * count;
memcpy(buf, utf16, 2 * count);
p_container->header->len += 2 * count;
return added_len;
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_cstring(mtp_generic_container_t* p_container, const char* str) {
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_cstring(mtp_container_info_t* p_container, const char* str) {
const uint8_t len = (uint8_t) (strlen(str) + 1); // include null
TU_ASSERT(p_container->len + 1 + 2 * len < sizeof(mtp_generic_container_t), 0);
uint8_t* container8 = (uint8_t*) p_container;
container8[p_container->len] = len;
p_container->len++;
TU_ASSERT(p_container->header->len + 1 + 2 * len < sizeof(mtp_generic_container_t), 0);
uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t);
if (len == 1) {
// empty string (null only)
container8[p_container->len] = 0;
// empty string (null only): single zero byte
*buf = 0;
p_container->header->len++;
return 1;
} else {
*buf++ = len;
p_container->header->len++;
for (uint8_t i = 0; i < len; i++) {
container8[p_container->len] = str[i];
container8[p_container->len + 1] = 0;
p_container->len += 2;
buf[0] = str[i];
buf[1] = 0;
buf += 2;
p_container->header->len += 2;
}
return 1 + 2 * len;
}
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint8(mtp_generic_container_t* p_container, uint8_t data) {
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint8(mtp_container_info_t* p_container, uint8_t data) {
return mtp_container_add_raw(p_container, &data, 1);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint16(mtp_generic_container_t* p_container, uint16_t data) {
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint16(mtp_container_info_t* p_container, uint16_t data) {
return mtp_container_add_raw(p_container, &data, 2);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint32(mtp_generic_container_t* p_container, uint32_t data) {
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint32(mtp_container_info_t* p_container, uint32_t data) {
return mtp_container_add_raw(p_container, &data, 4);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint64(mtp_generic_container_t* p_container, uint64_t data) {
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint64(mtp_container_info_t* p_container, uint64_t data) {
return mtp_container_add_raw(p_container, &data, 8);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint128(mtp_generic_container_t* p_container, const void* data) {
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint128(mtp_container_info_t* p_container, const void* data) {
return mtp_container_add_raw(p_container, data, 16);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint8(mtp_generic_container_t* p_container, uint32_t count, const uint8_t* data) {
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint8(mtp_container_info_t* p_container, uint32_t count, const uint8_t* data) {
return mtp_container_add_array(p_container, sizeof(uint8_t), count, data);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint16(mtp_generic_container_t* p_container, uint32_t count, const uint16_t* data) {
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint16(mtp_container_info_t* p_container, uint32_t count, const uint16_t* data) {
return mtp_container_add_array(p_container, sizeof(uint16_t), count, data);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint32(mtp_generic_container_t* p_container, uint32_t count, const uint32_t* data) {
TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint32(mtp_container_info_t* p_container, uint32_t count, const uint32_t* data) {
return mtp_container_add_array(p_container, sizeof(uint32_t), count, data);
}

View File

@ -67,7 +67,8 @@ typedef struct {
bool xfer_completed; // true when DATA-IN/DATA-OUT transfer is completed
uint32_t session_id;
mtp_container_header_t cmd_header;
mtp_container_command_t command;
// mtp_container_header_t reply_header;
} mtpd_interface_t;
typedef struct {
@ -81,7 +82,7 @@ typedef struct {
static mtp_phase_type_t mtpd_chk_generic(const char *func_name, const bool err_cd, const uint16_t ret_code, const char *message);
// MTP commands
static mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp);
static mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp, tud_mtp_cb_data_t* cb_data);
static mtp_phase_type_t mtpd_handle_data(void);
static mtp_phase_type_t mtpd_handle_cmd_delete_object(void);
static mtp_phase_type_t mtpd_handle_cmd_send_object_info(void);
@ -265,26 +266,24 @@ bool mtpd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
return true;
}
bool tud_mtp_data_send(mtp_generic_container_t* data_block) {
bool tud_mtp_data_send(mtp_container_info_t* p_container) {
mtpd_interface_t* p_mtp = &_mtpd_itf;
p_mtp->phase = MTP_PHASE_DATA;
p_mtp->total_len = data_block->len;
p_mtp->total_len = p_container->header->len;
p_mtp->xferred_len = 0;
p_mtp->handled_len = 0;
p_mtp->xfer_completed = false;
data_block->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
data_block->transaction_id = p_mtp->cmd_header.transaction_id;
TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, (uint8_t*) data_block, (uint16_t)data_block->len));
p_container->header->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, (uint8_t *)(&_mtpd_epbuf.container), (uint16_t)p_container->header->len));
return true;
}
bool tud_mtp_response_send(mtp_generic_container_t* resp_block) {
bool tud_mtp_response_send(mtp_container_info_t* p_container) {
mtpd_interface_t* p_mtp = &_mtpd_itf;
p_mtp->phase = MTP_PHASE_RESPONSE_QUEUED;
resp_block->type = MTP_CONTAINER_TYPE_RESPONSE_BLOCK;
resp_block->transaction_id = p_mtp->cmd_header.transaction_id;
TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, (uint8_t*) resp_block, (uint16_t)resp_block->len));
p_container->header->type = MTP_CONTAINER_TYPE_RESPONSE_BLOCK;
TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, (uint8_t *)(&_mtpd_epbuf.container), (uint16_t)p_container->header->len));
return true;
}
@ -300,6 +299,13 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
mtpd_interface_t* p_mtp = &_mtpd_itf;
mtp_generic_container_t* p_container = &_mtpd_epbuf.container;
tud_mtp_cb_data_t cb_data;
cb_data.idx = 0;
cb_data.command = &p_mtp->command;
cb_data.reply.header = (mtp_container_header_t*) p_container;
cb_data.reply.payload32 = p_container->data;
cb_data.offset = 0;
switch (p_mtp->phase) {
case MTP_PHASE_IDLE:
// received new command
@ -308,7 +314,8 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
TU_ATTR_FALLTHROUGH; // handle in the next case
case MTP_PHASE_COMMAND: {
mtpd_handle_cmd(p_mtp);
memcpy(&p_mtp->command, p_container, sizeof(mtp_container_command_t)); // copy new command
mtpd_handle_cmd(p_mtp, &cb_data);
break;
}
@ -320,7 +327,7 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
if (xferred_bytes == 0 || // ZLP
(xferred_bytes & (bulk_mps - 1)) || // short packet
p_mtp->xferred_len > p_mtp->total_len) {
tud_mtp_data_complete_cb(0, &p_mtp->cmd_header, p_container, event, p_mtp->xferred_len);
tud_mtp_data_complete_cb(&cb_data);
} else {
TU_ASSERT(false);
}
@ -404,7 +411,7 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
case MTP_PHASE_RESPONSE_QUEUED:
// response phase is complete -> prepare for new command
TU_ASSERT(ep_addr == p_mtp->ep_in);
tud_mtp_response_complete_cb(0, &p_mtp->cmd_header, p_container, event, xferred_bytes);
tud_mtp_response_complete_cb(&cb_data);
prepare_new_command(p_mtp);
break;
@ -429,23 +436,15 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
//--------------------------------------------------------------------+
// Decode command and prepare response
mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp) {
mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp, tud_mtp_cb_data_t* cb_data) {
mtp_generic_container_t* p_container = &_mtpd_epbuf.container;
p_container->len = sizeof(mtp_container_header_t); // default data/response length
mtp_generic_container_t cmd_block; // copy command block for callback
memcpy(&cmd_block, p_container, p_container->len);
memcpy(&p_mtp->cmd_header, p_container, sizeof(mtp_container_header_t));
p_container->len = MTP_CONTAINER_HEADER_LENGTH; // default data/response length
tu_lookup_find(&_mtp_op_table, p_mtp->command.header.code);
TU_LOG_DRV(" MTP command: %s\r\n", (char const*) tu_lookup_find(&_mtp_op_table, p_mtp->command.header.code));
if (p_container->code != MTP_OP_SEND_OBJECT) {
_mtpd_soi.object_handle = 0;
}
tu_lookup_find(&_mtp_op_table, cmd_block.code);
TU_LOG_DRV(" MTP command: %s\r\n", (char const*) tu_lookup_find(&_mtp_op_table, cmd_block.code));
mtp_phase_type_t ret = MTP_PHASE_RESPONSE;
switch (cmd_block.code) {
// pre-processed commands
switch (p_mtp->command.header.code) {
case MTP_OP_GET_DEVICE_INFO: {
tud_mtp_device_info_t dev_info = {
.standard_version = 100,
@ -486,12 +485,8 @@ mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp) {
dev_info.mtp_extensions.utf16[i] = (uint16_t)CFG_TUD_MTP_DEVICEINFO_EXTENSIONS[i];
}
#endif
p_container->len = MTP_CONTAINER_HEADER_LENGTH + sizeof(tud_mtp_device_info_t);
mtp_container_add_raw(&cb_data->reply, &dev_info, sizeof(tud_mtp_device_info_t));
p_container->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
p_container->code = MTP_OP_GET_DEVICE_INFO;
memcpy(p_container->data, &dev_info, sizeof(tud_mtp_device_info_t));
ret = MTP_PHASE_RESPONSE;
break;
}
@ -499,8 +494,8 @@ mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp) {
break;
}
tud_mtp_command_received_cb(0, &cmd_block, p_container);
return ret;
tud_mtp_command_received_cb(cb_data);
return MTP_PHASE_RESPONSE;
}
#if 0
@ -640,7 +635,7 @@ mtp_phase_type_t mtpd_chk_generic(const char *func_name, const bool err_cd, cons
TU_LOG_DRV(" MTP error in %s: (%x) %s\n", func_name, ret_code, message);
p_container->type = MTP_CONTAINER_TYPE_RESPONSE_BLOCK;
p_container->code = ret_code;
p_container->len = MTP_CONTAINER_HEADER_LENGTH;
p_container->len = sizeof(mtp_container_header_t);
return MTP_PHASE_RESPONSE;
}
return MTP_PHASE_NONE;

View File

@ -37,10 +37,22 @@
#endif
typedef struct {
const mtp_container_header_t* cmd_header;
uint8_t idx; // mtp instance
const mtp_container_command_t* command;
mtp_container_info_t reply;
union {
uint8_t* buffer;
uint16_t* buffer16;
uint32_t* buffer32;
};
uint32_t bufsize;
uint32_t offset; // offset from start of header, since data can span multiple xfers
tusb_xfer_result_t xfer_result;
uint32_t xferred_bytes;
} tud_mtp_cb_complete_data_t;
} tud_mtp_cb_data_t;
// Number of supported operations, events, device properties, capture formats, playback formats
// and max number of characters for strings manufacturer, model, device_version, serial_number
@ -91,23 +103,28 @@ typedef struct {
//--------------------------------------------------------------------+
// Application API
//--------------------------------------------------------------------+
bool tud_mtp_data_send(mtp_generic_container_t* data_block);
bool tud_mtp_data_send(mtp_container_info_t* p_container);
// bool tud_mtp_block_data_receive();
bool tud_mtp_response_send(mtp_generic_container_t* resp_block);
bool tud_mtp_response_send(mtp_container_info_t* p_container);
//--------------------------------------------------------------------+
// Application Callbacks
// Control request Callbacks
//--------------------------------------------------------------------+
// bool tud_mtp_control_xfer_cb(uint8_t idx, uint8_t stage, tusb_control_request_t const *p_request);
//--------------------------------------------------------------------+
// Bulk only protocol Callbacks
//--------------------------------------------------------------------+
// Invoked when new command is received. Application fill the out_block with either DATA or RESPONSE container
// return MTP response code
int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_block, mtp_generic_container_t* out_block);
int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t * cb_data);
// Invoked when data phase is complete
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);
int32_t tud_mtp_data_complete_cb(tud_mtp_cb_data_t* cb_data);
// Invoked when response phase is complete
int32_t tud_mtp_response_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);
int32_t tud_mtp_response_complete_cb(tud_mtp_cb_data_t* cb_data);
//--------------------------------------------------------------------+
// Helper functions