130 lines
4.1 KiB
C++
130 lines
4.1 KiB
C++
#pragma once
|
|
|
|
// Objects IO
|
|
//
|
|
// created on 2023-03-10
|
|
|
|
#include <base/utils.h>
|
|
#include <base/packet.h>
|
|
#include <base/data.h>
|
|
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <vector>
|
|
#include <thread>
|
|
|
|
|
|
// 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<dyn_mem_ptr> io_buf_;
|
|
#endif
|
|
safe_fifo<dyn_mem_ptr> cmd_que_;
|
|
safe_fifo<data_source_ptr> 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<FUNCTION_PROTO_COMMAND_HANDLE> handle_cmd_;
|
|
std::function<void(bool)> 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<FUNCTION_PROTO_COMMAND_HANDLE> cmd_handler = std::function<FUNCTION_PROTO_COMMAND_HANDLE>()
|
|
, std::function<void(bool)> dev_conn = std::function<void(bool)>());
|
|
|
|
protected:
|
|
~async_usb_gadget();
|
|
|
|
public:
|
|
int stop(void);
|
|
int write_bulk(data_source_ptr data); // return sent-que length
|
|
int last_error(void);
|
|
uint32_t current_session(void);
|
|
|
|
void get_ep_status(LPEP0REPLYSTATUS status);
|
|
};
|
|
|