2 * This file is part of INAV.
4 * INAV is free software. You can redistribute this software
5 * and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * INAV is distributed in the hope that they will be
11 * useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
26 #include <sys/select.h>
32 #if defined(SITL_BUILD)
34 #include <sys/socket.h>
36 #include <netinet/in.h>
38 #include <arpa/inet.h>
41 #include "common/utils.h"
43 #include "drivers/serial.h"
44 #include "drivers/serial_tcp.h"
46 static const struct serialPortVTable tcpVTable
[];
47 static tcpPort_t tcpPorts
[SERIAL_PORT_COUNT
];
48 static bool tcpThreadRunning
= false;
50 static int lookup_address (char *name
, int port
, int type
, struct sockaddr
*addr
, socklen_t
* len
)
52 struct addrinfo
*servinfo
, *p
;
53 struct addrinfo hints
= {.ai_family
= AF_UNSPEC
, .ai_socktype
= type
, .ai_flags
= AI_V4MAPPED
|AI_ADDRCONFIG
};
55 hints
.ai_flags
|= AI_PASSIVE
;
58 This nonsense is to uniformly deliver the same sa_family regardless of whether
59 name is NULL or non-NULL
60 Otherwise, at least on Linux, we get
61 - V6,V4 for the non-null case and
62 - V4,V6 for the null case, regardless of gai.conf
63 Which may confuse consumers.
64 FreeBSD and Windows behave consistently, giving V6 for Ipv6 enabled stacks in all cases
65 unless a quad dotted address is specificied
67 struct addrinfo
*p4
= NULL
;
68 struct addrinfo
*p6
= NULL
;
71 snprintf(aport
, sizeof(aport
), "%d", port
);
72 if ((result
= getaddrinfo(name
, aport
, &hints
, &servinfo
)) != 0) {
73 fprintf(stderr
, "getaddrinfo: %s\n", gai_strerror(result
));
77 for(p
= servinfo
; p
!= NULL
; p
= p
->ai_next
) {
78 if(p
->ai_family
== AF_INET6
)
80 else if(p
->ai_family
== AF_INET
)
90 memcpy(addr
, p
->ai_addr
, p
->ai_addrlen
);
92 freeaddrinfo(servinfo
);
97 static char *tcpGetAddressString(struct sockaddr
*addr
)
99 static char straddr
[INET6_ADDRSTRLEN
];
101 if (addr
->sa_family
== AF_INET6
) {
102 struct sockaddr_in6
* ip
= (struct sockaddr_in6
*)addr
;
103 ipaddr
= &ip
->sin6_addr
;
105 struct sockaddr_in
* ip
= (struct sockaddr_in
*)addr
;
106 ipaddr
= &ip
->sin_addr
;
108 const char *res
= inet_ntop(addr
->sa_family
, ipaddr
, straddr
, sizeof straddr
);
112 static void *tcpReceiveThread(void* arg
)
114 tcpPort_t
*port
= (tcpPort_t
*)arg
;
116 while(tcpThreadRunning
) {
117 if (tcpReceive(port
) < 0) {
125 static tcpPort_t
*tcpReConfigure(tcpPort_t
*port
, uint32_t id
)
127 socklen_t sockaddrlen
;
128 if (port
->isInitalized
){
132 if (pthread_mutex_init(&port
->receiveMutex
, NULL
) != 0){
136 uint16_t tcpPort
= BASE_IP_ADDRESS
+ id
- 1;
137 if (lookup_address(NULL
, tcpPort
, SOCK_STREAM
, (struct sockaddr
*)&port
->sockAddress
, &sockaddrlen
) != 0) {
140 port
->socketFd
= socket(((struct sockaddr
*)&port
->sockAddress
)->sa_family
, SOCK_STREAM
, IPPROTO_TCP
);
142 if (port
->socketFd
< 0) {
143 fprintf(stderr
, "[SOCKET] Unable to create tcp socket\n");
148 // Sadly necesary to enforce dual-stack behaviour on Windows networking ,,,
149 if (((struct sockaddr
*)&port
->sockAddress
)->sa_family
== AF_INET6
) {
151 err
= setsockopt(port
->socketFd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &v6only
, sizeof(v6only
));
153 fprintf(stderr
,"[SOCKET] setting V6ONLY=false: %s\n", strerror(errno
));
159 err
= setsockopt(port
->socketFd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
160 err
= fcntl(port
->socketFd
, F_SETFL
, fcntl(port
->socketFd
, F_GETFL
, 0) | O_NONBLOCK
);
163 fprintf(stderr
, "[SOCKET] Unable to set socket options\n");
167 port
->isClientConnected
= false;
168 port
->isInitalized
= true;
171 if (bind(port
->socketFd
, (struct sockaddr
*)&port
->sockAddress
, sockaddrlen
) < 0) {
172 fprintf(stderr
, "[SOCKET] Unable to bind socket\n");
176 if (listen(port
->socketFd
, 100) < 0) {
177 fprintf(stderr
, "[SOCKET] Unable to listen.\n");
181 fprintf(stderr
, "[SOCKET] Bind TCP %s port %d to UART%d\n",
182 tcpGetAddressString((struct sockaddr
*)&port
->sockAddress
), tcpPort
, id
);
187 int tcpReceive(tcpPort_t
*port
)
189 if (!port
->isClientConnected
) {
194 FD_SET(port
->socketFd
, &fds
);
196 if (select(port
->socketFd
+ 1, &fds
, NULL
, NULL
, NULL
) < 0) {
197 fprintf(stderr
, "[SOCKET] Unable to wait for connection.\n");
201 socklen_t addrLen
= sizeof(struct sockaddr_storage
);
202 port
->clientSocketFd
= accept(port
->socketFd
,(struct sockaddr
*)&port
->clientAddress
, &addrLen
);
203 if (port
->clientSocketFd
< 1) {
204 fprintf(stderr
, "[SOCKET] Can't accept connection.\n");
208 fprintf(stderr
, "[SOCKET] %s connected to UART%d\n", tcpGetAddressString((struct sockaddr
*)&port
->clientAddress
), port
->id
);
209 port
->isClientConnected
= true;
212 uint8_t buffer
[TCP_BUFFER_SIZE
];
213 ssize_t recvSize
= recv(port
->clientSocketFd
, buffer
, TCP_BUFFER_SIZE
, 0);
216 if (port
->isClientConnected
&& recvSize
== 0)
218 fprintf(stderr
, "[SOCKET] %s disconnected from UART%d\n", tcpGetAddressString((struct sockaddr
*)&port
->clientAddress
), port
->id
);
219 close(port
->clientSocketFd
);
220 memset(&port
->clientAddress
, 0, sizeof(port
->clientAddress
));
221 port
->isClientConnected
= false;
226 for (ssize_t i
= 0; i
< recvSize
; i
++) {
228 if (port
->serialPort
.rxCallback
) {
229 port
->serialPort
.rxCallback((uint16_t)buffer
[i
], port
->serialPort
.rxCallbackData
);
231 pthread_mutex_lock(&port
->receiveMutex
);
232 port
->serialPort
.rxBuffer
[port
->serialPort
.rxBufferHead
] = buffer
[i
];
233 port
->serialPort
.rxBufferHead
= (port
->serialPort
.rxBufferHead
+ 1) % port
->serialPort
.rxBufferSize
;
234 pthread_mutex_unlock(&port
->receiveMutex
);
242 return (int)recvSize
;
245 serialPort_t
*tcpOpen(USART_TypeDef
*USARTx
, serialReceiveCallbackPtr callback
, void *rxCallbackData
, uint32_t baudRate
, portMode_t mode
, portOptions_t options
)
247 tcpPort_t
*port
= NULL
;
249 #if defined(USE_UART1) || defined(USE_UART2) || defined(USE_UART3) || defined(USE_UART4) || defined(USE_UART5) || defined(USE_UART6) || defined(USE_UART7) || defined(USE_UART8)
250 uint32_t id
= (uintptr_t)USARTx
;
251 if (id
< SERIAL_PORT_COUNT
) {
252 port
= tcpReConfigure(&tcpPorts
[id
-1], id
);
261 port
->serialPort
.vTable
= tcpVTable
;
262 port
->serialPort
.rxCallback
= callback
;
263 port
->serialPort
.rxCallbackData
= rxCallbackData
;
264 port
->serialPort
.rxBufferHead
= port
->serialPort
.rxBufferTail
= 0;
265 port
->serialPort
.rxBufferSize
= TCP_BUFFER_SIZE
;
266 port
->serialPort
.rxBuffer
= port
->rxBuffer
;
267 port
->serialPort
.mode
= mode
;
268 port
->serialPort
.baudRate
= baudRate
;
269 port
->serialPort
.options
= options
;
271 int err
= pthread_create(&port
->receiveThread
, NULL
, tcpReceiveThread
, (void*)port
);
273 fprintf(stderr
, "[SOCKET] Unable to create receive thread for UART%d\n", id
);
276 tcpThreadRunning
= true;
278 return (serialPort_t
*)port
;
281 uint8_t tcpRead(serialPort_t
*instance
)
284 tcpPort_t
*port
= (tcpPort_t
*)instance
;
285 pthread_mutex_lock(&port
->receiveMutex
);
287 ch
= port
->serialPort
.rxBuffer
[port
->serialPort
.rxBufferTail
];
288 port
->serialPort
.rxBufferTail
= (port
->serialPort
.rxBufferTail
+ 1) % port
->serialPort
.rxBufferSize
;
290 pthread_mutex_unlock(&port
->receiveMutex
);
295 void tcpWritBuf(serialPort_t
*instance
, const void *data
, int count
)
297 tcpPort_t
*port
= (tcpPort_t
*)instance
;
299 if (!port
->isClientConnected
) {
303 send(port
->clientSocketFd
, data
, count
, 0);
306 void tcpWrite(serialPort_t
*instance
, uint8_t ch
)
308 tcpWritBuf(instance
, (void*)&ch
, 1);
311 uint32_t tcpTotalRxBytesWaiting(const serialPort_t
*instance
)
313 tcpPort_t
*port
= (tcpPort_t
*)instance
;
316 pthread_mutex_lock(&port
->receiveMutex
);
318 if (port
->serialPort
.rxBufferHead
>= port
->serialPort
.rxBufferTail
) {
319 count
= port
->serialPort
.rxBufferHead
- port
->serialPort
.rxBufferTail
;
321 count
= port
->serialPort
.rxBufferSize
+ port
->serialPort
.rxBufferHead
- port
->serialPort
.rxBufferTail
;
324 pthread_mutex_unlock(&port
->receiveMutex
);
329 uint32_t tcpTotalTxBytesFree(const serialPort_t
*instance
)
331 tcpPort_t
*port
= (tcpPort_t
*)instance
;
333 if (port
->isClientConnected
) {
334 return TCP_MAX_PACKET_SIZE
;
340 bool isTcpTransmitBufferEmpty(const serialPort_t
*instance
)
347 bool tcpIsConnected(const serialPort_t
*instance
)
349 return ((tcpPort_t
*)instance
)->isClientConnected
;
352 void tcpSetBaudRate(serialPort_t
*instance
, uint32_t baudRate
)
359 void tcpSetMode(serialPort_t
*instance
, portMode_t mode
)
365 static const struct serialPortVTable tcpVTable
[] = {
367 .serialWrite
= tcpWrite
,
368 .serialTotalRxWaiting
= tcpTotalRxBytesWaiting
,
369 .serialTotalTxFree
= tcpTotalTxBytesFree
,
370 .serialRead
= tcpRead
,
371 .serialSetBaudRate
= tcpSetBaudRate
,
372 .isSerialTransmitBufferEmpty
= isTcpTransmitBufferEmpty
,
373 .setMode
= tcpSetMode
,
374 .isConnected
= tcpIsConnected
,
375 .writeBuf
= tcpWritBuf
,