1 /*
2  * Trace Recorder for Tracealyzer v4.6.6
3  * Copyright 2021 Percepio AB
4  * www.percepio.com
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  * Supporting functions for trace streaming ("stream ports").
9  * This "stream port" sets up the recorder to use USB CDC as streaming channel.
10  * The example is for STM32 using STM32Cube.
11  */
12 
13 #include <trcRecorder.h>
14 
15 #include <usb_device.h>
16 #include <usbd_CDC_if.h>
17 
18 #if (TRC_USE_TRACEALYZER_RECORDER == 1)
19 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
20 
21 static void prvCDCInit(void);
22 
23 static int8_t CDC_Receive_FS_modified(uint8_t* pbuf, uint32_t *puiLength);
24 
25 extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS;
26 
27 static int8_t(*CDC_Receive_FS)(uint8_t* Buf, uint32_t* Len);
28 
29 typedef struct TraceStreamPortUSBCommandBuffer {
30 	TraceUnsignedBaseType_t idx;
31 	uint8_t bufferUSB[TRC_STREAM_PORT_USB_BUFFER_SIZE];
32 	uint8_t bufferInternal[TRC_STREAM_PORT_INTERNAL_BUFFER_SIZE];
33 } TraceStreamPortUSBBuffers_t;
34 
35 TraceStreamPortUSBBuffers_t* pxUSBBuffers;
36 
CDC_Receive_FS_modified(uint8_t * pBuffer,uint32_t * puiLength)37 static int8_t CDC_Receive_FS_modified(uint8_t* pBuffer, uint32_t *puiLength)
38 {
39 	for(uint32_t i = 0; i < *puiLength; i++)
40 	{
41 		pxUSBBuffers->bufferUSB[pxUSBBuffers->idx] = pBuffer[i];
42 		pxUSBBuffers->idx++;
43 	}
44 
45 	CDC_Receive_FS(pBuffer, puiLength);
46 
47 	return (USBD_OK);
48 }
49 
prvCDCInit(void)50 static void prvCDCInit(void)
51 {
52 	/* Store the original "Receive" function, from the static initialization */
53 	CDC_Receive_FS = USBD_Interface_fops_FS.Receive;
54 
55 	/* Update the function pointer with our modified variant */
56 	USBD_Interface_fops_FS.Receive = CDC_Receive_FS_modified;
57 
58 	pxUSBBuffers->idx = 0;
59 
60 	MX_USB_DEVICE_Init();
61 }
62 
63 /* The READ function, used in trcStreamPort.h */
prvTraceCDCReceive(void * data,uint32_t uiSize,int32_t * piBytesReceived)64 traceResult prvTraceCDCReceive(void *data, uint32_t uiSize, int32_t* piBytesReceived)
65 {
66 	uint32_t i, uiDiff;
67 
68 	if(pxUSBBuffers->idx > 0)
69 	{
70 		if ((TraceUnsignedBaseType_t)uiSize >= pxUSBBuffers->idx) // More than what is stored, number of bytes will be .idx
71 		{
72 			TRC_MEMCPY(data, pxUSBBuffers->bufferUSB, pxUSBBuffers->idx);
73 			*piBytesReceived = (int32_t)pxUSBBuffers->idx;
74 			pxUSBBuffers->idx = 0; // Make the buffer ready for a new command
75 		}
76 		else  // If some data in the buffer is not read
77 		{
78 			uiDiff = pxUSBBuffers->idx - uiSize;
79 			TRC_MEMCPY(data, pxUSBBuffers->bufferUSB, uiSize);
80 
81 			for(i = 0; i < uiDiff; i++)
82 			{
83 				pxUSBBuffers->bufferUSB[i] = pxUSBBuffers->bufferUSB[i + uiSize];
84 			}
85 
86 			*piBytesReceived = uiSize;
87 
88 			pxUSBBuffers->idx = uiDiff;
89 		}
90 	}
91 	else
92 	{
93 		*piBytesReceived = 0;
94 	}
95 
96 	return TRC_SUCCESS;
97 }
98 
99 /* The WRITE function, used in trcStreamPort.h */
prvTraceCDCTransmit(void * pvData,uint32_t uiSize,int32_t * piBytesSent)100 traceResult prvTraceCDCTransmit(void* pvData, uint32_t uiSize, int32_t * piBytesSent )
101 {
102 	static int fail_counter = 0;
103 
104 	int32_t result;
105 
106 	*piBytesSent = 0;
107 
108 	result = CDC_Transmit_FS(pvData, uiSize);
109 
110 	if (result == USBD_OK)
111 	{
112 		fail_counter = 0;
113 		*piBytesSent = uiSize;
114 		return TRC_SUCCESS;
115 	}
116 	else
117 	{
118 		fail_counter++;
119 
120 		/* We keep trying to send more pvData. If busy, we delay for a while. This function will be called again afterwards. */
121 		xTraceKernelPortDelay(TRC_CFG_STREAM_PORT_DELAY_ON_BUSY);
122 
123 		if (fail_counter >= 100)
124 		{
125 			/* If many unsuccessful attempts in a row, something is very wrong. Returning -1 will stop the recorder. */
126 			return TRC_FAIL;
127 		}
128 	}
129 
130 	return TRC_SUCCESS;
131 }
132 
xTraceStreamPortInitialize(TraceStreamPortBuffer_t * pxBuffer)133 traceResult xTraceStreamPortInitialize(TraceStreamPortBuffer_t* pxBuffer)
134 {
135 	TRC_ASSERT_EQUAL_SIZE(TraceStreamPortBuffer_t, TraceStreamPortUSBBuffers_t);
136 
137 	if (pxBuffer == 0)
138 	{
139 		return TRC_FAIL;
140 	}
141 
142 	pxUSBBuffers = (TraceStreamPortUSBBuffers_t*)pxBuffer;
143 
144 	prvCDCInit();
145 
146 	return xTraceInternalEventBufferInitialize(pxUSBBuffers->bufferInternal, sizeof(pxUSBBuffers->bufferInternal));
147 }
148 
149 #endif	/*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
150 #endif  /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/
151 
152