1
0
Fork 0
mirror of https://github.com/iNavFlight/inav.git synced 2025-07-13 03:19:58 +03:00

6.1.0 sitl interop (#8913)

* fix getopts 'has_arg' usage (iaw getopt_long(3))

* Rexec the SITL on reboot

* Allow hostnames, facilitate compilation on non-GNU OS (e.g. *BSD), add IPV6 [xplane.c]

* add required interop header files [simple_soap_client.c]

* add required interop header files [simple_soap_client.h]

* update serial_tcp (headers, IPv6, lookup etc)

* conditional for  pthread_attr_getschedpolicy availability

* fix error in xplane socket familiy

* remove unnecessary added headers [xplane.c]

* fix gcc 12  warning is osd.c

* update docs

* fix for older gcc without closefrom(3)

* add AI_V4MAPPED|AI_ADDRCONFIG to ai_flags (to support V4 only hosts)
This commit is contained in:
Jonathan Hudson 2023-03-26 13:39:44 +01:00 committed by GitHub
parent 4fa7e508ed
commit 064a809ad2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 343 additions and 133 deletions

View file

@ -33,6 +33,7 @@ Select "FAKE" as type for all mentioned, so that they receive the data from the
UARTs are replaced by TCP starting with port 5760 ascending. UART 1 port 5760, UART2 6761, ... UARTs are replaced by TCP starting with port 5760 ascending. UART 1 port 5760, UART2 6761, ...
By default, UART1 and UART2 are available as MSP connections. By default, UART1 and UART2 are available as MSP connections.
To connect the Configurator to SITL: Select TCP and connect to ```127.0.0.1:5760``` (if SITL is running on the same machine). To connect the Configurator to SITL: Select TCP and connect to ```127.0.0.1:5760``` (if SITL is running on the same machine).
IPv4 and IPv6 are supported, either raw addresses of hostname lookup.
The assignment and status of user UART/TCP connections is displayed on the console. The assignment and status of user UART/TCP connections is displayed on the console.
@ -78,7 +79,7 @@ For normal use, please use the SITL tab in the configurator.
The following SITL specific command line options are available: The following SITL specific command line options are available:
If SITL is started without command line options, only the Configurator can be used. If SITL is started without command line options, only a serial MSP / CLI connection can be used (e.g. Configurator or other application) can be used.
```--path``` Full path and file name to config file, if not present, eeprom.bin in the current directory is used. Example: ```C:\INAV_SITL\flying-wing.bin``` ```--path``` Full path and file name to config file, if not present, eeprom.bin in the current directory is used. Example: ```C:\INAV_SITL\flying-wing.bin```
@ -108,7 +109,7 @@ It is recommended to start the tools in the following order:
## Compile ## Compile
### Linux: ### Linux and FreeBSD:
Almost like normal, ruby, cmake and make are also required. Almost like normal, ruby, cmake and make are also required.
With cmake, the option "-DSITL=ON" must be specified. With cmake, the option "-DSITL=ON" must be specified.
@ -122,3 +123,24 @@ make
### Windows: ### Windows:
Compile under cygwin, then as in Linux. Compile under cygwin, then as in Linux.
Copy cygwin1.dll into the directory, or include cygwin's /bin/ directory in the environment variable PATH. Copy cygwin1.dll into the directory, or include cygwin's /bin/ directory in the environment variable PATH.
#### Build manager
`ninja` may also be used (parallel builds without `-j $(nproc)`):
```
cmake -GNinja -DSITL=ON ..
ninja
```
### Compiler requirements
* Modern GCC. Must be a *real* GCC, macOS faking it with clang will not work.
* Unix sockets networking. Cygwin is required on Windows (vice `winsock`).
* Pthreads
## Supported environments
* Linux on x86_64, Aarch64 (e.g. Rpi4), RISC-V (e.g. VisionFive2)
* Windows on x86_64
* FreeBSD (x86_64 at least).

View file

@ -38,3 +38,7 @@ The assignment of the "virtual receiver" is fixed:
The internal mixer (e.g. for flying wings) cannot be deactivated without further ado, therefore always select "Aircraft with tail" in INAV. The internal mixer (e.g. for flying wings) cannot be deactivated without further ado, therefore always select "Aircraft with tail" in INAV.
For the standard Aircraft preset the channelmap is: For the standard Aircraft preset the channelmap is:
```--chanmap=M01-01,S01-03,S03-02,S04-04``` ```--chanmap=M01-01,S01-03,S03-02,S04-04```
## Other applications
[fl2sitl](https://github.com/stronnag/bbl2kml/wiki/fl2sitl) is an open source application to replay an INAV Blackbox log through the INAV SITL via `blackbox_decode`. The output may be visualised in any MSP capable application, such as the INAV Configurator or [mwp](https://github.com/stronnag/mwptools). fl2sitl uses the X-plane protocol.

View file

@ -33,6 +33,10 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <fcntl.h> #include <fcntl.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>
#include "common/utils.h" #include "common/utils.h"
@ -43,6 +47,68 @@ static const struct serialPortVTable tcpVTable[];
static tcpPort_t tcpPorts[SERIAL_PORT_COUNT]; static tcpPort_t tcpPorts[SERIAL_PORT_COUNT];
static bool tcpThreadRunning = false; static bool tcpThreadRunning = false;
static int lookup_address (char *name, int port, int type, struct sockaddr *addr, socklen_t* len )
{
struct addrinfo *servinfo, *p;
struct addrinfo hints = {.ai_family = AF_UNSPEC, .ai_socktype = type, .ai_flags = AI_V4MAPPED|AI_ADDRCONFIG};
if (name == NULL) {
hints.ai_flags |= AI_PASSIVE;
}
/*
This nonsense is to uniformly deliver the same sa_family regardless of whether
name is NULL or non-NULL
Otherwise, at least on Linux, we get
- V6,V4 for the non-null case and
- V4,V6 for the null case, regardless of gai.conf
Which may confuse consumers.
FreeBSD and Windows behave consistently, giving V6 for Ipv6 enabled stacks in all cases
unless a quad dotted address is specificied
*/
struct addrinfo *p4 = NULL;
struct addrinfo *p6 = NULL;
int result;
char aport[16];
snprintf(aport, sizeof(aport), "%d", port);
if ((result = getaddrinfo(name, aport, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(result));
return result;
} else {
int j = 0;
for(p = servinfo; p != NULL; p = p->ai_next) {
if(p->ai_family == AF_INET6)
p6 = p;
else if(p->ai_family == AF_INET)
p4 = p;
j++;
}
if (p6 != NULL)
p = p6;
else if (p4 != NULL)
p = p4;
else
return -1;
memcpy(addr, p->ai_addr, p->ai_addrlen);
*len = p->ai_addrlen;
freeaddrinfo(servinfo);
}
return 0;
}
static char *tcpGetAddressString(struct sockaddr *addr)
{
static char straddr[INET6_ADDRSTRLEN];
void *ipaddr;
if (addr->sa_family == AF_INET6) {
struct sockaddr_in6 * ip = (struct sockaddr_in6*)addr;
ipaddr = &ip->sin6_addr;
} else {
struct sockaddr_in * ip = (struct sockaddr_in*)addr;
ipaddr = &ip->sin_addr;
}
const char *res = inet_ntop(addr->sa_family, ipaddr, straddr, sizeof straddr);
return (char *)res;
}
static void *tcpReceiveThread(void* arg) static void *tcpReceiveThread(void* arg)
{ {
tcpPort_t *port = (tcpPort_t*)arg; tcpPort_t *port = (tcpPort_t*)arg;
@ -58,6 +124,7 @@ static void *tcpReceiveThread(void* arg)
static tcpPort_t *tcpReConfigure(tcpPort_t *port, uint32_t id) static tcpPort_t *tcpReConfigure(tcpPort_t *port, uint32_t id)
{ {
socklen_t sockaddrlen;
if (port->isInitalized){ if (port->isInitalized){
return port; return port;
} }
@ -66,14 +133,29 @@ static tcpPort_t *tcpReConfigure(tcpPort_t *port, uint32_t id)
return NULL; return NULL;
} }
port->socketFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); uint16_t tcpPort = BASE_IP_ADDRESS + id - 1;
if (lookup_address(NULL, tcpPort, SOCK_STREAM, (struct sockaddr*)&port->sockAddress, &sockaddrlen) != 0) {
return NULL;
}
port->socketFd = socket(((struct sockaddr*)&port->sockAddress)->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (port->socketFd < 0) { if (port->socketFd < 0) {
fprintf(stderr, "[SOCKET] Unable to create tcp socket\n"); fprintf(stderr, "[SOCKET] Unable to create tcp socket\n");
return NULL; return NULL;
} }
int err = 0;
#ifdef __CYGWIN__
// Sadly necesary to enforce dual-stack behaviour on Windows networking ,,,
if (((struct sockaddr*)&port->sockAddress)->sa_family == AF_INET6) {
int v6only=0;
err = setsockopt(port->socketFd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only));
if (err != 0) {
fprintf(stderr,"[SOCKET] setting V6ONLY=false: %s\n", strerror(errno));
}
}
#endif
int one = 1; int one = 1;
int err = 0;
err = setsockopt(port->socketFd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); err = setsockopt(port->socketFd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
err = fcntl(port->socketFd, F_SETFL, fcntl(port->socketFd, F_GETFL, 0) | O_NONBLOCK); err = fcntl(port->socketFd, F_SETFL, fcntl(port->socketFd, F_GETFL, 0) | O_NONBLOCK);
@ -82,14 +164,10 @@ static tcpPort_t *tcpReConfigure(tcpPort_t *port, uint32_t id)
return NULL; return NULL;
} }
uint16_t tcpPort = BASE_IP_ADDRESS + id - 1;
port->sockAddress.sin_family = AF_INET;
port->sockAddress.sin_port = htons(tcpPort);
port->sockAddress.sin_addr.s_addr = INADDR_ANY;
port->isClientConnected = false; port->isClientConnected = false;
port->id = id; port->id = id;
if (bind(port->socketFd, (struct sockaddr*)&port->sockAddress, sizeof(port->sockAddress)) < 0) { if (bind(port->socketFd, (struct sockaddr*)&port->sockAddress, sockaddrlen) < 0) {
fprintf(stderr, "[SOCKET] Unable to bind socket\n"); fprintf(stderr, "[SOCKET] Unable to bind socket\n");
return NULL; return NULL;
} }
@ -99,16 +177,12 @@ static tcpPort_t *tcpReConfigure(tcpPort_t *port, uint32_t id)
return NULL; return NULL;
} }
fprintf(stderr, "[SOCKET] Bind TCP port %d to UART%d\n", tcpPort, id); fprintf(stderr, "[SOCKET] Bind TCP %s port %d to UART%d\n",
tcpGetAddressString((struct sockaddr*)&port->sockAddress), tcpPort, id);
return port; return port;
} }
static char *tcpGetAddressString(struct sockaddr *addr)
{
return inet_ntoa(((struct sockaddr_in *)addr)->sin_addr);
}
int tcpReceive(tcpPort_t *port) int tcpReceive(tcpPort_t *port)
{ {
if (!port->isClientConnected) { if (!port->isClientConnected) {
@ -123,14 +197,14 @@ int tcpReceive(tcpPort_t *port)
return -1; return -1;
} }
socklen_t addrLen = sizeof(port->sockAddress); socklen_t addrLen = sizeof(struct sockaddr_storage);
port->clientSocketFd = accept(port->socketFd, &port->clientAddress, &addrLen); port->clientSocketFd = accept(port->socketFd,(struct sockaddr*)&port->clientAddress, &addrLen);
if (port->clientSocketFd < 1) { if (port->clientSocketFd < 1) {
fprintf(stderr, "[SOCKET] Can't accept connection.\n"); fprintf(stderr, "[SOCKET] Can't accept connection.\n");
return -1; return -1;
} }
fprintf(stderr, "[SOCKET] %s connected to UART%d\n", tcpGetAddressString(&port->clientAddress), port->id); fprintf(stderr, "[SOCKET] %s connected to UART%d\n", tcpGetAddressString((struct sockaddr *)&port->clientAddress), port->id);
port->isClientConnected = true; port->isClientConnected = true;
} }
@ -140,7 +214,7 @@ int tcpReceive(tcpPort_t *port)
// Disconnect // Disconnect
if (port->isClientConnected && recvSize == 0) if (port->isClientConnected && recvSize == 0)
{ {
fprintf(stderr, "[SOCKET] %s disconnected from UART%d\n", tcpGetAddressString(&port->clientAddress), port->id); fprintf(stderr, "[SOCKET] %s disconnected from UART%d\n", tcpGetAddressString((struct sockaddr *)&port->clientAddress), port->id);
close(port->clientSocketFd); close(port->clientSocketFd);
memset(&port->clientAddress, 0, sizeof(port->clientAddress)); memset(&port->clientAddress, 0, sizeof(port->clientAddress));
port->isClientConnected = false; port->isClientConnected = false;

View file

@ -22,6 +22,9 @@
#include <pthread.h> #include <pthread.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define BASE_IP_ADDRESS 5760 #define BASE_IP_ADDRESS 5760
#define TCP_BUFFER_SIZE 2048 #define TCP_BUFFER_SIZE 2048
@ -39,8 +42,8 @@ typedef struct
pthread_t receiveThread; pthread_t receiveThread;
int socketFd; int socketFd;
int clientSocketFd; int clientSocketFd;
struct sockaddr_in sockAddress; struct sockaddr_storage sockAddress;
struct sockaddr clientAddress; struct sockaddr_storage clientAddress;
bool isClientConnected; bool isClientConnected;
} tcpPort_t; } tcpPort_t;

View file

@ -444,7 +444,7 @@ static void osdFormatWindSpeedStr(char *buff, int32_t ws, bool isValid)
*/ */
void osdSimpleAltitudeSymbol(char *buff, int32_t alt) { void osdSimpleAltitudeSymbol(char *buff, int32_t alt) {
int32_t convertedAltutude; int32_t convertedAltutude = 0;
char suffix = '\0'; char suffix = '\0';
switch ((osd_unit_e)osdConfig()->units) { switch ((osd_unit_e)osdConfig()->units) {

View file

@ -31,6 +31,8 @@
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <sys/socket.h> #include <sys/socket.h>
# include <netinet/in.h>
# include <netdb.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/select.h> #include <sys/select.h>
@ -165,4 +167,3 @@ char* soapClientReceive(soap_client_t *client)
recBuffer[size] = '\0'; recBuffer[size] = '\0';
return strdup(body); return strdup(body);
} }

View file

@ -23,6 +23,8 @@
*/ */
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#define SOAP_REC_BUF_SIZE 256 * 1024 #define SOAP_REC_BUF_SIZE 256 * 1024

View file

@ -29,6 +29,9 @@
#include <stdarg.h> #include <stdarg.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <pthread.h> #include <pthread.h>
#include <errno.h> #include <errno.h>
#include <math.h> #include <math.h>
@ -63,7 +66,8 @@
static uint8_t pwmMapping[XP_MAX_PWM_OUTS]; static uint8_t pwmMapping[XP_MAX_PWM_OUTS];
static uint8_t mappingCount; static uint8_t mappingCount;
static struct sockaddr_in serverAddr; static struct sockaddr_storage serverAddr;
static socklen_t serverAddrLen;
static int sockFd; static int sockFd;
static pthread_t listenThread; static pthread_t listenThread;
static bool initalized = false; static bool initalized = false;
@ -152,18 +156,18 @@ static void registerDref(dref_t id, char* dref, uint32_t freq)
memcpy(buf + 9, &id, 4); memcpy(buf + 9, &id, 4);
memcpy(buf + 13, dref, strlen(dref) + 1); memcpy(buf + 13, dref, strlen(dref) + 1);
sendto(sockFd, (void*)buf, sizeof(buf), 0, (struct sockaddr*)&serverAddr, sizeof(serverAddr)); sendto(sockFd, (void*)buf, sizeof(buf), 0, (struct sockaddr*)&serverAddr, serverAddrLen);
} }
static void sendDref(char* dref, float value) static void sendDref(char* dref, float value)
{ {
char buf[509]; char buf[509];
strcpy(buf, "DREF"); strcpy(buf, "DREF");
memcpy(buf + 5, &value, 4); memcpy(buf + 5, &value, 4);
memset(buf + 9, ' ', sizeof(buf) - 9); memset(buf + 9, ' ', sizeof(buf) - 9);
strcpy(buf + 9, dref); strcpy(buf + 9, dref);
sendto(sockFd, (void*)buf, sizeof(buf), 0, (struct sockaddr*)&serverAddr, sizeof(serverAddr)); sendto(sockFd, (void*)buf, sizeof(buf), 0, (struct sockaddr*)&serverAddr, serverAddrLen);
} }
static void* listenWorker(void* arg) static void* listenWorker(void* arg)
@ -171,7 +175,7 @@ static void* listenWorker(void* arg)
UNUSED(arg); UNUSED(arg);
uint8_t buf[1024]; uint8_t buf[1024];
struct sockaddr remoteAddr; struct sockaddr_storage remoteAddr;
socklen_t slen = sizeof(remoteAddr); socklen_t slen = sizeof(remoteAddr);
int recvLen; int recvLen;
@ -435,22 +439,113 @@ static void* listenWorker(void* arg)
return NULL; return NULL;
} }
static int lookup_address (char *name, int port, int type, struct sockaddr *addr, socklen_t* len )
{
struct addrinfo *servinfo, *p;
struct addrinfo hints = {.ai_family = AF_UNSPEC, .ai_socktype = type, .ai_flags = AI_V4MAPPED|AI_ADDRCONFIG};
if (name == NULL) {
hints.ai_flags |= AI_PASSIVE;
}
/*
This nonsense is to uniformly deliver the same sa_family regardless of whether
name is NULL or non-NULL ** ON LINUX **
Otherwise, at least on Linux, we get
- V6,V4 for the non-null case and
- V4,V6 for the null case, regardless of gai.conf
Which may confuse consumers
FreeBSD and Windows behave consistently, giving V6 for Ipv6 enabled stacks
unless a quad dotted address is specified (or a name resolveds to V4,
or system policy enforces IPv4 over V6
*/
struct addrinfo *p4 = NULL;
struct addrinfo *p6 = NULL;
int result;
char aport[16];
snprintf(aport, sizeof(aport), "%d", port);
if ((result = getaddrinfo(name, aport, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(result));
return result;
} else {
int j = 0;
for(p = servinfo; p != NULL; p = p->ai_next) {
if(p->ai_family == AF_INET6)
p6 = p;
else if(p->ai_family == AF_INET)
p4 = p;
j++;
}
if (p6 != NULL)
p = p6;
else if (p4 != NULL)
p = p4;
else
return -1;
memcpy(addr, p->ai_addr, p->ai_addrlen);
*len = p->ai_addrlen;
freeaddrinfo(servinfo);
}
return 0;
}
static char * pretty_print_address(struct sockaddr* p)
{
char straddr[INET6_ADDRSTRLEN];
void *addr;
uint16_t port;
if (p->sa_family == AF_INET6) {
struct sockaddr_in6 * ip = (struct sockaddr_in6*)p;
addr = &ip->sin6_addr;
port = ntohs(ip->sin6_port);
} else {
struct sockaddr_in * ip = (struct sockaddr_in*)p;
port = ntohs(ip->sin_port);
addr = &ip->sin_addr;
}
const char *res = inet_ntop(p->sa_family, addr, straddr, sizeof straddr);
if (res != NULL) {
int nb = strlen(res)+16;
char *buf = calloc(nb,1);
char *ptr = buf;
if (p->sa_family == AF_INET6) {
*ptr++='[';
}
ptr = stpcpy(ptr, res);
if (p->sa_family == AF_INET6) {
*ptr++=']';
}
sprintf(ptr, ":%d", port);
return buf;
}
return NULL;
}
bool simXPlaneInit(char* ip, int port, uint8_t* mapping, uint8_t mapCount, bool imu) bool simXPlaneInit(char* ip, int port, uint8_t* mapping, uint8_t mapCount, bool imu)
{ {
memcpy(pwmMapping, mapping, mapCount); memcpy(pwmMapping, mapping, mapCount);
mappingCount = mapCount; mappingCount = mapCount;
useImu = imu; useImu = imu;
sockFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (port == 0) {
port = XP_PORT; // use default port
}
if (sockFd < 0) { if(lookup_address(ip, port, SOCK_DGRAM, (struct sockaddr*)&serverAddr, &serverAddrLen) != 0) {
return false; return false;
} }
struct sockaddr_in addr; sockFd = socket(((struct sockaddr*)&serverAddr)->sa_family, SOCK_DGRAM, IPPROTO_UDP);
addr.sin_family = AF_INET; if (sockFd < 0) {
addr.sin_addr.s_addr = htonl(INADDR_ANY); return false;
addr.sin_port = htons(0); } else {
char *nptr = pretty_print_address((struct sockaddr *)&serverAddr);
if (nptr != NULL) {
fprintf(stderr, "[SOCKET] xplane address = %s, fd=%d\n", nptr, sockFd);
free(nptr);
}
}
struct timeval tv; struct timeval tv;
tv.tv_sec = 1; tv.tv_sec = 1;
@ -463,12 +558,6 @@ bool simXPlaneInit(char* ip, int port, uint8_t* mapping, uint8_t mapCount, bool
return false; return false;
} }
bind(sockFd, (struct sockaddr *) &addr, sizeof(addr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr(ip);
serverAddr.sin_port = htons(port);
if (pthread_create(&listenThread, NULL, listenWorker, NULL) < 0) { if (pthread_create(&listenThread, NULL, listenWorker, NULL) < 0) {
return false; return false;
} }

View file

@ -66,20 +66,23 @@ static bool useImu = false;
static char *simIp = NULL; static char *simIp = NULL;
static int simPort = 0; static int simPort = 0;
static char **c_argv;
void systemInit(void) { void systemInit(void) {
fprintf(stderr, "INAV %d.%d.%d SITL\n", FC_VERSION_MAJOR, FC_VERSION_MINOR, FC_VERSION_PATCH_LEVEL); fprintf(stderr, "INAV %d.%d.%d SITL\n", FC_VERSION_MAJOR, FC_VERSION_MINOR, FC_VERSION_PATCH_LEVEL);
clock_gettime(CLOCK_MONOTONIC, &start_time); clock_gettime(CLOCK_MONOTONIC, &start_time);
fprintf(stderr, "[SYSTEM] Init...\n"); fprintf(stderr, "[SYSTEM] Init...\n");
#if !defined(__FreeBSD__) // maybe also || !defined(__APPLE__)
pthread_attr_t thAttr; pthread_attr_t thAttr;
int policy = 0; int policy = 0;
pthread_attr_init(&thAttr); pthread_attr_init(&thAttr);
pthread_attr_getschedpolicy(&thAttr, &policy); pthread_attr_getschedpolicy(&thAttr, &policy);
pthread_setschedprio(pthread_self(), sched_get_priority_min(policy)); pthread_setschedprio(pthread_self(), sched_get_priority_min(policy));
pthread_attr_destroy(&thAttr); pthread_attr_destroy(&thAttr);
#endif
if (pthread_mutex_init(&mainLoopLock, NULL) != 0) { if (pthread_mutex_init(&mainLoopLock, NULL) != 0) {
fprintf(stderr, "[SYSTEM] Unable to create mainLoop lock.\n"); fprintf(stderr, "[SYSTEM] Unable to create mainLoop lock.\n");
@ -174,16 +177,21 @@ void printCmdLineOptions(void)
void parseArguments(int argc, char *argv[]) void parseArguments(int argc, char *argv[])
{ {
// Stash these so we can rexec on reboot, just like a FC does
c_argv = calloc(argc+1, sizeof(char *));
for (int i = 0; i < argc; i++) {
c_argv[i] = strdup(argv[i]);
}
int c; int c;
while(true) { while(true) {
static struct option longOpt[] = { static struct option longOpt[] = {
{"sim", optional_argument, 0, 's'}, {"sim", required_argument, 0, 's'},
{"useimu", optional_argument, 0, 'u'}, {"useimu", no_argument, 0, 'u'},
{"chanmap", optional_argument, 0, 'c'}, {"chanmap", required_argument, 0, 'c'},
{"simip", optional_argument, 0, 'i'}, {"simip", required_argument, 0, 'i'},
{"simport", optional_argument, 0, 'p'}, {"simport", required_argument, 0, 'p'},
{"help", optional_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"path", optional_argument, 0, 'e'}, {"path", required_argument, 0, 'e'},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
@ -276,7 +284,14 @@ void delay(timeMs_t ms)
void systemReset(void) void systemReset(void)
{ {
fprintf(stderr, "[SYSTEM] Reset\n"); fprintf(stderr, "[SYSTEM] Reset\n");
exit(0); #if defined(__CYGWIN__) || defined(__APPLE__) || GCC_MAJOR < 12
for(int j = 3; j < 1024; j++) {
close(j);
}
#else
closefrom(3);
#endif
execvp(c_argv[0], c_argv); // restart
} }
void systemResetToBootloader(void) void systemResetToBootloader(void)