Initial cut of a driver for the TI CC3000 network module with support on the Freescale KL25Z board from Alan Carvalho de Assis

This commit is contained in:
Gregory Nutt 2013-09-03 14:59:48 -06:00
parent 04c04b4106
commit 16868bf39d
8 changed files with 1336 additions and 0 deletions

View File

@ -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"

View File

@ -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

11
examples/cc3000/.gitignore vendored Normal file
View File

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

13
examples/cc3000/Kconfig Normal file
View File

@ -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

109
examples/cc3000/Makefile Normal file
View File

@ -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

216
examples/cc3000/board.c Normal file
View File

@ -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);
}

220
examples/cc3000/board.h Normal file
View File

@ -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;

View File

@ -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;
}