implement get object, close session

This commit is contained in:
hathach
2025-09-22 12:26:03 +07:00
parent 4c818998d4
commit 6fa5268a9c
5 changed files with 90 additions and 266 deletions

View File

@ -30,10 +30,10 @@
#define MTPD_VOLUME_IDENTIFIER "volume"
//--------------------------------------------------------------------+
// Device Info
// Dataset
//--------------------------------------------------------------------+
// device info string (including terminating null)
//------------- device info -------------//
#define DEV_INFO_MANUFACTURER "TinyUSB"
#define DEV_INFO_MODEL "MTP Example"
#define DEV_INFO_VERSION "1.0"
@ -41,6 +41,14 @@
#define DEV_PROP_FRIENDLY_NAME "TinyUSB MTP"
//------------- storage info -------------//
#define STORAGE_DESCRIPTRION { 'd', 'i', 's', 'k', 0 }
#define VOLUME_IDENTIFIER { 'v', 'o', 'l', 0 }
typedef MTP_STORAGE_INFO_STRUCT(TU_ARRAY_SIZE((uint16_t[]) STORAGE_DESCRIPTRION),
TU_ARRAY_SIZE(((uint16_t[])VOLUME_IDENTIFIER))
) storage_info_t;
//--------------------------------------------------------------------+
// RAM FILESYSTEM
//--------------------------------------------------------------------+
@ -77,12 +85,7 @@ static fs_object_info_t fs_objects[FS_MAX_NODES] = {
};
//------------- Storage Info -------------//
#define STORAGE_DESCRIPTRION { 'd', 'i', 's', 'k', 0 }
#define VOLUME_IDENTIFIER { 'v', 'o', 'l', 0 }
typedef MTP_STORAGE_INFO_STRUCT(TU_ARRAY_SIZE((uint16_t[]) STORAGE_DESCRIPTRION),
TU_ARRAY_SIZE(((uint16_t[])VOLUME_IDENTIFIER))
) storage_info_t;
storage_info_t storage_info = {
.storage_type = MTP_STORAGE_TYPE_FIXED_RAM,
@ -105,6 +108,7 @@ enum {
SUPPORTED_STORAGE_ID = 0x00010001u // physical = 1, logical = 1
};
static bool is_session_opened = false;
//--------------------------------------------------------------------+
// OPERATING STATUS
@ -160,14 +164,9 @@ unsigned int fs_get_object_count(void) {
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;
// switch (cmd_header->code) {
// default: break;
// }
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);
return 0;
}
@ -195,7 +194,24 @@ int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_bl
}
case MTP_OP_OPEN_SESSION:
out_block->code = MTP_RESP_OK;
if (is_session_opened) {
//return MTP_RESP_SESSION_ALREADY_OPEN;
out_block->code = MTP_RESP_SESSION_ALREADY_OPEN;
}else {
out_block->code = MTP_RESP_OK;
}
is_session_opened = true;
tud_mtp_response_send(out_block);
break;
case MTP_OP_CLOSE_SESSION:
if (!is_session_opened) {
// return MTP_RESP_SESSION_NOT_OPEN;
out_block->code = MTP_RESP_SESSION_NOT_OPEN;
} else {
out_block->code = MTP_RESP_OK;
}
is_session_opened = false;
tud_mtp_response_send(out_block);
break;
@ -272,13 +288,12 @@ int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_bl
}
case MTP_OP_GET_OBJECT_INFO: {
const uint32_t object_handle = cmd_block->data[0];
fs_object_info_t* obj = fs_object_get_from_handle(object_handle);
const uint32_t obj_handle = cmd_block->data[0];
fs_object_info_t* obj = fs_object_get_from_handle(obj_handle);
if (obj == NULL) {
TU_LOG1("ERR: Object with handle %ld does not exist\r\n", object_handle);
return MTP_RESP_INVALID_OBJECT_HANDLE;
}
mtp_object_info_header_t object_info_header = {
mtp_object_info_header_t obj_info_header = {
.storage_id = SUPPORTED_STORAGE_ID,
.object_format = MTP_OBJ_FORMAT_TEXT,
.protection_status = MTP_PROTECTION_STATUS_NO_PROTECTION,
@ -295,7 +310,7 @@ 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, &object_info_header, sizeof(object_info_header));
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, obj->created);
mtp_container_add_cstring(out_block, obj->modified);
@ -305,6 +320,18 @@ int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_bl
break;
}
case MTP_OP_GET_OBJECT: {
const uint32_t obj_handle = cmd_block->data[0];
fs_object_info_t* obj = fs_object_get_from_handle(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);
break;
}
default: return MTP_RESP_OPERATION_NOT_SUPPORTED;
}
@ -314,22 +341,12 @@ int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_bl
//--------------------------------------------------------------------+
// API
//--------------------------------------------------------------------+
mtp_response_t tud_mtp_storage_close_session(uint32_t session_id) {
if (session_id != _fs_operation.session_id) {
TU_LOG1("ERR: Session %ld not open\r\n", session_id);
return MTP_RESP_SESSION_NOT_OPEN;
}
_fs_operation.session_id = 0;
TU_LOG1("Session closed\r\n");
return MTP_RESP_OK;
}
mtp_response_t tud_mtp_storage_format(uint32_t storage_id) {
if (_fs_operation.session_id == 0) {
TU_LOG1("ERR: Session not open\r\n");
return MTP_RESP_SESSION_NOT_OPEN;
}
if (storage_id != STORAGE_ID(0x0001, 0x0001)) {
if (storage_id != SUPPORTED_STORAGE_ID) {
TU_LOG1("ERR: Unexpected storage id %ld\r\n", storage_id);
return MTP_RESP_INVALID_STORAGE_ID;
}
@ -341,45 +358,6 @@ mtp_response_t tud_mtp_storage_format(uint32_t storage_id) {
return MTP_RESP_OK;
}
mtp_response_t tud_mtp_storage_association_get_object_handle(uint32_t storage_id, uint32_t parent_object_handle,
uint32_t* next_child_handle) {
fs_object_info_t* obj;
if (_fs_operation.session_id == 0) {
TU_LOG1("ERR: Session not open\r\n");
return MTP_RESP_SESSION_NOT_OPEN;
}
// We just have one storage, same reply if querying all storages
if (storage_id != 0xFFFFFFFF && storage_id != STORAGE_ID(0x0001, 0x0001)) {
TU_LOG1("ERR: Unexpected storage id %ld\r\n", storage_id);
return MTP_RESP_INVALID_STORAGE_ID;
}
// Request for objects with no parent (0xFFFFFFFF) are considered root objects
// Note: implementation may pass 0 as parent_object_handle
if (parent_object_handle == 0xFFFFFFFF)
parent_object_handle = 0;
if (parent_object_handle != _fs_operation.traversal_parent) {
_fs_operation.traversal_parent = parent_object_handle;
_fs_operation.traversal_index = 0;
}
for (unsigned int i = _fs_operation.traversal_index; i < FS_MAX_NODES; i++) {
obj = &fs_objects[i];
if (obj->allocated && obj->parent == parent_object_handle) {
_fs_operation.traversal_index = i + 1;
*next_child_handle = obj->handle;
TU_LOG1("Association %ld -> child %ld\r\n", parent_object_handle, obj->handle);
return MTP_RESP_OK;
}
}
TU_LOG1("Association traversal completed\r\n");
_fs_operation.traversal_index = 0;
*next_child_handle = 0;
return MTP_RESP_OK;
}
mtp_response_t tud_mtp_storage_object_write_info(uint32_t storage_id, uint32_t parent_object,
uint32_t* new_object_handle, const mtp_object_info_header_t* info) {
fs_object_info_t* obj = NULL;
@ -389,7 +367,7 @@ mtp_response_t tud_mtp_storage_object_write_info(uint32_t storage_id, uint32_t p
return MTP_RESP_SESSION_NOT_OPEN;
}
// Accept command on default storage
if (storage_id != 0xFFFFFFFF && storage_id != STORAGE_ID(0x0001, 0x0001)) {
if (storage_id != 0xFFFFFFFF && storage_id != SUPPORTED_STORAGE_ID) {
TU_LOG1("ERR: Unexpected storage id %ld\r\n", storage_id);
return MTP_RESP_INVALID_STORAGE_ID;
}
@ -480,55 +458,6 @@ mtp_response_t tud_mtp_storage_object_write(uint32_t object_handle, const uint8_
return MTP_RESP_OK;
}
mtp_response_t tud_mtp_storage_object_size(uint32_t object_handle, uint32_t* size) {
const fs_object_info_t* obj;
obj = fs_object_get_from_handle(object_handle);
if (obj == NULL) {
TU_LOG1("ERR: Object with handle %ld does not exist\r\n", object_handle);
return MTP_RESP_INVALID_OBJECT_HANDLE;
}
*size = obj->size;
return MTP_RESP_OK;
}
mtp_response_t tud_mtp_storage_object_read(uint32_t object_handle, void* buffer, uint32_t buffer_size,
uint32_t* read_count) {
const fs_object_info_t* obj;
obj = fs_object_get_from_handle(object_handle);
if (obj == NULL) {
TU_LOG1("ERR: Object with handle %ld does not exist\r\n", object_handle);
return MTP_RESP_INVALID_OBJECT_HANDLE;
}
// It's not a requirement that this command is preceded by a read info
if (object_handle != _fs_operation.read_handle) {
TU_LOG1("ERR: Object %ld not open for read\r\n", object_handle);
_fs_operation.read_handle = object_handle;
_fs_operation.read_pos = 0;
}
if (obj->size - _fs_operation.read_pos > buffer_size) {
TU_LOG1("Read object %ld: %ld bytes at offset %ld\r\n", object_handle, buffer_size, _fs_operation.read_pos);
*read_count = buffer_size;
if (_fs_operation.read_pos + buffer_size < FS_MAX_NODE_BYTES) {
memcpy(buffer, &obj->data[_fs_operation.read_pos], *read_count);
}
_fs_operation.read_pos += *read_count;
} else {
TU_LOG1("Read object %ld: %ld bytes at offset %ld\r\n", object_handle, obj->size - _fs_operation.read_pos,
_fs_operation.read_pos);
*read_count = obj->size - _fs_operation.read_pos;
if (_fs_operation.read_pos + *read_count < FS_MAX_NODE_BYTES) {
memcpy(buffer, &obj->data[_fs_operation.read_pos], *read_count);
}
// Read operation completed
_fs_operation.read_handle = 0;
_fs_operation.read_pos = 0;
}
return MTP_RESP_OK;
}
mtp_response_t tud_mtp_storage_object_move(uint32_t object_handle, uint32_t new_parent_object_handle) {
fs_object_info_t* obj;