mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
230 lines
5.7 KiB
C
230 lines
5.7 KiB
C
|
/* SLIP Client Example
|
||
|
|
||
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||
|
|
||
|
Unless required by applicable law or agreed to in writing, this
|
||
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||
|
CONDITIONS OF ANY KIND, either express or implied.
|
||
|
*/
|
||
|
#include <string.h>
|
||
|
#include "freertos/FreeRTOS.h"
|
||
|
#include "freertos/task.h"
|
||
|
#include "freertos/event_groups.h"
|
||
|
|
||
|
|
||
|
#include "esp_system.h"
|
||
|
#include "esp_log.h"
|
||
|
#include "esp_event.h"
|
||
|
#include "esp_netif.h"
|
||
|
#include "esp_netif_slip.h"
|
||
|
|
||
|
#include "lwip/sockets.h"
|
||
|
#include "lwip/dns.h"
|
||
|
#include "lwip/netdb.h"
|
||
|
|
||
|
#include "slip_modem.h"
|
||
|
|
||
|
static const char *TAG = "SLIP_EXAMPLE";
|
||
|
|
||
|
#define STACK_SIZE (10 * 1024)
|
||
|
#define PRIORITY 10
|
||
|
|
||
|
TaskHandle_t udp_rx_tx_handle;
|
||
|
|
||
|
static void udp_rx_tx_task(void *arg)
|
||
|
{
|
||
|
char addr_str[128];
|
||
|
uint8_t rx_buff[1024];
|
||
|
|
||
|
int sock = *(int *)arg;
|
||
|
|
||
|
struct sockaddr_in6 source_addr;
|
||
|
socklen_t socklen = sizeof(source_addr);
|
||
|
|
||
|
|
||
|
ESP_LOGI(TAG, "Starting node manager UDP task");
|
||
|
|
||
|
while (1) {
|
||
|
// Receive data
|
||
|
int len = recvfrom(sock, rx_buff, sizeof(rx_buff) - 1, 0, (struct sockaddr *)&source_addr, &socklen);
|
||
|
if (len < 0) {
|
||
|
ESP_LOGE(TAG, "recvfrom failed: errno %d", errno);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Parse out address to string
|
||
|
inet6_ntoa_r(source_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
|
||
|
|
||
|
// Force null termination of received data and print
|
||
|
rx_buff[len] = 0;
|
||
|
ESP_LOGI(TAG, "Received '%s' from '%s'", rx_buff, addr_str);
|
||
|
|
||
|
// Send data back
|
||
|
int err = sendto(sock, rx_buff, len, 0, (struct sockaddr *)&source_addr, socklen);
|
||
|
if (err < 0) {
|
||
|
ESP_LOGE(TAG, "sendto failed: errno %d", errno);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
vTaskDelete(NULL);
|
||
|
}
|
||
|
|
||
|
esp_err_t udp_rx_tx_init()
|
||
|
{
|
||
|
// Setup bind address
|
||
|
struct sockaddr_in6 dest_addr;
|
||
|
bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un));
|
||
|
dest_addr.sin6_family = AF_INET6;
|
||
|
dest_addr.sin6_port = htons(CONFIG_EXAMPLE_UDP_PORT);
|
||
|
|
||
|
// Create socket
|
||
|
int sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IPV6);
|
||
|
if (sock < 0) {
|
||
|
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// Disable IPv4 and reuse address
|
||
|
int opt = 1;
|
||
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||
|
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
|
||
|
|
||
|
// Bind socket
|
||
|
int err = bind(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
|
||
|
if (err < 0) {
|
||
|
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
|
||
|
return -2;
|
||
|
}
|
||
|
ESP_LOGI(TAG, "Socket bound, port %d", CONFIG_EXAMPLE_UDP_PORT);
|
||
|
|
||
|
|
||
|
// Start UDP rx thread
|
||
|
xTaskCreate(udp_rx_tx_task, "udp_rx_tx", STACK_SIZE, &sock, PRIORITY, &udp_rx_tx_handle);
|
||
|
|
||
|
return ESP_OK;
|
||
|
}
|
||
|
|
||
|
// Write a prefix to the contiki slip device
|
||
|
static void slip_set_prefix(esp_netif_t *slip_netif)
|
||
|
{
|
||
|
uint8_t buff[10] = {0};
|
||
|
|
||
|
// Fetch the slip interface IP
|
||
|
const ip6_addr_t *addr = esp_slip_get_ip6(slip_netif);
|
||
|
|
||
|
ESP_LOGI(TAG, "%s: prefix set (%08x:%08x)", __func__,
|
||
|
lwip_ntohl(addr->addr[0]), lwip_ntohl(addr->addr[1]));
|
||
|
|
||
|
// Build slip set message
|
||
|
buff[0] = '!';
|
||
|
buff[1] = 'P';
|
||
|
for (int i = 0; i < 2; i++) {
|
||
|
for (int j = 0; j < 4; j++) {
|
||
|
buff[2 + i * 4 + j] = addr->addr[i] >> (j * 8);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Write raw data out the slip interface
|
||
|
esp_netif_lwip_slip_raw_output(slip_netif, buff, 2 + 8);
|
||
|
}
|
||
|
|
||
|
// slip_rx_filter filters incomming commands from the slip interface
|
||
|
// this implementation is designed for use with contiki slip devices
|
||
|
bool slip_rx_filter(void *ctx, uint8_t *data, uint32_t len)
|
||
|
{
|
||
|
|
||
|
esp_netif_t *slip_netif = (esp_netif_t *)ctx;
|
||
|
|
||
|
if (data[1] == '?') {
|
||
|
switch (data[2]) {
|
||
|
case 'P':
|
||
|
ESP_LOGI(TAG, "Prefix request");
|
||
|
slip_set_prefix(slip_netif);
|
||
|
|
||
|
return true;
|
||
|
|
||
|
default:
|
||
|
ESP_LOGI(TAG, "Unhandled request '%c'", data[2]);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
|
||
|
} else if (data[1] == '!') {
|
||
|
switch (data[2]) {
|
||
|
default:
|
||
|
ESP_LOGI(TAG, "Unhandled command '%c'", data[2]);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Initialise the SLIP interface
|
||
|
esp_netif_t *slip_if_init()
|
||
|
{
|
||
|
ESP_LOGI(TAG, "Initialising SLIP interface");
|
||
|
|
||
|
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_SLIP();
|
||
|
esp_netif_t *slip_netif = esp_netif_new(&cfg);
|
||
|
|
||
|
esp_netif_slip_config_t slip_config = {
|
||
|
.uart_dev = UART_NUM_2,
|
||
|
};
|
||
|
|
||
|
IP6_ADDR(&slip_config.addr,
|
||
|
lwip_htonl(0xfd000000),
|
||
|
lwip_htonl(0x00000000),
|
||
|
lwip_htonl(0x00000000),
|
||
|
lwip_htonl(0x000000001)
|
||
|
);
|
||
|
|
||
|
esp_netif_slip_set_params(slip_netif, &slip_config);
|
||
|
|
||
|
ESP_LOGI(TAG, "Initialising SLIP modem");
|
||
|
|
||
|
esp_slip_modem_config_t modem_cfg = {
|
||
|
.uart_dev = UART_NUM_2,
|
||
|
|
||
|
.uart_tx_pin = CONFIG_EXAMPLE_UART_TX_PIN,
|
||
|
.uart_rx_pin = CONFIG_EXAMPLE_UART_RX_PIN,
|
||
|
.uart_baud = CONFIG_EXAMPLE_UART_BAUD,
|
||
|
|
||
|
.rx_buffer_len = 1024,
|
||
|
|
||
|
.rx_filter = slip_rx_filter,
|
||
|
.rx_filter_ctx = slip_netif,
|
||
|
};
|
||
|
|
||
|
void *slip_modem = esp_slip_modem_create(slip_netif, &modem_cfg);
|
||
|
ESP_ERROR_CHECK(esp_netif_attach(slip_netif, slip_modem));
|
||
|
|
||
|
ESP_LOGI(TAG, "SLIP init complete");
|
||
|
|
||
|
return slip_netif;
|
||
|
}
|
||
|
|
||
|
void app_main(void)
|
||
|
{
|
||
|
// Setup networking
|
||
|
tcpip_adapter_init();
|
||
|
|
||
|
esp_log_level_set("*", ESP_LOG_DEBUG);
|
||
|
|
||
|
// Create event loop
|
||
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||
|
|
||
|
// Setup slip interface
|
||
|
slip_if_init();
|
||
|
|
||
|
// Setup UDP loopback service
|
||
|
udp_rx_tx_init();
|
||
|
|
||
|
// Run
|
||
|
while (1) {
|
||
|
vTaskDelay(portTICK_PERIOD_MS * 10);
|
||
|
}
|
||
|
}
|