/* * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \addtogroup cc13xx-cc26xx-web-demo * @{ * * \file * A process which receives data over UART and transmits them over UDP * to a pre-defined IPv6 address and port. It also listens on the same UDP * port for messages, which it prints out over UART. * * For this example to work, you will have to modify the destination IPv6 * address by adjusting the set_dest_addr() macro below. * * To listen on your linux or OS X box: * nc -6ulkw 1 REMOTE_PORT * * (REMOTE_PORT should be the actual value of the define below, e.g. 7777) * * Once netcat is up and listening, type something to the CC13xx/CC26xx's terminal * Bear in mind that the datagram will only be sent after a 0x0a (LF) char * has been received. Therefore, if you are on Win, do NOT use PuTTY for * this purpose, since it does not send 0x0a as part of the line end. On * Win XP use hyperterm. On Win 7 use some other software (e.g. Tera Term, * which can be configured to send CRLF on enter keystrokes). * * To send data in the other direction from your linux or OS X box: * * nc -6u \ REMOTE_PORT */ /*---------------------------------------------------------------------------*/ #include "contiki.h" #include "sys/cc.h" #include "sys/process.h" #include "dev/serial-line.h" #include "net/ipv6/uip.h" #include "net/ipv6/uip-udp-packet.h" #include "net/ipv6/uiplib.h" /*---------------------------------------------------------------------------*/ #include "uart0-arch.h" /*---------------------------------------------------------------------------*/ #include "net-uart.h" #include "httpd-simple.h" /*---------------------------------------------------------------------------*/ #include #include #include #include #include /*---------------------------------------------------------------------------*/ #define DEBUG DEBUG_NONE #include "net/ipv6/uip-debug.h" /*---------------------------------------------------------------------------*/ #define REMOTE_PORT 7777 #define MAX_MSG_SIZE 100 #define set_dest_addr() uip_ip6addr(&remote_addr, \ 0xBBBB, 0x0000, 0x0000, 0x0000, \ 0x3E07, 0x54FF, 0xFE74, 0x4885); /*---------------------------------------------------------------------------*/ #define ADDRESS_CONVERSION_OK 1 #define ADDRESS_CONVERSION_ERROR 0 /*---------------------------------------------------------------------------*/ static struct uip_udp_conn *udp_conn = NULL; static uint8_t buffer[MAX_MSG_SIZE]; static uint8_t msg_len; static uip_ip6addr_t remote_addr; /*---------------------------------------------------------------------------*/ #define IPV6_ADDR_STR_LEN 64 /*---------------------------------------------------------------------------*/ PROCESS(net_uart_process, "Net UART Process"); /*---------------------------------------------------------------------------*/ /* * \brief Attempts to convert a string representation of an IPv6 address to a * numeric one. * \param buf The buffer with the string to be converted. * \return ADDRESS_CONVERSION_OK or ADDRESS_CONVERSION_ERROR * * ToDo: Add support for NAT64 conversion in case the incoming address is a v4 * This is now supported in the current master, so when we pull it in this will * be very straightforward. */ static int set_new_ip_address(char *buf) { /* * uiplib_ip6addrconv will immediately start writing into the supplied buffer * even if it subsequently fails. Thus, pass an intermediate buffer */ uip_ip6addr_t tmp_addr; int rv = uiplib_ip6addrconv(buf, &tmp_addr); if(rv == ADDRESS_CONVERSION_OK) { /* Conversion OK, copy to our main buffer */ memcpy(&remote_addr, &tmp_addr, sizeof(remote_addr)); PRINTF("Updated remote address "); PRINT6ADDR(&remote_addr); PRINTF("\n"); } return rv; } /*---------------------------------------------------------------------------*/ static void net_input(void) { if(uip_newdata()) { memset(buffer, 0, MAX_MSG_SIZE); msg_len = MIN(uip_datalen(), MAX_MSG_SIZE - 1); /* Copy data */ memcpy(buffer, uip_appdata, msg_len); printf("%s", (char *)buffer); } return; } /*---------------------------------------------------------------------------*/ static void release_uart(void) { uart0_set_callback(NULL); } /*---------------------------------------------------------------------------*/ static void keep_uart_on(void) { uart0_set_callback(serial_line_input_byte); } /*---------------------------------------------------------------------------*/ static int remote_port_post_handler(char *key, int key_len, char *val, int val_len) { int rv; if(key_len != strlen("net_uart_port") || strncasecmp(key, "net_uart_port", strlen("net_uart_port")) != 0) { /* Not ours */ return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; } rv = atoi(val); if(rv <= 65535 && rv > 0) { web_demo_config.net_uart.remote_port = (uint16_t)rv; } else { return HTTPD_SIMPLE_POST_HANDLER_ERROR; } return HTTPD_SIMPLE_POST_HANDLER_OK; } /*---------------------------------------------------------------------------*/ static int remote_ipv6_post_handler(char *key, int key_len, char *val, int val_len) { int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; if(key_len != strlen("net_uart_ip") || strncasecmp(key, "net_uart_ip", strlen("net_uart_ip")) != 0) { /* Not ours */ return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; } if(val_len > IPV6_ADDR_STR_LEN) { /* Ours but bad value */ rv = HTTPD_SIMPLE_POST_HANDLER_ERROR; } else { if(set_new_ip_address(val)) { memset(web_demo_config.net_uart.remote_address, 0, NET_UART_IP_ADDR_STRLEN); memcpy(web_demo_config.net_uart.remote_address, val, val_len); rv = HTTPD_SIMPLE_POST_HANDLER_OK; } } return rv; } /*---------------------------------------------------------------------------*/ static int on_off_post_handler(char *key, int key_len, char *val, int val_len) { int rv; if(key_len != strlen("net_uart_on") || strncasecmp(key, "net_uart_on", strlen("net_uart_on")) != 0) { /* Not ours */ return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN; } rv = atoi(val); /* Be pedantic: only accept 0 and 1, not just any non-zero value */ if(rv == 0) { web_demo_config.net_uart.enable = 0; release_uart(); } else if(rv == 1) { web_demo_config.net_uart.enable = 1; keep_uart_on(); } else { return HTTPD_SIMPLE_POST_HANDLER_ERROR; } return HTTPD_SIMPLE_POST_HANDLER_OK; } /*---------------------------------------------------------------------------*/ HTTPD_SIMPLE_POST_HANDLER(remote_port, remote_port_post_handler); HTTPD_SIMPLE_POST_HANDLER(remote_ipv6, remote_ipv6_post_handler); HTTPD_SIMPLE_POST_HANDLER(on_off, on_off_post_handler); /*---------------------------------------------------------------------------*/ static void set_config_defaults(void) { /* Set a hard-coded destination address to start with */ set_dest_addr(); /* Set config defaults */ web_demo_ipaddr_sprintf(web_demo_config.net_uart.remote_address, NET_UART_IP_ADDR_STRLEN, &remote_addr); web_demo_config.net_uart.remote_port = REMOTE_PORT; web_demo_config.net_uart.enable = 1; } /*---------------------------------------------------------------------------*/ PROCESS_THREAD(net_uart_process, ev, data) { PROCESS_BEGIN(); printf("CC13xx/CC26xx Net UART Process\n"); set_config_defaults(); udp_conn = udp_new(NULL, UIP_HTONS(0), NULL); udp_bind(udp_conn, UIP_HTONS(REMOTE_PORT)); if(udp_conn == NULL) { printf("No UDP connection available, exiting the process!\n"); PROCESS_EXIT(); } httpd_simple_register_post_handler(&remote_port_handler); httpd_simple_register_post_handler(&remote_ipv6_handler); httpd_simple_register_post_handler(&on_off_handler); while(1) { PROCESS_YIELD(); if(ev == serial_line_event_message) { /* * If the message contains a new IP address, save it and go back to * waiting. */ if(set_new_ip_address((char *)data) == ADDRESS_CONVERSION_ERROR) { /* Not an IP address in the message. Send to current destination */ memset(buffer, 0, MAX_MSG_SIZE); /* We need to add a line feed, thus never fill the entire buffer */ msg_len = MIN(strlen(data), MAX_MSG_SIZE - 1); memcpy(buffer, data, msg_len); /* Add a line feed */ buffer[msg_len] = 0x0A; msg_len++; uip_udp_packet_sendto( udp_conn, buffer, msg_len, &remote_addr, UIP_HTONS(web_demo_config.net_uart.remote_port)); } } else if(ev == tcpip_event) { net_input(); } else if(ev == web_demo_config_loaded_event) { /* * New config. Check if it's possible to update the remote address. * The port will have been updated already */ set_new_ip_address(web_demo_config.net_uart.remote_address); if(web_demo_config.net_uart.enable == 1) { keep_uart_on(); } } else if(ev == web_demo_load_config_defaults) { set_config_defaults(); } } PROCESS_END(); } /*---------------------------------------------------------------------------*/ /** * @} * @} */