1 /*
2  * @brief Virtual Comm port call back routines
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2013
6  * All rights reserved.
7  *
8  * @par
9  * Software that is described herein is for illustrative purposes only
10  * which provides customers with programming information regarding the
11  * LPC products.  This software is supplied "AS IS" without any warranties of
12  * any kind, and NXP Semiconductors and its licensor disclaim any and
13  * all warranties, express or implied, including all implied warranties of
14  * merchantability, fitness for a particular purpose and non-infringement of
15  * intellectual property rights.  NXP Semiconductors assumes no responsibility
16  * or liability for the use of the software, conveys no license or rights under any
17  * patent, copyright, mask work right, or any other intellectual property rights in
18  * or to any products. NXP Semiconductors reserves the right to make changes
19  * in the software without notification. NXP Semiconductors also makes no
20  * representation or warranty that such application will be suitable for the
21  * specified use without further testing or modification.
22  *
23  * @par
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, under NXP Semiconductors' and its
26  * licensor's relevant copyrights in the software, without fee, provided that it
27  * is used in conjunction with NXP Semiconductors microcontrollers.  This
28  * copyright, permission, and disclaimer notice must appear in all copies of
29  * this code.
30  */
31 #include <string.h>
32 #include "app_usbd_cfg.h"
33 #include "board.h"
34 #include "cdc_vcom.h"
35 
36 /*****************************************************************************
37  * Private types/enumerations/variables
38  ****************************************************************************/
39 
40 /*****************************************************************************
41  * Public types/enumerations/variables
42  ****************************************************************************/
43 
44 /**
45  * Global variable to hold Virtual COM port control data.
46  */
47 VCOM_DATA_T g_vCOM;
48 
49 /*****************************************************************************
50  * Private functions
51  ****************************************************************************/
52 
53 /* VCOM bulk EP_IN endpoint handler */
VCOM_bulk_in_hdlr(USBD_HANDLE_T hUsb,void * data,uint32_t event)54 static ErrorCode_t VCOM_bulk_in_hdlr(USBD_HANDLE_T hUsb, void *data, uint32_t event)
55 {
56 	VCOM_DATA_T *pVcom = (VCOM_DATA_T *) data;
57 
58 	if (event == USB_EVT_IN) {
59 		pVcom->tx_flags &= ~VCOM_TX_BUSY;
60 	}
61 	return LPC_OK;
62 }
63 
64 /* VCOM bulk EP_OUT endpoint handler */
VCOM_bulk_out_hdlr(USBD_HANDLE_T hUsb,void * data,uint32_t event)65 static ErrorCode_t VCOM_bulk_out_hdlr(USBD_HANDLE_T hUsb, void *data, uint32_t event)
66 {
67 	VCOM_DATA_T *pVcom = (VCOM_DATA_T *) data;
68 
69 	switch (event) {
70 	case USB_EVT_OUT:
71 		pVcom->rx_count = USBD_API->hw->ReadEP(hUsb, USB_CDC_OUT_EP, pVcom->rx_buff);
72 		if (pVcom->rx_flags & VCOM_RX_BUF_QUEUED) {
73 			pVcom->rx_flags &= ~VCOM_RX_BUF_QUEUED;
74 			if (pVcom->rx_count != 0) {
75 				pVcom->rx_flags |= VCOM_RX_BUF_FULL;
76 			}
77 
78 		}
79 		else if (pVcom->rx_flags & VCOM_RX_DB_QUEUED) {
80 			pVcom->rx_flags &= ~VCOM_RX_DB_QUEUED;
81 			pVcom->rx_flags |= VCOM_RX_DONE;
82 		}
83 		break;
84 
85 	case USB_EVT_OUT_NAK:
86 		/* queue free buffer for RX */
87 		if ((pVcom->rx_flags & (VCOM_RX_BUF_FULL | VCOM_RX_BUF_QUEUED)) == 0) {
88 			USBD_API->hw->ReadReqEP(hUsb, USB_CDC_OUT_EP, pVcom->rx_buff, VCOM_RX_BUF_SZ);
89 			pVcom->rx_flags |= VCOM_RX_BUF_QUEUED;
90 		}
91 		break;
92 
93 	default:
94 		break;
95 	}
96 
97 	return LPC_OK;
98 }
99 
100 /* Set line coding call back routine */
VCOM_SetLineCode(USBD_HANDLE_T hCDC,CDC_LINE_CODING * line_coding)101 static ErrorCode_t VCOM_SetLineCode(USBD_HANDLE_T hCDC, CDC_LINE_CODING *line_coding)
102 {
103 	VCOM_DATA_T *pVcom = &g_vCOM;
104 
105 	/* Called when baud rate is changed/set. Using it to know host connection state */
106 	pVcom->tx_flags = VCOM_TX_CONNECTED;	/* reset other flags */
107 
108 	return LPC_OK;
109 }
110 
111 /*****************************************************************************
112  * Public functions
113  ****************************************************************************/
114 
115 /* Virtual com port init routine */
vcom_init(USBD_HANDLE_T hUsb,USB_CORE_DESCS_T * pDesc,USBD_API_INIT_PARAM_T * pUsbParam)116 ErrorCode_t vcom_init(USBD_HANDLE_T hUsb, USB_CORE_DESCS_T *pDesc, USBD_API_INIT_PARAM_T *pUsbParam)
117 {
118 	USBD_CDC_INIT_PARAM_T cdc_param;
119 	ErrorCode_t ret = LPC_OK;
120 	uint32_t ep_indx;
121 
122 	g_vCOM.hUsb = hUsb;
123 	memset((void *) &cdc_param, 0, sizeof(USBD_CDC_INIT_PARAM_T));
124 	cdc_param.mem_base = pUsbParam->mem_base;
125 	cdc_param.mem_size = pUsbParam->mem_size;
126 	cdc_param.cif_intf_desc = (uint8_t *) find_IntfDesc(pDesc->high_speed_desc, CDC_COMMUNICATION_INTERFACE_CLASS);
127 	cdc_param.dif_intf_desc = (uint8_t *) find_IntfDesc(pDesc->high_speed_desc, CDC_DATA_INTERFACE_CLASS);
128 	cdc_param.SetLineCode = VCOM_SetLineCode;
129 
130 	ret = USBD_API->cdc->init(hUsb, &cdc_param, &g_vCOM.hCdc);
131 
132 	if (ret == LPC_OK) {
133 		/* allocate transfer buffers */
134 		g_vCOM.rx_buff = (uint8_t *) cdc_param.mem_base;
135 		cdc_param.mem_base += VCOM_RX_BUF_SZ;
136 		cdc_param.mem_size -= VCOM_RX_BUF_SZ;
137 
138 		/* register endpoint interrupt handler */
139 		ep_indx = (((USB_CDC_IN_EP & 0x0F) << 1) + 1);
140 		ret = USBD_API->core->RegisterEpHandler(hUsb, ep_indx, VCOM_bulk_in_hdlr, &g_vCOM);
141 		if (ret == LPC_OK) {
142 			/* register endpoint interrupt handler */
143 			ep_indx = ((USB_CDC_OUT_EP & 0x0F) << 1);
144 			ret = USBD_API->core->RegisterEpHandler(hUsb, ep_indx, VCOM_bulk_out_hdlr, &g_vCOM);
145 
146 		}
147 		/* update mem_base and size variables for cascading calls. */
148 		pUsbParam->mem_base = cdc_param.mem_base;
149 		pUsbParam->mem_size = cdc_param.mem_size;
150 	}
151 
152 	return ret;
153 }
154 
155 /* Virtual com port buffered read routine */
vcom_bread(uint8_t * pBuf,uint32_t buf_len)156 uint32_t vcom_bread(uint8_t *pBuf, uint32_t buf_len)
157 {
158 	VCOM_DATA_T *pVcom = &g_vCOM;
159 	uint16_t cnt = 0;
160 	/* read from the default buffer if any data present */
161 	if (pVcom->rx_count) {
162 		cnt = (pVcom->rx_count < buf_len) ? pVcom->rx_count : buf_len;
163 		memcpy(pBuf, pVcom->rx_buff, cnt);
164 		pVcom->rx_rd_count += cnt;
165 
166 		/* enter critical section */
167 		NVIC_DisableIRQ(USB0_IRQn);
168 		if (pVcom->rx_rd_count >= pVcom->rx_count) {
169 			pVcom->rx_flags &= ~VCOM_RX_BUF_FULL;
170 			pVcom->rx_rd_count = pVcom->rx_count = 0;
171 		}
172 		/* exit critical section */
173 		NVIC_EnableIRQ(USB0_IRQn);
174 	}
175 	return cnt;
176 
177 }
178 
179 /* Virtual com port read routine */
vcom_read_req(uint8_t * pBuf,uint32_t len)180 ErrorCode_t vcom_read_req(uint8_t *pBuf, uint32_t len)
181 {
182 	VCOM_DATA_T *pVcom = &g_vCOM;
183 
184 	/* check if we queued Rx buffer */
185 	if (pVcom->rx_flags & (VCOM_RX_BUF_QUEUED | VCOM_RX_DB_QUEUED)) {
186 		return ERR_BUSY;
187 	}
188 	/* enter critical section */
189 	NVIC_DisableIRQ(USB0_IRQn);
190 	/* if not queue the request and return 0 bytes */
191 	USBD_API->hw->ReadReqEP(pVcom->hUsb, USB_CDC_OUT_EP, pBuf, len);
192 	/* exit critical section */
193 	NVIC_EnableIRQ(USB0_IRQn);
194 	pVcom->rx_flags |= VCOM_RX_DB_QUEUED;
195 
196 	return LPC_OK;
197 }
198 
199 /* Gets current read count. */
vcom_read_cnt(void)200 uint32_t vcom_read_cnt(void)
201 {
202 	VCOM_DATA_T *pVcom = &g_vCOM;
203 	uint32_t ret = 0;
204 
205 	if (pVcom->rx_flags & VCOM_RX_DONE) {
206 		ret = pVcom->rx_count;
207 		pVcom->rx_count = 0;
208 	}
209 
210 	return ret;
211 }
212 
213 /* Virtual com port write routine*/
vcom_write(uint8_t * pBuf,uint32_t len)214 uint32_t vcom_write(uint8_t *pBuf, uint32_t len)
215 {
216 	VCOM_DATA_T *pVcom = &g_vCOM;
217 	uint32_t ret = 0;
218 
219 	if ( (pVcom->tx_flags & VCOM_TX_CONNECTED) && ((pVcom->tx_flags & VCOM_TX_BUSY) == 0) ) {
220 		pVcom->tx_flags |= VCOM_TX_BUSY;
221 
222 		/* enter critical section */
223 		NVIC_DisableIRQ(USB0_IRQn);
224 		ret = USBD_API->hw->WriteEP(pVcom->hUsb, USB_CDC_IN_EP, pBuf, len);
225 		/* exit critical section */
226 		NVIC_EnableIRQ(USB0_IRQn);
227 	}
228 
229 	return ret;
230 }
231