mirror of
https://github.com/meshtastic/firmware.git
synced 2026-10-12 12:26:11 -04:00
Add native Windows build of meshtasticd (#11031)
This commit is contained in:
1 parent
4726375282
commit
a808e992a1
16 files changed
+910
-21
No files matched your search
@@ -3,13 +3,92 @@
|
||||
#include "GpsdSerial.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <cerrno>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <mutex>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
// Winsock needs explicit init, closesocket(), ioctlsocket() and WSAGetLastError().
|
||||
// SOCKET fits the header's `int` on Win64, and INVALID_SOCKET narrows to -1.
|
||||
#ifdef _WIN32
|
||||
// Done lazily to keep the dependency local to the one file that needs it.
|
||||
void initSocketsOnce()
|
||||
{
|
||||
static std::once_flag flag;
|
||||
std::call_once(flag, [] {
|
||||
WSADATA wsaData;
|
||||
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
});
|
||||
}
|
||||
|
||||
void closeSocket(int fd)
|
||||
{
|
||||
::closesocket(static_cast<SOCKET>(fd));
|
||||
}
|
||||
|
||||
void setNonBlocking(int fd)
|
||||
{
|
||||
u_long mode = 1;
|
||||
::ioctlsocket(static_cast<SOCKET>(fd), FIONBIO, &mode);
|
||||
}
|
||||
|
||||
// Winsock has no MSG_DONTWAIT, but the socket is already non-blocking so a plain
|
||||
// recv() has the same semantics.
|
||||
int recvNonBlocking(int fd, void *buf, size_t len)
|
||||
{
|
||||
return ::recv(static_cast<SOCKET>(fd), static_cast<char *>(buf), static_cast<int>(len), 0);
|
||||
}
|
||||
|
||||
int sendAll(int fd, const void *buf, size_t len)
|
||||
{
|
||||
return ::send(static_cast<SOCKET>(fd), static_cast<const char *>(buf), static_cast<int>(len), 0);
|
||||
}
|
||||
|
||||
bool lastErrorWasWouldBlock()
|
||||
{
|
||||
return WSAGetLastError() == WSAEWOULDBLOCK;
|
||||
}
|
||||
#else
|
||||
void initSocketsOnce() {}
|
||||
|
||||
void closeSocket(int fd)
|
||||
{
|
||||
::close(fd);
|
||||
}
|
||||
|
||||
void setNonBlocking(int fd)
|
||||
{
|
||||
::fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
}
|
||||
|
||||
int recvNonBlocking(int fd, void *buf, size_t len)
|
||||
{
|
||||
return static_cast<int>(::recv(fd, buf, len, MSG_DONTWAIT));
|
||||
}
|
||||
|
||||
int sendAll(int fd, const void *buf, size_t len)
|
||||
{
|
||||
return static_cast<int>(::write(fd, buf, len));
|
||||
}
|
||||
|
||||
bool lastErrorWasWouldBlock()
|
||||
{
|
||||
return errno == EAGAIN || errno == EWOULDBLOCK;
|
||||
}
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
namespace arduino
|
||||
{
|
||||
@@ -28,6 +107,8 @@ bool GpsdSerial::connectToGpsd()
|
||||
if (_host.empty())
|
||||
return false;
|
||||
|
||||
initSocketsOnce();
|
||||
|
||||
struct addrinfo hints = {}, *res = nullptr;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
@@ -41,12 +122,12 @@ bool GpsdSerial::connectToGpsd()
|
||||
// Try every address returned by getaddrinfo (e.g. ::1 before 127.0.0.1).
|
||||
int fd = -1;
|
||||
for (struct addrinfo *rp = res; rp != nullptr; rp = rp->ai_next) {
|
||||
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
fd = static_cast<int>(socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol));
|
||||
if (fd < 0)
|
||||
continue;
|
||||
if (connect(fd, rp->ai_addr, rp->ai_addrlen) == 0)
|
||||
if (connect(fd, rp->ai_addr, static_cast<int>(rp->ai_addrlen)) == 0)
|
||||
break; // connected
|
||||
::close(fd);
|
||||
closeSocket(fd);
|
||||
fd = -1;
|
||||
}
|
||||
freeaddrinfo(res);
|
||||
@@ -57,11 +138,11 @@ bool GpsdSerial::connectToGpsd()
|
||||
}
|
||||
|
||||
// Switch to non-blocking so available()/read() never stall the GPS thread.
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
setNonBlocking(fd);
|
||||
|
||||
// Ask gpsd to stream raw NMEA sentences.
|
||||
const char watchCmd[] = "?WATCH={\"enable\":true,\"nmea\":true}\n";
|
||||
::write(fd, watchCmd, sizeof(watchCmd) - 1);
|
||||
sendAll(fd, watchCmd, sizeof(watchCmd) - 1);
|
||||
|
||||
_sockfd = fd;
|
||||
_rxBuf.clear();
|
||||
@@ -80,7 +161,7 @@ void GpsdSerial::begin(unsigned long /*baud*/, uint16_t /*config*/)
|
||||
void GpsdSerial::end()
|
||||
{
|
||||
if (_sockfd >= 0) {
|
||||
::close(_sockfd);
|
||||
closeSocket(_sockfd);
|
||||
_sockfd = -1;
|
||||
}
|
||||
_rxBuf.clear();
|
||||
@@ -96,18 +177,18 @@ void GpsdSerial::fillBuffer()
|
||||
return;
|
||||
|
||||
uint8_t tmp[256];
|
||||
ssize_t n;
|
||||
while (_rxBuf.size() < RX_BUF_MAX && (n = recv(_sockfd, tmp, sizeof(tmp), MSG_DONTWAIT)) > 0) {
|
||||
int n;
|
||||
while (_rxBuf.size() < RX_BUF_MAX && (n = recvNonBlocking(_sockfd, tmp, sizeof(tmp))) > 0) {
|
||||
size_t space = RX_BUF_MAX - _rxBuf.size();
|
||||
size_t toCopy = (static_cast<size_t>(n) < space) ? static_cast<size_t>(n) : space;
|
||||
for (size_t i = 0; i < toCopy; i++)
|
||||
_rxBuf.push_back(tmp[i]);
|
||||
}
|
||||
|
||||
if (n == 0 || (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK)) {
|
||||
if (n == 0 || (n < 0 && !lastErrorWasWouldBlock())) {
|
||||
// gpsd closed the connection or a real error occurred.
|
||||
LOG_WARN("gpsdSerial: disconnected, will retry");
|
||||
::close(_sockfd);
|
||||
closeSocket(_sockfd);
|
||||
_sockfd = -1;
|
||||
_rxBuf.clear();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user