Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions hal/inc/usb_hal_private.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2026 Particle Industries, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/

// This header defines private USART HAL APIs that may be implemented only on certain platforms
// and are not intended to be exported.
#pragma once

#include "usb_hal.h"
#include <FreeRTOS.h>
#include <event_groups.h>
#include "system_tick_hal.h"

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

int hal_usb_cdc_pvt_get_event_group_handle(EventGroupHandle_t* handle);
int hal_usb_cdc_pvt_wait_event(uint32_t events, system_tick_t timeout);

#ifdef __cplusplus
}
#endif // __cplusplus
9 changes: 5 additions & 4 deletions hal/network/api/ifapi_driver_specific.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ typedef enum if_req_driver_specific_type {
IF_REQ_DRIVER_SPECIFIC_WIZNET_PIN_REMAP = 1,
// FIXME: for compatibility
IF_WIZNET_DRIVER_SPECIFIC_PIN_REMAP = IF_REQ_DRIVER_SPECIFIC_WIZNET_PIN_REMAP,
IF_REQ_DRIVER_SPECIFIC_PPP_SERVER_UART_SETTINGS = 2
IF_REQ_DRIVER_SPECIFIC_PPP_SERVER_SERIAL_SETTINGS = 2
} if_req_driver_specific_type;

typedef struct if_wiznet_pin_remap {
Expand All @@ -42,14 +42,15 @@ typedef struct if_wiznet_pin_remap {
uint16_t int_pin;
} if_wiznet_pin_remap;

typedef struct if_req_ppp_server_uart_settings {
typedef struct if_req_ppp_server_serial_settings {
if_req_driver_specific base;
uint8_t serial;
uint8_t reserved[3];
uint8_t usbserial;
uint8_t reserved[2];
uint32_t baud;
uint32_t config;
uint32_t reserved1;
} if_req_ppp_server_uart_settings;
} if_req_ppp_server_serial_settings;

#ifdef __cplusplus
}
Expand Down
113 changes: 73 additions & 40 deletions hal/network/lwip/pppservernetif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,11 @@ PppServerNetif::PppServerNetif()
client_.setNotifyCallback(pppEventHandlerCb, this);
client_.start();

// Defaults
// Defaults, assume USART
settings_.serial = HAL_PLATFORM_PPP_SERVER_USART;
settings_.baud = HAL_PLATFORM_PPP_SERVER_USART_BAUDRATE;
settings_.config = HAL_PLATFORM_PPP_SERVER_USART_FLAGS;
settings_.usbserial = 0x00;
}

PppServerNetif::~PppServerNetif() {
Expand All @@ -165,11 +166,17 @@ int PppServerNetif::start() {
return SYSTEM_ERROR_INVALID_STATE;
}

LOG(TRACE, "Starting PppServerNetif interface");
LOG(TRACE, "Starting PppServerNetif interface on %s", settings_.serial ? "USART" : "USB");

auto serial = std::make_unique<SerialStream>((hal_usart_interface_t)settings_.serial, settings_.baud, settings_.config, DEFAULT_SERIAL_BUFFER_SIZE, DEFAULT_SERIAL_BUFFER_SIZE);
SPARK_ASSERT(serial);
serial_ = std::move(serial);
if (settings_.serial) {
auto serial = std::make_unique<SerialStream>((hal_usart_interface_t)settings_.serial, settings_.baud, settings_.config, DEFAULT_SERIAL_BUFFER_SIZE, DEFAULT_SERIAL_BUFFER_SIZE);
SPARK_ASSERT(serial);
serial_ = std::move(serial);
} else {
auto serial = std::make_unique<SerialUSBStream>((HAL_USB_USART_Serial)settings_.usbserial, settings_.baud, DEFAULT_SERIAL_BUFFER_SIZE, DEFAULT_SERIAL_BUFFER_SIZE);
SPARK_ASSERT(serial)
serial_ = std::move(serial);
}

dns_ = std::make_unique<Dns>();
SPARK_ASSERT(dns_);
Expand Down Expand Up @@ -289,29 +296,39 @@ int PppServerNetif::start() {
}, nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::TEST, "+IFC", "+IFC: (0-2)(0-2)"));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+IFC", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
auto stream = (SerialStream*)data;
CHECK_TRUE(stream, SYSTEM_ERROR_INVALID_STATE);
if (stream->config() & SERIAL_FLOW_CONTROL_RTS_CTS) {
request->sendResponse("+IFC: 2,2");
} else {
auto self = static_cast<PppServerNetif*>(data);
if (self->settings_.usbserial) {
// It's a SerialUSBStream — no flow control concept, just respond 0,0
request->sendResponse("+IFC: 0,0");
} else {
auto stream = static_cast<SerialStream*>(self->serial_.get());
CHECK_TRUE(stream, SYSTEM_ERROR_INVALID_STATE);
if (stream->config() & SERIAL_FLOW_CONTROL_RTS_CTS) {
request->sendResponse("+IFC: 2,2");
} else {
request->sendResponse("+IFC: 0,0");
}
}
return 0;
}, serial_.get()));
}, this));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+IFC", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
auto stream = (SerialStream*)data;
CHECK_TRUE(stream, SYSTEM_ERROR_INVALID_STATE);
int v[2] = {};
CHECK_TRUE(request->scanf("%d,%d", &v[0], &v[1]) == 2, SYSTEM_ERROR_INVALID_ARGUMENT);
if (v[0] == 2 || v[1] == 2) {
auto c = stream->config() | SERIAL_FLOW_CONTROL_RTS_CTS;
return stream->setConfig(c);
} else if (v[0] == 0 || v[1] == 0) {
auto c = stream->config() & (~SERIAL_FLOW_CONTROL_RTS_CTS);
return stream->setConfig(c);
}
auto self = static_cast<PppServerNetif*>(data);

if (self->settings_.serial) {
auto stream = static_cast<SerialStream*>(self->serial_.get());
CHECK_TRUE(stream, SYSTEM_ERROR_INVALID_STATE);
int v[2] = {};
CHECK_TRUE(request->scanf("%d,%d", &v[0], &v[1]) == 2, SYSTEM_ERROR_INVALID_ARGUMENT);
if (v[0] == 2 || v[1] == 2) {
auto c = stream->config() | SERIAL_FLOW_CONTROL_RTS_CTS;
return stream->setConfig(c);
} else if (v[0] == 0 || v[1] == 0) {
auto c = stream->config() & (~SERIAL_FLOW_CONTROL_RTS_CTS);
return stream->setConfig(c);
}
}
return SYSTEM_ERROR_INVALID_ARGUMENT;
}, serial_.get()));
}, this));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+CGEREP", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+CREG", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+CGREG", nullptr));
Expand All @@ -325,23 +342,39 @@ int PppServerNetif::start() {
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+COPS", "+COPS: 0,0,\"Particle\""));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::TEST, "+IPR", "+IPR: (0,9600,19200,38400,57600,115200,230400,460800,921600),()"));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+IPR", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
auto stream = (SerialStream*)data;
CHECK_TRUE(stream, SYSTEM_ERROR_INVALID_STATE);
request->sendResponse("+IPR: %u", stream->baudrate());
auto self = static_cast<PppServerNetif*>(data);
CHECK_TRUE(self->serial_.get(), SYSTEM_ERROR_INVALID_STATE);

unsigned int baud = self->settings_.usbserial
? static_cast<SerialUSBStream*>(self->serial_.get())->baudrate()
: static_cast<SerialStream*>(self->serial_.get())->baudrate();
request->sendResponse("+IPR: %u", baud);
return 0;
}, serial_.get()));
}, this));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+IPR", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
auto stream = (SerialStream*)data;
CHECK_TRUE(stream, SYSTEM_ERROR_INVALID_STATE);
auto self = static_cast<PppServerNetif*>(data);
int v = 0;
CHECK_TRUE(request->scanf("%d", &v) == 1, SYSTEM_ERROR_INVALID_ARGUMENT);
CHECK_TRUE(v > 0, SYSTEM_ERROR_INVALID_ARGUMENT);
CHECK(stream->setBaudRate(v));
CHECK_TRUE(self->serial_.get(), SYSTEM_ERROR_INVALID_STATE);

if (self->settings_.serial) {
auto stream = static_cast<SerialStream*>(self->serial_.get());
CHECK(stream->setBaudRate(v));
} else {
auto stream = static_cast<SerialUSBStream*>(self->serial_.get());
CHECK(stream->setBaudRate(v));
}
return 0;
}, serial_.get()));
}, this));
auto connectRequest = [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
auto client = (net::ppp::Client*)data;
request->sendResponse("CONNECT %u", ((SerialStream*)request->server()->config().stream())->baudrate());
auto self = static_cast<PppServerNetif*>(data);
auto client = (net::ppp::Client*)&self->client_;
unsigned int baud = self->settings_.usbserial
? static_cast<SerialUSBStream*>(self->serial_.get())->baudrate()
: static_cast<SerialStream*>(self->serial_.get())->baudrate();

request->sendResponse("CONNECT %u", baud);
request->setFinalResponse(AtServerRequest::CONNECT);
request->server()->suspend();
client->setOutputCallback([](const uint8_t* data, size_t size, void* ctx) -> int {
Expand All @@ -357,8 +390,8 @@ int PppServerNetif::start() {
client->notifyEvent(ppp::Client::EVENT_LOWER_UP);
return 0;
};
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WILDCARD, "D*", connectRequest, &client_));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::ONE_INT_ARG, "D", connectRequest, &client_));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WILDCARD, "D*", connectRequest, this));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::ONE_INT_ARG, "D", connectRequest, this));

SPARK_ASSERT(os_thread_create(&thread_, "pppserver", OS_THREAD_PRIORITY_NETWORK, &PppServerNetif::loop, this, OS_THREAD_STACK_SIZE_DEFAULT_HIGH) == 0);
return 0;
Expand Down Expand Up @@ -387,7 +420,7 @@ void PppServerNetif::loop(void* arg) {
char tmp[256] = {};
while (self->serial_->availForRead() > 0) {
int sz = self->serial_->read(tmp, sizeof(tmp));
// LOG(INFO, "input %d", sz);
LOG(INFO, "input %d", sz);
auto r = self->client_.input((const uint8_t*)tmp, sz);
(void)r;
// LOG(INFO, "input result = %d", r);
Expand Down Expand Up @@ -515,12 +548,12 @@ void PppServerNetif::mempEventHandler(memp_t type, unsigned available, unsigned

int PppServerNetif::request(if_req_driver_specific* req, size_t size) {
CHECK_TRUE(req, SYSTEM_ERROR_INVALID_ARGUMENT);
CHECK_TRUE(req->type == IF_REQ_DRIVER_SPECIFIC_PPP_SERVER_UART_SETTINGS, SYSTEM_ERROR_INVALID_ARGUMENT);
CHECK_TRUE(size >= sizeof(if_req_ppp_server_uart_settings), SYSTEM_ERROR_INVALID_ARGUMENT);
CHECK_TRUE(req->type == IF_REQ_DRIVER_SPECIFIC_PPP_SERVER_SERIAL_SETTINGS, SYSTEM_ERROR_INVALID_ARGUMENT);
CHECK_TRUE(size >= sizeof(if_req_ppp_server_serial_settings), SYSTEM_ERROR_INVALID_ARGUMENT);

auto settings = (if_req_ppp_server_uart_settings*)req;
auto settings = (if_req_ppp_server_serial_settings*)req;
memcpy(&settings_, settings, std::min(sizeof(settings_), size));
LOG(INFO, "Update PPP server netif settings: serial=%u baud=%u config=%08x", (unsigned)settings->serial, settings->baud, settings->config);
LOG(INFO, "Update PPP server netif settings: usb=%u serial=%u baud=%u config=%08x", (unsigned)settings->usbserial, (unsigned)settings->serial, settings->baud, settings->config);
return 0;
}

Expand Down
5 changes: 3 additions & 2 deletions hal/network/lwip/pppservernetif.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <lwip/pbuf.h>
#include "ppp_client.h"
#include "serial_stream.h"
#include "serial_usb_stream.h"
#include "at_server.h"

#ifdef __cplusplus
Expand Down Expand Up @@ -98,11 +99,11 @@ class PppServerNetif : public BaseNetif {
std::atomic_bool exit_;
particle::net::ppp::Client client_;
std::atomic<if_power_state_t> pwrState_;
std::unique_ptr<SerialStream> serial_;
std::unique_ptr<EventGroupBasedStream> serial_;
std::unique_ptr<Dns> dns_;
std::unique_ptr<::particle::ThreadRunner> dnsRunner_;
std::unique_ptr<particle::net::nat::Nat64> nat_;
if_req_ppp_server_uart_settings settings_;
if_req_ppp_server_serial_settings settings_;
std::unique_ptr<AtServer> server_;

};
Expand Down
Loading