#pragma once

#include <string.h>

#include "usb.h"

// Class specific requests
#define USBCDC_REQ_SEND_ENCAPSULATED_COMMAND    0x00
#define USBCDC_REQ_GET_ENCAPSULATED_RESPONSE    0x01
#define USBCDC_REQ_SET_COMM_FEATURE             0x02
#define USBCDC_REQ_GET_COMM_FEATURE             0x03
#define USBCDC_REQ_CLEAR_COMM_FEATURE           0x04
#define USBCDC_REQ_SET_LINE_CODING              0x20
#define USBCDC_REQ_GET_LINE_CODING              0x21
#define USBCDC_REQ_SET_CONTROL_LINE_STATE       0x22
#define USBCDC_REQ_SEND_BREAK                   0x23

#define USBCDC_ENDPOINT_SIZE                    64

typedef struct
{
    uint32_t dwDTERate;     // Data terminal rate, in baud
    uint8_t bCharFormat;    // 0: 1 stop bit, 1: 1.5 stop bits, 2: 2 stop bits
    uint8_t bParityType;    // 0: none, 1: odd, 2: even, 3: mark, 4: space
    uint8_t bDataBits;      // 5, 6, 7, 8 or 16
    uint8_t align;          // The PMA only supports word access
} __attribute__((packed)) USBCDC_LineCoding_t;

// Initialises the endpoints used by the virtual COM port after a reset
void USBCDC_InitEndpoints(void);

// Handler for USB interface setup packets
void USBCDC_HandleInterfaceSetup(USB_SetupPacket_t *sp,
    const void **reply_data, int *reply_length, uint8_t *reply_response);

// Handler for USB out packets directed to the virtual COM port's out endpoint
void USBCDC_HandleDataOut(void);

// Handler for the successful transmission of an USB in packet
void USBCDC_HandleDataInComplete(void);

// Send data over the virtual COM port. This routine will block if there is more
// data to be sent than remaining space in the transmit ring buffer.
void USBCDC_SendData(const void *data, int length);

// Writes received data into a buffer. Returns the number of bytes written into
// the buffer.
int USBCDC_ReceiveData(void *buffer, int length);

// Reads a single byte from the receive buffer. If none are available, this
// function returns -1.
int USBCDC_ReceiveByte(void);
