apps/examples/cc3000: This commit removes the CC3000 example.

This commit is contained in:
Alan Carvalho de Assis 2018-04-04 09:38:53 -06:00 committed by Gregory Nutt
parent 0094b411da
commit a62b8ff299
13 changed files with 0 additions and 3181 deletions

View File

@ -193,11 +193,6 @@ examples/canard
Example application for canutils/libcarnard.
examples/cc3000
^^^^^^^^^^^^^^^
This is a test for the TI CC3000 wireless networking module.
examples/cctype
^^^^^^^^^^^^^^^

View File

@ -1,11 +0,0 @@
/Make.dep
/.depend
/.built
/*.asm
/*.obj
/*.rel
/*.lst
/*.sym
/*.adb
/*.lib
/*.src

View File

@ -1,27 +0,0 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
config EXAMPLES_CC3000BASIC
bool "A Basic Application to use CC3000 Module"
default n
depends on WL_CC3000
---help---
Enable the CC3000BASIC example
if EXAMPLES_CC3000BASIC
config EXAMPLES_CC3000_MEM_CHECK
bool "Memory check instrumentation"
default n
---help---
Define to help debug memory issues
config EXAMPLES_CC3000_STACK_CHECK
bool "Stack check instrumentation"
default n
---help---
Define to help debug stack size issues
endif

View File

@ -1,39 +0,0 @@
############################################################################
# apps/examples/cc3000/Make.defs
# Adds selected applications to apps/ build
#
# Copyright (C) 2015 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# 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 NuttX 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 OWNER 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.
#
############################################################################
ifeq ($(CONFIG_EXAMPLES_CC3000BASIC),y)
CONFIGURED_APPS += examples/cc3000
endif

View File

@ -1,159 +0,0 @@
############################################################################
# apps/examples/cc3000/Makefile
#
# Copyright (C) 2008, 2010-2013 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# 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 NuttX 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 OWNER 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.
#
############################################################################
-include $(TOPDIR)/.config
-include $(TOPDIR)/Make.defs
include $(APPDIR)/Make.defs
# Hello, World! built-in application info
APPNAME = c3b
PRIORITY = SCHED_PRIORITY_DEFAULT
STACKSIZE = 608
APPNAME1 = shell
PRIORITY1 = SCHED_PRIORITY_DEFAULT
STACKSIZE1 = 980
# Hello, World! Example
ASRCS =
CSRCS = board.c telnetd_driver.c telnetd_daemon.c
CC3000SRC = cc3000basic.c
SHELLSRC = shell.c
MAINSRC = $(CC3000SRC) $(SHELLSRC)
AOBJS = $(ASRCS:.S=$(OBJEXT))
COBJS = $(CSRCS:.c=$(OBJEXT))
CC3000OBJ = $(CC3000SRC:.c=$(OBJEXT))
SHELLOBJ = $(SHELLSRC:.c=$(OBJEXT))
MAINOBJ = $(MAINSRC:.c=$(OBJEXT))
SRCS = $(ASRCS) $(CSRCS) $(MAINSRC)
OBJS = $(AOBJS) $(COBJS)
ifneq ($(CONFIG_BUILD_KERNEL),y)
OBJS += $(MAINOBJ)
endif
ifeq ($(CONFIG_WINDOWS_NATIVE),y)
BIN = ..\..\libapps$(LIBEXT)
else
ifeq ($(WINTOOL),y)
BIN = ..\\..\\libapps$(LIBEXT)
else
BIN = ../../libapps$(LIBEXT)
endif
endif
ifeq ($(WINTOOL),y)
INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}"
else
INSTALL_DIR = $(BIN_DIR)
endif
CONFIG_XYZ_PROGNAME1 ?= cc3000$(EXEEXT)
PROGNAME1 = $(CONFIG_XYZ_PROGNAME1)
CONFIG_XYZ_PROGNAME2 ?= shell$(EXEEXT)
PROGNAME2 = $(CONFIG_XYZ_PROGNAME2)
ROOTDEPPATH = --dep-path .
# Common build
VPATH =
all: .built
.PHONY: clean depend distclean preconfig
.PRECIOUS: ../../libapps$(LIBEXT)
$(AOBJS): %$(OBJEXT): %.S
$(call ASSEMBLE, $<, $@)
$(COBJS) $(MAINOBJ): %$(OBJEXT): %.c
$(call COMPILE, $<, $@)
.built: $(OBJS)
$(call ARCHIVE, $(BIN), $(OBJS))
@touch .built
ifeq ($(CONFIG_BUILD_KERNEL),y)
$(BIN_DIR)$(DELIM)$(PROGNAME1): $(OBJS) $(CC3000OBJ)
@echo "LD: $(PROGNAME1)"
$(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(PROGNAME1) $(ARCHCRT0OBJ) $(MAINOBJ) $(LDLIBS)
$(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(PROGNAME1)
$(BIN_DIR)$(DELIM)$(PROGNAME2): $(OBJS) $(SHELLOBJ)
@echo "LD: $(PROGNAME2)"
$(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(PROGNAME2) $(ARCHCRT0OBJ) $(MAINOBJ) $(LDLIBS)
$(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(PROGNAME2)
install: $(BIN_DIR)$(DELIM)$(PROGNAME1) $(BIN_DIR)$(DELIM)$(PROGNAME2)
else
install:
endif
ifeq ($(CONFIG_NSH_BUILTIN_APPS),y)
$(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat: $(DEPCONFIG) Makefile
$(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main)
$(call REGISTER,$(APPNAME1),$(PRIORITY1),$(STACKSIZE1),$(APPNAME1)_main)
context: $(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat $(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat
else
context:
endif
.depend: Makefile $(SRCS)
@$(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
@touch $@
depend: .depend
clean:
$(call DELFILE, .built)
$(call CLEAN)
distclean: clean
$(call DELFILE, Make.dep)
$(call DELFILE, .depend)
preconfig:
-include Make.dep

View File

@ -1,178 +0,0 @@
/****************************************************************************
* apps/examples/cc3000/board.c
*
* This code is based on the TI sample code "Basic WiFi Application"
* and has the callback routines that TI expects for their library.
*
* TI uses callback routines to make their library portable: these routines,
* and the routines in the SPI files, will be different for an Arduino,
* a TI MSP430, a PIC, etc. but the core library shouldn't have to be
* changed.
*
* Derives from an application to demo an Arduino connected to the TI CC3000
*
* Copyright (C) 2013 Chris Magagna - cmagagna@yahoo.com
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Don't sue me if my code blows up your board and burns down your house
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "board.h"
#include <stdbool.h>
#include <nuttx/wireless/cc3000/wlan.h>
#include <nuttx/wireless/cc3000/hci.h>
#include <nuttx/wireless/cc3000.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define NETAPP_IPCONFIG_MAC_OFFSET (20)
#define CC3000_APP_BUFFER_SIZE (5)
#define CC3000_RX_BUFFER_OVERHEAD_SIZE (20)
/****************************************************************************
* Public Data
****************************************************************************/
volatile unsigned long ulSmartConfigFinished,
ulCC3000Connected,
ulCC3000DHCP,
OkToDoShutDown,
ulCC3000DHCP_configured;
volatile uint8_t ucStopSmartConfig;
uint8_t asyncNotificationWaiting = false;
long lastAsyncEvent;
uint8_t dhcpIPAddress[4];
/****************************************************************************
* Public Functions
****************************************************************************/
/* The TI library calls this routine when asynchronous events happen.
*
* For example you tell the CC3000 to turn itself on and connect
* to an access point then your code can go on to do its own thing.
* When the CC3000 is done configuring itself (e.g. it gets an IP
* address from the DHCP server) it will call this routine so you
* can take appropriate action.
*/
void CC3000_AsyncCallback(long lEventType, char * data, uint8_t length)
{
lastAsyncEvent = lEventType;
switch (lEventType)
{
case HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE:
ulSmartConfigFinished = 1;
ucStopSmartConfig = 1;
asyncNotificationWaiting=true;
break;
case HCI_EVNT_WLAN_UNSOL_CONNECT:
ulCC3000Connected = 1;
asyncNotificationWaiting=true;
break;
case HCI_EVNT_WLAN_UNSOL_DISCONNECT:
ulCC3000Connected = 0;
ulCC3000DHCP = 0;
ulCC3000DHCP_configured = 0;
asyncNotificationWaiting=true;
break;
case HCI_EVNT_WLAN_UNSOL_DHCP:
/* Notes:
* 1) IP config parameters are received swapped
* 2) IP config parameters are valid only if status is OK, i.e. ulCC3000DHCP becomes 1
* only if status is OK, the flag is set to 1 and the addresses are valid
*/
if (*(data + NETAPP_IPCONFIG_MAC_OFFSET) == 0)
{
ulCC3000DHCP = 1;
dhcpIPAddress[0] = data[3];
dhcpIPAddress[1] = data[2];
dhcpIPAddress[2] = data[1];
dhcpIPAddress[3] = data[0];
}
else
{
ulCC3000DHCP = 0;
dhcpIPAddress[0] = 0;
dhcpIPAddress[1] = 0;
dhcpIPAddress[2] = 0;
dhcpIPAddress[3] = 0;
}
asyncNotificationWaiting=true;
break;
case HCI_EVENT_CC3000_CAN_SHUT_DOWN:
OkToDoShutDown = 1;
asyncNotificationWaiting=true;
break;
default:
asyncNotificationWaiting=true;
break;
}
}
/* The TI library calls these routines on CC3000 startup.
*
* This library does not send firmware, driver, or bootloader patches
* so we do nothing and we return NULL.
*/
char *SendFirmwarePatch(unsigned long *Length)
{
*Length = 0;
return NULL;
}
char *SendDriverPatch(unsigned long *Length)
{
*Length = 0;
return NULL;
}
char *SendBootloaderPatch(unsigned long *Length)
{
*Length = 0;
return NULL;
}
/* This is my routine to simplify CC3000 startup.
*
* It sets the Arduino pins then calls the normal CC3000 routines
* wlan_init() with all the callbacks and wlan_start() with 0
* to indicate we're not sending any patches.
*/
void CC3000_Init(void)
{
static bool once = false;
if (!once)
{
wireless_archinitialize(132);
once = true;
}
cc3000_wlan_init(132, CC3000_AsyncCallback,
SendFirmwarePatch,
SendDriverPatch,
SendBootloaderPatch);
wlan_start(0);
}

View File

@ -1,179 +0,0 @@
/****************************************************************************
* This file is part of the ArduinoCC3000 library.
* Version 1.0.1b
*
* Copyright (C) 2013 Chris Magagna - cmagagna@yahoo.com
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Don't sue me if my code blows up your board and burns down your house
*
* This file is the main module for the Arduino CC3000 library.
* Your program must call CC3000_Init() before any other API calls.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdint.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Some things are different for the Teensy 3.0, so set a flag if we're using
* that hardware.
*/
#if defined(__arm__) && defined(CORE_TEENSY) && defined(__MK20DX128__)
# define TEENSY3 1
#endif
/* I used the Teensy 3.0 to get the Arduino CC3000 library working but the
Teensy's hardware SPI and the CC3000's SPI didn't like each other so I had
to send the bits manually. For the Uno, Nano, etc. you can probably leave
this unchanged. If your Arduino can't talk to the CC3000 and you're sure
your wiring is OK then try changing this. */
#ifdef TEENSY3
#define USE_HARDWARE_SPI false
#else
#define USE_HARDWARE_SPI true
#endif
// These are the Arduino pins that connect to the CC3000
// (in addition to standard SPI pins MOSI, MISO, and SCK)
//
// The WLAN_IRQ pin must be supported by attachInterrupt
// on your platform
#ifndef TEENSY3
#define WLAN_CS 10 // Arduino pin connected to CC3000 WLAN_SPI_CS
#define WLAN_EN 9 // Arduino pin connected to CC3000 VBAT_SW_EN
#define WLAN_IRQ 3 // Arduino pin connected to CC3000 WLAN_SPI_IRQ
#define WLAN_IRQ_INTNUM 1 // The attachInterrupt() number that corresponds
// to WLAN_IRQ
#define WLAN_MOSI MOSI
#define WLAN_MISO MISO
#define WLAN_SCK SCK
#else
#define WLAN_CS 25
#define WLAN_MISO 26
#define WLAN_IRQ 27
#define WLAN_IRQ_INTNUM 27 // On the Teensy 3.0 the interrupt # is the same as the pin #
#define WLAN_MOSI 28
#define WLAN_SCK 29
#define WLAN_EN 30
#endif
/* The timing between setting the CS pin and reading the IRQ pin is very
* tight on the CC3000, and sometimes the default Arduino digitalRead()
* and digitalWrite() functions are just too slow.
*
* For many of the CC3000 library functions this isn't a big deal because the
* IRQ pin is tied to an interrupt routine but some of them of them disable
* the interrupt routine and read the pins directly. Because digitalRead()
* / Write() are so slow once in a while the Arduino will be in the middle of
* its pin code and the CC3000 will flip another pin's state and it will be
* missed, and everything locks up.
*
* The upshot of all of this is we need to read & write the pin states
* directly, which is very fast compared to the built in Arduino functions.
*
* The Teensy 3.0's library has built in macros called digitalReadFast()
* & digitalWriteFast() that compile down to direct port manipulations but
* are still readable, so use those if possible.
*
* There's a digitalReadFast() / digitalWriteFast() library for Arduino but
* it looks like it hasn't been updated since 2010 so I think it's best to
* just use the direct port manipulations.
*/
#ifdef TEENSY3
#define Read_CC3000_IRQ_Pin() digitalReadFast(WLAN_IRQ)
#define Set_CC3000_CS_NotActive() digitalWriteFast(WLAN_CS, HIGH)
#define Set_CC3000_CS_Active() digitalWriteFast(WLAN_CS, LOW)
#else
// This is hardcoded for an ATMega328 and pin 3. You will need to change this
// for other MCUs or pins
#define Read_CC3000_IRQ_Pin() ((PIND & B00001000) ? 1 : 0)
// This is hardcoded for an ATMega328 and pin 10. You will need to change this
// for other MCUs or pins
#define Set_CC3000_CS_NotActive() PORTB |= B00000100
#define Set_CC3000_CS_Active() PORTB &= B11111011
#endif
#define MAC_ADDR_LEN 6
#define DISABLE (0)
#define ENABLE (1)
/****************************************************************************
* Public Data
****************************************************************************/
#if 0
/* AES key "smartconfigAES16" */
const uint8_t smartconfigkey[] =
{
0x73, 0x6d, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x41, 0x45, 0x53, 0x31, 0x36
};
#endif
/* If you uncomment the line below the library will leave out a lot of the
* higher level functions but use a lot less memory. From:
*
* http://processors.wiki.ti.com/index.php/Tiny_Driver_Support
*
* CC3000's new driver has flexible memory compile options.
*
* This feature comes in handy when we want to use a limited RAM size MCU.
*
* Using The Tiny Driver Compilation option will create a tiny version of our
* host driver with lower data, stack and code consumption.
*
* By enabling this feature, host driver's RAM consumption can be reduced to
* minimum of 251 bytes.
*
* The Tiny host driver version will limit the host driver API to the most
* essential ones.
*
* Code size depends on actual APIs used.
*
* RAM size depends on the largest packet sent and received.
*
* CC3000 can now be used with ultra low cost MCUs, consuming 251 byte of RAM
* and 2K to 6K byte of code size, depending on the API usage.
*/
//#define CC3000_TINY_DRIVER 1
extern uint8_t asyncNotificationWaiting;
extern long lastAsyncEvent;
extern uint8_t dhcpIPAddress[];
extern volatile unsigned long ulSmartConfigFinished;
extern volatile unsigned long ulCC3000Connected;
extern volatile unsigned long ulCC3000DHCP;
extern volatile unsigned long OkToDoShutDown;
extern volatile unsigned long ulCC3000DHCP_configured;
extern volatile uint8_t ucStopSmartConfig;
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
void CC3000_Init(void);

View File

@ -1,987 +0,0 @@
/****************************************************************************
* apps/examples/cc3000basic.c
*
* Derives from an application to demo an Arduino connected to the TI CC3000
*
* Copyright (C) 2013 Chris Magagna - cmagagna@yahoo.com
* Port to nuttx:
* Alan Carvalho de Assis <acassis@gmail.com>
* David Sidrane <david_s5@nscdg.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Don't sue me if my code blows up your board and burns down your house
*
****************************************************************************
*
* To connect an Arduino to the CC3000 you'll need to make these 6 connections
* (in addition to the WiFi antenna, power etc).
*
* Name / pin on CC3000 module / pin on CC3000EM board / purpose
*
* SPI_CS / 12 / J4-8 / SPI Chip Select
* The Arduino will set this pin LOW when it wants to
* exchange data with the CC3000. By convention this is
* Arduino pin 10, but any pin can be used. In this
* program it will be called WLAN_CS
*
* SPI_DOUT / 13 / J4-9 / Data from the module to the Arduino
* This is Arduino's MISO pin, and is how the CC3000
* will get bytes to the Arduino. For most Arduinos
* MISO is pin 12
*
* SPI_IRQ / 14 / J4-10 / CC3000 host notify
* The CC3000 will drive this pin LOW to let the Arduino
* know it's ready to send data. For a regular Arduino
* (Uno, Nano, Leonardo) this will have to be connected
* to pin 2 or 3 so you can use attachInterrupt(). In
* this program it will be called WLAN_IRQ
*
* SPI_DIN / 15 / J4-11 Data from the Arduino to the CC3000
* This is the Arduino's MOSI pin, and is how the Arduino
* will get bytes to the CC3000. For most Arduinos
* MOSI is pin 11
*
* SPI_CLK / 17 / J4-12 SPI clock
* This is the Arduino's SCK pin. For most Arduinos
* SCK is pin 13
*
* VBAT_SW_EN / 26 / J5-5 Module enable
* The Arduino will set this pin HIGH to turn the CC3000
* on. Any pin can be used. In this program it will be
* called WLAN_EN
*
* WARNING #1: The CC3000 runs at 3.6V maximum so you can't run it from your
* regular 5V Arduino power pin. Run it from 3.3V!
*
* WARNING #2: When transmitting the CC3000 will use up to 275mA current. Most
* Arduinos' 3.3V pins can only supply up to 50mA current, so you'll need a
* separate power supply for it (or a voltage regulator like the LD1117V33
* connected to your Arduino's 5V power pin).
*
* WARNING #3: The CC3000's IO pins are not 5V tolerant. If you're using a 5V
* Arduino you will need a level shifter to convert these signals to 3.3V
* so you don't blow up the module.
*
* You'll need to shift the pins for WLAN_CS, MOSI, SCK, and WLAN_EN. MISO can be
* connected directly because it's an input pin for the Arduino and the Arduino
* can read 3.3V signals directly. For WLAN_IRQ use a pullup resistor of 20K to
* 100K Ohm -- one leg to the Arduino input pin + CC3000 SPI_IRQ pin, the other
* leg to +3.3V.
*
* You can use a level shifter chip like the 74LVC245 or TXB0104 or you can use
* a pair of resistors to make a voltage divider like this:
*
* Arduino pin -----> 560 Ohm --+--> 1K Ohm -----> GND
* |
* |
* +---> CC3000 pin
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
/*
* Memory Analyses
*
* total used free largest
* Mem: 16560 11144 5416 5384
* PID SIZE USED THREAD NAME
* 0 0 0 Idle Task
* 1 876 772 init
* 2 604 588 c3b
* 3 236 220 <pthread0>
*
* 8 364 348 <pthread0>
*
* 9 260 196 <pthread>
* 10 380 364 Telnet dd
* 11 860 844 Telnet sd
*/
#include <nuttx/config.h>
#include "board.h"
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <nuttx/arch.h>
#include <nuttx/wireless/cc3000/nvmem.h>
#include <nuttx/wireless/cc3000/include/sys/socket.h>
#include <nuttx/wireless/cc3000/wlan.h>
#include <nuttx/wireless/cc3000/hci.h>
#include <nuttx/wireless/cc3000/netapp.h>
#include "shell.h"
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
void Initialize(void);
void helpme(void);
int execute(int cmd);
void ShowBufferSize(void);
void StartSmartConfig(void);
void ManualConnect(void);
void ManualAddProfile(void);
void ListAccessPoints(void);
void PrintIPBytes(uint8_t *ipBytes);
void ShowInformation(void);
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define MS_PER_SEC 1000
#define US_PER_MS 1000
#define US_PER_SEC 1000000
/****************************************************************************
* Private Data
****************************************************************************/
static uint8_t isInitialized = false;
#ifdef CONFIG_EXAMPLES_CC3000_MEM_CHECK
static struct mallinfo mmstart;
static struct mallinfo mmprevious;
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
#ifdef CONFIG_EXAMPLES_CC3000_MEM_CHECK
static void show_memory_usage(struct mallinfo *mmbefore,
struct mallinfo *mmafter)
{
int diff;
printf(" total used free largest\n");
printf("Before:%11d%11d%11d%11d\n",
mmbefore->arena, mmbefore->uordblks, mmbefore->fordblks, mmbefore->mxordblk);
printf("After: %11d%11d%11d%11d\n",
mmafter->arena, mmafter->uordblks, mmafter->fordblks, mmafter->mxordblk);
diff = mmbefore->uordblks - mmafter->uordblks;
if (diff < 0)
{
printf("Change:%11d allocated\n", -diff);
}
else if (diff > 0)
{
printf("Change:%11d freed\n", diff);
}
#ifdef CONFIG_EXAMPLES_CC3000_STACK_CHECK
stkmon_disp();
#endif
}
#endif
#ifdef CONFIG_EXAMPLES_CC3000_STACK_CHECK
static char buff[CONFIG_TASK_NAME_SIZE+1];
static void _stkmon_disp(FAR struct tcb_s *tcb, FAR void *arg)
{
#if CONFIG_TASK_NAME_SIZE > 0
strncpy(buff,tcb->name,CONFIG_TASK_NAME_SIZE);
buff[CONFIG_TASK_NAME_SIZE] = '\0';
syslog(LOG_INFO, "%5d %6d %6d %s\n",
tcb->pid, tcb->adj_stack_size, up_check_tcbstack(tcb), buff);
#else
syslog(LOG_INFO, "%5d %6d %6d\n",
tcb->pid, tcb->adj_stack_size, up_check_tcbstack(tcb));
#endif
}
#endif
static bool wait(long timeoutMs, volatile unsigned long *what,
volatile unsigned long is)
{
long t_ms;
struct timeval end, start;
gettimeofday(&start, NULL);
while (*what != is)
{
usleep(10*US_PER_MS);
gettimeofday(&end, NULL);
t_ms = ((end.tv_sec - start.tv_sec) * MS_PER_SEC) + ((end.tv_usec - start.tv_usec) / US_PER_MS) ;
if (t_ms > timeoutMs)
{
return false;
}
}
return true;
}
static bool wait_on(long timeoutMs, volatile unsigned long *what,
volatile unsigned long is, char * msg)
{
printf(msg);
printf("...");
fflush(stdout);
bool ret = wait(timeoutMs,what,is);
if (!ret)
{
printf(" FAILED:Timeout!\n");
}
else
{
printf(" Succeed\n");
}
fflush(stdout);
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
#ifndef CONFIG_EXAMPLES_CC3000_STACK_CHECK
# define stkmon_disp()
#else
void stkmon_disp(void)
{
#if CONFIG_TASK_NAME_SIZE > 0
syslog(LOG_INFO, "%-5s %-6s %-6s %s\n", "PID", "SIZE", "USED", "THREAD NAME");
#else
syslog(LOG_INFO, "%-5s %-6s %-6s\n", "PID", "SIZE", "USED");
#endif
sched_foreach(_stkmon_disp, NULL);
}
#endif
void AsyncEventPrint(void)
{
printf("\n");
switch (lastAsyncEvent)
{
printf("CC3000 Async event: Simple config done\n");
break;
case HCI_EVNT_WLAN_UNSOL_CONNECT:
printf("CC3000 Async event: Unsolicited connect\n");
break;
case HCI_EVNT_WLAN_UNSOL_DISCONNECT:
printf("CC3000 Async event: Unsolicted disconnect\n");
break;
case HCI_EVNT_WLAN_UNSOL_DHCP:
printf("CC3000 Async event: Got IP address via DHCP: ");
printf("%d", dhcpIPAddress[0]);
printf(".");
printf("%d", dhcpIPAddress[1]);
printf(".");
printf("%d", dhcpIPAddress[2]);
printf(".");
printf("%d\n", dhcpIPAddress[3]);
break;
case HCI_EVENT_CC3000_CAN_SHUT_DOWN:
printf("CC3000 Async event: OK to shut down\n");
break;
case HCI_EVNT_WLAN_KEEPALIVE:
/* Once initialized, the CC3000 will send these keepalive events
* every 20 seconds.
*/
printf("CC3000 Async event: Keepalive\n");
return;
break;
default:
printf("AsyncCallback called with unhandled event! (0x%lx)\n",
(unsigned long)lastAsyncEvent);
break;
}
}
void helpme(void)
{
printf("\n+-------------------------------------------+\n");
printf("| Nuttx CC3000 Demo Program |\n");
printf("+-------------------------------------------+\n\n");
printf(" 01 - Initialize the CC3000\n");
printf(" 02 - Show RX & TX buffer sizes, & free RAM\n");
printf(" 03 - Start Smart Config\n");
printf(" 04 - Manually connect to AP\n");
printf(" 05 - Manually add connection profile\n");
printf(" 06 - List access points\n");
printf(" 07 - Show CC3000 information\n");
printf(" 08 - Telnet\n");
printf("\n Type 01-07 to select above option: ");
}
int execute(int cmd)
{
int ret = 0;
if (asyncNotificationWaiting)
{
asyncNotificationWaiting = false;
AsyncEventPrint();
}
printf("\n");
switch(cmd)
{
case '1':
Initialize();
break;
case '2':
ShowBufferSize();
break;
case '3':
StartSmartConfig();
break;
case '4':
ManualConnect();
break;
case '5':
ManualAddProfile();
break;
case '6':
ListAccessPoints();
break;
case '7':
ShowInformation();
break;
case '8':
if (!isInitialized)
{
Initialize();
}
#ifdef CONFIG_EXAMPLES_CC3000_MEM_CHECK
mmprevious= mallinfo();
show_memory_usage(&mmstart,&mmprevious);
#endif
shell_main(0, 0);
#ifdef CONFIG_EXAMPLES_CC3000_MEM_CHECK
mmprevious= mallinfo();
show_memory_usage(&mmstart,&mmprevious);
#endif
break;
case 'q':
case 'Q':
ret = 1;
break;
default:
printf("**Unknown command \"%d\" **\n", cmd);
break;
}
return ret;
}
void Initialize(void)
{
#ifdef CONFIG_EXAMPLES_CC3000_MEM_CHECK
mmstart = mallinfo();
memcpy(&mmprevious, &mmstart, sizeof(struct mallinfo));
show_memory_usage(&mmstart,&mmprevious);
#endif
uint8_t fancyBuffer[MAC_ADDR_LEN];
if (isInitialized)
{
printf("CC3000 already initialized. Shutting down and restarting...\n");
wlan_stop();
usleep(1000000); /* Delay 1s */
}
printf("Initializing CC3000...\n");
CC3000_Init();
#ifdef CONFIG_EXAMPLES_CC3000_STACK_CHECK
stkmon_disp();
#endif
printf(" CC3000 init complete.\n");
if (nvmem_read_sp_version(fancyBuffer) == 0)
{
printf(" Firmware version is: ");
printf("%d", fancyBuffer[0]);
printf(".");
printf("%d\n", fancyBuffer[1]);
}
else
{
printf("Unable to get firmware version. Can't continue.\n");
return;
}
#if 0
if (nvmem_get_mac_address(fancyBuffer) == 0)
{
printf(" MAC address: ");
for (i = 0; i < MAC_ADDR_LEN; i++)
{
if (i != 0)
{
printf(":");
}
printf("%x", fancyBuffer[i]);
}
printf("\n");
isInitialized = true;
}
else
{
printf("Unable to get MAC address. Can't continue.\n");
}
#else
isInitialized = true;
#endif
#ifdef CONFIG_EXAMPLES_CC3000_MEM_CHECK
mmprevious = mallinfo();
show_memory_usage(&mmstart,&mmprevious);
#endif
}
/* This just shows the compiled size of the transmit & recieve buffers */
void ShowBufferSize(void)
{
printf("Transmit buffer is %d bytes", CC3000_TX_BUFFER_SIZE);
printf("Receive buffer is %d bytes", CC3000_RX_BUFFER_SIZE);
}
/* Smart Config is TI's way to let you connect your device to your WiFi network
* without needing a keyboard and display to enter the network name, password,
* etc. You run a little app on your iPhone, Android device, or laptop with Java
* and it sends the config info to the CC3000 automagically, so the end user
* doesn't need to do anything complicated. More details here:
*
* http://processors.wiki.ti.com/index.php/CC3000_Smart_Config
*
* This example deletes any currently saved WiFi profiles and goes over the top
* with error checking, so it's easier to see exactly what's going on. You
* probably won't need all of this code for your own Smart Config implementation.
*
* This example also doesn't use any of the AES enhanced security setup API calls
* because frankly they're weirder than I want to deal with.
*/
/* The Simple Config Prefix always needs to be 'TTT' */
char simpleConfigPrefix[] = {'T', 'T', 'T'};
/* This is the default Device Name that TI's Smart Config app for iPhone etc. use.
* You can change it to whatever you want, but then your users will need to type
* that name into their phone or tablet when they run Smart Config.
*/
char device_name[] = "CC3000";
void StartSmartConfig(void)
{
long rval;
if (!isInitialized)
{
printf("CC3000 not initialized; can't run Smart Config.\n");
return;
}
printf("Starting Smart Config\n");
printf(" Disabling auto-connect policy...");
if ((rval = wlan_ioctl_set_connection_policy(DISABLE, DISABLE, DISABLE)) !=0)
{
printf(" Failed!\n Setting auto connection policy failed, error: %lx\n",
(unsigned long)rval);
return;
}
printf(" Succeed\n");
printf(" Deleting all existing profiles...");
fflush(stdout);
if ((rval = wlan_ioctl_del_profile(255)) !=0)
{
printf(" Failed!\n Deleting all profiles failed, error: %lx\n",
(unsigned long)rval);
return;
}
printf(" Succeed\n");
wait_on(20*MS_PER_SEC, &ulCC3000Connected, 0, " Waiting until disconnected");
printf(" Setting smart config prefix...");
fflush(stdout);
if ((rval = wlan_smart_config_set_prefix(simpleConfigPrefix)) !=0)
{
printf(" Failed!\n Setting smart config prefix failed, error: %lx",
(unsigned long)rval);
return;
}
printf(" Succeed\n");
printf(" Starting smart config...");
fflush(stdout);
if ((rval = wlan_smart_config_start(0)) !=0)
{
printf(" Failed!\n Starting smart config failed, error: %lx\n",
(unsigned long)rval);
return;
}
printf(" Succeed\n");
if (!wait_on(30*MS_PER_SEC, &ulSmartConfigFinished, 1, " Waiting on Starting smart config done"))
{
printf(" Timed out waiting for Smart Config to finish. Hopefully it did anyway\n");
}
printf(" Smart Config packet %s!\n",ulSmartConfigFinished ? "seen" : "NOT seen");
printf(" Enabling auto-connect policy...");
fflush(stdout);
if ((rval = wlan_ioctl_set_connection_policy(DISABLE, DISABLE, ENABLE)) !=0)
{
printf(" Failed!\n Setting auto connection policy failed, error: %lx\n",
(unsigned long)rval);
return;
}
printf(" Succeed\n");
printf(" Stopping CC3000...\n");
fflush(stdout);
wlan_stop(); /* No error returned here, so nothing to check */
printf(" Pausing for 2 seconds...\n");
usleep(2000000);
printf(" Restarting CC3000... \n");
wlan_start(0); /* No error returned here, so nothing to check */
if (!wait_on(20*MS_PER_SEC, &ulCC3000Connected, 1, " Waiting for connection to AP"))
{
printf(" Timed out waiting for connection to AP\n");
return;
}
if (!wait_on(15*MS_PER_SEC, &ulCC3000DHCP, 1, " Waiting for IP address from DHCP"))
{
printf(" Timed out waiting for IP address from DHCP\n");
return;
}
printf(" Sending mDNS broadcast to signal we're done with Smart Config...\n");
fflush(stdout);
/* The API documentation says mdnsAdvertiser() is supposed to return 0 on
* success and SOC_ERROR on failure, but it looks like what it actually
* returns is the socket number it used. So we ignore it.
*/
mdnsadvertiser(1, device_name, strlen(device_name));
printf(" Smart Config finished Successfully!\n");
ShowInformation();
fflush(stdout);
}
/* This is an example of how you'd connect the CC3000 to an AP without using
* Smart Config or a stored profile.
*
* All the code above wlan_connect() is just for this demo program; if you're
* always going to connect to your network this way you wouldn't need it.
*/
void ManualConnect(void)
{
char ssidName[] = "YourAP";
char AP_KEY[] = "yourpass";
uint8_t rval;
if (!isInitialized)
{
printf("CC3000 not initialized; can't run manual connect.\n");
return;
}
printf("Starting manual connect...\n");
printf(" Disabling auto-connect policy...\n");
(void)wlan_ioctl_set_connection_policy(DISABLE, DISABLE, DISABLE);
printf(" Deleting all existing profiles...\n");
(void)wlan_ioctl_del_profile(255);
wait_on(15*MS_PER_SEC, &ulCC3000Connected, 0, " Waiting until disconnected");
printf(" Manually connecting...\n");
/* Parameter 1 is the security type: WLAN_SEC_UNSEC, WLAN_SEC_WEP,
* WLAN_SEC_WPA or WLAN_SEC_WPA2
* Parameter 3 is the MAC adddress of the AP. All the TI examples
* use NULL. I suppose you would want to specify this
* if you were security paranoid.
*/
rval = wlan_connect(WLAN_SEC_WPA2,
ssidName,
strlen(ssidName),
NULL,
(uint8_t *)AP_KEY,
strlen(AP_KEY));
if (rval == 0)
{
printf(" Manual connect success.\n");
}
else
{
printf(" Unusual return value: %d\n", rval);
}
}
/* This is an example of manually adding a WLAN profile to the CC3000. See
* wlan_ioctl_set_connection_policy() for more details of how profiles are
* used but basically there's 7 slots where you can store AP info and if
* the connection policy is set to auto_start then the CC3000 will go
* through its profile table and try to auto-connect to something it knows
* about after it boots up.
*
* Note the API documentation for wlan_add_profile is wrong. It says it
* returns 0 on success and -1 on failure. What it really returns is
* the stored profile number (0-6, since the CC3000 can store 7) or
* 255 on failure.
*
* Unfortunately the API doesn't give you any way to see how many profiles
* are in use or which profile is stored in which slot, so if you want to
* manage multiple profiles you'll need to do that yourself.
*/
void ManualAddProfile(void)
{
char ssidName[] = "YourAP";
char AP_KEY[] = "yourpass";
uint8_t rval;
if (!isInitialized)
{
printf("CC3000 not initialized; can't run manual add profile.");
return;
}
printf("Starting manual add profile...\n");
printf(" Disabling auto connection...\n");
wlan_ioctl_set_connection_policy(DISABLE, DISABLE, DISABLE);
printf(" Adding profile...\n");
rval = wlan_add_profile (
WLAN_SEC_WPA2, /* WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2 */
(uint8_t *)ssidName,
strlen(ssidName),
NULL, /* BSSID, TI always uses NULL */
0, /* Profile priority */
0x18, /* Key length for WEP security, undocumented why this needs to be 0x18 */
0x1e, /* Key index, undocumented why this needs to be 0x1e */
0x2, /* key management, undocumented why this needs to be 2 */
(uint8_t *)AP_KEY, /* WPA security key */
strlen(AP_KEY) /* WPA security key length */
);
if (rval!=255)
{
/* This code is lifted from http://e2e.ti.com/support/low_power_rf/f/851/p/180859/672551.aspx;
* the actual API documentation on wlan_add_profile doesn't specify any of this....
*/
printf(" Manual add profile success, stored in profile: %d\n", rval);
printf(" Enabling auto connection...\n");
wlan_ioctl_set_connection_policy(DISABLE, DISABLE, ENABLE);
printf(" Stopping CC3000...\n");
wlan_stop();
printf(" Stopping for 5 seconds...\n");
usleep(5000000);
printf(" Restarting CC3000...\n");
wlan_start(0);
printf(" Manual add profile done!");
}
else
{
printf(" Manual add profile failured (all profiles full?).");
}
}
/* The call wlan_ioctl_get_scan_results returns this structure. I couldn't
* find it in the TI library so it's defined here. It's 50 bytes with
* a semi weird arrangement but fortunately it's not as bad as it looks.
*
* numNetworksFound - 4 bytes - On the first call to wlan_ioctl_get_scan_results
* this will be set to how many APs the CC3000 sees. Although
* with 4 bytes the CC3000 could see 4 billion APs in my testing
* this number was always 20 or less so there's probably an
* internal memory limit.
*
* results - 4 bytes - 0=aged results, 1=results valid, 2=no results. Why TI
* used 32 bits to store something that could be done in 2,
* and how this field is different than isValid below, is
* a mystery to me so I just igore this field completely.
*
* isValid & rssi - 1 byte - a packed structure. The top bit (isValid)
* indicates whether or not this structure has valid data,
* the bottom 7 bits (rssi) are the signal strength of this AP.
*
* securityMode & ssidLength - 1 byte - another packed structure. The top 2
* bits (securityMode) show how the AP is configured:
* 0 - open / no security
* 1 - WEP
* 2 - WPA
* 3 - WPA2
* ssidLength is the lower 6 bytes and shows how many characters
* (up to 32) of the ssid_name field are valid
*
* frameTime - 2 bytes - how long, in seconds, since the CC3000 saw this AP
* beacon
*
* ssid_name - 32 bytes - The ssid name for this AP. Note that this isn't a
* regular null-terminated C string so you can't use it
* directly with a strcpy() or Serial.println() etc. and you'll
* need a 33-byte string to store it (32 valid characters +
* null terminator)
*
* bssid - 6 bytes - the MAC address of this AP
*/
typedef struct scanResults
{
unsigned long numNetworksFound;
unsigned long results;
unsigned isValid:1;
unsigned rssi:7;
unsigned securityMode:2;
unsigned ssidLength:6;
uint16_t frameTime;
uint8_t ssid_name[32];
uint8_t bssid[6];
} scanResults;
#define NUM_CHANNELS 16
void ListAccessPoints(void)
{
unsigned long aiIntervalList[NUM_CHANNELS];
uint8_t rval;
scanResults sr;
int apCounter, i;
char localB[33];
if (!isInitialized)
{
printf("CC3000 not initialized; can't list access points.\n");
return;
}
printf("List visible access points\n");
printf(" Setting scan parameters...\n");
for (i=0; i<NUM_CHANNELS; i++)
{
aiIntervalList[i] = 2000;
}
rval = wlan_ioctl_set_scan_params(
1000, /* Enable start application scan */
100, /* Minimum dwell time on each channel */
100, /* Maximum dwell time on each channel */
5, /* Number of probe requests */
0x7ff, /* Channel mask */
-80, /* RSSI threshold */
0, /* SNR threshold */
205, /* Probe TX power */
aiIntervalList /* Table of scan intervals per channel */
);
if (rval!=0)
{
printf(" Got back unusual result from wlan_ioctl_set_scan_params, can't continue: %d\n", rval);
return;
}
#if 0
printf(" Sleeping 5 seconds to let the CC3000 discover APs...\n");
usleep(5000000);
#endif
printf(" Getting AP count...\n");
/* On the first call to get_scan_results, sr.numNetworksFound will return the
* actual # of APs currently seen. Get that # then loop through and print
* out what's found.
*/
if ((rval=wlan_ioctl_get_scan_results(2000, (uint8_t *)&sr))!=0)
{
printf(" Got back unusual result from wlan_ioctl_get scan results, can't continue: %d\n", rval);
return;
}
apCounter = sr.numNetworksFound;
printf(" Number of APs found: %d\n", apCounter);
do
{
if (sr.isValid)
{
printf(" ");
switch (sr.securityMode)
{
case WLAN_SEC_UNSEC: /* 0 */
printf("OPEN ");
break;
case WLAN_SEC_WEP: /* 1 */
printf("WEP ");
break;
case WLAN_SEC_WPA: /* 2 */
printf("WPA ");
break;
case WLAN_SEC_WPA2: /* 3 */
printf("WPA2 ");
break;
}
sprintf(localB, "%3u ", sr.rssi);
printf("%s", localB);
memset(localB, 0, 33);
memcpy(localB, sr.ssid_name, sr.ssidLength);
printf("%s\n", localB);
}
if (--apCounter>0)
{
if ((rval=wlan_ioctl_get_scan_results(2000, (uint8_t *)&sr)) !=0)
{
printf(" Got back unusual result from wlan_ioctl_get scan, can't continue: %d\n", rval);
return;
}
}
}
while (apCounter>0);
printf(" Access Point list finished.\n");
}
void PrintIPBytes(uint8_t *ipBytes)
{
printf("%d.%d.%d.%d\n", ipBytes[3], ipBytes[2], ipBytes[1], ipBytes[0]);
}
/* All the data in all the fields from netapp_ipconfig() are reversed,
* e.g. an IP address is read via bytes 3,2,1,0 instead of bytes
* 0,1,2,3 and the MAC address is read via bytes 5,4,3,2,1,0 instead
* of 0,1,2,3,4,5.
*
* N.B. TI is inconsistent here; nvmem_get_mac_address() returns them in
* the right order etc.
*/
void ShowInformation(void)
{
tNetappIpconfigRetArgs inf;
char localB[33];
int i;
if (!isInitialized)
{
printf("CC3000 not initialized; can't get information.\n");
return;
}
printf("CC3000 information:\n");
netapp_ipconfig(&inf);
printf(" IP address: ");
PrintIPBytes(inf.aucIP);
printf(" Subnet mask: ");
PrintIPBytes(inf.aucSubnetMask);
printf(" Gateway: ");
PrintIPBytes(inf.aucDefaultGateway);
printf(" DHCP server: ");
PrintIPBytes(inf.aucDHCPServer);
printf(" DNS server: ");
PrintIPBytes(inf.aucDNSServer);
printf(" MAC address: ");
for (i=(MAC_ADDR_LEN-1); i>=0; i--)
{
if (i!=(MAC_ADDR_LEN-1))
{
printf(":");
}
printf("%x", inf.uaMacAddr[i]);
}
printf("\n");
memset(localB, 0, sizeof(localB));
strncpy(localB, (char*)inf.uaSSID,sizeof(localB));
printf(" Connected to SSID: %s\n", localB);
}
#ifdef CONFIG_BUILD_KERNEL
int main(int argc, FAR char *argv[])
#else
int c3b_main(int argc, char *argv[])
#endif
{
char ch='0';
do
{
helpme();
stkmon_disp();
ch = getchar();
}
while (execute(ch) == 0);
return 0;
}

View File

@ -1,238 +0,0 @@
/****************************************************************************
* apps/examples/cc3000/shell.c
*
* Copyright (C) 2013, 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* This is a leverage of similar logic from uIP:
*
* Author: Adam Dunkels <adam@sics.se>
* Copyright (c) 2003, Adam Dunkels.
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h>
#include <arpa/inet.h>
#include "netutils/telnetd.h"
#include "netutils/netlib.h"
#include "shell.h"
#include "nshlib/nshlib.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
struct ptentry_s
{
FAR const char *commandstr;
void (*pfunc)(int argc, char **argv);
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static void shell_help(int argc, char **argv);
static void shell_quit(int argc, char **argv);
static void shell_unknown(int argc, char **argv);
static void shell_parse(FAR char *line, int len);
/****************************************************************************
* Private Data
****************************************************************************/
static struct ptentry_s g_parsetab[] =
{
{"help", shell_help},
{"exit", shell_quit},
{"?", shell_help},
{NULL, shell_unknown}
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: shell_help
****************************************************************************/
static void shell_help(int argc, char **argv)
{
printf("Available commands:\n");
printf(" help, ? - show help\n");
printf(" exit - exit shell\n");
}
/****************************************************************************
* Name: shell_help
****************************************************************************/
static void shell_unknown(int argc, char **argv)
{
if (argv[0])
{
printf("Unknown command: %s\n", argv[0]);
}
}
/****************************************************************************
* Name: shell_quit
****************************************************************************/
static void shell_quit(int argc, char **argv)
{
printf("Bye!\n");
#ifdef CONFIG_EXAMPLES_CC3000_MEM_CHECK
stkmon_disp();
#endif
exit(0);
}
/****************************************************************************
* Name: shell_parse
****************************************************************************/
static void shell_parse(FAR char *line, int len)
{
struct ptentry_s *entry;
FAR char *cmd;
FAR char *saveptr;
/* Get the command from the beginning the line */
cmd = strtok_r(line, " \t\n\r\f\v", &saveptr);
if (cmd)
{
/* Now find the matching command in the command table */
for (entry = g_parsetab; entry->commandstr != NULL; entry++)
{
if (strncmp(entry->commandstr, cmd, strlen(entry->commandstr)) == 0)
{
break;
}
}
entry->pfunc(1, &cmd);
}
}
/****************************************************************************
* Name: shell_session
****************************************************************************/
int shell_session(int argc, char *argv[])
{
char line[128];
printf("CC3000 command shell -- NuttX style\n");
printf("Type '?' and return for help\n");
#ifdef CONFIG_EXAMPLES_CC3000_MEM_CHECK
stkmon_disp();
#endif
for (;;)
{
printf(SHELL_PROMPT);
fflush(stdout);
if (fgets(line, 128, stdin) == NULL)
{
break;
}
shell_parse(line, 128);
}
return 0;
}
/****************************************************************************
* Name: shell_netinit
****************************************************************************/
static void shell_netinit(void)
{
}
/****************************************************************************
* Public Functions
****************************************************************************/
#ifdef CONFIG_BUILD_KERNEL
int main(int argc, FAR char *argv[])
#else
int shell_main(int argc, char *argv[])
#endif
{
struct telnetd_config_s config;
int ret;
/* Configure the network */
printf("shell_main: Initializing the network\n");
shell_netinit();
/* Configure the telnet daemon */
config.d_port = HTONS(23);
config.d_family = AF_INET;
config.d_priority = CONFIG_EXAMPLES_TELNETD_DAEMONPRIO;
config.d_stacksize = CONFIG_EXAMPLES_TELNETD_DAEMONSTACKSIZE;
config.t_priority = CONFIG_EXAMPLES_TELNETD_CLIENTPRIO;
config.t_stacksize = CONFIG_EXAMPLES_TELNETD_CLIENTSTACKSIZE;
config.t_entry = nsh_consolemain;
/* Start the telnet daemon */
printf("shell_main: Starting the Telnet daemon\n");
ret = telnetd_start(&config);
if (ret < 0)
{
printf("Failed to tart the Telnet daemon\n");
}
printf("shell_main: Exiting\n");
return 0;
}

View File

@ -1,83 +0,0 @@
/****************************************************************************
* apps/examples/cc3000/shell.h
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*
****************************************************************************/
#ifndef __APPS_EXAMPLES_CC3000_SHELL_H
#define __APPS_EXAMPLES_CC3000_SHELL_H
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
/* CONFIG_EXAMPLES_TELNETD_DAEMONPRIO - Priority of the Telnet daemon.
* Default: SCHED_PRIORITY_DEFAULT
* CONFIG_EXAMPLES_TELNETD_DAEMONSTACKSIZE - Stack size allocated for the
* Telnet daemon. Default: 2048
* CONFIG_EXAMPLES_TELNETD_CLIENTPRIO- Priority of the Telnet client.
* Default: SCHED_PRIORITY_DEFAULT
* CONFIG_EXAMPLES_TELNETD_CLIENTSTACKSIZE - Stack size allocated for the
* Telnet client. Default: 2048
* CONFIG_EXAMPLES_TELNETD_NOMAC - If the hardware has no MAC address of its
* own, define this =y to provide a bogus address for testing.
* CONFIG_EXAMPLES_TELNETD_IPADDR - The target IP address. Default 10.0.0.2
* CONFIG_EXAMPLES_TELNETD_DRIPADDR - The default router address. Default
* 10.0.0.1
* CONFIG_EXAMPLES_TELNETD_NETMASK - The network mask. Default: 255.255.255.0
*/
#ifndef CONFIG_EXAMPLES_TELNETD_DAEMONPRIO
# define CONFIG_EXAMPLES_TELNETD_DAEMONPRIO SCHED_PRIORITY_DEFAULT
#endif
#ifndef CONFIG_EXAMPLES_TELNETD_DAEMONSTACKSIZE
# define CONFIG_EXAMPLES_TELNETD_DAEMONSTACKSIZE 384
#endif
#ifndef CONFIG_EXAMPLES_TELNETD_CLIENTPRIO
# define CONFIG_EXAMPLES_TELNETD_CLIENTPRIO SCHED_PRIORITY_DEFAULT
#endif
#ifndef CONFIG_EXAMPLES_TELNETD_CLIENTSTACKSIZE
# define CONFIG_EXAMPLES_TELNETD_CLIENTSTACKSIZE 894
#endif
/* Other definitions ********************************************************/
#define SHELL_PROMPT "CC3000 1.0> "
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
int shell_main(int argc, char *argv[]);
#endif /* __APPS_EXAMPLES_CC3000_SHELL_H */

View File

@ -1,115 +0,0 @@
/****************************************************************************
* apps/examples/cc3000/telnetd.c
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 Gregory Nutt 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 OWNER 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.
*
****************************************************************************/
#ifndef __APPS_EXAMPLES_CC3000_TELNETD_H
#define __APPS_EXAMPLES_CC3000_TELNETD_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Types
****************************************************************************/
/* This structure represents the overall state of one telnet daemon instance
* (Yes, multiple telnet daemons are supported).
*/
struct telnetd_s
{
int port; /* The port to listen on (in network byte order) */
int priority; /* The execution priority of the spawned task, */
int stacksize; /* The stack size needed by the spawned task */
main_t entry; /* The entrypoint of the task to spawn when a new
* connection is accepted. */
};
/* This structure is used to passed information to telnet daemon when it
* started. It contains global information visable to all telnet daemons.
*/
struct telnetd_common_s
{
uint8_t ndaemons; /* The total number of daemons running */
sem_t startsem; /* Enforces one-at-a-time startup */
sem_t exclsem; /* Enforces exclusive access to 'minor' */
FAR struct telnetd_s *daemon; /* Describes the new daemon */
int minor; /* The next minor number to use */
};
/****************************************************************************
* Public Data
****************************************************************************/
/* This structure is used to passed information to telnet daemon when it
* started. It contains global information visable to all telnet daemons.
*/
extern struct telnetd_common_s g_telnetdcommon;
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: telnetd_driver
*
* Description:
* Create a character driver to "wrap" the telnet session. This function
* will select and return a unique path for the new telnet device.
*
* Parameters:
* sd - The socket descriptor that represents the new telnet connection.
* daemon - A pointer to the structure representing the overall state of
* this instance of the telnet daemon.
*
* Return:
* An allocated string represent the full path to the created driver. The
* receiver of the string must de-allocate this memory when it is no longer
* needed. NULL is returned on a failure.
*
****************************************************************************/
FAR char *telnetd_driver(long sd, FAR struct telnetd_s *daemon);
#endif /* __APPS_EXAMPLES_CC3000_TELNETD_H */

View File

@ -1,349 +0,0 @@
/****************************************************************************
* apps/examples/cc3000/telnetd_daemon.c
*
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 Gregory Nutt 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 OWNER 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <nuttx/wireless/cc3000/include/sys/socket.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sched.h>
#include <errno.h>
#include <debug.h>
#include <netinet/in.h>
#include "netutils/telnetd.h"
#include "netutils/netlib.h"
#include "telnetd.h"
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/* This structure is used to passed information to telnet daemon when it
* started.
*/
struct telnetd_common_s g_telnetdcommon;
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: telnetd_daemon
*
* Description:
* This function is the Telnet daemon. It does not return (unless an
* error occurs).
*
* Parameters:
* Standard task start up arguments.
*
* Return:
* Does not return unless an error occurs.
*
****************************************************************************/
static int telnetd_daemon(int argc, char *argv[])
{
FAR struct telnetd_s *daemon;
struct sockaddr_in myaddr;
#ifdef CONFIG_NET_SOLINGER
struct linger ling;
#endif
socklen_t addrlen;
FAR char *devpath;
pid_t pid;
int listensd;
int acceptsd;
int drvrfd;
#ifdef CONFIG_NET_HAVE_REUSEADDR
int optval;
#endif
/* Get daemon startup info */
daemon = g_telnetdcommon.daemon;
g_telnetdcommon.daemon = NULL;
sem_post(&g_telnetdcommon.startsem);
DEBUGASSERT(daemon != NULL);
/* Create a new TCP socket to use to listen for connections */
listensd = socket(PF_INET, SOCK_STREAM, 0);
if (listensd < 0)
{
int errval = errno;
nerr("ERROR: socket failure: %d\n", errval);
return -errval;
}
/* Set socket to reuse address */
#ifdef CONFIG_NET_HAVE_REUSEADDR
optval = 1;
if (setsockopt(listensd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)) < 0)
{
nerr("ERROR: setsockopt SO_REUSEADDR failure: %d\n", errno);
goto errout_with_socket;
}
#endif
/* Bind the socket to a local address */
myaddr.sin_family = AF_INET;
myaddr.sin_port = daemon->port;
myaddr.sin_addr.s_addr = INADDR_ANY;
if (bind(listensd, (struct sockaddr*)&myaddr, sizeof(struct sockaddr_in)) < 0)
{
nerr("ERROR: bind failure: %d\n", errno);
goto errout_with_socket;
}
/* Listen for connections on the bound TCP socket */
if (listen(listensd, 5) < 0)
{
nerr("ERROR: listen failure %d\n", errno);
goto errout_with_socket;
}
/* Now go silent. */
#ifndef CONFIG_DEBUG_FEATURES
close(0);
close(1);
close(2);
#endif
/* Begin accepting connections */
for (;;)
{
ninfo("Accepting connections on port %d\n", ntohs(daemon->port));
addrlen = sizeof(struct sockaddr_in);
acceptsd = accept(listensd, (struct sockaddr*)&myaddr, &addrlen);
if (acceptsd < 0)
{
nerr("ERROR: accept failed: %d\n", errno);
goto errout_with_socket;
}
/* Configure to "linger" until all data is sent when the socket is closed */
#ifdef CONFIG_NET_SOLINGER
ling.l_onoff = 1;
ling.l_linger = 30; /* timeout is seconds */
if (setsockopt(acceptsd, SOL_SOCKET, SO_LINGER, &ling, sizeof(struct linger)) < 0)
{
nerr("ERROR: setsockopt failed: %d\n", errno);
goto errout_with_acceptsd;
}
#endif
/* Create a character device to "wrap" the accepted socket descriptor */
ninfo("Creating the telnet driver\n");
devpath = telnetd_driver(acceptsd, daemon);
if (devpath == NULL)
{
nerr("ERROR: telnetd_driver failed\n");
goto errout_with_acceptsd;
}
/* Open the driver */
ninfo("Opening the telnet driver\n");
drvrfd = open(devpath, O_RDWR);
if (drvrfd < 0)
{
nerr("ERROR: Failed to open %s: %d\n", devpath, errno);
goto errout_with_acceptsd;
}
/* We can now free the driver string */
free(devpath);
/* Use this driver as stdin, stdout, and stderror */
(void)dup2(drvrfd, 0);
(void)dup2(drvrfd, 1);
(void)dup2(drvrfd, 2);
/* And we can close our original driver fd */
if (drvrfd > 2)
{
close(drvrfd);
}
/* Create a task to handle the connection. The created task
* will inherit the new stdin, stdout, and stderr.
*/
ninfo("Starting the telnet session\n");
pid = task_create("Telnet session", daemon->priority, daemon->stacksize,
daemon->entry, NULL);
if (pid < 0)
{
nerr("ERROR: Failed start the telnet session: %d\n", errno);
goto errout_with_acceptsd;
}
/* Forget about the connection. */
close(0);
close(1);
close(2);
}
errout_with_acceptsd:
close(acceptsd);
errout_with_socket:
close(listensd);
free(daemon);
return 1;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: telnetd_start
*
* Description:
* Start the telnet daemon.
*
* Parameters:
* config A pointer to a configuration structure that characterizes the
* telnet daemon. This configuration structure may be defined
* on the caller's stack because it is not retained by the
* daemon.
*
* Return:
* The process ID (pid) of the new telnet daemon is returned on
* success; A negated errno is returned if the daemon was not successfully
* started.
*
****************************************************************************/
int telnetd_start(FAR struct telnetd_config_s *config)
{
FAR struct telnetd_s *daemon;
pid_t pid;
int ret;
/* Allocate a state structure for the new daemon */
daemon = (FAR struct telnetd_s *)malloc(sizeof(struct telnetd_s));
if (!daemon)
{
return -ENOMEM;
}
/* Initialize the daemon structure */
daemon->port = config->d_port;
daemon->priority = config->t_priority;
daemon->stacksize = config->t_stacksize;
daemon->entry = config->t_entry;
/* Initialize the common structure if this is the first daemon */
if (g_telnetdcommon.ndaemons < 1)
{
sem_init(&g_telnetdcommon.startsem, 0, 0);
sem_init(&g_telnetdcommon.exclsem, 0, 1);
g_telnetdcommon.minor = 0;
}
/* Then start the new daemon */
g_telnetdcommon.daemon = daemon;
pid = task_create("Telnet daemon", config->d_priority, config->d_stacksize,
telnetd_daemon, NULL);
if (pid < 0)
{
int errval = errno;
free(daemon);
nerr("ERROR: Failed to start the telnet daemon: %d\n", errval);
return -errval;
}
/* Then wait for the daemon to start and complete the handshake */
do
{
ret = sem_wait(&g_telnetdcommon.startsem);
/* The only expected error condition is for sem_wait to be awakened by
* a receipt of a signal.
*/
if (ret < 0)
{
DEBUGASSERT(errno == EINTR || errno == ECANCELED);
}
}
while (ret < 0);
/* Return success */
return pid;
}

View File

@ -1,811 +0,0 @@
/****************************************************************************
* apps/examples/cc3000/telnetd_driver.c
*
* Copyright (C) 2007, 2009, 2011-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* This is a leverage of similar logic from uIP which has a compatible BSD
* license:
*
* Author: Adam Dunkels <adam@sics.se>
* Copyright (c) 2003, Adam Dunkels.
* 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 Institute, NuttX 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 INSTITUTE 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 INSTITUTE 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <nuttx/wireless/cc3000/include/sys/socket.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <poll.h>
#include <errno.h>
#include <nuttx/fs/fs.h>
#include <debug.h>
#include <nuttx/net/net.h>
#include "netutils/telnetd.h"
#include "telnetd.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Telnet protocol stuff ****************************************************/
#define ISO_nl 0x0a
#define ISO_cr 0x0d
#define TELNET_IAC 255
#define TELNET_WILL 251
#define TELNET_WONT 252
#define TELNET_DO 253
#define TELNET_DONT 254
#define TELNET_RXBUFFER_SIZE 256
#define TELNET_TXBUFFER_SIZE 256
/* Device stuff *************************************************************/
#define TELNETD_DEVFMT "/dev/telnetd%d"
/****************************************************************************
* Private Types
****************************************************************************/
/* The state of the telnet parser */
enum telnetd_state_e
{
STATE_NORMAL = 0,
STATE_IAC,
STATE_WILL,
STATE_WONT,
STATE_DO,
STATE_DONT
};
/* This structure describes the internal state of the driver */
struct telnetd_dev_s
{
sem_t td_exclsem; /* Enforces mutually exclusive access */
uint8_t td_state; /* (See telnetd_state_e) */
uint8_t td_pending; /* Number of valid, pending bytes in the rxbuffer */
uint8_t td_offset; /* Offset to the valid, pending bytes in the rxbuffer */
uint8_t td_crefs; /* The number of open references to the session */
int td_minor; /* Minor device number */
long td_psock; /* A clone of the internal socket structure */
char td_rxbuffer[TELNET_RXBUFFER_SIZE];
char td_txbuffer[TELNET_TXBUFFER_SIZE];
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* Support functions */
#ifdef CONFIG_TELNETD_DUMPBUFFER
static inline void telnetd_dumpbuffer(FAR const char *msg,
FAR const char *buffer, unsigned int nbytes);
#else
# define telnetd_dumpbuffer(msg,buffer,nbytes)
#endif
static void telnetd_getchar(FAR struct telnetd_dev_s *priv, uint8_t ch,
FAR char *dest, int *nread);
static ssize_t telnetd_receive(FAR struct telnetd_dev_s *priv,
FAR const char *src, size_t srclen, FAR char *dest,
size_t destlen);
static bool telnetd_putchar(FAR struct telnetd_dev_s *priv, uint8_t ch,
int *nwritten);
static void telnetd_sendopt(FAR struct telnetd_dev_s *priv, uint8_t option,
uint8_t value);
/* Character driver methods */
static int telnetd_open(FAR struct file *filep);
static int telnetd_close(FAR struct file *filep);
static ssize_t telnetd_read(FAR struct file *, FAR char *, size_t);
static ssize_t telnetd_write(FAR struct file *, FAR const char *, size_t);
static int telnetd_ioctl(FAR struct file *filep, int cmd,
unsigned long arg);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct file_operations g_telnetdfops =
{
telnetd_open, /* open */
telnetd_close, /* close */
telnetd_read, /* read */
telnetd_write, /* write */
0, /* seek */
telnetd_ioctl /* ioctl */
#ifndef CONFIG_DISABLE_POLL
, 0 /* poll */
#endif
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: telnetd_dumpbuffer
*
* Description:
* Dump a buffer of data (debug only)
*
****************************************************************************/
#ifdef CONFIG_TELNETD_DUMPBUFFER
static inline void telnetd_dumpbuffer(FAR const char *msg,
FAR const char *buffer,
unsigned int nbytes)
{
/* CONFIG_DEBUG_FEATURES, CONFIG_DEBUG_INFO, and CONFIG_DEBUG_NET have to be
* defined or the following does nothing.
*/
ninfodumpbuffer(msg, (FAR const uint8_t*)buffer, nbytes);
}
#endif
/****************************************************************************
* Name: telnetd_getchar
*
* Description:
* Get another character for the user received buffer from the RX buffer
*
****************************************************************************/
static void telnetd_getchar(FAR struct telnetd_dev_s *priv, uint8_t ch,
FAR char *dest, int *nread)
{
register int index;
/* Ignore carriage returns */
if (ch != ISO_cr)
{
/* Add all other characters to the destination buffer */
index = *nread;
dest[index++] = ch;
*nread = index;
}
}
/****************************************************************************
* Name: telnetd_receive
*
* Description:
* Process a received telenet buffer
*
****************************************************************************/
static ssize_t telnetd_receive(FAR struct telnetd_dev_s *priv, FAR const char *src,
size_t srclen, FAR char *dest, size_t destlen)
{
int nread;
uint8_t ch;
ninfo("srclen: %d destlen: %d\n", srclen, destlen);
for (nread = 0; srclen > 0 && nread < destlen; srclen--)
{
ch = *src++;
ninfo("ch=%02x state=%d\n", ch, priv->td_state);
switch (priv->td_state)
{
case STATE_IAC:
if (ch == TELNET_IAC)
{
telnetd_getchar(priv, ch, dest, &nread);
priv->td_state = STATE_NORMAL;
}
else
{
switch (ch)
{
case TELNET_WILL:
priv->td_state = STATE_WILL;
break;
case TELNET_WONT:
priv->td_state = STATE_WONT;
break;
case TELNET_DO:
priv->td_state = STATE_DO;
break;
case TELNET_DONT:
priv->td_state = STATE_DONT;
break;
default:
priv->td_state = STATE_NORMAL;
break;
}
}
break;
case STATE_WILL:
/* Reply with a DONT */
telnetd_sendopt(priv, TELNET_DONT, ch);
priv->td_state = STATE_NORMAL;
break;
case STATE_WONT:
/* Reply with a DONT */
telnetd_sendopt(priv, TELNET_DONT, ch);
priv->td_state = STATE_NORMAL;
break;
case STATE_DO:
/* Reply with a WONT */
telnetd_sendopt(priv, TELNET_WONT, ch);
priv->td_state = STATE_NORMAL;
break;
case STATE_DONT:
/* Reply with a WONT */
telnetd_sendopt(priv, TELNET_WONT, ch);
priv->td_state = STATE_NORMAL;
break;
case STATE_NORMAL:
if (ch == TELNET_IAC)
{
priv->td_state = STATE_IAC;
}
else
{
telnetd_getchar(priv, ch, dest, &nread);
}
break;
}
}
/* We get here if (1) all of the received bytes have been processed, or
* (2) if the user's buffer has become full.
*/
if (srclen > 0)
{
/* Remember where we left off. These bytes will be returned the next
* time that telnetd_read() is called.
*/
priv->td_pending = srclen;
priv->td_offset = (src - priv->td_rxbuffer);
}
else
{
/* All of the received bytes were consumed */
priv->td_pending = 0;
priv->td_offset = 0;
}
return nread;
}
/****************************************************************************
* Name: telnetd_putchar
*
* Description:
* Put another character from the user buffer to the TX buffer.
*
****************************************************************************/
static bool telnetd_putchar(FAR struct telnetd_dev_s *priv, uint8_t ch,
int *nread)
{
register int index;
bool ret = false;
/* Ignore carriage returns (we will put these in automatically as necesary) */
if (ch != ISO_cr)
{
/* Add all other characters to the destination buffer */
index = *nread;
priv->td_txbuffer[index++] = ch;
/* Check for line feeds */
if (ch == ISO_nl)
{
/* Now add the carriage return */
priv->td_txbuffer[index++] = ISO_cr;
priv->td_txbuffer[index++] = '\0';
/* End of line */
ret = true;
}
*nread = index;
}
return ret;
}
/****************************************************************************
* Name: telnetd_sendopt
*
* Description:
* Send the telnet option bytes
*
****************************************************************************/
static void telnetd_sendopt(FAR struct telnetd_dev_s *priv, uint8_t option,
uint8_t value)
{
uint8_t optbuf[4];
optbuf[0] = TELNET_IAC;
optbuf[1] = option;
optbuf[2] = value;
optbuf[3] = 0;
telnetd_dumpbuffer("Send optbuf", optbuf, 4);
if (send(priv->td_psock, optbuf, 4, 0) < 0)
{
nerr("ERROR: Failed to send TELNET_IAC\n");
}
}
/****************************************************************************
* Name: telnetd_open
****************************************************************************/
static int telnetd_open(FAR struct file *filep)
{
FAR struct inode *inode = filep->f_inode;
FAR struct telnetd_dev_s *priv = inode->i_private;
int tmp;
int ret;
ninfo("td_crefs: %d\n", priv->td_crefs);
/* O_NONBLOCK is not supported */
if (filep->f_oflags & O_NONBLOCK)
{
ret = -ENOSYS;
goto errout;
}
/* Get exclusive access to the device structures */
ret = sem_wait(&priv->td_exclsem);
if (ret < 0)
{
ret = -errno;
goto errout;
}
/* Increment the count of references to the device. If this the first
* time that the driver has been opened for this device, then initialize
* the device.
*/
tmp = priv->td_crefs + 1;
if (tmp > 255)
{
/* More than 255 opens; uint8_t would overflow to zero */
ret = -EMFILE;
goto errout_with_sem;
}
/* Save the new open count on success */
priv->td_crefs = tmp;
ret = OK;
errout_with_sem:
sem_post(&priv->td_exclsem);
errout:
return ret;
}
/****************************************************************************
* Name: telnetd_close
****************************************************************************/
static int telnetd_close(FAR struct file *filep)
{
FAR struct inode *inode = filep->f_inode;
FAR struct telnetd_dev_s *priv = inode->i_private;
FAR char *devpath;
int ret;
ninfo("td_crefs: %d\n", priv->td_crefs);
/* Get exclusive access to the device structures */
ret = sem_wait(&priv->td_exclsem);
if (ret < 0)
{
ret = -errno;
goto errout;
}
/* Decrement the references to the driver. If the reference count will
* decrement to 0, then uninitialize the driver.
*/
if (priv->td_crefs > 1)
{
/* Just decrement the reference count and release the semaphore */
priv->td_crefs--;
sem_post(&priv->td_exclsem);
}
else
{
/* Re-create the path to the driver. */
sched_lock();
ret = asprintf(&devpath, TELNETD_DEVFMT, priv->td_minor);
if (ret < 0)
{
nerr("ERROR: Failed to allocate the driver path\n");
}
else
{
/* Unregister the character driver */
ret = unregister_driver(devpath);
if (ret < 0)
{
nerr("ERROR: Failed to unregister the driver %s: %d\n", devpath, ret);
}
free(devpath);
}
/* Close the socket */
closesocket(priv->td_psock);
/* Release the driver memory. What if there are threads waiting on
* td_exclsem? They will never be awakened! How could this happen?
* crefs == 1 so there are no other open references to the driver.
* But this could have if someone were trying to re-open the driver
* after every other thread has closed it. That really should not
* happen in the intended usage model.
*/
DEBUGASSERT(priv->td_exclsem.semcount == 0);
sem_destroy(&priv->td_exclsem);
free(priv);
sched_unlock();
}
ret = OK;
errout:
return ret;
}
/****************************************************************************
* Name: telnetd_read
****************************************************************************/
static ssize_t telnetd_read(FAR struct file *filep, FAR char *buffer, size_t len)
{
FAR struct inode *inode = filep->f_inode;
FAR struct telnetd_dev_s *priv = inode->i_private;
ssize_t ret;
ninfo("len: %d\n", len);
/* First, handle the case where there are still valid bytes left in the
* I/O buffer from the last time that read was called. NOTE: Much of
* what we read may be protocol stuff and may not correspond to user
* data. Hence we need the loop and we need may need to call psock_recv()
* multiple times in order to get data that the client is interested in.
*/
do
{
if (priv->td_pending > 0)
{
/* Process the buffered telnet data */
FAR const char *src = &priv->td_rxbuffer[priv->td_offset];
ret = telnetd_receive(priv, src, priv->td_pending, buffer, len);
}
/* Read a buffer of data from the telnet client */
else
{
ret = recv(priv->td_psock, priv->td_rxbuffer,
TELNET_RXBUFFER_SIZE, 0);
/* Did we receive anything? */
if (ret > 0)
{
/* Yes.. Process the newly received telnet data */
telnetd_dumpbuffer("Received buffer", priv->td_rxbuffer, ret);
ret = telnetd_receive(priv, priv->td_rxbuffer, ret, buffer, len);
}
/* Otherwise the peer closed the connection (ret == 0) or an error
* occurred (ret < 0).
*/
else
{
break;
}
}
}
while (ret == 0);
/* Return:
*
* ret > 0: The number of characters copied into the user buffer by
* telnetd_receive().
* ret <= 0: Loss of connection or error events reported by recv().
*/
return ret;
}
/****************************************************************************
* Name: telnetd_write
****************************************************************************/
static ssize_t telnetd_write(FAR struct file *filep, FAR const char *buffer, size_t len)
{
FAR struct inode *inode = filep->f_inode;
FAR struct telnetd_dev_s *priv = inode->i_private;
FAR const char *src = buffer;
ssize_t nsent;
ssize_t ret;
int ncopied;
char ch;
bool eol;
ninfo("len: %d\n", len);
/* Process each character from the user buffer */
for (nsent = 0, ncopied = 0; nsent < len; nsent++)
{
/* Get the next character from the user buffer */
ch = *src++;
/* Add the character to the TX buffer */
eol = telnetd_putchar(priv, ch, &ncopied);
/* Was that the end of a line? Or is the buffer too full to hold the
* next largest character sequence ("\r\n\0")?
*/
if (eol || ncopied > TELNET_TXBUFFER_SIZE-3)
{
/* Yes... send the data now */
ret = send(priv->td_psock, priv->td_txbuffer, ncopied, 0);
if (ret < 0)
{
nerr("ERROR: psock_send failed '%s': %d\n", priv->td_txbuffer, ret);
return ret;
}
/* Reset the index to the beginning of the TX buffer. */
ncopied = 0;
}
}
/* Send anything remaining in the TX buffer */
if (ncopied > 0)
{
ret = send(priv->td_psock, priv->td_txbuffer, ncopied, 0);
if (ret < 0)
{
nerr("ERROR: psock_send failed '%s': %d\n", priv->td_txbuffer, ret);
return ret;
}
}
/* Notice that we don't actually return the number of bytes sent, but
* rather, the number of bytes that the caller asked us to send. We may
* have sent more bytes (because of CR-LF expansion and because of NULL
* termination). But it confuses some logic if you report that you sent
* more than you were requested to.
*/
return len;
}
/****************************************************************************
* Name: telnetd_poll
****************************************************************************/
static int telnetd_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
#if 0 /* No ioctl commands are yet supported */
struct inode *inode = filep->f_inode;
struct cdcacm_dev_s *priv = inode->i_private;
int ret = OK;
switch (cmd)
{
/* Add ioctl commands here */
default:
ret = -ENOTTY;
break;
}
return ret;
#else
return -ENOTTY;
#endif
}
/****************************************************************************
* Name: telnetd_poll
****************************************************************************/
#if 0 /* Not used by this driver */
static int telnetd_poll(FAR struct file *filep, FAR struct pollfd *fds,
bool setup)
{
FAR struct inode *inode = filep->f_inode;
FAR struct telnetd_dev_s *priv = inode->i_private;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: telnetd_driver
*
* Description:
* Create a character driver to "wrap" the telnet session. This function
* will select and return a unique path for the new telnet device.
*
* Parameters:
* sd - The socket descriptor that represents the new telnet connection.
* daemon - A pointer to the structure representing the overall state of
* this instance of the telnet daemon.
*
* Return:
* An allocated string represent the full path to the created driver. The
* receiver of the string must de-allocate this memory when it is no longer
* needed. NULL is returned on a failure.
*
****************************************************************************/
FAR char *telnetd_driver(long sd, FAR struct telnetd_s *daemon)
{
FAR struct telnetd_dev_s *priv;
FAR char *devpath = NULL;
int ret;
/* Allocate instance data for this driver */
priv = (FAR struct telnetd_dev_s*)malloc(sizeof(struct telnetd_dev_s));
if (!priv)
{
nerr("ERROR: Failed to allocate the driver data structure\n");
return NULL;
}
/* Initialize the allocated driver instance */
sem_init(&priv->td_exclsem, 0, 1);
priv->td_state = STATE_NORMAL;
priv->td_crefs = 0;
priv->td_pending = 0;
priv->td_offset = 0;
priv->td_psock = sd;
/* Allocation a unique minor device number of the telnet drvier */
do
{
ret = sem_wait(&g_telnetdcommon.exclsem);
if (ret < 0 && errno != -EINTR)
{
goto errout_with_dev;
}
}
while (ret < 0);
priv->td_minor = g_telnetdcommon.minor;
g_telnetdcommon.minor++;
sem_post(&g_telnetdcommon.exclsem);
/* Create a path and name for the driver. */
ret = asprintf(&devpath, TELNETD_DEVFMT, priv->td_minor);
if (ret < 0)
{
nerr("ERROR: Failed to allocate the driver path\n");
goto errout_with_dev;
}
/* Register the driver */
ret = register_driver(devpath, &g_telnetdfops, 0666, priv);
if (ret < 0)
{
nerr("ERROR: Failed to register the driver %s: %d\n", devpath, ret);
goto errout_with_devpath;
}
/* Return the path to the new telnet driver */
return devpath;
errout_with_devpath:
free(devpath);
errout_with_dev:
free(priv);
return NULL;
}