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>
40 #include <netinet/tcp.h>
42 #include "common/utils.h"
44 #include "drivers/serial.h"
45 #include "drivers/serial_tcp.h"
46 #include "target/SITL/serial_proxy.h"
48 static const struct serialPortVTable tcpVTable
[];
49 static tcpPort_t tcpPorts
[SERIAL_PORT_COUNT
];
51 static void *tcpReceiveThread(void* arg
)
53 tcpPort_t
*port
= (tcpPort_t
*)arg
;
54 while(tcpReceive(port
) >= 0)
58 static tcpPort_t
*tcpReConfigure(tcpPort_t
*port
, uint32_t id
)
60 socklen_t sockaddrlen
;
61 if (port
->isInitalized
){
65 if (pthread_mutex_init(&port
->receiveMutex
, NULL
) != 0){
69 uint16_t tcpPort
= BASE_IP_ADDRESS
+ id
- 1;
70 if (lookupAddress(NULL
, tcpPort
, SOCK_STREAM
, (struct sockaddr
*)&port
->sockAddress
, &sockaddrlen
) != 0) {
73 port
->socketFd
= socket(((struct sockaddr
*)&port
->sockAddress
)->sa_family
, SOCK_STREAM
, IPPROTO_TCP
);
75 if (port
->socketFd
< 0) {
76 fprintf(stderr
, "[SOCKET] Unable to create tcp socket\n");
81 // Sadly necesary to enforce dual-stack behaviour on Windows networking ,,,
82 if (((struct sockaddr
*)&port
->sockAddress
)->sa_family
== AF_INET6
) {
84 err
= setsockopt(port
->socketFd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &v6only
, sizeof(v6only
));
86 fprintf(stderr
,"[SOCKET] setting V6ONLY=false: %s\n", strerror(errno
));
92 err
= setsockopt(port
->socketFd
, IPPROTO_TCP
, TCP_NODELAY
, &one
, sizeof(one
));
93 err
= setsockopt(port
->socketFd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
94 err
= fcntl(port
->socketFd
, F_SETFL
, fcntl(port
->socketFd
, F_GETFL
, 0) | O_NONBLOCK
);
97 fprintf(stderr
, "[SOCKET] Unable to set socket options\n");
101 port
->isClientConnected
= false;
102 port
->isInitalized
= true;
105 if (bind(port
->socketFd
, (struct sockaddr
*)&port
->sockAddress
, sockaddrlen
) < 0) {
106 fprintf(stderr
, "[SOCKET] Unable to bind socket\n");
110 if (listen(port
->socketFd
, 100) < 0) {
111 fprintf(stderr
, "[SOCKET] Unable to listen.\n");
114 char addrbuf
[IPADDRESS_PRINT_BUFLEN
];
115 char *addrptr
= prettyPrintAddress((struct sockaddr
*)&port
->sockAddress
, addrbuf
, IPADDRESS_PRINT_BUFLEN
);
116 if (addrptr
!= NULL
) {
117 fprintf(stderr
, "[SOCKET] Bind TCP %s to UART%d\n", addrptr
, id
);
122 void tcpReceiveBytes( tcpPort_t
*port
, const uint8_t* buffer
, ssize_t recvSize
) {
123 for (ssize_t i
= 0; i
< recvSize
; i
++) {
124 if (port
->serialPort
.rxCallback
) {
125 port
->serialPort
.rxCallback((uint16_t)buffer
[i
], port
->serialPort
.rxCallbackData
);
127 pthread_mutex_lock(&port
->receiveMutex
);
128 port
->serialPort
.rxBuffer
[port
->serialPort
.rxBufferHead
] = buffer
[i
];
129 port
->serialPort
.rxBufferHead
= (port
->serialPort
.rxBufferHead
+ 1) % port
->serialPort
.rxBufferSize
;
130 pthread_mutex_unlock(&port
->receiveMutex
);
135 void tcpReceiveBytesEx( int portIndex
, const uint8_t* buffer
, ssize_t recvSize
) {
136 tcpReceiveBytes( &tcpPorts
[portIndex
], buffer
, recvSize
);
139 int tcpReceive(tcpPort_t
*port
)
141 char addrbuf
[IPADDRESS_PRINT_BUFLEN
];
142 if (!port
->isClientConnected
) {
147 FD_SET(port
->socketFd
, &fds
);
149 if (select(port
->socketFd
+ 1, &fds
, NULL
, NULL
, NULL
) < 0) {
150 fprintf(stderr
, "[SOCKET] Unable to wait for connection.\n");
154 socklen_t addrLen
= sizeof(struct sockaddr_storage
);
155 port
->clientSocketFd
= accept(port
->socketFd
,(struct sockaddr
*)&port
->clientAddress
, &addrLen
);
156 if (port
->clientSocketFd
< 1) {
157 fprintf(stderr
, "[SOCKET] Can't accept connection.\n");
161 char *addrptr
= prettyPrintAddress((struct sockaddr
*)&port
->clientAddress
, addrbuf
, IPADDRESS_PRINT_BUFLEN
);
162 if (addrptr
!= NULL
) {
163 fprintf(stderr
, "[SOCKET] %s connected to UART%d\n", addrptr
, port
->id
);
165 port
->isClientConnected
= true;
168 uint8_t buffer
[TCP_BUFFER_SIZE
];
169 ssize_t recvSize
= recv(port
->clientSocketFd
, buffer
, TCP_BUFFER_SIZE
, 0);
171 // recv() under cygwin does not recognise the closed connection under certain circumstances, but returns ECONNRESET as an error.
172 if (port
->isClientConnected
&& (recvSize
== 0 || ( recvSize
== -1 && errno
== ECONNRESET
))) {
173 char *addrptr
= prettyPrintAddress((struct sockaddr
*)&port
->clientAddress
, addrbuf
, IPADDRESS_PRINT_BUFLEN
);
174 if (addrptr
!= NULL
) {
175 fprintf(stderr
, "[SOCKET] %s disconnected from UART%d\n", addrptr
, port
->id
);
177 close(port
->clientSocketFd
);
178 memset(&port
->clientAddress
, 0, sizeof(port
->clientAddress
));
179 port
->isClientConnected
= false;
187 tcpReceiveBytes( port
, buffer
, recvSize
);
189 return (int)recvSize
;
192 serialPort_t
*tcpOpen(USART_TypeDef
*USARTx
, serialReceiveCallbackPtr callback
, void *rxCallbackData
, uint32_t baudRate
, portMode_t mode
, portOptions_t options
)
194 tcpPort_t
*port
= NULL
;
196 #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)
197 uint32_t id
= (uintptr_t)USARTx
;
198 if (id
<= SERIAL_PORT_COUNT
) {
199 port
= tcpReConfigure(&tcpPorts
[id
-1], id
);
208 port
->serialPort
.vTable
= tcpVTable
;
209 port
->serialPort
.rxCallback
= callback
;
210 port
->serialPort
.rxCallbackData
= rxCallbackData
;
211 port
->serialPort
.rxBufferHead
= port
->serialPort
.rxBufferTail
= 0;
212 port
->serialPort
.rxBufferSize
= TCP_BUFFER_SIZE
;
213 port
->serialPort
.rxBuffer
= port
->rxBuffer
;
214 port
->serialPort
.mode
= mode
;
215 port
->serialPort
.baudRate
= baudRate
;
216 port
->serialPort
.options
= options
;
218 int err
= pthread_create(&port
->receiveThread
, NULL
, tcpReceiveThread
, (void*)port
);
220 fprintf(stderr
, "[SOCKET] Unable to create receive thread for UART%d\n", id
);
223 return (serialPort_t
*)port
;
226 uint8_t tcpRead(serialPort_t
*instance
)
229 tcpPort_t
*port
= (tcpPort_t
*)instance
;
230 pthread_mutex_lock(&port
->receiveMutex
);
232 ch
= port
->serialPort
.rxBuffer
[port
->serialPort
.rxBufferTail
];
233 port
->serialPort
.rxBufferTail
= (port
->serialPort
.rxBufferTail
+ 1) % port
->serialPort
.rxBufferSize
;
235 pthread_mutex_unlock(&port
->receiveMutex
);
240 void tcpWritBuf(serialPort_t
*instance
, const void *data
, int count
)
242 tcpPort_t
*port
= (tcpPort_t
*)instance
;
244 if (!port
->isClientConnected
) {
248 send(port
->clientSocketFd
, data
, count
, 0);
251 int getTcpPortIndex(const serialPort_t
*instance
) {
252 for (int i
= 0; i
< SERIAL_PORT_COUNT
; i
++) {
253 if ( &(tcpPorts
[i
].serialPort
) == instance
) return i
;
258 void tcpWrite(serialPort_t
*instance
, uint8_t ch
)
260 tcpWritBuf(instance
, (void*)&ch
, 1);
262 int index
= getTcpPortIndex(instance
);
263 if ( !serialFCProxy
&& serialProxyIsConnected() && (index
== (serialUartIndex
-1)) ) {
264 serialProxyWriteData( (unsigned char *)&ch
, 1);
268 uint32_t tcpTotalRxBytesWaiting(const serialPort_t
*instance
)
270 tcpPort_t
*port
= (tcpPort_t
*)instance
;
273 pthread_mutex_lock(&port
->receiveMutex
);
275 if (port
->serialPort
.rxBufferHead
>= port
->serialPort
.rxBufferTail
) {
276 count
= port
->serialPort
.rxBufferHead
- port
->serialPort
.rxBufferTail
;
278 count
= port
->serialPort
.rxBufferSize
+ port
->serialPort
.rxBufferHead
- port
->serialPort
.rxBufferTail
;
281 pthread_mutex_unlock(&port
->receiveMutex
);
286 uint32_t tcpRXBytesFree(int portIndex
) {
287 return tcpPorts
[portIndex
].serialPort
.rxBufferSize
- tcpTotalRxBytesWaiting( &tcpPorts
[portIndex
].serialPort
);
290 uint32_t tcpTotalTxBytesFree(const serialPort_t
*instance
)
293 return TCP_MAX_PACKET_SIZE
;
296 bool isTcpTransmitBufferEmpty(const serialPort_t
*instance
)
302 bool tcpIsConnected(const serialPort_t
*instance
)
304 return ((tcpPort_t
*)instance
)->isClientConnected
;
307 void tcpSetBaudRate(serialPort_t
*instance
, uint32_t baudRate
)
314 void tcpSetMode(serialPort_t
*instance
, portMode_t mode
)
320 static const struct serialPortVTable tcpVTable
[] = {
322 .serialWrite
= tcpWrite
,
323 .serialTotalRxWaiting
= tcpTotalRxBytesWaiting
,
324 .serialTotalTxFree
= tcpTotalTxBytesFree
,
325 .serialRead
= tcpRead
,
326 .serialSetBaudRate
= tcpSetBaudRate
,
327 .isSerialTransmitBufferEmpty
= isTcpTransmitBufferEmpty
,
328 .setMode
= tcpSetMode
,
329 .isConnected
= tcpIsConnected
,
330 .writeBuf
= tcpWritBuf
,