/* This test is designed to test the simple dpump host/device class operation. */ #include #include "tx_api.h" #include "ux_api.h" #include "ux_system.h" #include "ux_utility.h" #include "ux_hcd_sim_host.h" #include "fx_api.h" #include "ux_device_class_dfu.h" #include "ux_device_stack.h" #include "ux_host_stack.h" #include "ux_test_dcd_sim_slave.h" #include "ux_test_hcd_sim_host.h" #include "ux_test_utility_sim.h" #define UX_DEMO_REQUEST_MAX_LENGTH \ ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ? \ (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH)) /* Define constants. */ #define UX_DEMO_MEMORY_SIZE (128*1024) #define UX_DEMO_STACK_SIZE (1024) /* Define local/extern function prototypes. */ static void test_thread_entry(ULONG); static TX_THREAD tx_test_thread_host_simulation; static TX_THREAD tx_test_thread_slave_simulation; static VOID demo_thread_dfu_activate(VOID *dfu); static VOID demo_thread_dfu_deactivate(VOID *dfu); static UINT demo_thread_dfu_read(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *actual_length); static UINT demo_thread_dfu_write(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *media_status); static UINT demo_thread_dfu_get_status(VOID *dfu, ULONG *media_status); static UINT demo_thread_dfu_notify(VOID *dfu, ULONG notification); static UINT demo_thread_dfu_custom_request(VOID *dfu, UX_SLAVE_TRANSFER *transfer); static void ux_test_thread_simulation_0_entry(ULONG); /* Define global data structures. */ static UCHAR usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)]; static ULONG error_counter; static ULONG set_cfg_counter; static ULONG rsc_mem_free_on_set_cfg; static ULONG rsc_sem_on_set_cfg; static ULONG rsc_sem_get_on_set_cfg; static ULONG rsc_mutex_on_set_cfg; static ULONG rsc_enum_sem_usage; static ULONG rsc_enum_sem_get_count; static ULONG rsc_enum_mutex_usage; static ULONG rsc_enum_mem_usage; static ULONG interaction_count; static UCHAR error_callback_ignore = UX_TRUE; static ULONG error_callback_counter; static UX_SLAVE_CLASS_DFU_PARAMETER dfu_parameter; static UX_DEVICE *device; static ULONG dfu_block; static ULONG dfu_transfer_length; static ULONG dfu_actual_length; static UCHAR dfu_host_buffer[UX_DEMO_REQUEST_MAX_LENGTH]; static UCHAR dfu_device_buffer[UX_DEMO_REQUEST_MAX_LENGTH]; static TX_THREAD ux_test_thread_simulation_0; /* Define device framework. */ /* DFU descriptor must be same for all frameworks!!! */ #define DFU_FUNCTION_DESCRIPTOR \ /* Functional descriptor for DFU. */ \ 0x09, 0x21, \ 0x0f, /* bmAttributes: B3 bitWillDetach */ \ /* B2 bitManifestationTolerant */ \ /* B1 bitCanUpload, B0 bitCanDnload */ \ 0xE8, 0x03, /* wDetachTimeOut: 0x03E8 (1000) */ \ UX_W0(UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH), \ UX_W1(UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH), /* wTransferSize: */ \ 0x00, 0x01, /* bcdDFUVersion: 0x0100 */ /* Interface descriptor for APP/DFU mode. */ #define DFU_INTERFACE_DESCRIPTOR(bInterfaceNumber, bInterfaceProtocol) \ /* Interface descriptor for DFU. */ \ 0x09, 0x04, \ (bInterfaceNumber), 0x00, 0x00, \ 0xFE, 0x01, (bInterfaceProtocol), \ 0x00, \ #define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed) static UCHAR device_framework_full_speed[] = { /* Device descriptor */ 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x40, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x01, /* Configuration descriptor */ 0x09, 0x02, 0x1b, 0x00, 0x01, 0x01, 0x00, 0xc0, 0x32, /* Interface descriptor for DFU (bInterfaceProtocol = 1). */ DFU_INTERFACE_DESCRIPTOR(0x00, 0x01) DFU_FUNCTION_DESCRIPTOR }; #define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed) static UCHAR device_framework_high_speed[] = { /* Device descriptor */ 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x99, 0x99, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, /* Device qualifier descriptor */ 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, /* Configuration descriptor */ 0x09, 0x02, 0x1b, 0x00, 0x01, 0x01, 0x00, 0xc0, 0x32, /* Interface descriptor for DFU (bInterfaceProtocol = 1). */ DFU_INTERFACE_DESCRIPTOR(0x00, 0x01) DFU_FUNCTION_DESCRIPTOR }; /* String Device Framework : Byte 0 and 1 : Word containing the language ID : 0x0904 for US Byte 2 : Byte containing the index of the descriptor Byte 3 : Byte containing the length of the descriptor string */ #define STRING_FRAMEWORK_LENGTH sizeof(string_framework) static UCHAR string_framework[] = { /* Manufacturer string descriptor : Index 1 - "Microsoft AzureRTOS" */ 0x09, 0x04, 0x01, 19, 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', ' ', 'A', 'z', 'u', 'r', 'e', 'R', 'T', 'O', 'S', /* Product string descriptor : Index 2 - "DFU Demo Device" */ 0x09, 0x04, 0x02, 15, 'D', 'F', 'U', ' ', 'D', 'e', 'm', 'o', ' ', 'D', 'e', 'v', 'i', 'c', 'e', /* Serial Number string descriptor : Index 3 - "0000" */ 0x09, 0x04, 0x03, 0x04, '0', '0', '0', '0' }; /* Multiple languages are supported on the device, to add a language besides english, the unicode language code must be appended to the language_id_framework array and the length adjusted accordingly. */ #define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework) static UCHAR language_id_framework[] = { /* English. */ 0x09, 0x04 }; #define DEVICE_FRAMEWORK_LENGTH_DFU sizeof(device_framework_dfu) static UCHAR device_framework_dfu[] = { /* Device descriptor */ 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x40, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x01, /* Configuration descriptor */ 0x09, 0x02, 0x1B, 0x00, 0x01, 0x01, 0x00, 0xc0, 0x32, /* Interface descriptor for DFU (bInterfaceProtocol = 2). */ DFU_INTERFACE_DESCRIPTOR(0x00, 0x02) DFU_FUNCTION_DESCRIPTOR }; /* Define the ISR dispatch. */ extern VOID (*test_isr_dispatch)(void); /* Prototype for test control return. */ void test_control_return(UINT status); static VOID error_callback(UINT system_level, UINT system_context, UINT error_code) { error_callback_counter ++; if (!error_callback_ignore) { { /* Failed test. */ printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code); test_control_return(1); } } } /* Define the ISR dispatch routine. */ static void test_isr(void) { /* For further expansion of interrupt-level testing. */ } static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst) { if (event == UX_DEVICE_CONNECTION) { device = (UX_DEVICE *)inst; } if (event == UX_DEVICE_DISCONNECTION) { if ((VOID *)device == inst) device = UX_NULL; } } /* Define what the initial system looks like. */ #ifdef CTEST void test_application_define(void *first_unused_memory) #else void usbx_uxe_device_dfu_test_application_define(void *first_unused_memory) #endif { UINT status; CHAR * stack_pointer; CHAR * memory_pointer; ULONG test_n; /* Inform user. */ printf("Running uxe_device_dfu APIs Test.................................... "); #if !defined(UX_DEVICE_CLASS_DFU_ENABLE_ERROR_CHECKING) #warning Tests skipped due to compile option! printf("SKIP SUCCESS!\n"); test_control_return(0); return; #endif /* UX_DEVICE_CLASS_DFU_ENABLE_ERROR_CHECKING */ /* Reset testing counts. */ ux_test_utility_sim_mutex_create_count_reset(); ux_test_utility_sim_sem_create_count_reset(); ux_test_utility_sim_sem_get_count_reset(); /* Reset error generations */ ux_test_utility_sim_sem_error_generation_stop(); ux_test_utility_sim_mutex_error_generation_stop(); ux_test_utility_sim_sem_get_error_generation_stop(); /* Initialize the free memory pointer */ stack_pointer = (CHAR *) usbx_memory; memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2); /* Initialize USBX Memory */ status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0); /* Check for error. */ if (status != UX_SUCCESS) { printf("ERROR #%d\n", __LINE__); test_control_return(1); } /* Register the error callback. */ _ux_utility_error_callback_register(error_callback); /* The code below is required for installing the host portion of USBX */ status = ux_host_stack_initialize(demo_system_host_change_function); if (status != UX_SUCCESS) { printf("ERROR #%d\n", __LINE__); test_control_return(1); } /* There is no host class for DFU now. */ /* The code below is required for installing the device portion of USBX. No call back for device status change in this example. */ status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED, device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED, string_framework, STRING_FRAMEWORK_LENGTH, language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL); if(status!=UX_SUCCESS) { printf("ERROR #%d\n", __LINE__); test_control_return(1); } /* Store the DFU parameters. */ dfu_parameter.ux_slave_class_dfu_parameter_instance_activate = demo_thread_dfu_activate; dfu_parameter.ux_slave_class_dfu_parameter_instance_deactivate = demo_thread_dfu_deactivate; dfu_parameter.ux_slave_class_dfu_parameter_read = demo_thread_dfu_read; dfu_parameter.ux_slave_class_dfu_parameter_write = demo_thread_dfu_write; dfu_parameter.ux_slave_class_dfu_parameter_get_status = demo_thread_dfu_get_status; dfu_parameter.ux_slave_class_dfu_parameter_notify = demo_thread_dfu_notify; #ifdef UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE dfu_parameter.ux_device_class_dfu_parameter_custom_request = demo_thread_dfu_custom_request; #endif dfu_parameter.ux_slave_class_dfu_parameter_framework = UX_NULL; dfu_parameter.ux_slave_class_dfu_parameter_framework_length = DEVICE_FRAMEWORK_LENGTH_DFU; /* Initilize the device dfu class. The class is connected with interface 1 on configuration 1. */ // status = ux_device_stack_class_register(_ux_system_slave_class_dfu_name, ux_device_class_dfu_entry, // 1, 0, (VOID *)&dfu_parameter); status = ux_device_stack_class_register(_ux_system_slave_class_dfu_name, ux_device_class_dfu_entry, 1, 0, UX_NULL); if(status != UX_INVALID_PARAMETER) { printf("ERROR #%d\n", __LINE__); test_control_return(1); } status = ux_device_stack_class_register(_ux_system_slave_class_dfu_name, ux_device_class_dfu_entry, 1, 0, (VOID *)&dfu_parameter); if(status != UX_INVALID_PARAMETER) { printf("ERROR #%d\n", __LINE__); test_control_return(1); } dfu_parameter.ux_slave_class_dfu_parameter_framework = device_framework_dfu; status = ux_device_stack_class_register(_ux_system_slave_class_dfu_name, ux_device_class_dfu_entry, 1, 0, (VOID *)&dfu_parameter); if(status != UX_SUCCESS) { printf("ERROR #%d\n", __LINE__); test_control_return(1); } /* Create the simulation thread. */ status = tx_thread_create(&ux_test_thread_simulation_0, "test simulation", ux_test_thread_simulation_0_entry, 0, stack_pointer, UX_DEMO_STACK_SIZE, 20, 20, 1, TX_AUTO_START); /* Check for error. */ if (status != TX_SUCCESS) { printf("ERROR #%d\n", __LINE__); test_control_return(1); } } static void ux_test_thread_simulation_0_entry(ULONG arg) { /* Sleep for a tick to make sure everything is complete. */ tx_thread_sleep(1); /* Check for errors from other threads. */ if (error_counter) { /* Test error. */ printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter); test_control_return(1); } else { /* Successful test. */ printf("SUCCESS!\n"); test_control_return(0); } } static UINT _req_DFU_LOCK(UX_TRANSFER *control_transfer) { UINT status; #if defined(UX_HOST_STANDALONE) while(1) { ux_system_tasks_run(); tx_thread_relinquish(); UX_ENDPOINT *endpoint = control_transfer -> ux_transfer_request_endpoint; if (endpoint == UX_NULL || endpoint -> ux_endpoint_state != UX_ENDPOINT_RUNNING) { status = UX_ENDPOINT_HANDLE_UNKNOWN; break; } UX_DEVICE *device = endpoint -> ux_endpoint_device; if (device == UX_NULL || device -> ux_device_handle != (ULONG)(ALIGN_TYPE)(device)) { status = UX_DEVICE_HANDLE_UNKNOWN; break; } if ((device -> ux_device_flags & UX_DEVICE_FLAG_LOCK) == 0) { device -> ux_device_flags |= UX_DEVICE_FLAG_LOCK; control_transfer -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_DEVICE_UNLOCK; control_transfer -> ux_transfer_request_timeout_value = UX_WAIT_FOREVER; status = UX_SUCCESS; break; } } #else status = _ux_utility_semaphore_get(&control_transfer->ux_transfer_request_endpoint->ux_endpoint_device->ux_device_protection_semaphore, UX_WAIT_FOREVER); #endif if (status != UX_SUCCESS) { printf("ERROR #%d: %x\n", __LINE__, status); test_control_return(1); } } static UINT _req_DFU_GETSTATE(UX_TRANSFER *control_transfer) { _req_DFU_LOCK(control_transfer); control_transfer->ux_transfer_request_type = 0xA1; control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE; control_transfer->ux_transfer_request_index = 0; control_transfer->ux_transfer_request_requested_length = 1; control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; control_transfer->ux_transfer_request_value = 0; return ux_host_stack_transfer_request(control_transfer); } static UINT _req_DFU_GETSTATUS(UX_TRANSFER *control_transfer) { _req_DFU_LOCK(control_transfer); control_transfer->ux_transfer_request_type = 0xA1; control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS; control_transfer->ux_transfer_request_index = 0; control_transfer->ux_transfer_request_requested_length = 6; control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; control_transfer->ux_transfer_request_value = 0; return ux_host_stack_transfer_request(control_transfer); } static UINT _req_DFU_DETACH(UX_TRANSFER *control_transfer) { _req_DFU_LOCK(control_transfer); control_transfer->ux_transfer_request_type = 0x21; control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DETACH; control_transfer->ux_transfer_request_index = 0; control_transfer->ux_transfer_request_value = 1000; control_transfer->ux_transfer_request_requested_length = 0; return ux_host_stack_transfer_request(control_transfer); } static UINT _req_DFU_DNLOAD_IN(UX_TRANSFER *control_transfer, ULONG block, ULONG len) { _req_DFU_LOCK(control_transfer); control_transfer->ux_transfer_request_type = 0xA1; control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD; control_transfer->ux_transfer_request_index = 0; control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; control_transfer->ux_transfer_request_requested_length = len; control_transfer->ux_transfer_request_value = block; return ux_host_stack_transfer_request(control_transfer); } static UINT _req_DFU_DNLOAD(UX_TRANSFER *control_transfer, ULONG block, ULONG len) { _req_DFU_LOCK(control_transfer); control_transfer->ux_transfer_request_type = 0x21; control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD; control_transfer->ux_transfer_request_index = 0; control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; control_transfer->ux_transfer_request_requested_length = len; control_transfer->ux_transfer_request_value = block; return ux_host_stack_transfer_request(control_transfer); } static UINT _req_DFU_UPLOAD(UX_TRANSFER *control_transfer, ULONG block, ULONG len) { _req_DFU_LOCK(control_transfer); control_transfer->ux_transfer_request_type = 0xA1; control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_UPLOAD; control_transfer->ux_transfer_request_index = 0; control_transfer->ux_transfer_request_data_pointer = dfu_host_buffer; control_transfer->ux_transfer_request_requested_length = len; control_transfer->ux_transfer_request_value = block; return ux_host_stack_transfer_request(control_transfer); } static UINT _req_DFU_CLRSTATUS(UX_TRANSFER *control_transfer) { _req_DFU_LOCK(control_transfer); control_transfer->ux_transfer_request_type = 0x21; control_transfer->ux_transfer_request_function = UX_SLAVE_CLASS_DFU_COMMAND_CLEAR_STATUS; control_transfer->ux_transfer_request_index = 0; control_transfer->ux_transfer_request_data_pointer = UX_NULL; control_transfer->ux_transfer_request_requested_length = 0; control_transfer->ux_transfer_request_value = 0; return ux_host_stack_transfer_request(control_transfer); } static UINT demo_device_state_change(ULONG event) { return(UX_SUCCESS); } static VOID demo_thread_dfu_activate(VOID *dfu) { } static VOID demo_thread_dfu_deactivate(VOID *dfu) { } static UINT demo_thread_dfu_read(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *actual_length) { ULONG return_length; stepinfo("dfuRead %ld,%ld: %2x %2x %2x %2x ... -> %p\n", block_number, length, dfu_device_buffer[0], dfu_device_buffer[1], dfu_device_buffer[2], dfu_device_buffer[3], data_pointer); dfu_block = block_number; dfu_transfer_length = length; return_length = UX_MIN(length, sizeof(dfu_device_buffer)); return_length = UX_MIN(return_length, dfu_actual_length); ux_utility_memory_copy(data_pointer, dfu_device_buffer, return_length); /* Here is where the data block is read from the firmware. */ /* Some code needs to be inserted specifically for a target platform. */ *actual_length = return_length; return(UX_SUCCESS); } static UINT demo_thread_dfu_write(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *media_status) { stepinfo("dfuWrite %ld,%ld\n", block_number, length); dfu_block = block_number; dfu_transfer_length = length; ux_utility_memory_copy(dfu_device_buffer, data_pointer, UX_MIN(length, sizeof(dfu_device_buffer))); /* Here is where the data block is coming to be written to the firmware. */ /* Some code needs to be inserted specifically for a target platform. */ /* Return media status ok. */ *media_status = UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK ; return(UX_SUCCESS); } static UINT demo_thread_dfu_get_status(VOID *dfu, ULONG *media_status) { /* Return media status ok. */ *media_status = UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK ; return(UX_SUCCESS); } static UINT demo_thread_dfu_notify(VOID *dfu, ULONG notification) { stepinfo("dfuNotify 0x%lx\n", notification); switch (notification) { case UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_DOWNLOAD : /* Begin of Download. */ break; case UX_SLAVE_CLASS_DFU_NOTIFICATION_END_DOWNLOAD : /* Completion of Download. */ break; case UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_DOWNLOAD : /* Download was aborted. */ break; case UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_UPLOAD : /* Begin of UPLOAD. */ break; case UX_SLAVE_CLASS_DFU_NOTIFICATION_END_UPLOAD : /* Completion of UPLOAD. */ break; case UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_UPLOAD : /* Download was aborted. */ break; default : /* Bad notification signal. Should never get here. */ break; } return(UX_SUCCESS); } static UINT demo_thread_dfu_custom_request(VOID *dfu, UX_SLAVE_TRANSFER *transfer) { UCHAR *setup; UCHAR *buffer; /* Check state and request to insert custom operation, before the standard handling process. If no standard handling process is needed, return UX_SUCCESS. */ /* E.g., accept DNLOAD command with wLength 0 in dfuIDLE. */ if (ux_device_class_dfu_state_get((UX_SLAVE_CLASS_DFU *)dfu) == UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_IDLE) { setup = transfer -> ux_slave_transfer_request_setup; buffer = transfer -> ux_slave_transfer_request_data_pointer; if (setup[UX_SETUP_REQUEST] == UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD && setup[UX_SETUP_LENGTH] == 0 && setup[UX_SETUP_LENGTH + 1] == 0) { /* Accept the case (by default it's stalled). */ stepinfo("dfuIDLE - accept dfuDNLOAD & wLength 0\n"); /* Fill the status data payload. First with status. */ *buffer = UX_SLAVE_CLASS_DFU_STATUS_OK; /* Poll time out value is set to 500ms. */ *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(500); *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(500); *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(500); /* Next state: still dfuIDLE. */ *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) UX_SYSTEM_DFU_STATE_DFU_IDLE; /* String index set to 0. */ *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0; /* We have a request to obtain the status of the DFU instance. */ _ux_device_stack_transfer_request(transfer, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH); /* Inform stack it's taken. */ return(UX_SUCCESS); } } /* No custom request. */ return(UX_ERROR); }