#pragma once // Objects IO // // created on 2023-03-10 #include #include #include #include #include #include #include // callback proto // // parameters: usb_functionfs_event* - the function event ptr // // dyn_mem_ptr - the packet buffer, read-only // // uint32_t* - to return how many data in bytes the handler consumed // // normally, the value should be sizeof(PACK_BASE) + PACK_BASE::payload_len, i.e. the handler consume all data of an entire packet // // when invalid packet, suggest use the entire data // // packet_data_base_ptr* - return data_holder or data_source or nullptr // // data_holder: the packet/command need more data than dyn_mem_ptr provides to complete the business. such as 'write a large file' // // data_source: the reply content may be a large data (a large file content) // // return value of all routines is the reply packet, nullptr if the packet need not reply // #define FUNCTION_PROTO_UNHANDLED_EP0 dyn_mem_ptr(struct usb_functionfs_event*) #define MEM_POOL class usb_device; class async_usb_gadget : public refer { volatile bool run_ = true; volatile bool cancel_io_ = false; usb_device *dev_ = nullptr; safe_thread threads_; size_t unit_in_ = 0x200; size_t unit_out_ = 0x200; uint16_t buf_coef_ = 1; MUTEX buf_coef_lock_; volatile bool online_ = false; volatile uint32_t session_id_ = 0; platform_event wait_in_; platform_event wait_out_; uint32_t enc_head_; uint32_t enc_payload_; uint8_t enc_data_; int last_err_ = 0; uint8_t statu_in_ = WORKER_STATUS_NOT_START; uint32_t want_bytes_in_ = 0; uint8_t statu_out_ = WORKER_STATUS_NOT_START; uint8_t statu_task_ = WORKER_STATUS_NOT_START; uint32_t want_bytes_task_ = 0; uint32_t task_cmd_ = 0; uint32_t task_packet_id_ = 0; uint64_t host_pid_ = 0; #ifdef MEM_POOL dyn_mem_pool *io_buf_ = nullptr; #else safe_fifo io_buf_; #endif safe_fifo cmd_que_; safe_fifo sent_que_; enum { EP0_STATUS_IDLE = 0, EP0_STATUS_READ_DATA, // ep0_statu::data is rest data len EP0_STATUS_READ_INVAL_DATA, // ep0_statu::data is rest data len EP0_STATUS_HANDLE_CMD, }; std::function handle_cmd_; std::function dev_connect_; dyn_mem_ptr get_io_buffer(void); void free_io_buffer(dyn_mem_ptr buf); const char* ep0_status_desc(int ep0_status, char* unk_buf/*>= 40 bytes*/); int wait_fd_event(int fd, int to_ms = -1); uint16_t get_buf_coefficient(void); void set_buf_coefficient(int coef); dyn_mem_ptr handle_ctrl_message(dyn_mem_ptr data); dyn_mem_ptr handle_ctrl_setup(dyn_mem_ptr data); // user command ... int inner_write_bulk_memory(int fd, uint8_t* buf, uint32_t* len/*in - to sent; out - real sent*/, uint32_t bulk_size, data_source_ptr prog = nullptr); // return error code int inner_write_bulk(int fd, data_source_ptr data, dyn_mem_ptr mem/*to load data in if data was not memory*/, uint32_t bulk_size); // return error dyn_mem_ptr handle_bulk_command(dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* pkd); void thread_read_ep0(void); void thread_read_bulk(int fd); void thread_write_bulk(int fd); void thread_pump_task(void); public: async_usb_gadget(std::function cmd_handler = std::function() , std::function dev_conn = std::function()); protected: ~async_usb_gadget(); public: int stop(void); int write_bulk(data_source_ptr data); // return sent-que length int last_error(void); };