diff --git a/examples/device/mtp/src/mtp_fs_example.c b/examples/device/mtp/src/mtp_fs_example.c index 2feb69758..a13acfcdd 100644 --- a/examples/device/mtp/src/mtp_fs_example.c +++ b/examples/device/mtp/src/mtp_fs_example.c @@ -47,71 +47,16 @@ typedef MTP_STORAGE_INFO_STRUCT(TU_ARRAY_SIZE((uint16_t[]) STORAGE_DESCRIPTRION) TU_ARRAY_SIZE(((uint16_t[])VOLUME_IDENTIFIER)) ) storage_info_t; -//--------------------------------------------------------------------+ -// RAM FILESYSTEM -//--------------------------------------------------------------------+ -#define FS_MAX_FILE_COUNT 5UL -#define FS_MAX_CAPACITY_BYTES (4 * 1024UL) -#define FS_MAX_FILENAME_LEN 16 -#define FS_FIXED_DATETIME "20250808T173500.0" // "YYYYMMDDTHHMMSS.s" - -#define README_TXT_CONTENT "TinyUSB MTP on RAM Filesystem example" - -typedef struct { - uint16_t name[FS_MAX_FILENAME_LEN]; - mtp_object_formats_t object_format; - uint16_t protection_status; - uint32_t image_pix_width; - uint32_t image_pix_height; - uint32_t image_bit_depth; - - uint32_t parent; - uint16_t association_type; - - uint32_t size; - uint8_t* data; - -} fs_file_t; - -// object data buffer (excluding 2 predefined files) -// with simple allocation pointer -uint8_t fs_buf[FS_MAX_CAPACITY_BYTES]; -size_t fs_buf_head = 0; - -// Files system, handle is index + 1 -static fs_file_t fs_objects[FS_MAX_FILE_COUNT] = { - { - .name = { 'r', 'e', 'a', 'd', 'm', 'e', '.', 't', 'x', 't', 0 }, // readme.txt - .object_format = MTP_OBJ_FORMAT_TEXT, - .protection_status = MTP_PROTECTION_STATUS_NO_PROTECTION, - .image_pix_width = 0, - .image_pix_height = 0, - .image_bit_depth = 0, - .parent = 0, - .association_type = MTP_ASSOCIATION_UNDEFINED, - .data = (uint8_t*) (uintptr_t) README_TXT_CONTENT, - .size = sizeof(README_TXT_CONTENT) - }, - { - .name = { 't', 'i', 'n', 'y', 'u', 's', 'b', '.', 'p', 'n', 'g', 0 }, // "tinyusb.png" - .object_format = MTP_OBJ_FORMAT_PNG, - .protection_status = MTP_PROTECTION_STATUS_NO_PROTECTION, - .image_pix_width = 128, - .image_pix_height = 64, - .image_bit_depth = 32, - .parent = 0, - .association_type = MTP_ASSOCIATION_UNDEFINED, - .data = (uint8_t*) (uintptr_t) logo_bin, - .size = logo_len, - } -}; - -//------------- Storage Info -------------// storage_info_t storage_info = { + #ifdef CFG_EXAMPLE_MTP_READONLY + .storage_type = MTP_STORAGE_TYPE_FIXED_ROM, + #else .storage_type = MTP_STORAGE_TYPE_FIXED_RAM, + #endif + .filesystem_type = MTP_FILESYSTEM_TYPE_GENERIC_HIERARCHICAL, .access_capability = MTP_ACCESS_CAPABILITY_READ_WRITE, - .max_capacity_in_bytes = sizeof(README_TXT_CONTENT) + logo_len + FS_MAX_CAPACITY_BYTES, + .max_capacity_in_bytes = 0, // calculated at runtime .free_space_in_bytes = 0, // calculated at runtime .free_space_in_objects = 0, // calculated at runtime .storage_description = { @@ -124,6 +69,69 @@ storage_info_t storage_info = { } }; + +//--------------------------------------------------------------------+ +// MTP FILESYSTEM +//--------------------------------------------------------------------+ +#define FS_MAX_FILE_COUNT 5UL +#define FS_MAX_FILENAME_LEN 16 + +#ifdef CFG_EXAMPLE_MTP_READONLY + #define FS_MAX_CAPACITY_BYTES 0 +#else + #define FS_MAX_CAPACITY_BYTES (4 * 1024UL) + + // object data buffer (excluding 2 predefined files) + // with simple allocation pointer + uint8_t fs_buf[FS_MAX_CAPACITY_BYTES]; +#endif +size_t fs_buf_head = 0; + +#define FS_FIXED_DATETIME "20250808T173500.0" // "YYYYMMDDTHHMMSS.s" +#define README_TXT_CONTENT "TinyUSB MTP Filesystem example" + +typedef struct { + uint16_t name[FS_MAX_FILENAME_LEN]; + mtp_object_formats_t object_format; + uint16_t protection_status; + uint32_t image_pix_width; + uint32_t image_pix_height; + uint32_t image_bit_depth; + uint32_t parent; + uint16_t association_type; + uint32_t size; + uint8_t* data; +} fs_file_t; + +// Files system, handle is index + 1 +static fs_file_t fs_objects[FS_MAX_FILE_COUNT] = { + { + .name = { 'r', 'e', 'a', 'd', 'm', 'e', '.', 't', 'x', 't', 0 }, // readme.txt + .object_format = MTP_OBJ_FORMAT_TEXT, + .protection_status = MTP_PROTECTION_STATUS_READ_ONLY, + .image_pix_width = 0, + .image_pix_height = 0, + .image_bit_depth = 0, + .parent = 0, + .association_type = MTP_ASSOCIATION_UNDEFINED, + .data = (uint8_t*) (uintptr_t) README_TXT_CONTENT, + .size = sizeof(README_TXT_CONTENT) + }, + { + .name = { 't', 'i', 'n', 'y', 'u', 's', 'b', '.', 'p', 'n', 'g', 0 }, // "tinyusb.png" + .object_format = MTP_OBJ_FORMAT_PNG, + .protection_status = MTP_PROTECTION_STATUS_READ_ONLY, + .image_pix_width = 128, + .image_pix_height = 64, + .image_bit_depth = 32, + .parent = 0, + .association_type = MTP_ASSOCIATION_UNDEFINED, + .data = (uint8_t*) (uintptr_t) logo_bin, + .size = logo_len, + } +}; + + enum { SUPPORTED_STORAGE_ID = 0x00010001u // physical = 1, logical = 1 }; @@ -167,16 +175,21 @@ static inline fs_file_t* fs_create_file(void) { // simple malloc static inline uint8_t* fs_malloc(size_t size) { +#ifdef CFG_EXAMPLE_MTP_READONLY + (void) size; + return NULL; +#else if (fs_buf_head + size > FS_MAX_CAPACITY_BYTES) { return NULL; } uint8_t* ptr = &fs_buf[fs_buf_head]; fs_buf_head += size; return ptr; +#endif } //--------------------------------------------------------------------+ -// +// Bulk Only Protocol //--------------------------------------------------------------------+ int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t* cb_data) { const mtp_container_command_t* command = cb_data->command_container; @@ -223,6 +236,7 @@ int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t* cb_data) { const uint32_t storage_id = command->params[0]; TU_VERIFY(SUPPORTED_STORAGE_ID == storage_id, -1); // update storage info with current free space + storage_info.max_capacity_in_bytes = sizeof(README_TXT_CONTENT) + logo_len + FS_MAX_CAPACITY_BYTES; storage_info.free_space_in_objects = FS_MAX_FILE_COUNT - fs_get_file_count(); storage_info.free_space_in_bytes = FS_MAX_CAPACITY_BYTES-fs_buf_head; mtp_container_add_raw(io_container, &storage_info, sizeof(storage_info)); @@ -299,7 +313,7 @@ int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t* cb_data) { mtp_object_info_header_t obj_info_header = { .storage_id = SUPPORTED_STORAGE_ID, .object_format = f->object_format, - .protection_status = MTP_PROTECTION_STATUS_NO_PROTECTION, + .protection_status = f->protection_status, .object_compressed_size = f->size, .thumb_format = MTP_OBJ_FORMAT_UNDEFINED, .thumb_compressed_size = 0, @@ -433,7 +447,17 @@ int32_t tud_mtp_data_xfer_cb(tud_mtp_cb_data_t* cb_data) { } } + uint8_t* f_buf = fs_malloc(obj_info->object_compressed_size); + if (f_buf == NULL) { + resp_code = MTP_RESP_STORE_FULL; + break; + } fs_file_t* f = fs_create_file(); + if (f == NULL) { + resp_code = MTP_RESP_STORE_FULL; + break; + } + f->object_format = obj_info->object_format; f->protection_status = obj_info->protection_status; f->image_pix_width = obj_info->image_pix_width; @@ -442,11 +466,7 @@ int32_t tud_mtp_data_xfer_cb(tud_mtp_cb_data_t* cb_data) { f->parent = obj_info->parent_object; f->association_type = obj_info->association_type; f->size = obj_info->object_compressed_size; - f->data = fs_malloc(f->size); - if (f->data == NULL) { - resp_code = MTP_RESP_STORE_FULL; - break; - } + f->data = f_buf; uint8_t* buf = io_container->payload + sizeof(mtp_object_info_header_t); mtp_container_get_string(buf, f->name); // ignore date created/modified/keywords @@ -498,10 +518,6 @@ int32_t tud_mtp_data_complete_cb(tud_mtp_cb_data_t* cb_data) { break; } - case MTP_OP_SEND_OBJECT: - resp->header->code = (cb_data->xfer_result == XFER_RESULT_SUCCESS) ? MTP_RESP_OK : MTP_RESP_GENERAL_ERROR; - break; - default: resp->header->code = (cb_data->xfer_result == XFER_RESULT_SUCCESS) ? MTP_RESP_OK : MTP_RESP_GENERAL_ERROR; break; diff --git a/hw/bsp/samd11/family.cmake b/hw/bsp/samd11/family.cmake index 965b1cfb5..e3dc23c35 100644 --- a/hw/bsp/samd11/family.cmake +++ b/hw/bsp/samd11/family.cmake @@ -54,6 +54,7 @@ function(add_board_target BOARD_TARGET) OSC32K_OVERWRITE_CALIBRATION=0 CFG_EXAMPLE_MSC_READONLY CFG_EXAMPLE_VIDEO_READONLY + CFG_EXAMPLE_MTP_READONLY ) update_board(${BOARD_TARGET}) diff --git a/src/class/mtp/mtp_device.c b/src/class/mtp/mtp_device.c index 61b1c9613..b3d982323 100644 --- a/src/class/mtp/mtp_device.c +++ b/src/class/mtp/mtp_device.c @@ -424,14 +424,10 @@ void process_cmd(mtpd_interface_t* p_mtp, tud_mtp_cb_data_t* cb_data) { .standard_version = 100, .mtp_vendor_extension_id = 6, // MTP specs say 0xFFFFFFFF but libMTP check for value 6 .mtp_version = 100, -#ifdef CFG_TUD_MTP_DEVICEINFO_EXTENSIONS .mtp_extensions = { .count = sizeof(CFG_TUD_MTP_DEVICEINFO_EXTENSIONS), .utf16 = { 0 } }, -#else - .mtp_extensions = 0, -#endif .functional_mode = 0x0000, .supported_operations = { .count = TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS), @@ -454,11 +450,11 @@ void process_cmd(mtpd_interface_t* p_mtp, tud_mtp_cb_data_t* cb_data) { .arr = { CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS } } }; -#ifdef CFG_TUD_MTP_DEVICEINFO_EXTENSIONS + for (uint8_t i=0; i < dev_info.mtp_extensions.count; i++) { dev_info.mtp_extensions.utf16[i] = (uint16_t)CFG_TUD_MTP_DEVICEINFO_EXTENSIONS[i]; } -#endif + mtp_container_add_raw(&cb_data->io_container, &dev_info, sizeof(tud_mtp_device_info_t)); break; } diff --git a/src/class/mtp/mtp_device.h b/src/class/mtp/mtp_device.h index d0c894742..b10c3abda 100644 --- a/src/class/mtp/mtp_device.h +++ b/src/class/mtp/mtp_device.h @@ -62,34 +62,11 @@ typedef struct { /* string fields will be added using append function */ \ } -#define MTP_DEVICE_INFO_NO_EXTENSION_STRUCT(_op_count, _event_count, _devprop_count, _capture_count, _playback_count) \ - struct TU_ATTR_PACKED { \ - uint16_t standard_version; \ - uint32_t mtp_vendor_extension_id; \ - uint16_t mtp_version; \ - uint8_t mtp_extensions; \ - uint16_t functional_mode; \ - mtp_auint16_t(_op_count) supported_operations; \ - mtp_auint16_t(_event_count) supported_events; \ - mtp_auint16_t(_devprop_count) supported_device_properties; \ - mtp_auint16_t(_capture_count) capture_formats; \ - mtp_auint16_t(_playback_count) playback_formats; \ - /* string fields will be added using append function */ \ - } - -#ifdef CFG_TUD_MTP_DEVICEINFO_EXTENSIONS - typedef MTP_DEVICE_INFO_STRUCT( - sizeof(CFG_TUD_MTP_DEVICEINFO_EXTENSIONS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS), - TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES), - TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS) - ) tud_mtp_device_info_t; -#else - typedef MTP_DEVICE_INFO_NO_EXTENSION_STRUCT( - TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS), - TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES), - TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS) - ) tud_mtp_device_info_t; -#endif +typedef MTP_DEVICE_INFO_STRUCT( + sizeof(CFG_TUD_MTP_DEVICEINFO_EXTENSIONS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS), + TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES), + TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS) +) tud_mtp_device_info_t; //--------------------------------------------------------------------+ // Application API