#include "usb_cdc.h" #include /** * Send_Encapsulated_Command * * Nothing to do other than unloading the data sent in the data stage. */ bool USB_CDC::ClassRequest::send_encapsulated_command(const USB::SetupBuffer &buf){ if((buf.bmRequestType == USB::SetupBuffer::OUT_CL_INTERFACE) && (buf.wValue == 0) && (buf.wLength <= sizeof(LineCoding))){ parent.usb.ep0_rx( &(set_line_coding_complete.new_value), buf.wLength, set_line_coding_complete); return true; } return false; } /** * Get_Encapsulated_Response * * Return a zero-length packet */ bool USB_CDC::ClassRequest::get_encapsulated_response(const USB::SetupBuffer &buf){ if((buf.bmRequestType == USB::SetupBuffer::IN_CL_INTERFACE) && (buf.wValue == 0)){ parent.usb.ep0_tx(NULL, 0); // Send ZLP return true; } return false; } void USB_CDC::ClassRequest::SetLineCodingComplete::operator()(){ parent.line_coding = new_value; if(parent.config_changed_callback){ Uint32 baudrate; std::memcpy(&baudrate, new_value.baudrate, sizeof(new_value.baudrate)); parent.config_changed_callback( baudrate, new_value.stopbit, new_value.parity, new_value.databit); } } USB_CDC::ClassRequest::SetLineCodingComplete::SetLineCodingComplete(USB_CDC &usb_cdc) : parent(usb_cdc){ } USB_CDC::ClassRequest::SetLineCodingComplete::~SetLineCodingComplete(){} /** * Set_Line_Coding * * Unload the line coding structure (7 bytes) sent in the data stage. * Apply this setting to the UART * Flush the communication buffer * * Line Coding Structure (7 bytes) * 0-3 dwDTERate Data terminal rate (baudrate), in bits per second (LSB first) * 4 bCharFormat Stop bits: 0 - 1 Stop bit, 1 - 1.5 Stop bits, 2 - 2 Stop bits * 5 bParityType Parity: 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space * 6 bDataBits Data bits: 5, 6, 7, 8, 16 */ bool USB_CDC::ClassRequest::set_line_coding(const USB::SetupBuffer &buf){ if((buf.bmRequestType == USB::SetupBuffer::OUT_CL_INTERFACE) && (buf.wValue == 0) && (buf.wLength == sizeof(LineCoding))){ parent.usb.ep0_rx( &(set_line_coding_complete.new_value), buf.wLength, set_line_coding_complete); return true; } return false; } /** * Get_Line_Coding * * Return the line coding structure */ bool USB_CDC::ClassRequest::get_line_coding(const USB::SetupBuffer &buf){ if((buf.bmRequestType == USB::SetupBuffer::IN_CL_INTERFACE) && (buf.wValue == 0) && (buf.wLength == sizeof(LineCoding))){ parent.usb.ep0_tx(&(parent.line_coding), buf.wLength); return true; } return false; } /** * Set_ControlLine_State * * Set/reset RTS/DTR according to wValue * wValue * bit 1 RTS * bit 0 DTR */ bool USB_CDC::ClassRequest::set_control_line_state(const USB::SetupBuffer &buf){ if((buf.bmRequestType == USB::SetupBuffer::OUT_CL_INTERFACE) && (buf.wLength == 0)){ if(parent.line_status_changed_callback){ parent.line_status_changed_callback(buf.wValue, 2, 1); } return true; } return false; } /** * Send_Break * * Send break from UART TX port, for wValue (msec) duration. * wValue * 0xFFFF: continuous break * 0x0000: stop break */ bool USB_CDC::ClassRequest::send_break(const USB::SetupBuffer &buf){ if ((buf.bmRequestType == USB::SetupBuffer::OUT_CL_INTERFACE) && (buf.wLength == 0)){ parent.send_break(buf.wValue); return true; } return false; } USB_CDC::ClassRequest::ClassRequest(USB_CDC &usb_cdc) : parent(usb_cdc), set_line_coding_complete(usb_cdc) { } USB_CDC::ClassRequest::~ClassRequest(){} bool USB_CDC::ClassRequest::handle(const USB::SetupBuffer &buf){ switch(buf.bRequest){ case SEND_ENCAPSULATED_COMMAND: return send_encapsulated_command(buf); case GET_ENCAPSULATED_RESPONSE: return get_encapsulated_response(buf); case SET_LINE_CODING: return set_line_coding(buf); case GET_LINE_CODING: return get_line_coding(buf); case SET_CONTROL_LINE_STATE: return set_control_line_state(buf); case SEND_BREAK: return send_break(buf); } return false; } void USB_CDC::send_break(const int &value){} void USB_CDC::handle_ctl(){ #if 0 Uint8 buf_res_available[] = { 0xA1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // ResponseAvailable usb.write(ep_in_ctl, buf_res_available, sizeof(buf_res_available)); #endif if(true || uart_state_changed){ // TODO uart_state_changed = false; Uint8 buf_state[] = { 0xA1, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, uart_state, 0x00}; // SerialState usb.write(ep_in_ctl, buf_state, sizeof(buf_state)); } } #define ARRANGE_TX_SIZE 0 // Using functionality of arrange packet size #if ARRANGE_TX_SIZE static char buf_tx[0x40]; static char *buf_tx_index(buf_tx); static const int buf_tx_size(sizeof(buf_tx)); static unsigned int buf_tx_count(0); #endif unsigned int USB_CDC::transmit(const char *buf, const unsigned int &buf_size){ #if ARRANGE_TX_SIZE unsigned int _buf_size(buf_size); unsigned int transmitted; unsigned int margin(buf_tx_size - (buf_tx_index - buf_tx)); if(margin <= _buf_size){ if(margin < buf_tx_size){ std::memcpy(buf_tx_index, buf, margin); transmitted = usb.write(ep_in_data, buf_tx, buf_tx_size); if(transmitted < buf_tx_size){ std::memmove(buf_tx, buf_tx + transmitted, buf_tx_size - transmitted); buf_tx_index = buf_tx + buf_tx_size - transmitted; return margin; } buf += margin; _buf_size -= margin; buf_tx_index = buf_tx; } for(int i(0); i < _buf_size / buf_tx_size; i++){ transmitted = usb.write(ep_in_data, buf, buf_tx_size); buf += transmitted; _buf_size -= transmitted; if(transmitted < buf_tx_size){ return buf_size - _buf_size; } } } std::memcpy(buf_tx_index, buf, _buf_size); buf_tx_index += _buf_size; return buf_size; #else unsigned int total_transmitted(0); while(total_transmitted < buf_size){ unsigned int challenge(buf_size - total_transmitted); if(challenge >= 0x40){ // TODO: Workaround => When size equals to maxPacketsize, ZLP is requires, however, DMA cannot generate it. challenge = 0x3F; } unsigned int result(usb.write(ep_in_data, buf + total_transmitted, challenge)); total_transmitted += result; if(result < challenge){break;} } return total_transmitted; #endif } unsigned int USB_CDC::receive(char *buf, const unsigned int &buf_size){ return usb.read(ep_out_data, buf, buf_size); } USB_CDC::USB_CDC( USB &target, const Uint8 &ep_in_ctl_index, const Uint8 &ep_in_data_index, const Uint8 &ep_out_data_index) : MinimalIO(), usb(target), line_coding(), class_request_handler(*this), ep_in_ctl(ep_in_ctl_index), ep_in_data(ep_in_data_index), ep_out_data(ep_out_data_index), uart_state(UART_STATE_TXCARRIER | UART_STATE_RXCARRIER), uart_state_changed(true), config_changed_callback(NULL), line_status_changed_callback(NULL) { Uint32 baudrate(115200u); std::memcpy(line_coding.baudrate, &baudrate, sizeof(line_coding.baudrate)); line_coding.stopbit = 0; line_coding.parity = 0; line_coding.databit = 8; } USB_CDC::~USB_CDC(){ }