Skip to content

Commit

Permalink
Release: 3.4.3 (#14)
Browse files Browse the repository at this point in the history
* release: v3.4.3
  • Loading branch information
ewasjon authored Feb 8, 2024
1 parent fa8d2ec commit 854434d
Show file tree
Hide file tree
Showing 27 changed files with 323 additions and 89 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## [3.4.3]
- Added option to export NMEA sentences to a unix socket or a TCP connection. See `--nmea-export-*` command-line arguments. This requires the use of the NMEA receiver.
- Fixed a bug where in cases of TCP connection failure, the addrinfo struct was not freed.

## [3.4.2]
- Fixed a bug where GAD messages had TF009 set to 0. It will now be set to time specified in the STEC/Gridded IE.
- Fixed a bug where parsing bitfields in UBX-NAV-PVT would not be incorrect.
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ find_package(OpenSSL REQUIRED)
endif (USE_OPENSSL)

add_definitions(-D_POSIX_C_SOURCE=200809L)
add_definitions(-DCLIENT_VERSION="3.4.2")
add_definitions(-DCLIENT_VERSION="3.4.3")

if(${ASN_DEBUG})
add_definitions(-DASN_EMIT_DEBUG=1)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SUPL 3GPP LPP client

![version](https://img.shields.io/badge/version-3.4.2-green)
![version](https://img.shields.io/badge/version-3.4.3-green)
![license](https://img.shields.io/badge/license-MXM-blue)

This project is a set of libraries, examples and tools to facilitate the development of 3GPP LPP clients.
Expand Down
7 changes: 6 additions & 1 deletion examples/lpp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ There are a few required arguments:
```
./example-lpp COMMAND {OPTIONS}
3GPP LPP Example (3.4.0) - This sample code is a simple client that asks for
3GPP LPP Example (3.4.3) - This sample code is a simple client that asks for
assistance data from a location server. It can handle OSR, SSR, and AGNSS
requests. The assistance data can converted to RTCM or SPARTN before being
sent to a GNSS receiver or other interface. The client also supports to 3GPP
Expand Down Expand Up @@ -96,6 +96,11 @@ There are a few required arguments:
Parity Bits
One of: none, odd, even
Default: none
--nmea-export-un=[unix socket] Export NMEA to unix socket
--nmea-export-tcp=[ip] Export NMEA to TCP
--nmea-export-tcp-port=[port] Export NMEA to TCP Port
Other Receiver Options:
--print-receiver-messages, --prm Print Receiver Messages
Output:
File:
--file=[file_path] Path
Expand Down
35 changes: 34 additions & 1 deletion examples/lpp/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,22 @@ args::ValueFlag<std::string> nmea_serial_parity_bits{nmea_receiver_group,
"Parity Bits",
{"nmea-serial-parity"},
args::Options::Single};
// export nmea to unix socket
args::ValueFlag<std::string> nmea_export_un{nmea_receiver_group,
"unix socket",
"Export NMEA to unix socket",
{"nmea-export-un"},
args::Options::Single};
args::ValueFlag<std::string> nmea_export_tcp{nmea_receiver_group,
"ip",
"Export NMEA to TCP",
{"nmea-export-tcp"},
args::Options::Single};
args::ValueFlag<int> nmea_export_tcp_port{nmea_receiver_group,
"port",
"Export NMEA to TCP Port",
{"nmea-export-tcp-port"},
args::Options::Single};

//
// Output
Expand Down Expand Up @@ -691,10 +707,27 @@ static NmeaOptions nmea_parse_options() {
}
}

std::vector<std::unique_ptr<interface::Interface>> nmea_export_interfaces;
if (nmea_export_un) {
auto interface = interface::Interface::unix_socket_stream(nmea_export_un.Get(), true);
nmea_export_interfaces.emplace_back(interface);
}

if (nmea_export_tcp) {
if (!nmea_export_tcp_port) {
throw args::RequiredError("nmea-export-tcp-port");
}

auto interface =
interface::Interface::tcp(nmea_export_tcp.Get(), nmea_export_tcp_port.Get(), true);
nmea_export_interfaces.emplace_back(interface);
}

auto interface = interface::Interface::serial(nmea_serial_device.Get(), baud_rate,
data_bits, stop_bits, parity_bit);
auto print_messages = print_receiver_options_parse();
return NmeaOptions{std::unique_ptr<Interface>(interface), print_messages};
return NmeaOptions{std::unique_ptr<Interface>(interface), print_messages,
std::move(nmea_export_interfaces)};
} else {
return NmeaOptions{};
}
Expand Down
2 changes: 2 additions & 0 deletions examples/lpp/options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ struct NmeaOptions {
std::unique_ptr<interface::Interface> interface;
/// Whether to print messages.
bool print_messages;
/// Export messages to other interfaces.
std::vector<std::unique_ptr<interface::Interface>> export_interfaces;
};

/// Location information options.
Expand Down
11 changes: 10 additions & 1 deletion examples/lpp/osr_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,17 @@ void execute(Options options, osr_example::Format format, osr_example::MsmType m
nmea_options.interface->open();
nmea_options.interface->print_info();

if (!nmea_options.export_interfaces.empty()) {
printf("[nmea-export]\n");
for (auto& interface : nmea_options.export_interfaces) {
interface->open();
interface->print_info();
}
}

gNmeaReceiver = std::unique_ptr<NReceiver>(
new NReceiver(std::move(nmea_options.interface), nmea_options.print_messages));
new NReceiver(std::move(nmea_options.interface), nmea_options.print_messages,
std::move(nmea_options.export_interfaces)));
gNmeaReceiver->start();
}

Expand Down
11 changes: 10 additions & 1 deletion examples/lpp/ssr_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,17 @@ void execute(Options options, ssr_example::Format format, int ura_override,
nmea_options.interface->open();
nmea_options.interface->print_info();

if (!nmea_options.export_interfaces.empty()) {
printf("[nmea-export]\n");
for (auto& interface : nmea_options.export_interfaces) {
interface->open();
interface->print_info();
}
}

gNmeaReceiver = std::unique_ptr<NReceiver>(
new NReceiver(std::move(nmea_options.interface), nmea_options.print_messages));
new NReceiver(std::move(nmea_options.interface), nmea_options.print_messages,
std::move(nmea_options.export_interfaces)));
gNmeaReceiver->start();
}

Expand Down
1 change: 1 addition & 0 deletions interface/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ add_library(dependency_interface STATIC
"reconnectable_socket.cpp"
"tcp.cpp"
"udp.cpp"
"unix_socket.cpp"
)
add_library(dependency::interface ALIAS dependency_interface)

Expand Down
2 changes: 1 addition & 1 deletion interface/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ void FileInterface::open() {
}

if (fd < 0) {
throw std::runtime_error("Failed to open file");
throw std::runtime_error("Failed to open file: " + mFilePath);
}

mFileDescriptor = FileDescriptor(fd);
Expand Down
5 changes: 5 additions & 0 deletions interface/include/interface/interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ class Interface {

/// Create a stdin interface.
static Interface* stdin();

/// Create a unix socket interface. The socket type is SOCK_STREAM.
/// @param socket_path The path to the unix socket.
/// @param reconnect Whether to reconnect if the connection is lost.
static Interface* unix_socket_stream(std::string socket_path, bool reconnect);
};

} // namespace interface
2 changes: 2 additions & 0 deletions interface/reconnectable_socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ void ReconnectableSocket::print_info() IF_NOEXCEPT {
switch (mAddress.family()) {
case AF_INET: printf(" family: AF_INET\n"); break;
case AF_INET6: printf(" family: AF_INET6\n"); break;
case AF_UNIX: printf(" family: AF_UNIX\n"); break;
default: printf(" family: AF_??? (%d)\n", mAddress.family()); break;
}
switch (mAddress.type()) {
Expand All @@ -106,6 +107,7 @@ void ReconnectableSocket::print_info() IF_NOEXCEPT {
switch (mAddress.protocol()) {
case IPPROTO_TCP: printf(" protocol: IPPROTO_TCP\n"); break;
case IPPROTO_UDP: printf(" protocol: IPPROTO_UDP\n"); break;
case IPPROTO_IP: printf(" protocol: IPPROTO_IP\n"); break;
default: printf(" protocol: IPPROTO_??? (%d)\n", mAddress.protocol()); break;
}
printf(" address: %s\n", mAddress.to_string().c_str());
Expand Down
17 changes: 17 additions & 0 deletions interface/socket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <stdexcept>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include "types.hpp"

namespace interface {
Expand All @@ -18,6 +19,7 @@ class NetworkAddress {
switch (addr->ai_family) {
case AF_INET: break;
case AF_INET6: break;
case AF_UNIX: break;
default: throw std::runtime_error("Unsupported network address");
}
NetworkAddress rtrn{};
Expand All @@ -31,12 +33,25 @@ class NetworkAddress {
return rtrn;
}

static NetworkAddress unix_socket_stream(const std::string& path) {
if (path.size() >= sizeof(sockaddr_un::sun_path)) throw std::runtime_error("Path too long");

NetworkAddress rtrn{};
rtrn.mFamily = AF_UNIX;
rtrn.mType = SOCK_STREAM;
rtrn.mProtocol = 0;
rtrn.mAddr.un.sun_family = AF_UNIX;
strncpy(rtrn.mAddr.un.sun_path, path.c_str(), sizeof(rtrn.mAddr.un.sun_path));
return rtrn;
}

IF_NODISCARD struct sockaddr* ptr() IF_NOEXCEPT { return &mAddr.base; }

IF_NODISCARD std::size_t length() const IF_NOEXCEPT {
switch (mFamily) {
case AF_INET: return sizeof(mAddr.in4);
case AF_INET6: return sizeof(mAddr.in6);
case AF_UNIX: return sizeof(mAddr.un);
default: return 0; /* fail safe in later call */
}
}
Expand All @@ -54,6 +69,7 @@ class NetworkAddress {
case AF_INET6:
inet_ntop(mFamily, &mAddr.in6.sin6_addr, buffer, INET6_ADDRSTRLEN);
return std::string(buffer) + ":" + std::to_string(ntohs(mAddr.in6.sin6_port));
case AF_UNIX: return std::string(mAddr.un.sun_path);
default: return "Unsupported network address";
}
}
Expand All @@ -67,6 +83,7 @@ class NetworkAddress {
sockaddr base;
sockaddr_in in4;
sockaddr_in6 in6;
sockaddr_un un;
} mAddr;
};

Expand Down
2 changes: 2 additions & 0 deletions interface/tcp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ void TcpInterface::open() {
auto address = NetworkAddress::from_addrinfo(rp);
mSocket = ReconnectableSocket::connect(address, mReconnect);
if (mSocket.is_open()) {
freeaddrinfo(result);
return;
}
}

freeaddrinfo(result);
throw std::runtime_error("Failed to connect to host");
}

Expand Down
79 changes: 79 additions & 0 deletions interface/unix_socket.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "unix_socket.hpp"
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdexcept>
#include <sys/socket.h>
#include <unistd.h>

namespace interface {

UnixSocketInterface::UnixSocketInterface(std::string path, bool reconnect) IF_NOEXCEPT
: mPath(std::move(path)),
mReconnect(reconnect) {}

UnixSocketInterface::~UnixSocketInterface() IF_NOEXCEPT {
close();
}

void UnixSocketInterface::open() {
if (mSocket.is_open()) {
return;
}

auto address = NetworkAddress::unix_socket_stream(mPath);
mSocket = ReconnectableSocket::connect(address, mReconnect);
if (!mSocket.is_open()) {
throw std::runtime_error("Failed to connect to unix socket: '" + mPath + "'");
}
}

void UnixSocketInterface::close() {
mSocket.close();
}

size_t UnixSocketInterface::read(void* data, const size_t size) {
return mSocket.read(data, size);
}

size_t UnixSocketInterface::write(const void* data, const size_t size) {
return mSocket.write(data, size);
}

bool UnixSocketInterface::can_read() IF_NOEXCEPT {
return mSocket.can_read();
}

bool UnixSocketInterface::can_write() IF_NOEXCEPT {
return mSocket.can_write();
}

void UnixSocketInterface::wait_for_read() IF_NOEXCEPT {
mSocket.wait_for_read();
}

void UnixSocketInterface::wait_for_write() IF_NOEXCEPT {
mSocket.wait_for_write();
}

bool UnixSocketInterface::is_open() IF_NOEXCEPT {
return mSocket.is_open();
}

void UnixSocketInterface::print_info() IF_NOEXCEPT {
printf("[interface]\n");
printf(" type: unix-socket (stream)\n");
printf(" path: %s\n", mPath.c_str());
printf(" reconnect: %s\n", mReconnect ? "true" : "false");
mSocket.print_info();
}

//
//
//

Interface* Interface::unix_socket_stream(std::string path, bool reconnect) {
return new UnixSocketInterface(std::move(path), reconnect);
}

} // namespace interface
35 changes: 35 additions & 0 deletions interface/unix_socket.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once
#include <cstddef>
#include <string>
#include "interface.hpp"
#include "reconnectable_socket.hpp"

namespace interface {

class UnixSocketInterface final : public Interface {
public:
explicit UnixSocketInterface(std::string path, bool reconnect) IF_NOEXCEPT;
~UnixSocketInterface() IF_NOEXCEPT override;

void open() override;
void close() override;

size_t read(void* data, size_t length) override;
size_t write(const void* data, size_t length) override;

IF_NODISCARD bool can_read() IF_NOEXCEPT override;
IF_NODISCARD bool can_write() IF_NOEXCEPT override;

void wait_for_read() IF_NOEXCEPT override;
void wait_for_write() IF_NOEXCEPT override;

IF_NODISCARD bool is_open() IF_NOEXCEPT override;
void print_info() IF_NOEXCEPT override;

private:
std::string mPath;
bool mReconnect;
ReconnectableSocket mSocket;
};

} // namespace interface
Loading

0 comments on commit 854434d

Please sign in to comment.