b516581093e89085b1f3fa44a28e08afccfabc60
[platform/upstream/connectedhomeip.git] / third_party / openthread / repo / examples / platforms / gp712 / uart-socket.c
1 /*
2  *  Copyright (c) 2016-2017, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 /**
30  * @file
31  *   This file implements the OpenThread platform abstraction for cli over ip socket communication.
32  *
33  */
34
35 #include "alarm_qorvo.h"
36 #include "platform_qorvo.h"
37 #include "uart_qorvo.h"
38
39 #include <assert.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <poll.h>
43 #include <signal.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <termios.h>
48 #include <unistd.h>
49
50 #include <netdb.h>
51 #include <netinet/in.h>
52 #include <netinet/tcp.h>
53 #include <sys/socket.h>
54 #include <sys/types.h>
55
56 #include <pthread.h>
57
58 #include <openthread/config.h>
59
60 #include <common/code_utils.hpp>
61 #include <openthread/platform/uart.h>
62
63 #include "utils/code_utils.h"
64
65 #define BUFFER_MAX_SIZE 255
66 #define SOCKET_PORT 9190
67 #define SOCKET_WRITE(socketInfo, buf, length) \
68     sendto(socketInfo.socketId, (const char *)buf, length, 0, &socketInfo.addr, sizeof(socketInfo.addr))
69 #define SOCKET_READ(socketId, buf, length) recv(socketId, buf, length, 0)
70
71 typedef struct
72 {
73     uint32_t        socketId;
74     bool            isValid;
75     struct sockaddr addr;
76     pthread_t       rfReadThread;
77 } PlatSocket_t;
78
79 PlatSocket_t PlatSocketConnection;
80 int          PlatSocketPipeFd[2];
81 int          PlatServerSocketId;
82
83 void PlatSocketRxNewConn(uint8_t id);
84 void PlatSocketInit(void);
85 void PlatSocketDeInit(void);
86 int  PlatSocketTxData(uint16_t length, uint8_t *pData, uint32_t socketId);
87
88 #define PLAT_UART_MAX_CHAR 1024
89
90 uint32_t PlatSocketId = 0;
91
92 void PlatSocketSendInput(void *buffer)
93 {
94     uint8_t  len = 0;
95     uint8_t *buf = (uint8_t *)buffer;
96     len          = strlen((char *)buf);
97     otPlatUartReceived((uint8_t *)buf, (uint16_t)len);
98     free(buf);
99     buf = 0;
100     len = 0;
101 }
102
103 void PlatSocketRx(uint16_t length, const char *buffer, uint32_t socketId)
104 {
105     uint8_t *buf = 0;
106     PlatSocketId = socketId;
107
108     if (length > 0)
109     {
110         buf = malloc(length + 2);
111         memcpy(buf, buffer, length);
112         buf[length]     = '\n';
113         buf[length + 1] = 0;
114         qorvoAlarmScheduleEventArg(0, PlatSocketSendInput, (void *)buf);
115     }
116 }
117
118 void PlatSocketClose(uint32_t socketId)
119 {
120     OT_UNUSED_VARIABLE(socketId);
121 }
122
123 otError otPlatUartEnable(void)
124 {
125     PlatSocketInit();
126     return OT_ERROR_NONE;
127 }
128
129 otError otPlatUartDisable(void)
130 {
131     PlatSocketDeInit();
132     return OT_ERROR_NONE;
133 }
134
135 otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength)
136 {
137     otError error = OT_ERROR_NONE;
138     char    localbuf[PLAT_UART_MAX_CHAR];
139
140     memcpy(localbuf, aBuf, aBufLength);
141     localbuf[aBufLength] = 0;
142     printf("%s", localbuf);
143
144     if (PlatSocketId)
145     {
146         PlatSocketTxData(aBufLength, (uint8_t *)aBuf, PlatSocketId);
147     }
148
149     otPlatUartSendDone();
150     return error;
151 }
152
153 otError otPlatUartFlush(void)
154 {
155     return OT_ERROR_NOT_IMPLEMENTED;
156 }
157
158 void platformUartInit(void)
159 {
160 }
161
162 void platformUartProcess(void)
163 {
164 }
165
166 int PlatSocketListenForClients()
167 {
168     // Setup server side socket
169     int                sockfd;
170     struct sockaddr_in serv_addr;
171     uint32_t           flag = 1;
172     int                ret;
173
174     sockfd = socket(AF_INET, SOCK_STREAM, 0);
175     otEXPECT_ACTION(sockfd >= 0, sockfd = -1);
176
177     // disable Nagle's algorithm to avoid long latency
178     setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag));
179     // allow reuse of the same address
180     setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag));
181     memset(&serv_addr, 0, sizeof(serv_addr));
182
183     serv_addr.sin_addr.s_addr = INADDR_ANY;
184     serv_addr.sin_family      = AF_INET;
185     serv_addr.sin_port        = htons(SOCKET_PORT);
186     ret                       = bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
187     otEXPECT_ACTION(ret >= 0, close(sockfd); sockfd = -1);
188     ret = listen(sockfd, 10);
189     otEXPECT_ACTION(ret != -1, exit(1));
190 exit:
191     return sockfd;
192 }
193
194 void PlatSocketRxSignaled(uint8_t id)
195 {
196     OT_UNUSED_VARIABLE(id);
197
198     // Dummy callback function to flush pipe
199     uint8_t readChar;
200     // Remove trigger byte from pipe
201     read(PlatSocketPipeFd[0], &readChar, 1);
202 }
203
204 void *PlatSocketReadThread(void *pClientSocket)
205 {
206     char          buffer[BUFFER_MAX_SIZE];
207     PlatSocket_t *clientSocket = ((PlatSocket_t *)pClientSocket);
208
209     memset(buffer, 0, BUFFER_MAX_SIZE);
210
211     while (1)
212     {
213         int readLen = SOCKET_READ(clientSocket->socketId, buffer, BUFFER_MAX_SIZE);
214
215         if (readLen < 0)
216         {
217             perror("Reading socket");
218             break;
219         }
220         else
221         {
222             if (readLen == 0)
223             {
224                 break;
225             }
226
227             {
228                 uint8_t someByte = 0x12; // No functional use  only using pipe to kick main thread
229
230                 PlatSocketRx(readLen, buffer, clientSocket->socketId);
231
232                 write(PlatSocketPipeFd[1], &someByte, 1); //[1] = write fd
233             }
234         }
235     }
236
237     clientSocket->isValid = 0;
238     qorvoPlatUnRegisterPollFunction(clientSocket->socketId);
239     close(clientSocket->socketId);
240
241     PlatSocketClose(clientSocket->socketId);
242
243     return NULL;
244 }
245
246 void PlatSocketRxNewConn(uint8_t id)
247 {
248     // Find first non-valid client in list - add here
249     if (PlatSocketConnection.isValid == 0)
250     {
251         // Add new client to client list
252         socklen_t len;
253         len        = sizeof(PlatSocketConnection.addr);
254         int retval = accept(id, (struct sockaddr *)&PlatSocketConnection.addr, (socklen_t *)&len);
255
256         if (retval >= 0)
257         {
258             int retErr;
259             PlatSocketConnection.socketId = retval;
260             retErr =
261                 pthread_create(&PlatSocketConnection.rfReadThread, NULL, PlatSocketReadThread, &PlatSocketConnection);
262
263             if (retErr)
264             {
265                 close(PlatSocketConnection.socketId);
266             }
267             else
268             {
269                 PlatSocketConnection.isValid = 1;
270             }
271         }
272     }
273     else
274     {
275         int tempfd;
276         tempfd = accept(id, (struct sockaddr *)NULL, NULL);
277
278         if (tempfd >= 0)
279         {
280             close(tempfd);
281         }
282     }
283 }
284
285 /*****************************************************************************
286  *                    Public Function Definitions
287  *****************************************************************************/
288
289 void PlatSocketInit(void)
290 {
291     memset(&PlatSocketConnection, 0, sizeof(PlatSocketConnection));
292
293     // in case we are a server, setup listening for client
294     PlatServerSocketId = PlatSocketListenForClients();
295     qorvoPlatRegisterPollFunction(PlatServerSocketId, PlatSocketRxNewConn);
296
297     // hack
298     pipe(PlatSocketPipeFd);
299     qorvoPlatRegisterPollFunction(PlatSocketPipeFd[0], PlatSocketRxSignaled);
300 }
301
302 void platformUartRestore(void)
303 {
304     PlatSocketDeInit();
305 }
306
307 void PlatSocketDeInit(void)
308 {
309     qorvoPlatUnRegisterPollFunction(PlatServerSocketId);
310     close(PlatServerSocketId);
311     qorvoPlatUnRegisterPollFunction(PlatSocketPipeFd[0]);
312     close(PlatSocketPipeFd[0]);
313     close(PlatSocketPipeFd[1]);
314     close(PlatSocketConnection.socketId);
315 }
316
317 int PlatSocketTxData(uint16_t length, uint8_t *pData, uint32_t socketId)
318 {
319     int result = -1;
320
321     // All sockets
322     if (PlatSocketConnection.isValid)
323     {
324         if (PlatSocketConnection.socketId == socketId)
325         {
326             if (SOCKET_WRITE(PlatSocketConnection, (const char *)pData, length) < 0)
327             {
328                 perror("TxSocket: Error Writing to client");
329                 close(PlatSocketConnection.socketId);
330                 PlatSocketConnection.isValid = 0;
331             }
332             else
333             {
334                 result = 0;
335             }
336         }
337     }
338
339     return result;
340 }