summaryrefslogtreecommitdiff
path: root/apps/examples/cc3000
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-09-03 14:59:48 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-09-03 14:59:48 -0600
commitdceb2d4a91921794ce9277e43c26821816a93135 (patch)
treee1b86ca39583b5b0cfba274b88dad04216872b76 /apps/examples/cc3000
parentb4bb68d62079c291a1ff35330c82e8f078a117a0 (diff)
downloadnuttx-dceb2d4a91921794ce9277e43c26821816a93135.tar.gz
nuttx-dceb2d4a91921794ce9277e43c26821816a93135.tar.bz2
nuttx-dceb2d4a91921794ce9277e43c26821816a93135.zip
Initial cut of a driver for the TI CC3000 network module with support on the Freescale KL25Z board from Alan Carvalho de Assis
Diffstat (limited to 'apps/examples/cc3000')
-rw-r--r--apps/examples/cc3000/.gitignore11
-rw-r--r--apps/examples/cc3000/Kconfig13
-rw-r--r--apps/examples/cc3000/Makefile109
-rw-r--r--apps/examples/cc3000/board.c216
-rw-r--r--apps/examples/cc3000/board.h220
-rw-r--r--apps/examples/cc3000/cc3000basic.c762
6 files changed, 1331 insertions, 0 deletions
diff --git a/apps/examples/cc3000/.gitignore b/apps/examples/cc3000/.gitignore
new file mode 100644
index 000000000..fa1ec7579
--- /dev/null
+++ b/apps/examples/cc3000/.gitignore
@@ -0,0 +1,11 @@
+/Make.dep
+/.depend
+/.built
+/*.asm
+/*.obj
+/*.rel
+/*.lst
+/*.sym
+/*.adb
+/*.lib
+/*.src
diff --git a/apps/examples/cc3000/Kconfig b/apps/examples/cc3000/Kconfig
new file mode 100644
index 000000000..61ecf2ade
--- /dev/null
+++ b/apps/examples/cc3000/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_CC3000BASIC
+ bool "A Basic Application to use CC3000 Module"
+ default n
+ ---help---
+ Enable the CC3000BASIC example
+
+if EXAMPLES_CC3000BASIC
+endif
diff --git a/apps/examples/cc3000/Makefile b/apps/examples/cc3000/Makefile
new file mode 100644
index 000000000..41d8c4acb
--- /dev/null
+++ b/apps/examples/cc3000/Makefile
@@ -0,0 +1,109 @@
+############################################################################
+# apps/examples/hello/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 = 4096
+
+# Hello, World! Example
+
+ASRCS =
+CSRCS = cc3000basic.c board.c
+
+AOBJS = $(ASRCS:.S=$(OBJEXT))
+COBJS = $(CSRCS:.c=$(OBJEXT))
+
+SRCS = $(ASRCS) $(CSRCS)
+OBJS = $(AOBJS) $(COBJS)
+
+ifeq ($(CONFIG_WINDOWS_NATIVE),y)
+ BIN = ..\..\libapps$(LIBEXT)
+else
+ifeq ($(WINTOOL),y)
+ BIN = ..\\..\\libapps$(LIBEXT)
+else
+ BIN = ../../libapps$(LIBEXT)
+endif
+endif
+
+ROOTDEPPATH = --dep-path .
+
+# Common build
+
+VPATH =
+
+all: .built
+.PHONY: clean depend distclean
+
+$(AOBJS): %$(OBJEXT): %.S
+ $(call ASSEMBLE, $<, $@)
+
+$(COBJS): %$(OBJEXT): %.c
+ $(call COMPILE, $<, $@)
+
+.built: $(OBJS)
+ $(call ARCHIVE, $(BIN), $(OBJS))
+ @touch .built
+
+ifeq ($(CONFIG_NSH_BUILTIN_APPS),y)
+$(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat: $(DEPCONFIG) Makefile
+ $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main)
+
+context: $(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)
+
+-include Make.dep
diff --git a/apps/examples/cc3000/board.c b/apps/examples/cc3000/board.c
new file mode 100644
index 000000000..feba5bbe4
--- /dev/null
+++ b/apps/examples/cc3000/board.c
@@ -0,0 +1,216 @@
+/**************************************************************************
+*
+* ArduinoCC3000Core.cpp - Wrapper routines to make interfacing the Arduino
+* and the TI CC3000 easier.
+*
+* 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.
+*
+* 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
+*
+****************************************************************************/
+
+
+#include "board.h"
+#include <stdbool.h>
+#include <nuttx/cc3000/wlan.h>
+#include <nuttx/cc3000/hci.h>
+#include <nuttx/cc3000/spi.h>
+#include <arch/board/kl_wifi.h>
+
+
+volatile unsigned long ulSmartConfigFinished,
+ ulCC3000Connected,
+ ulCC3000DHCP,
+ OkToDoShutDown,
+ ulCC3000DHCP_configured;
+
+volatile unsigned char ucStopSmartConfig;
+
+
+
+#define NETAPP_IPCONFIG_MAC_OFFSET (20)
+#define CC3000_APP_BUFFER_SIZE (5)
+#define CC3000_RX_BUFFER_OVERHEAD_SIZE (20)
+
+/*
+unsigned char pucCC3000_Rx_Buffer[CC3000_APP_BUFFER_SIZE + CC3000_RX_BUFFER_OVERHEAD_SIZE];
+*/
+
+
+/* The original version of the function below had Serial.prints()
+ to display an event, but since an async event can happen at any time,
+ even in the middle of another Serial.print(), sometimes the sketch
+ would lock up because we were trying to print in the middle of
+ a print.
+
+ So now we just set a flag and write to a string, and the master
+ loop can deal with it when it wants.
+*/
+unsigned char asyncNotificationWaiting = false;
+long lastAsyncEvent;
+unsigned char dhcpIPAddress[4];
+
+
+/*-------------------------------------------------------------------
+
+ 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, unsigned char 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;
+}
+
+/*-------------------------------------------------------------------
+
+ The TI library calls these routines to enable or disable interrupts
+ on the WLAN_IRQ pin.
+
+ Originally WlanInterruptEnable() called attachInterrupt() and
+ WlanInterruptDisable() called detachInterrupt() but the library
+ was occationally locking up here, so now these routines just
+ set a flag. The interrupt routine will always fire but if the
+ flag isn't set it just returns immediately.
+
+ --------------------------------------------------------------------*/
+
+void WlanInterruptEnable(void) {
+ SPIInterruptsEnabled = 1;
+}
+
+
+void WlanInterruptDisable(void) {
+ SPIInterruptsEnabled = 0;
+}
+
+
+/*-------------------------------------------------------------------
+
+ 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) {
+
+ SPIInterruptsEnabled = 0;
+
+ Wlan_Setup();
+
+ wlan_init( CC3000_AsyncCallback,
+ SendFirmwarePatch,
+ SendDriverPatch,
+ SendBootloaderPatch,
+ ReadWlanInterruptPin,
+ WlanInterruptEnable,
+ WlanInterruptDisable,
+ WriteWlanEnablePin);
+
+ wlan_start(0);
+}
+
diff --git a/apps/examples/cc3000/board.h b/apps/examples/cc3000/board.h
new file mode 100644
index 000000000..2d659fabe
--- /dev/null
+++ b/apps/examples/cc3000/board.h
@@ -0,0 +1,220 @@
+/**************************************************************************
+*
+* 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.
+*
+****************************************************************************/
+
+
+
+
+
+
+/*
+ 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)
+
+//AES key "smartconfigAES16"
+//const unsigned char smartconfigkey[] = {0x73,0x6d,0x61,0x72,0x74,0x63,0x6f,0x6e,0x66,0x69,0x67,0x41,0x45,0x53,0x31,0x36};
+
+
+
+
+
+/* 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 unsigned char asyncNotificationWaiting;
+extern long lastAsyncEvent;
+extern unsigned char dhcpIPAddress[];
+
+
+
+extern void CC3000_Init(void);
+
+
+extern volatile unsigned long ulSmartConfigFinished,
+ ulCC3000Connected,
+ ulCC3000DHCP,
+ OkToDoShutDown,
+ ulCC3000DHCP_configured;
+
+extern volatile unsigned char ucStopSmartConfig;
diff --git a/apps/examples/cc3000/cc3000basic.c b/apps/examples/cc3000/cc3000basic.c
new file mode 100644
index 000000000..ae60abc6a
--- /dev/null
+++ b/apps/examples/cc3000/cc3000basic.c
@@ -0,0 +1,762 @@
+/**************************************************************************
+*
+* ArduinoCC3000.ino - An application to demo an Arduino connected to the
+ TI CC3000
+*
+* 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
+*
+****************************************************************************
+
+
+
+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
+
+
+****************************************************************************/
+
+
+#include "board.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/time.h>
+#include <nuttx/cc3000/nvmem.h>
+#include <nuttx/cc3000/socket.h>
+#include <nuttx/cc3000/wlan.h>
+#include <nuttx/cc3000/hci.h>
+#include <nuttx/cc3000/security.h>
+#include <nuttx/cc3000/netapp.h>
+
+void Initialize(void);
+void helpme(void);
+void execute(int cmd);
+void ShowBufferSize(void);
+void ShowFreeRAM(void);
+void Blinker(void);
+void StartSmartConfig(void);
+void ManualConnect(void);
+void ManualConnect(void);
+void ManualAddProfile(void);
+void ListAccessPoints(void);
+void PrintIPBytes(unsigned char *ipBytes);
+void ShowInformation(void);
+
+// When operations that take a long time (like Smart Config) are running, the
+// function Blinker() flashes this LED. It's not required for actual use.
+
+#define BLINKER_LED 6
+
+uint8_t isInitialized = false;
+
+
+void AsyncEventPrint(void) {
+ 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%X)\n", lastAsyncEvent);
+ break;
+ }
+
+ }
+
+
+void helpme(void) {
+
+ printf("\n+-------------------------------------------+\n");
+ printf("| Arduino CC3000 Demo Program |\n");
+ printf("+-------------------------------------------+\n\n");
+ printf(" 1 - Initialize the CC3000\n");
+ printf(" 2 - Show RX & TX buffer sizes, & free RAM\n");
+ printf(" 3 - Start Smart Config\n");
+ printf(" 4 - Manually connect to AP\n");
+ printf(" 5 - Manually add connection profile\n");
+ printf(" 6 - List access points\n");
+ printf(" 7 - Show CC3000 information\n");
+ printf("\n Type 1-7 to select above option or (q/Q) to quit: ");
+}
+
+
+void execute(int cmd)
+{
+ if (asyncNotificationWaiting) {
+ asyncNotificationWaiting = false;
+ AsyncEventPrint();
+ }
+
+ switch(cmd) {
+ case '1':
+ Initialize();
+ break;
+ case '2':
+ ShowBufferSize();
+ ShowFreeRAM();
+ break;
+ case '3':
+ StartSmartConfig();
+ break;
+ case '4':
+ ManualConnect();
+ break;
+ case '5':
+ ManualAddProfile();
+ break;
+ case '6':
+ ListAccessPoints();
+ break;
+ case '7':
+ ShowInformation();
+ break;
+ default:
+ printf("**Unknown command \"%d\" **\n", cmd);
+ break;
+ }
+
+ return;
+}
+
+
+void Initialize(void)
+{
+
+ unsigned char fancyBuffer[MAC_ADDR_LEN], i = 0;
+
+ if (isInitialized) {
+ printf("CC3000 already initialized. Shutting down and restarting...\n");
+ wlan_stop();
+ usleep(1000000); //delay 1s
+ }
+
+ printf("Initializing CC3000...\n");
+ CC3000_Init();
+ 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 (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");
+ }*/
+
+}
+
+
+/* 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);
+}
+
+
+void ShowFreeRAM(void)
+{
+ printf("Free RAM is XXXX bytes... I don't care\n");
+}
+
+void Blinker(void)
+{
+}
+
+
+/*
+ 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;
+ double t_us;
+ struct timeval end, start;
+
+ if (!isInitialized) {
+ printf("CC3000 not initialized; can't run Smart Config.\n");
+ return;
+ }
+
+ printf("Starting Smart Config...\n");
+
+ printf(" Disabling auto-connect policy...\n");
+ if ((rval = wlan_ioctl_set_connection_policy(DISABLE, DISABLE, DISABLE))!=0) {
+ printf(" Setting auto connection policy failed, error: %X\n", rval);
+ return;
+ }
+
+ printf(" Deleting all existing profiles...\n");
+ if ((rval = wlan_ioctl_del_profile(255))!=0) {
+ printf(" Deleting all profiles failed, error: %X\n", rval);
+ return;
+ }
+
+ printf(" Waiting until disconnected...\n");
+ while (ulCC3000Connected == 1) {
+ Blinker();
+ }
+
+ printf(" Setting smart config prefix...\n");
+ if ((rval = wlan_smart_config_set_prefix(simpleConfigPrefix))!=0) {
+ printf(" Setting smart config prefix failed, error: %X", rval);
+ return;
+ }
+
+ printf(" Starting smart config...");
+ if ((rval = wlan_smart_config_start(0))!=0) {
+ printf(" Starting smart config failed, error: %X\n", rval);
+ return;
+ }
+
+ // Wait for Smartconfig process complete, or 30 seconds, whichever
+ // comes first. The Uno isn't seeing the HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE
+ // event and I can't figure out why (it works fine on the Teensy) so my
+ // temporary workaround is I just stop waiting after a while
+ gettimeofday(&start, NULL);
+ while (ulSmartConfigFinished == 0)
+ {
+ Blinker();
+ gettimeofday(&end, NULL);
+ t_us = ((end.tv_sec - start.tv_sec) * 1000*1000) + (end.tv_usec - start.tv_usec) ;
+ if (t_us > 3000000) //3s
+ {
+ printf(" Timed out waiting for Smart Config to finish. Hopefully it did anyway\n");
+ break;
+ }
+ }
+
+ printf(" Smart Config packet seen!\n");
+
+ printf(" Enabling auto-connect policy...\n");
+ if ((rval=wlan_ioctl_set_connection_policy(DISABLE, DISABLE, ENABLE))!=0)
+ {
+ printf(" Setting auto connection policy failed, error: %X\n", rval);
+ return;
+ }
+
+ printf(" Stopping CC3000...\n");
+ 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
+
+ printf(" Waiting for connection to AP...\n");
+ while (ulCC3000Connected!=1)
+ {
+ Blinker();
+ }
+
+ printf(" Waiting for IP address from DHCP...\n");
+ while (ulCC3000DHCP!=1)
+ {
+ Blinker();
+ }
+
+ printf(" Sending mDNS broadcast to signal we're done with Smart Config...\n");
+ mdnsAdvertiser(1,device_name,strlen(device_name)); // 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.
+
+ printf(" Smart Config finished!\n");
+}
+
+
+/*
+ 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[] = "OpenNET";
+ char AP_KEY[] = "gargame1";
+ unsigned char 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");
+ rval = wlan_ioctl_set_connection_policy(DISABLE, DISABLE, DISABLE);
+
+ printf(" Deleting all existing profiles...\n");
+ rval = wlan_ioctl_del_profile(255);
+
+ printf(" Waiting until disconnected...\n");
+ while (ulCC3000Connected == 1)
+ {
+ usleep(100000); //delay 100ms in busy wait
+ }
+
+ 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,
+ (unsigned char *)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";
+ unsigned char 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
+ (unsigned char *)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
+ (unsigned char *)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;
+ unsigned short frameTime;
+ unsigned char ssid_name[32];
+ unsigned char bssid[6];
+ } scanResults;
+
+#define NUM_CHANNELS 16
+
+void ListAccessPoints(void) {
+ unsigned long aiIntervalList[NUM_CHANNELS];
+ unsigned char 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 paramters...\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;
+ }
+
+ printf(" Sleeping 5 seconds to let the CC3000 discover APs...\n");
+ usleep(5000000);
+
+ 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, (unsigned char *)&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(" \n");
+ 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, "%3d ", sr.rssi);
+ printf("%s", localB);
+ memset(localB, 0, 33);
+ memcpy(localB, sr.ssid_name, sr.ssidLength);
+ printf("%s", localB);
+ }
+
+ if (--apCounter>0) {
+ if ((rval=wlan_ioctl_get_scan_results(2000, (unsigned char *)&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(unsigned char *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, 32);
+ memcpy(localB, inf.uaSSID, 32);
+
+ printf(" Connected to SSID: %d\n", localB);
+}
+
+int c3b_main(int argc, char *argv[])
+{
+ char ch='0';
+
+ while(ch != 'q' && ch != 'Q')
+ {
+ helpme();
+
+ ch = getchar();
+
+ execute(ch);
+ }
+
+ return 0;
+}
+