From dceb2d4a91921794ce9277e43c26821816a93135 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 3 Sep 2013 14:59:48 -0600 Subject: Initial cut of a driver for the TI CC3000 network module with support on the Freescale KL25Z board from Alan Carvalho de Assis --- apps/examples/Kconfig | 1 + apps/examples/Make.defs | 4 + apps/examples/cc3000/.gitignore | 11 + apps/examples/cc3000/Kconfig | 13 + apps/examples/cc3000/Makefile | 109 ++++++ apps/examples/cc3000/board.c | 216 +++++++++++ apps/examples/cc3000/board.h | 220 +++++++++++ apps/examples/cc3000/cc3000basic.c | 762 +++++++++++++++++++++++++++++++++++++ 8 files changed, 1336 insertions(+) create mode 100644 apps/examples/cc3000/.gitignore create mode 100644 apps/examples/cc3000/Kconfig create mode 100644 apps/examples/cc3000/Makefile create mode 100644 apps/examples/cc3000/board.c create mode 100644 apps/examples/cc3000/board.h create mode 100644 apps/examples/cc3000/cc3000basic.c (limited to 'apps') diff --git a/apps/examples/Kconfig b/apps/examples/Kconfig index 2546fea40..ad75af005 100644 --- a/apps/examples/Kconfig +++ b/apps/examples/Kconfig @@ -6,6 +6,7 @@ source "$APPSDIR/examples/adc/Kconfig" source "$APPSDIR/examples/buttons/Kconfig" source "$APPSDIR/examples/can/Kconfig" +source "$APPSDIR/examples/cc3000/Kconfig" source "$APPSDIR/examples/cdcacm/Kconfig" source "$APPSDIR/examples/composite/Kconfig" source "$APPSDIR/examples/cxxtest/Kconfig" diff --git a/apps/examples/Make.defs b/apps/examples/Make.defs index 91fb19788..12f554654 100644 --- a/apps/examples/Make.defs +++ b/apps/examples/Make.defs @@ -46,6 +46,10 @@ ifeq ($(CONFIG_EXAMPLES_CAN),y) CONFIGURED_APPS += examples/can endif +ifeq ($(CONFIG_EXAMPLES_CC3000BASIC),y) +CONFIGURED_APPS += examples/cc3000 +endif + ifeq ($(CONFIG_EXAMPLES_CDCACM),y) CONFIGURED_APPS += examples/cdcacm endif 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 +# +# 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 +#include +#include +#include +#include + + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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; i0) { + 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; +} + -- cgit v1.2.3