1 /*
2  * Trace Recorder for Tracealyzer v4.10.3
3  * Copyright 2023 Percepio AB
4  * www.percepio.com
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  * Supporting functions for trace streaming, used by the "stream ports"
9  * for reading and writing data to the interface.
10  * Existing ports can easily be modified to fit another setup, e.g., a
11  * different UDP stack, or to define your own stream port.
12  */
13 
14 #include <trcRecorder.h>
15 
16 #if (TRC_USE_TRACEALYZER_RECORDER == 1)
17 
18 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
19 
20 /* udp includes - for lwIP in this case */
21 #include <lwip/sockets.h>
22 #include <lwip/errno.h>
23 
24 int sock = -1;
25 int remoteSize;
26 struct sockaddr_in address_out;
27 
28 typedef struct TraceStreamPortUDP
29 {
30 #if (TRC_USE_INTERNAL_BUFFER)
31 	uint8_t buffer[(TRC_ALIGNED_STREAM_PORT_BUFFER_SIZE)];
32 #else
33 	TraceUnsignedBaseType_t buffer[1];
34 #endif
35 } TraceStreamPortUDP_t;
36 
37 static TraceStreamPortUDP_t* pxStreamPortUDP TRC_CFG_RECORDER_DATA_ATTRIBUTE;
38 
39 static int32_t prvSocketSend(void* pvData, uint32_t uiSize, int32_t* piBytesWritten);
40 static int32_t prvSocketReceive(void* pvData, uint32_t uiSize, int32_t* piBytesRead);
41 static int32_t prvSocketInitialize(void);
42 
prvSocketSend(void * pvData,uint32_t uiSize,int32_t * piBytesWritten)43 static int32_t prvSocketSend( void* pvData, uint32_t uiSize, int32_t* piBytesWritten )
44 {
45 	if (sock < 0)
46 	{
47 		return -1;
48 	}
49 
50 	if (piBytesWritten == (void*)0)
51 	{
52 		return -1;
53 	}
54 
55 	*piBytesWritten = sendto( sock, pvData, uiSize, 0, (struct sockaddr *)&address_out, sizeof(address_out) );
56 
57 	if (*piBytesWritten < 0)
58 	{
59 		*piBytesWritten = 0;
60 
61 		/* EWOULDBLOCK may be expected when buffers are full */
62 		if (errno != EWOULDBLOCK)
63 		{
64 			close(sock);
65 			sock = -1;
66 			return -1;
67 		}
68 	}
69 
70 	return 0;
71 }
72 
prvSocketReceive(void * pvData,uint32_t uiSize,int32_t * piBytesRead)73 static int32_t prvSocketReceive( void* pvData, uint32_t uiSize, int32_t* piBytesRead )
74 {
75 	if (sock < 0)
76 		return -1;
77 
78 	if (piBytesRead == (void*)0)
79 		return -1;
80 
81 	*piBytesRead = recv( sock, pvData, uiSize, 0 );
82 
83 	if (*piBytesRead < 0)
84 	{
85 		*piBytesRead = 0;
86 
87 		/* EWOULDBLOCK may be expected when there is no pvData to receive */
88 		if (errno != EWOULDBLOCK)
89 		{
90 		close(sock);
91 		sock = -1;
92 		return -1;
93 		}
94 	}
95 
96 	return 0;
97 }
98 
prvSocketInitialize(void)99 static int32_t prvSocketInitialize(void)
100 {
101 	int flags = 0;
102 	struct sockaddr_in address_in;
103 
104 	if (sock >= 0)
105 	{
106 		return 0;
107 	}
108 
109 	sock = socket(AF_INET, SOCK_DGRAM, 0);
110 
111 	if (sock < 0)
112 	{
113 		return -1;
114 	}
115 
116 	address_in.sin_family = AF_INET;
117 	address_in.sin_port = htons(TRC_CFG_STREAM_PORT_UDP_PORT);
118 	address_in.sin_addr.s_addr = INADDR_ANY;
119 
120 	if (bind(sock, (struct sockaddr*)&address_in, sizeof(address_in)) != 0)
121 	{
122 		close(sock);
123 		sock = -1;
124 		return -1;
125 	}
126 
127 	flags = fcntl( sock, F_GETFL, 0 );
128 	fcntl( sock, F_SETFL, flags | O_NONBLOCK );
129 
130 	address_out.sin_family = AF_INET;
131 	address_out.sin_port = htons(TRC_CFG_STREAM_PORT_UDP_PORT);
132 	address_out.sin_addr.s_addr = inet_addr(TRC_CFG_STREAM_PORT_UDP_ADDRESS);
133 
134 	return 0;
135 }
136 
137 /************** MODIFY THE ABOVE PART TO USE YOUR UDP STACK ****************/
138 
prvTraceUdpWrite(void * pvData,uint32_t uiSize,int32_t * piBytesWritten)139 int32_t prvTraceUdpWrite(void* pvData, uint32_t uiSize, int32_t *piBytesWritten)
140 {
141 	prvSocketInitialize();
142 
143 	return prvSocketSend(pvData, uiSize, piBytesWritten);
144 }
145 
prvTraceUdpRead(void * pvData,uint32_t uiSize,int32_t * piBytesRead)146 int32_t prvTraceUdpRead(void* pvData, uint32_t uiSize, int32_t *piBytesRead)
147 {
148 	prvSocketInitialize();
149 
150 	return prvSocketReceive(pvData, uiSize, piBytesRead);
151 }
152 
xTraceStreamPortInitialize(TraceStreamPortBuffer_t * pxBuffer)153 traceResult xTraceStreamPortInitialize(TraceStreamPortBuffer_t* pxBuffer)
154 {
155 	TRC_ASSERT_EQUAL_SIZE(TraceStreamPortBuffer_t, TraceStreamPortUDP_t);
156 
157 	if (pxBuffer == 0)
158 	{
159 		return TRC_FAIL;
160 	}
161 
162 	pxStreamPortUDP = (TraceStreamPortUDP_t*)pxBuffer;
163 
164 #if (TRC_USE_INTERNAL_BUFFER == 1)
165 	return xTraceInternalEventBufferInitialize(pxStreamPortUDP->buffer, sizeof(pxStreamPortUDP->buffer));
166 #else
167 	return TRC_SUCCESS;
168 #endif
169 }
170 
xTraceStreamPortOnTraceEnd(void)171 traceResult xTraceStreamPortOnTraceEnd(void)
172 {
173 	if (sock >= 0)
174 	{
175 		close(sock);
176 	}
177 
178 	return TRC_SUCCESS;
179 }
180 
181 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
182 
183 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/
184