osd-contiki/examples/cc26xx/cc26xx-web-demo/net-uart.c
George Oikonomou 421fbfae25 Change the LPM locks API:
Instead of using a separate data structure to request that a PD remain powered during deep sleep,
we do the same within the main LPM data structure through an additional field.

This allows us to maintain only one linked list of LPM modules and overall improves code clarity
2015-05-15 09:21:02 +01:00

324 lines
11 KiB
C

/*
* 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 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 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 \<node IPv6 address\> REMOTE_PORT
*/
/*---------------------------------------------------------------------------*/
#include "contiki-conf.h"
#include "sys/process.h"
#include "dev/serial-line.h"
#include "dev/cc26xx-uart.h"
#include "net/ip/uip.h"
#include "net/ip/uip-udp-packet.h"
#include "net/ip/uiplib.h"
#include "net-uart.h"
#include "httpd-simple.h"
#include "ti-lib.h"
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/*---------------------------------------------------------------------------*/
#define DEBUG DEBUG_NONE
#include "net/ip/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
/*---------------------------------------------------------------------------*/
#ifndef MIN
#define MIN(n, m) (((n) < (m)) ? (n) : (m))
#endif
/*---------------------------------------------------------------------------*/
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)
{
cc26xx_uart_set_input(NULL);
}
/*---------------------------------------------------------------------------*/
static void
keep_uart_on(void)
{
cc26xx_uart_set_input(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) {
cc26xx_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(cc26xx_web_demo_config.net_uart.remote_address, 0,
NET_UART_IP_ADDR_STRLEN);
memcpy(cc26xx_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) {
cc26xx_web_demo_config.net_uart.enable = 0;
release_uart();
} else if(rv == 1) {
cc26xx_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 */
cc26xx_web_demo_ipaddr_sprintf(cc26xx_web_demo_config.net_uart.remote_address,
NET_UART_IP_ADDR_STRLEN, &remote_addr);
cc26xx_web_demo_config.net_uart.remote_port = REMOTE_PORT;
cc26xx_web_demo_config.net_uart.enable = 1;
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(net_uart_process, ev, data)
{
PROCESS_BEGIN();
printf("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(cc26xx_web_demo_config.net_uart.remote_port));
}
} else if(ev == tcpip_event) {
net_input();
} else if(ev == cc26xx_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(cc26xx_web_demo_config.net_uart.remote_address);
if(cc26xx_web_demo_config.net_uart.enable == 1) {
keep_uart_on();
}
} else if(ev == cc26xx_web_demo_load_config_defaults) {
set_config_defaults();
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/**
* @}
* @}
*/