BSP430  20141115
Board Support Package for MSP430 microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
CC3000 SimpleLink Exploration

Table of Contents

This example is a fairly complex program demonstrating the basic goal that drove BSP430 development: the ability to quickly develop tools to explore new capabilities in an interactive fashion without being tied to a particular MSP430 product line or board, and to abstract the capabilities as modules that could be used in other applications.

The Texas Instruments SimpleLink(TM) CC3000 Wi-Fi SOC is a solution intended to enable microcontrollers to communicate over 802.11 Wi-Fi networks. It is available in RF evaluation module form-factor, and comes with example programs from Texas Instruments that are mostly tested on the MSP-EXP430F5529LP "USB Launchpad".

The example here uses the TI-provided host driver with a BSP430 SPI interface to provide an interactive program to invoke various capabilities of the SimpleLink hardware.

To build the program, you will need a copy of the CC3000 Host Driver. This application uses one that has been repackaged to place header files out of the application namespace, support MSPGCC, fix a few bugs, and support building as a library that can be linked into an application. It can be obtained from: http://github.com/pabigot/cc3000

An example build command line is:

make PLATFORM=exp430f5529lp \
   CC3000_ROOT=/usr/local/msp430-cc3000 \
   CC3000BOOST=1 \
   WITH_SMART=1 WITH_PROFILES=1 WITH_RMPARAM=1 \
   install

Several build-time flags control available features:

Available Commands and Examples

The API is a command-line, it supports editing commands, and will accept the shortest unique command prefix. Below are the commands supported when built with the options above.

help # No help available
test # No help available
uptime # No help available
mdns [name] # enable/disable mDNS
info # No help available
  load # load wlan AP params from INFO_B
  erase # erase INFO_B
  store # store wlan AP params in INFO_B
  dump # display INFO_B contents
nvmem # No help available
  mac # get mac address
  read fileid [len(=128) [ofs(=0)]] # read block from nvmem file
  rmparam # display radio module parameters
  sp # read firmware service pack level
  create [fileid=12 [length=16]] # create a new NVMEM section
  dir # describe NVMEM sections
scan # No help available
  start  [interval=1] # start periodic scan (ms)
  stop # disable periodic scan
  show  [with_mem=0] # display scan results
wlan # No help available
  start [patchcount=0] # power-up CC3000
  timeouts # set CC3000 timeouts
  status # get CC3000 status and AP config
  smart # No help available
    start [encrypted=0] # start smart config process
    stop # stop smart config process
    process # process AES received data
    aes [key] # set or read AES key
  profile # No help available
    update [profile=0] # add configured profiles
    del [profile=0] # delete profile, 255 for all
  connect # connect to specified access point using AP config
  autocon [open_ap=0 [fast_conn=1 [auto_conn=1]]]
  sectype [{sectype}] # Display or set AP sectype
  passphrase [{passphrase}] # Display or set AP passphrase
  ssid [{ssid}] # Display or set AP SSID for connect
  ipconfig # show IP parameters
  disconnect # disconnect from AP
  stop # shut down CC3000

Basic Boot with Manual Configuration

A demonstration boot sequence with a couple commands is:

cc3000 Mar 10 2014 12:00:54
System reset bitmask 4; causes:
        RST/NMI
System reset included: BOR POR PUC
PWR_EN at PORT6.5
SPI_IRQ HAL at PORT2.0
CSn HAL at PORT2.2
SPI is USCI5_B0
SPI Pins: MOSI/SDA=P3.0; MISO/SCL=P3.1; CLK=P3.2; STE=P2.7
CC3000 host driver: 15
Mar 10 2014 12:00:54
 0:00.807 Initialize returned 0

And wlan has been started.
ERR: Stored connection params invalid
> wlan ssid myssid
AP SSID is myssid (7 chars)
> wlan passph key-for-myssid
AP passphrase is 'key-for-myssid' (15 chars)
> wlan sec wpa2
AP security type is wpa2 (3)
> wlan con
connect to ssid 'myssid' by wpa2 using 'key-for-myssid'
con 0 in  0:06.334
>  0:26.615 wlan_cb 0x8001 0 at 0 SR 0x44
 0:26.678 wlan_cb 0x8010 21 at 0x43ba SR 0x44
w ip
IP: 192.168.0.100
NM: 255.255.255.0
GW: 192.168.0.1
DHCP: 192.168.0.1
DNS: 192.168.0.1
MAC: 08:00:28:57:d4:df
SSID: myssid
> info store
Erasing stored params at 0x1900...0
Copying current configuration...106
Command execution returned 106
>

Smart Configuration

Although Smart Config can be used without encryption, you'll probably want to use it for any real-world application. The encryption key is stored in the NVMEM section of the CC3000. Display the NVMEM file table with this command:

> nvm dir
16 NVMEM files with 14 documented:
ID Addr  Size  Flg : Doc ID  Size Description
 0 01f0   416  av         0   512 NVS
 1 0050   416  a          1   512 NVS (shadow)
 2 0390  4096  av         2  4096 WLAN Config
 3 1390  4096  av         3  4096 WLAN Config (shadow)
 4 2390  8192  av         4     0 WLAN Driver SP
 5 4390  8192  av         5     0 WLAN Firmware SP
 6 6390    16  av         6    16 MAC address
 7 63a0    16  a          7     0 Front End Vars ??
 8 63b0    64  a          8    64 IP Config
 9 63f0    64  a          9    64 IP Config (shadow)
10 6430  1024  a         10     0 Bootloader SP
11 6830   512  av        11     0 Radio Module
12 0000     0            12     0 AES128 Key
13 0000     0            13     0 Shared Memory ??
14 6a30    64  av
15 0000     0

If this table shows that file 12, which holds the AES key, does not have the available and valid flags (av), create it:

> nvm create
nvmem_create_entry(12, 16) got 0

The file entry should now be:

12 6a70    16  a         12     0 AES128 Key

Store a key with this command:

> wlan smart aes 123456789abcdef0
aes_write_key got 0
Key:
0000  31 32 33 34 35 36 37 38  39 61 62 63 64 65 66 30    123456789abcdef0

The key must be ASCII and a full 16 characters. The FAT entry will update to mark the section valid:

12 6a70    16  av        12     0 AES128 Key

You can now initiate the smart config process on your Android or IOS device, and at the demo application do the following:

> wlan smart start 1
Prefix set returned 0
Config with AES key:
0000  31 32 33 34 35 36 37 38  39 61 62 63 64 65 66 30    123456789abcdef0
wlan_smart_config_start(1) got 0
> wlan smart stop
wlan_smart_config_stop() got 0
> wlan smart process
wlan_smart_config_process() got 0
> wlan autocon
Current connection policy:
should_connect_to_open_ap = 0x00000000
should_use_fast_connect = 0x00000000
use_profiles = 0x00000000
New connection policy: open_ap=0 fast_connect=1 use_profiles=1
Connection policy set got 0
> wlan stop
> wlan start
wlan_start(0) took  0:01.190
>  0:36.572 wlan_cb 0x8001 0 at 0 SR 0x44
 0:37.212 wlan_cb 0x8010 21 at 0x43ba SR 0x44
wlan ip
IP: 192.168.0.100
NM: 255.255.255.0
GW: 192.168.0.1
DHCP: 192.168.0.1
DNS: 192.168.0.1
MAC: 08:00:28:57:d4:df
SSID: myssid
>

Multiple Profile Automated Configuration

Manual configuration works, but the startup procedure is slow. Smart Configuration is a pain when you have the ability to interact with the device. The following sequence shows how to store a set of profiles with priorities when the application is built with WITH_PROFILES=1:

> wlan profile del
 7:53.662 wlan_cb 0x8010 21 at 0x42d0 SR 0x44
 7:53.710 wlan_cb 0x8002 0 at 0 SR 0x44
Del profile 255 got 0
> wlan profile update
Add SSID 'pab-stream' sec 'wpa2' pri 3 got 0
Add SSID 'pabmn' sec 'wpa2' pri 2 got 1
Add SSID 'pab-llc' sec 'wpa2' pri 1 got 2
> wlan stop
> wlan start
wlan_start(0) took  0:01.190
>  8:29.536 wlan_cb 0x8001 0 at 0 SR 0x44
 8:30.647 wlan_cb 0x8010 21 at 0x43ba SR 0x44
w ip
IP: 192.168.66.244
NM: 255.255.252.0
GW: 192.168.64.1
DHCP: 192.168.66.10
DNS: 192.168.66.10
MAC: 08:00:28:57:d4:df
SSID: pab-stream
>

cc3000spi.c

The CC3000 Host Driver library is independent of the underlying interface via SPI. A demonstration interface for specific MSP430 processors is part of the TI example programs, but it is rather confusing and has board-specific material tightly integrated.

The <bsp430/rf/cc3000spi.h> header bridges between the host driver and BSP430's serial abstraction following the specfication at the CC3000 Host Driver Porting Guide.

main.c

The bulk of the application is taken up with bridge code that interprets user input and invokes CC3000 host API calls. It is mostly of interest in that it demonstrates how to arrange command definitions so they can be easily included/excluded based on available memory.

#include <bsp430/clock.h>
#if (BSP430_CORE_TOOLCHAIN_GCC_MSPGCC - 0)
#include <sys/crtld.h>
#elif (BSP430_CORE_TOOLCHAIN_GCC_MSP430_ELF - 0)
#ifdef __MSP430F5438A__
#define __infob ((unsigned char *)0x1980)
#define __info_segment_size 128
#endif
#endif /* get info section information */
#include <cc3000/host_driver_version.h>
#include <cc3000/wlan.h>
#include <cc3000/nvmem.h>
#include <cc3000/netapp.h>
#include <cc3000/hci.h>
#include <cc3000/security.h>
#include <cc3000/socket.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifndef BYPASS_SP_LOAD
/* If defined to a true value, the wlan_init() call at power-up will
* inhibit loading of any service packs that may be present in the
* NVMEM. This will allow you to get access to the board when the
* NVMEM is corrupt.
*
* BSP430 does not currently have support for complete restoration of
* the NVMEM, which includes defining the FAT, providing radio module
* parameters, etc. */
#define BYPASS_SP_LOAD 0
#endif /* BYPASS_SP_LOAD */
/* Memory is extremely tight on the FR5739 (16 kB including CC3000
* buffers). Set these to restrict the set of commands to ones of
* interest that will fit. You'll probably find you'll need to
* disable WLAN_CONNECT, which makes this pretty useless.
*
* On the EXP430G2 there isn't enough memory to do anything, so
* disable everything.
*
* No issues on the "real" chips: MSP430F5438, MSP430F5529, .... */
#if ! (BSP430_PLATFORM_EXP430G2 - 0)
#define CMD_WLAN 1
#define CMD_WLAN_BROKEN 1
#define CMD_WLAN_STOP 1
#define CMD_WLAN_STATUS 1
#define CMD_WLAN_CONNECT 1
#define CMD_WLAN_IPCONFIG 1
#define CMD_WLAN_DISCONNECT 1
#define CMD_WLAN_START 1
#define CMD_WLAN_PROFILE 1
#if (BSP430_CC3000_ENABLE_SMART - 0) && (BSP430_CC3000SPI_RX_BUFFER_SIZE < 1500)
#error BSP430_CC3000_ENABLE_SMART requires BSP430_CC3000SPI_RX_BUFFER_SIZE >= 1500
#endif /* BSP430_CC3000_ENABLE_SMART diagnostic */
#ifndef CMD_WLAN_SMART
#define CMD_WLAN_SMART (BSP430_CC3000SPI_RX_BUFFER_SIZE >= 1500)
#endif /* CMD_WLAN_SMART */
#define CMD_NVMEM 1
#define CMD_NVMEM_SP 1
#define CMD_NVMEM_RMPARAM 1
#define CMD_NVMEM_READ 1
#define CMD_NVMEM_MAC 1
#define CMD_SCAN 1
#define CMD_INFO 1
#define CMD_HELP 1
#endif /* CC3000BOOST */
#if (NO_HELP - 0)
#define HELP_STRING(h_) NULL
#else /* NO_HELP */
#define HELP_STRING(h_) h_
#endif /* NO_HELP */
#define MAGIC_CONNECT_PARAMS 0x3000
#define MAX_SSID_LEN 32
#define MAX_PASSPHRASE_LEN 64
typedef struct sConnectParams {
unsigned int magic;
int security_type;
size_t ssid_len;
size_t passphrase_len;
char ssid[MAX_SSID_LEN+1];
unsigned char passphrase[MAX_PASSPHRASE_LEN+1];
} sConnectParams;
static uint32_t lebtohl (uint8_t * vp)
{
return ((uint32_t)vp[0]
| ((uint32_t)vp[1] << 8)
| ((uint32_t)vp[2] << 16)
| ((uint32_t)vp[3] << 24));
}
static uint32_t bebtohl (uint8_t * vp)
{
return ((uint32_t)vp[3]
| ((uint32_t)vp[2] << 8)
| ((uint32_t)vp[1] << 16)
| ((uint32_t)vp[0] << 24));
}
const char *
ipv4AsText (const unsigned char * ipaddr)
{
static char buffer[16];
snprintf(buffer, sizeof(buffer), "%u.%u.%u.%u", ipaddr[3], ipaddr[2], ipaddr[1], ipaddr[0]);
return buffer;
}
const char *
net_ipv4AsText (const unsigned char * ipaddr)
{
static char buffer[16];
snprintf(buffer, sizeof(buffer), "%u.%u.%u.%u", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
return buffer;
}
volatile unsigned long lastKeepAlive_utt;
volatile unsigned long lastCallback_utt;
volatile long lastEventType;
static void wlan_cb (long event_type,
char * data,
unsigned char length)
{
lastEventType = event_type;
lastCallback_utt = ulBSP430uptime_ni();
/* Ignore unsolicited keep-alives, which occur every 10 seconds
* whenever the WLAN has been started, regardless of whether it's
* connected or scanning. */
if (HCI_EVNT_WLAN_KEEPALIVE == event_type) {
lastKeepAlive_utt = lastCallback_utt;
return;
}
cprintf("%s wlan_cb %#lx %u at %p SR %#x\n",
xBSP430uptimeAsText_ni(lastCallback_utt),
event_type, length, data, __read_status_register());
}
const sBSP430cliCommand * commandSet;
#define LAST_COMMAND NULL
#if (CMD_WLAN - 0)
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND NULL
#if (CMD_WLAN_STOP - 0)
static int
cmd_wlan_stop (const char * argstr)
{
wlan_stop();
return 0;
}
static sBSP430cliCommand dcmd_wlan_stop = {
.key = "stop",
.help = HELP_STRING("# shut down CC3000"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_wlan_stop
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_stop
#endif /* CMD_WLAN_STOP */
#if (CMD_WLAN_DISCONNECT - 0)
static int
cmd_wlan_disconnect (const char * argstr)
{
long rl = wlan_disconnect();
cprintf("disconnect returned %ld\n", rl);
return 0;
}
static sBSP430cliCommand dcmd_wlan_disconnect = {
.key = "disconnect",
.help = HELP_STRING("# disconnect from AP"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_wlan_disconnect
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_disconnect
#endif /* CMD_WLAN_DISCONNECT */
#if (CMD_WLAN_IPCONFIG - 0)
static int
cmd_wlan_ipconfig (const char * argstr)
{
tNetappIpconfigRetArgs ipc;
const unsigned char * p;
memset(&ipc, 0, sizeof(ipc));
netapp_ipconfig(&ipc);
cprintf("IP: %s\n", ipv4AsText(ipc.aucIP));
cprintf("NM: %s\n", ipv4AsText(ipc.aucSubnetMask));
cprintf("GW: %s\n", ipv4AsText(ipc.aucDefaultGateway));
cprintf("DHCP: %s\n", ipv4AsText(ipc.aucDHCPServer));
cprintf("DNS: %s\n", ipv4AsText(ipc.aucDNSServer));
p = ipc.uaMacAddr;
/* WTF? A little-endian MAC address? This may be because of a bug
* fix in the host driver; the original version was completely
* wrong. */
cprintf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
p[5], p[4], p[3], p[2], p[1], p[0]);
cprintf("SSID: %s\n", ipc.uaSSID);
return 0;
}
static sBSP430cliCommand dcmd_wlan_ipconfig = {
.key = "ipconfig",
.help = HELP_STRING("# show IP parameters"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_wlan_ipconfig
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_ipconfig
static int
cmd_wlan_dhcp (const char * argstr)
{
size_t argstr_len = strlen(argstr);
int store_ipc = 0;
long lrc;
union {
uint32_t u32;
uint8_t u8[4];
} address[4];
(void)iBSP430cliStoreExtractedI(&argstr, &argstr_len, &store_ipc);
if (store_ipc) {
tNetappIpconfigRetArgs ipc;
memset(&ipc, 0, sizeof(ipc));
netapp_ipconfig(&ipc);
cprintf("Copying DHCP from IP config\n");
address[0].u32 = bebtohl(ipc.aucIP);
address[1].u32 = bebtohl(ipc.aucSubnetMask);
address[2].u32 = bebtohl(ipc.aucDefaultGateway);
address[3].u32 = bebtohl(ipc.aucDNSServer);
} else {
cprintf("Clearing DHCP config\n");
memset(address, 0, sizeof(address));
}
cprintf("IP: %s\n", net_ipv4AsText(address[0].u8));
cprintf("NM: %s\n", net_ipv4AsText(address[1].u8));
cprintf("GW: %s\n", net_ipv4AsText(address[2].u8));
cprintf("DNS: %s\n", net_ipv4AsText(address[3].u8));
lrc = netapp_dhcp(&address[0].u32,
&address[1].u32,
&address[2].u32,
&address[3].u32);
cprintf("dhcp got %ld\n", lrc);
return 0;
}
static sBSP430cliCommand dcmd_wlan_dhcp = {
.key = "dhcp",
.help = HELP_STRING("[1] # reset(0)/set(1) dhcp params"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_wlan_dhcp
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_dhcp
#endif /* CMD_WLAN_IPCONFIG */
typedef struct sWlanSecMap {
unsigned int val;
const char * tag;
} sWlanSecMap;
static const sWlanSecMap wlanSecMap[] = {
{ WLAN_SEC_UNSEC, "unsec" },
{ WLAN_SEC_WEP, "wep" },
{ WLAN_SEC_WPA, "wpa" },
{ WLAN_SEC_WPA2, "wpa2" },
};
static const sWlanSecMap * const wlanSecMap_end = wlanSecMap + sizeof(wlanSecMap)/sizeof(*wlanSecMap);
static const sWlanSecMap * wlanSecMapFromValue (unsigned int val)
{
const sWlanSecMap * mp;
for (mp = wlanSecMap; mp < wlanSecMap_end; ++mp) {
if (mp->val == val) {
return mp;
}
}
return NULL;
}
static const sWlanSecMap * wlanSecMapFromTag (const char * tag)
{
const sWlanSecMap * mp;
for (mp = wlanSecMap; mp < wlanSecMap_end; ++mp) {
if (0 == strcmp(mp->tag, tag)) {
return mp;
}
}
return NULL;
}
#if (CMD_WLAN_CONNECT - 0)
sConnectParams connectParams;
static int
cmd_wlan_sectype (const char * argstr)
{
size_t remaining = strlen(argstr);
size_t len;
const char * tp;
const sWlanSecMap * mp;
tp = xBSP430cliNextQToken(&argstr, &remaining, &len);
if (0 < len) {
mp = wlanSecMapFromTag(tp);
if (0 != mp) {
connectParams.security_type = mp->val;
} else {
cprintf("ERR: Unrecognized sectype '%s': valid are", tp);
for (mp = wlanSecMap; mp < wlanSecMap_end; ++mp) {
cprintf(" %s", mp->tag);
}
cprintf("\n");
}
}
mp = wlanSecMapFromValue(connectParams.security_type);
cprintf("AP security type is %s (%u)\n", (mp ? mp->tag : "<UNDEF>"), connectParams.security_type);
return 0;
}
static int
cmd_wlan_ssid (const char * argstr)
{
size_t remaining = strlen(argstr);
size_t len;
const char * tp;
tp = xBSP430cliNextQToken(&argstr, &remaining, &len);
if (0 < len) {
memcpy(connectParams.ssid, tp, len);
connectParams.ssid[len] = 0;
connectParams.ssid_len = len;
}
cprintf("AP SSID is %s (%u chars)\n", connectParams.ssid, (unsigned int)connectParams.ssid_len);
return 0;
}
static int
cmd_wlan_passphrase (const char * argstr)
{
size_t remaining = strlen(argstr);
size_t len;
const char * tp;
tp = xBSP430cliNextQToken(&argstr, &remaining, &len);
if (0 < len) {
if (sizeof(connectParams.passphrase) <= (len+1)) {
cprintf("ERR: Passphrase too long (> %u chars + EOS)\n", (unsigned int)sizeof(connectParams.passphrase));
} else {
memcpy(connectParams.passphrase, tp, len);
connectParams.passphrase[len] = 0;
connectParams.passphrase_len = len;
}
}
cprintf("AP passphrase is '%s' (%u chars)\n", connectParams.passphrase, (unsigned int)connectParams.passphrase_len);
return 0;
}
static int
cmd_wlan_autocon (const char * argstr)
{
long rc;
int rv;
size_t argstr_len = strlen(argstr);
unsigned int should_connect_to_open_ap = 0;
unsigned int should_use_fast_connect = 1;
unsigned int use_profiles = 1;
uint8_t u32octets[4];
/* Analysis shows:
* should_connect_to_open_ap in NVS at 0x44 32-bit int
* should_use_fast_connect in NVS at 0x48 32-bit int
* use_profiles in NVS at 0x50 32-bit int */
cprintf("Current connection policy:\n");
rc = nvmem_read(NVMEM_WLAN_CONFIG_FILEID, sizeof(uint32_t), 0x44, u32octets);
if (0 == rc) {
cprintf("should_connect_to_open_ap = 0x%08lx\n", lebtohl(u32octets));
}
rc = nvmem_read(NVMEM_WLAN_CONFIG_FILEID, sizeof(uint32_t), 0x48, u32octets);
if (0 == rc) {
cprintf("should_use_fast_connect = 0x%08lx\n", lebtohl(u32octets));
}
rc = nvmem_read(NVMEM_WLAN_CONFIG_FILEID, sizeof(uint32_t), 0x50, u32octets);
if (0 == rc) {
cprintf("use_profiles = 0x%08lx\n", lebtohl(u32octets));
}
rv = iBSP430cliStoreExtractedUI(&argstr, &argstr_len, &should_connect_to_open_ap);
if (0 == rv) {
rv = iBSP430cliStoreExtractedUI(&argstr, &argstr_len, &should_use_fast_connect);
}
if (0 == rv) {
rv = iBSP430cliStoreExtractedUI(&argstr, &argstr_len, &use_profiles);
}
cprintf("New connection policy: open_ap=%u fast_connect=%u use_profiles=%u\n",
should_connect_to_open_ap, should_use_fast_connect, use_profiles);
rc = wlan_ioctl_set_connection_policy(should_connect_to_open_ap, should_use_fast_connect, use_profiles);
cprintf("Connection policy set got %ld\n", rc);
return 0;
}
static int
cmd_wlan_connect (const char * argstr)
{
long rl;
const sWlanSecMap * mp;
unsigned long t[2];
mp = wlanSecMapFromValue(connectParams.security_type);
cprintf("connect to ssid '%s' by %s using '%s'\n",
connectParams.ssid, (mp ? mp->tag : "<UNDEF>"),
connectParams.passphrase);
rl = wlan_connect(connectParams.security_type,
connectParams.ssid, connectParams.ssid_len,
NULL,
connectParams.passphrase, connectParams.passphrase_len);
cprintf("con %ld in %s\n", rl, xBSP430uptimeAsText_ni(t[1]-t[0]));
return 0;
}
static sBSP430cliCommand dcmd_wlan_ssid = {
.key = "ssid",
.help = HELP_STRING("[{ssid}] # Display or set AP SSID for connect"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_wlan_ssid
};
static sBSP430cliCommand dcmd_wlan_passphrase = {
.key = "passphrase",
.help = HELP_STRING("[{passphrase}] # Display or set AP passphrase"),
.next = &dcmd_wlan_ssid,
.param.simple_handler = cmd_wlan_passphrase
};
static sBSP430cliCommand dcmd_wlan_sectype = {
.key = "sectype",
.help = HELP_STRING("[{sectype}] # Display or set AP sectype"),
.next = &dcmd_wlan_passphrase,
.param.simple_handler = cmd_wlan_sectype
};
static sBSP430cliCommand dcmd_wlan_autocon = {
.key = "autocon",
.help = HELP_STRING("[open_ap=0 [fast_conn=1 [auto_conn=1]]]"),
.next = &dcmd_wlan_sectype,
.param.simple_handler = cmd_wlan_autocon
};
static sBSP430cliCommand dcmd_wlan_connect = {
.key = "connect",
.help = HELP_STRING("# connect to specified access point using AP config"),
.next = &dcmd_wlan_autocon,
.param.simple_handler = cmd_wlan_connect
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_connect
#endif /* CMD_WLAN_CONNECT */
#if (CMD_WLAN_PROFILE - 0)
static int
cmd_wlan_profile_del (const char * argstr)
{
size_t argstr_len = strlen(argstr);
long rc;
int profile = 255;
/* Use 255 to delete all profiles. */
(void)iBSP430cliStoreExtractedI(&argstr, &argstr_len, &profile);
rc = wlan_ioctl_del_profile(profile);
cprintf("Del profile %d got %ld\n", profile, rc);
return 0;
}
typedef struct sProfileEntry {
unsigned int priority;
int security_type;
const char * ssid;
const char * passphrase;
} sProfileEntry;
static int
cmd_wlan_profile_update (const char * argstr)
{
static const sProfileEntry entries[] = {
#if (WITH_PROFILES - 0)
#include "profiles.inc"
#endif /* WITH_PROFILES */
};
const sProfileEntry * pep = entries;
const sProfileEntry * const pepe = pep + sizeof(entries)/sizeof(*entries);
long rc;
if (pep == pepe) {
cprintf("No profiles available\n");
return -1;
}
/* Per
* http://e2e.ti.com/support/low_power_rf/f/851/p/285991/999909.aspx#999909
* the magic constants below are from wpa_supplicant. */
#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2 0x00000002
#define WPA_CIPHER_NONE 0x01
#define WPA_CIPHER_WEP40 0x02
#define WPA_CIPHER_WEP104 0x04
#define WPA_CIPHER_TKIP 0x08
#define WPA_CIPHER_CCMP 0x10
while (pep < pepe) {
uint32_t pairwisecipher_or_keylen = 0;
uint32_t groupcipher_or_keyindex = 0;
uint32_t key_mgmt = 0;
uint8_t * pf_or_key = NULL;
uint32_t key_length = 0;
const sWlanSecMap * const mp = wlanSecMapFromValue(pep->security_type);
if (NULL != mp) {
if ((WLAN_SEC_WPA == pep->security_type)
|| (WLAN_SEC_WPA2 == pep->security_type)) {
pairwisecipher_or_keylen = WPA_CIPHER_TKIP | WPA_CIPHER_CCMP;
groupcipher_or_keyindex = WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104 | WPA_CIPHER_TKIP | WPA_CIPHER_CCMP;
key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2;
pf_or_key = (uint8_t*)pep->passphrase;
key_length = strlen(pep->passphrase);
} else if (WLAN_SEC_WEP == pep->security_type) {
pairwisecipher_or_keylen = strlen(pep->passphrase);
groupcipher_or_keyindex = 0;
key_mgmt = 0;
pf_or_key = (uint8_t*)pep->passphrase;
key_length = 0;
} else if (WLAN_SEC_UNSEC == pep->security_type) {
pairwisecipher_or_keylen = 0;
groupcipher_or_keyindex = 0;
key_mgmt = 0;
pf_or_key = NULL;
key_length = 0;
}
rc = wlan_add_profile(pep->security_type,
(uint8_t*)pep->ssid,
strlen(pep->ssid),
NULL, /* bssid is inferred */
pep->priority,
pairwisecipher_or_keylen,
groupcipher_or_keyindex,
key_mgmt,
pf_or_key,
key_length);
cprintf("Add SSID '%s' sec '%s' pri %u got %ld\n",
pep->ssid, mp->tag, pep->priority, rc);
} else {
cprintf("ERR: Profile %u %s has invalid security type %d\n",
(unsigned int)(pep - entries),
pep->ssid, pep->security_type);
}
++pep;
}
return 0;
}
static sBSP430cliCommand dcmd_wlan_profile_del = {
.key = "del",
.help = HELP_STRING("[profile=0] # delete profile, 255 for all"),
.next = NULL,
.param.simple_handler = cmd_wlan_profile_del
};
static sBSP430cliCommand dcmd_wlan_profile_update = {
.key = "update",
.help = HELP_STRING("[profile=0] # add configured profiles"),
.next = &dcmd_wlan_profile_del,
.param.simple_handler = cmd_wlan_profile_update
};
static sBSP430cliCommand dcmd_wlan_profile = {
.key = "profile",
.next = LAST_SUB_COMMAND,
.child = &dcmd_wlan_profile_update
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_profile
#endif /* CMD_WLAN_PROFILE */
#if (CMD_WLAN_SMART - 0)
static int
cmd_wlan_smart_aes (const char * argstr)
{
size_t argstr_len = strlen(argstr);
const char * key = NULL;
size_t keylen;
unsigned char keybuf[AES128_KEY_SIZE];
long rc;
while (isspace((unsigned char)*argstr)) {
++argstr;
}
argstr_len = strlen(argstr);
if (*argstr) {
key = xBSP430cliNextQToken(&argstr, &argstr_len, &keylen);
memset(keybuf, 0, sizeof(keybuf));
if (sizeof(keybuf) < keylen) {
keylen = sizeof(keybuf);
}
memcpy(keybuf, key, keylen);
rc = aes_write_key(keybuf);
cprintf("aes_write_key got %ld\n", rc);
} else {
rc = aes_read_key(keybuf);
cprintf("aes_read_key got %ld\n", rc);
}
cprintf("Key:\n");
vBSP430consoleDisplayMemory((unsigned char *)keybuf, sizeof(keybuf), 0);
return 0;
}
static int
cmd_wlan_smart_process (const char * argstr)
{
long rc;
rc = wlan_smart_config_process();
cprintf("wlan_smart_config_process() got %ld\n", rc);
return 0;
}
static int
cmd_wlan_smart_stop (const char * argstr)
{
long rc;
rc = wlan_smart_config_stop();
cprintf("wlan_smart_config_stop() got %ld\n", rc);
return 0;
}
static int
cmd_wlan_smart_start (const char * argstr)
{
size_t argstr_len = strlen(argstr);
unsigned int encrypted = 0;
long rc;
/* This has to be TTT. It doesn't matter what you pass as long as
* it's non-null; SP 1.10.1 through 1.12 (at least) will use TTT.
* In fact, it will helpfully overwrite whatever you pass in so that
* you know you're using TTT. So you can't pass a string literal
* unless your MCU allows you to write into flash, which is probably
* a bad thing to promote given the use of FRAM devices. */
{
char prefix[] = "123";
cprintf("Setting prefix to '%s'\n", prefix);
rc = wlan_smart_config_set_prefix(prefix);
cprintf("Prefix set returned %ld, now '%s'\n", rc, prefix);
}
(void)iBSP430cliStoreExtractedUI(&argstr, &argstr_len, &encrypted);
if (encrypted) {
unsigned char keybuf[AES128_KEY_SIZE];
rc = aes_read_key(keybuf);
cprintf("Config with AES key:\n");
vBSP430consoleDisplayMemory((unsigned char *)keybuf, sizeof(keybuf), 0);
} else {
cprintf("Config unencrypted\n");
}
rc = wlan_smart_config_start(encrypted);
cprintf("wlan_smart_config_start(%d) got %ld\n", encrypted, rc);
return 0;
}
static sBSP430cliCommand dcmd_wlan_smart_aes = {
.key = "aes",
.help = HELP_STRING("[key] # set or read AES key"),
.next = NULL,
.param.simple_handler = cmd_wlan_smart_aes
};
static sBSP430cliCommand dcmd_wlan_smart_process = {
.key = "process",
.help = HELP_STRING("# process AES received data"),
.next = &dcmd_wlan_smart_aes,
.param.simple_handler = cmd_wlan_smart_process
};
static sBSP430cliCommand dcmd_wlan_smart_stop = {
.key = "stop",
.help = HELP_STRING("# stop smart config process"),
.next = &dcmd_wlan_smart_process,
.param.simple_handler = cmd_wlan_smart_stop
};
static sBSP430cliCommand dcmd_wlan_smart_start = {
.key = "start",
.help = HELP_STRING("[encrypted=0] # start smart config process"),
.next = &dcmd_wlan_smart_stop,
.param.simple_handler = cmd_wlan_smart_start
};
static sBSP430cliCommand dcmd_wlan_smart = {
.key = "smart",
.next = LAST_SUB_COMMAND,
.child = &dcmd_wlan_smart_start
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_smart
#endif /* CMD_WLAN_SMART */
#if (CMD_WLAN_STATUS - 0)
static int
cmd_wlan_status (const char * argstr)
{
/* Contrary to the documentation, there are no macro constants
* defined for these states */
static const char * status_str[] = {
"disconnected",
"scanning",
"connecting",
"connected"
};
long rl = wlan_ioctl_statusget();
#if (CMD_WLAN_CONNECT - 0)
{
const sWlanSecMap * mp;
mp = wlanSecMapFromValue(connectParams.security_type);
cprintf("AP configuration SSID '%s', passphrase '%s'\n",
connectParams.ssid, connectParams.passphrase);
cprintf("AP security type %s (%u)\n", (mp ? mp->tag : "<UNDEF>"), connectParams.security_type);
}
#endif /* CMD_WLAN_CONNECT */
cprintf("WLAN status %ld", rl);
if ((0 <= rl) && (rl < (sizeof(status_str)/sizeof(*status_str)))) {
cprintf(": %s", status_str[rl]);
}
cputchar('\n');
return 0;
}
static sBSP430cliCommand dcmd_wlan_status = {
.key = "status",
.help = HELP_STRING("# get CC3000 status and AP config"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_wlan_status
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_status
#endif /* CMD_WLAN_STATUS */
#if (CMD_WLAN_BROKEN - 0)
static int
cmd_wlan_timeouts (const char * argstr)
{
long rc;
struct {
unsigned long dhcp_s;
unsigned long arp_s;
unsigned long ka_s;
unsigned long inactive_s;
} params;
params.dhcp_s = 14400;
params.arp_s = 3600;
params.ka_s = 600000;
params.inactive_s = 600000;
cprintf("*** NOTE: No evidence this function works (KA does not)\n");
cprintf("DHCP timeout: %lu sec\n", params.dhcp_s);
cprintf("ARP timeout: %lu sec\n", params.arp_s);
cprintf("Keep-Alive timeout: %lu sec\n", params.ka_s);
cprintf("Inactive timeout: %lu sec\n", params.inactive_s);
rc = netapp_timeout_values(&params.dhcp_s, &params.arp_s, &params.ka_s, &params.inactive_s);
cprintf("Timeout set got %ld\n", rc);
return 0;
}
static sBSP430cliCommand dcmd_wlan_timeouts = {
.key = "timeouts",
.help = HELP_STRING("# set CC3000 timeouts"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_wlan_timeouts
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_timeouts
#endif /* CMD_WLAN_BROKEN */
#if (CMD_WLAN_START - 0)
static int
cmd_wlan_start (const char * argstr)
{
size_t argstr_len = strlen(argstr);
unsigned int patches_available = 0;
unsigned long t[2];
(void)iBSP430cliStoreExtractedUI(&argstr, &argstr_len, &patches_available);
wlan_start(patches_available);
cprintf("wlan_start(%u) took %s\n", patches_available, xBSP430uptimeAsText_ni(t[1]-t[0]));
return 0;
}
static sBSP430cliCommand dcmd_wlan_start = {
.key = "start",
.help = HELP_STRING("[patchcount=0] # power-up CC3000"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_wlan_start
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_start
#endif /* CMD_WLAN_START */
static sBSP430cliCommand dcmd_wlan = {
.key = "wlan",
.next = LAST_COMMAND,
.child = LAST_SUB_COMMAND
};
#undef LAST_COMMAND
#define LAST_COMMAND &dcmd_wlan
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND NULL
#endif /* CMD_WLAN */
#if (CMD_SCAN - 0)
#define X_WLAN_SCAN_STATUS_AGED 0
#define X_WLAN_SCAN_STATUS_VALID 1
#define X_WLAN_SCAN_STATUS_NONE 2
typedef struct sWLANFullScanResults {
uint32_t network_count;
uint32_t scan_status;
unsigned int isValid:1;
unsigned int rssi:7;
unsigned int securityMode:2;
unsigned int ssidNameLength:6;
uint16_t entryTime;
char ssid[32];
unsigned char bssid[6];
} sWLANFullScanResults;
static int
cmd_scan_show (const char * argstr)
{
size_t argstr_len = strlen(argstr);
int with_mem = 0;
long rc;
union {
sWLANFullScanResults structure;
unsigned char bytes[1];
} uresult;
const sWLANFullScanResults * const sp = &uresult.structure;
(void)iBSP430cliStoreExtractedI(&argstr, &argstr_len, &with_mem);
cprintf("Scan results:\n"
"SSID "
"Scty "
"BSSID "
"RSSI "
"Time"
"\n");
do {
rc = wlan_ioctl_get_scan_results(0, uresult.bytes);
if (0 != rc) {
cprintf("ERR: rc %ld\n", rc);
break;
}
if (X_WLAN_SCAN_STATUS_NONE == sp->scan_status) {
cprintf("No results\n");
break;
}
if (X_WLAN_SCAN_STATUS_AGED == sp->scan_status) {
cprintf("No new results\n");
break;
}
if (! sp->isValid) {
cprintf("Invalid\n");
continue;
}
if (with_mem) {
vBSP430consoleDisplayMemory(uresult.bytes, sizeof(*sp), 0);
}
{ /* SSID */
const int nsp = sp->ssidNameLength;
int i;
for (i = 0; i < sizeof(sp->ssid); ++i) {
cputchar((i < nsp) ? sp->ssid[i] : ' ');
}
cputchar(' ');
}
{ /* Security */
const sWlanSecMap * mp = wlanSecMapFromValue(sp->securityMode);
cprintf("%-5s ", (NULL == mp) ? "???" : mp->tag);
}
{ /* BSSI */
int i;
cprintf("%02x", sp->bssid[0]);
for (i = 1; i < sizeof(sp->bssid); ++i) {
cprintf(":%02x", sp->bssid[i]);
}
cputchar(' '); /* 17 chars plus separating space */
}
cprintf("% 3d ", -128 + sp->rssi); /* RSSI */
cprintf("%-5u ", sp->entryTime); /* Time */
cputchar('\n');
} while (1 < sp->network_count);
return 0;
}
static int
cmd_scan_start (const char * argstr)
{
size_t argstr_len = strlen(argstr);
unsigned long rc;
unsigned long interval_ms = 1;
unsigned long delays[16];
int i;
(void)iBSP430cliStoreExtractedUL(&argstr, &argstr_len, &interval_ms);
for (i = 0; i < sizeof(delays)/sizeof(*delays); ++i) {
delays[i] = 2000;
}
rc = wlan_ioctl_set_scan_params(interval_ms, /* Enable (1 is 10 min interval; other values are interval between active probe sweeps, in ms) */
100, /* Min dwell per channel */
150, /* Max dwell per channel */
5, /* Probes within dwell. 0 will still send one probe. */
0x7ff, /* Channel mask: 0x7ff enables 1..11 */
-80, /* Default RSSI threshold. No apparent effect changing this. */
0, /* SNR threshold */
205, /* Probe TX power */
delays); /* Timeout between scans */
cprintf("Scan start %lu ms got %ld\n", interval_ms, rc);
return rc;
}
static int
cmd_scan_stop (const char * argstr)
{
unsigned long rc;
unsigned long delays[16];
int i;
for (i = 0; i < sizeof(delays)/sizeof(*delays); ++i) {
delays[i] = 2000;
}
/* This stops the scan within the current session, but it will
* automatically restart on the next power-up. */
rc = wlan_ioctl_set_scan_params(0, 150, 150, 5, 0x1fff, -80, 0, 205, delays);
cprintf("Scan stop got %ld\n", rc);
return rc;
}
static sBSP430cliCommand dcmd_scan_show = {
.key = "show",
.help = HELP_STRING(" [with_mem=0] # display scan results"),
.next = NULL,
.param.simple_handler = cmd_scan_show
};
static sBSP430cliCommand dcmd_scan_stop = {
.key = "stop",
.help = HELP_STRING("# disable periodic scan"),
.next = &dcmd_scan_show,
.param.simple_handler = cmd_scan_stop
};
static sBSP430cliCommand dcmd_scan_start = {
.key = "start",
.help = HELP_STRING(" [interval=1] # start periodic scan (ms)"),
.next = &dcmd_scan_stop,
.param.simple_handler = cmd_scan_start
};
static sBSP430cliCommand dcmd_scan = {
.key = "scan",
.next = LAST_COMMAND,
.child = &dcmd_scan_start
};
#undef LAST_COMMAND
#define LAST_COMMAND &dcmd_scan
#endif /* CMD_SCAN */
#if (CMD_NVMEM - 0)
typedef struct sNVMEMFileIds {
unsigned int fileid;
unsigned int size;
const char * tag;
} sNVMEMFileIds;
static const sNVMEMFileIds nvmemFiles[] = {
{ NVMEM_NVS_FILEID, 512, "NVS", },
{ NVMEM_NVS_SHADOW_FILEID, 512, "NVS (shadow)" },
{ NVMEM_WLAN_CONFIG_FILEID, 4096, "WLAN Config", },
{ NVMEM_WLAN_CONFIG_SHADOW_FILEID, 4096, "WLAN Config (shadow)" },
{ NVMEM_WLAN_DRIVER_SP_FILEID, 0, "WLAN Driver SP" },
{ NVMEM_WLAN_FW_SP_FILEID, 0, "WLAN Firmware SP" },
{ NVMEM_MAC_FILEID, 16, "MAC address" },
{ NVMEM_FRONTEND_VARS_FILEID, 0, "Front End Vars ??" },
{ NVMEM_IP_CONFIG_FILEID, 64, "IP Config" },
{ NVMEM_IP_CONFIG_SHADOW_FILEID, 64, "IP Config (shadow)" },
{ NVMEM_BOOTLOADER_SP_FILEID, 0, "Bootloader SP" },
{ NVMEM_RM_FILEID, 0, "Radio Module" },
{ NVMEM_AES128_KEY_FILEID, 0, "AES128 Key" },
{ NVMEM_SHARED_MEM_FILEID, 0, "Shared Memory ??" },
};
#if (WITH_UPDATE - 0)
/* Firmware updates for the CC3000 are distributed by TI through the
* Patch Programmer utility available at:
* http://processors.wiki.ti.com/index.php/CC3000_Wi-Fi_Downloads#Patch_Programmer
*
* This utility is export-controlled, and there is no indication that
* the binary firmware data is licensed with rights to redistribute.
* Therefore, if you want to update firmware or compare radio module
* parameters, you need to obtain the source to the patch programmer
* and create files that contain the byte literal initializer sequence
* to fill in the arrays below. */
/* This array should hold WLAN driver patches. The length is
* somewhere around 8kB, and the values can be found in the
* wlan_drv_patch array in PatchProgrammer_DR_Patch.c from the TI
* patch programmer utility. */
const uint8_t wlan_drv_patch[] = {
#include "wlan_drv_patch.inc"
};
/* This array should hold WLAN firmware patches. The length is
* somewhere around 8kB, and the values can be found in the fw_patch
* array in PatchProgrammer_FW_Patch.c from the TI patch programmer
* utility. */
const uint8_t fw_patch[] = {
#include "fw_patch.inc"
};
static int
cmd_nvmem_update (const char * argstr)
{
int rc;
int stage;
const uint16_t drv_sp_size = sizeof(wlan_drv_patch);
const uint16_t fw_sp_size = sizeof(fw_patch);
uint16_t drv_sp_fatsize;
uint16_t fw_sp_fatsize;
do {
stage = __LINE__;
rc = nvmem_read(NVMEM_MAX_ENTRY, sizeof(drv_sp_fatsize), 4*(1 + NVMEM_WLAN_DRIVER_SP_FILEID) + 2, (uint8_t*)&drv_sp_fatsize);
if (0 != rc) {
break;
}
stage = __LINE__;
rc = nvmem_read(NVMEM_MAX_ENTRY, sizeof(drv_sp_fatsize), 4*(1 + NVMEM_WLAN_FW_SP_FILEID) + 2, (uint8_t*)&fw_sp_fatsize);
if (0 != rc) {
break;
}
cprintf("Driver update size %u, file size %u\n"
"Firmware update size %u, file size %u\n",
drv_sp_size, drv_sp_fatsize,
fw_sp_size, fw_sp_fatsize);
if ((0 == drv_sp_size) || (drv_sp_size > drv_sp_fatsize)) {
cprintf("ERROR: No driver, or driver too large\n");
return -1;
}
if ((0 == fw_sp_size) || (fw_sp_size > fw_sp_fatsize)) {
cprintf("ERROR: No firmware, or firmware too large\n");
return -1;
}
cprintf("Shutting down WLAN for driver update\n");
wlan_stop();
cprintf("Waiting a few...");
cprintf("back now\n");
cprintf("Starting WLAN in patch mode\n");
wlan_start(2);
wlan_ioctl_set_connection_policy(0, 0, 0);
wlan_ioctl_del_profile(255);
wlan_set_event_mask(HCI_EVNT_WLAN_KEEPALIVE|HCI_EVNT_WLAN_UNSOL_INIT|HCI_EVNT_WLAN_ASYNC_PING_REPORT);
cprintf("Updating driver firmware...");
stage = __LINE__;
rc = nvmem_write_patch(NVMEM_WLAN_DRIVER_SP_FILEID, drv_sp_size, (uint8_t *)wlan_drv_patch);
if (0 != rc) {
break;
}
cprintf("success.\n"
"Updating firmware...");
stage = __LINE__;
rc = nvmem_write_patch(NVMEM_WLAN_FW_SP_FILEID, fw_sp_size, (uint8_t *)fw_patch);
if (0 != rc) {
break;
}
cprintf("success.\n"
"Shutting down WLAN after driver update\n");
wlan_stop();
cprintf("Restarting WLAN with new drivers\n");
wlan_start(0);
} while (0);
if (0 != rc) {
cprintf("ERROR %d in update at line %u\n", rc, stage);
}
return 0;
}
static sBSP430cliCommand dcmd_nvmem_update = {
.key = "update",
.help = HELP_STRING("# Update firmware"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_nvmem_update
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_nvmem_update
#endif /* WITH_UPDATE */
static int
cmd_nvmem_dir (const char * argstr)
{
int rc;
const unsigned int num_doc_files = sizeof(nvmemFiles) / sizeof(*nvmemFiles);
uint8_t fat[4*(NVMEM_MAX_ENTRY+1)];
const uint16_t * fp = (const uint16_t *)(fat+4);
const uint16_t * efp = (const uint16_t *)(fat+sizeof(fat));
int ffi = 0;
cprintf("%u NVMEM files with %u documented:\n", NVMEM_MAX_ENTRY, num_doc_files);
rc = nvmem_read(NVMEM_MAX_ENTRY, sizeof(fat), 0, fat);
if (0 != rc) {
cprintf("ERROR: nvmem read got %d\n", rc);
return 0;
}
if (('L' != fat[0]) || ('S' != fat[1])) {
cprintf("ERROR: nvmem signature %02x %02x not %02x %02x\n",
fat[0], fat[1], 'L', 'S');
return 0;
}
cprintf("ID Addr Size Flg : Doc ID Size Description\n");
while (fp < efp) {
cprintf("%2d %04x %5d %c%c%c",
ffi, fp[0] & ~(BIT0|BIT1|BIT2), fp[1],
(fp[0] & BIT0) ? 'a' : ' ',
(fp[0] & BIT1) ? 'v' : ' ',
(fp[0] & BIT2) ? 'p' : ' ');
if (ffi < sizeof(nvmemFiles)/sizeof(*nvmemFiles)) {
cprintf(" %2d %5d %s",
nvmemFiles[ffi].fileid,
nvmemFiles[ffi].size,
nvmemFiles[ffi].tag);
}
cputchar('\n');
++ffi;
fp += 2;
}
return 0;
}
static sBSP430cliCommand dcmd_nvmem_dir = {
.key = "dir",
.help = HELP_STRING("# describe NVMEM sections"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_nvmem_dir
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_nvmem_dir
static int
cmd_nvmem_create (const char * argstr)
{
size_t argstr_len = strlen(argstr);
unsigned int fileid = NVMEM_AES128_KEY_FILEID;
unsigned int length = AES128_KEY_SIZE;
long rc;
int rv;
rv = iBSP430cliStoreExtractedUI(&argstr, &argstr_len, &fileid);
if (0 == rv) {
rv = iBSP430cliStoreExtractedUI(&argstr, &argstr_len, &length);
}
rc = nvmem_create_entry(fileid, length);
cprintf("nvmem_create_entry(%u, %u) got %ld\n", fileid, length, rc);
return 0;
}
static sBSP430cliCommand dcmd_nvmem_create = {
.key = "create",
.help = HELP_STRING("[fileid=12 [length=16]] # create a new NVMEM section"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_nvmem_create
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_nvmem_create
#if (CMD_NVMEM_SP - 0)
static int
cmd_nvmem_sp (const char * argstr)
{
unsigned char patch_version[2];
unsigned char rv;
memset(patch_version, -1, sizeof(patch_version));
rv = nvmem_read_sp_version(patch_version);
cprintf("sp ret %u: %u.%u\n", rv, patch_version[0], patch_version[1]);
cprintf("Host driver %u\n", DRIVER_VERSION_NUMBER);
return 0;
}
static sBSP430cliCommand dcmd_nvmem_sp = {
.key = "sp",
.help = HELP_STRING("# read firmware service pack level"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_nvmem_sp
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_nvmem_sp
#endif /* CMD_NVMEM_SP */
#if (CMD_NVMEM_RMPARAM - 0)
#if (WITH_RMPARAM - 0)
/* This array should hold the default radio module parameters. The
* length is nominally 128 bytes, and the values can be found in the
* cRMdefaultParams array in PatchProgrammer_DR_Patch.c from the TI
* patch programmer utility. */
const uint8_t default_rm_param[] = {
#include "rm_param.inc"
};
#endif
static int
cmd_nvmem_rmparam (const char * argstr)
{
uint8_t rmparam[128];
const uint8_t * const rmpe = rmparam + sizeof(rmparam);
uint8_t * rp = rmparam;
int rc;
while (rp < rmpe) {
unsigned int offset = rp - rmparam;
unsigned int nb = rmpe - rp;
if (16 < nb) {
nb = 16;
}
rc = nvmem_read(NVMEM_RM_FILEID, nb, offset, rp);
if (0 != rc) {
cprintf("ERROR %d reading at offset %u\n", rc, offset);
return 0;
}
rp += nb;
}
cprintf("Radio module parameters:\n");
vBSP430consoleDisplayMemory(rmparam, sizeof(rmparam), 0);
#if (WITH_RMPARAM - 0)
{
const uint8_t * drp = default_rm_param;
const uint8_t * const drpe = default_rm_param + sizeof(default_rm_param);
rp = rmparam;
while ((rp < rmpe) && (drp < drpe)) {
*rp++ ^= *drp++;
}
}
cprintf("Bitwise difference from default:\n");
vBSP430consoleDisplayMemory(rmparam, sizeof(rmparam), 0);
cprintf("Default RM parameters:\n");
vBSP430consoleDisplayMemory(default_rm_param, sizeof(default_rm_param), 0);
#endif /* WITH_RMPARAM */
return 0;
}
static sBSP430cliCommand dcmd_nvmem_rmparam = {
.key = "rmparam",
.help = HELP_STRING("# display radio module parameters"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_nvmem_rmparam
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_nvmem_rmparam
#endif /* CMD_NVMEM_SP */
#if (CMD_NVMEM_READ - 0)
static int
cmd_nvmem_read (const char * argstr)
{
int rc;
unsigned int fileid = 0;
unsigned int len = 128;
unsigned int ofs = 0;
unsigned char data[16]; /* Page size? */
unsigned int end_read;
unsigned int ui;
size_t argstr_len = strlen(argstr);
unsigned int nb;
rc = iBSP430cliStoreExtractedUI(&argstr, &argstr_len, &ui);
if (0 == rc) {
fileid = ui;
rc = iBSP430cliStoreExtractedUI(&argstr, &argstr_len, &ui);
}
if (0 == rc) {
len = ui;
rc = iBSP430cliStoreExtractedUI(&argstr, &argstr_len, &ui);
}
if (0 == rc) {
ofs = ui;
}
end_read = ofs + len;
rc = 0;
while ((0 == rc) && (ofs < end_read)) {
nb = (end_read - ofs);
if (sizeof(data) < nb) {
nb = sizeof(data);
}
/* Return is 0 if successful, 4 if offset too large, 3 unknown
* error. */
rc = nvmem_read(fileid, nb, ofs, data);
if (0 == rc) {
ofs += nb;
}
}
if (0 != rc) {
cprintf("\nERR: Read returned %u for %u bytes at %u of fileid %u\n",
rc, nb, ofs, fileid);
}
return 0;
}
static sBSP430cliCommand dcmd_nvmem_read = {
.key = "read",
.help = HELP_STRING("fileid [len(=128) [ofs(=0)]] # read block from nvmem file"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_nvmem_read
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_nvmem_read
#endif /* CMD_NVMEM_READ */
#if (CMD_NVMEM_MAC - 0)
static int
cmd_nvmem_mac (const char * argstr)
{
int rc;
unsigned char mac[6];
/* Could extend this to parse "set {addr}" if you wanted. */
rc = nvmem_get_mac_address(mac);
if (0 == rc) {
cprintf("nvmem mac is %02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
} else {
cprintf("ERR: nvmem mac read got %u\n", rc);
}
return 0;
}
static sBSP430cliCommand dcmd_nvmem_mac = {
.key = "mac",
.help = HELP_STRING("# get mac address"),
.next = LAST_SUB_COMMAND,
.param.simple_handler = cmd_nvmem_mac
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_nvmem_mac
#endif /* CMD_NVMEM_MAC */
static sBSP430cliCommand dcmd_nvmem = {
.key = "nvmem",
.next = LAST_COMMAND,
.child = LAST_SUB_COMMAND
};
#undef LAST_COMMAND
#define LAST_COMMAND &dcmd_nvmem
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND NULL
#endif /* CMD_NVMEM */
#if ! (BSP430_MODULE_FLASH - 0)
/* No support for this on FRAM boards yet */
#undef CMD_INFO
#endif
#if (CMD_INFO - 0)
static sConnectParams * const infoConnectParams = (sConnectParams *)__infob;
static int
cmd_info_load (const char * argstr)
{
if (MAGIC_CONNECT_PARAMS != infoConnectParams->magic) {
cprintf("ERR: Stored connection params invalid\n");
return -1;
}
#if (CMD_WLAN_CONNECT - 0)
connectParams = *infoConnectParams;
#endif /* CMD_WLAN_CONNECT */
return 0;
}
static int
cmd_info_erase_ni (void)
{
int rv;
cprintf("Erasing stored params at %p...", infoConnectParams);
rv = iBSP430flashEraseSegment_ni(infoConnectParams);
cprintf("%d\n", rv);
return rv;
}
static int
cmd_info_erase (const char * argstr)
{
int rv;
do {
rv = cmd_info_erase_ni();
} while (0);
return rv;
}
static int
cmd_info_store (const char * argstr)
{
int rv;
do {
rv = cmd_info_erase_ni();
if (0 == rv) {
connectParams.magic = MAGIC_CONNECT_PARAMS;
cprintf("Copying current configuration...");
rv = iBSP430flashWriteData_ni(infoConnectParams, &connectParams, sizeof(connectParams));
cprintf("%d\n", rv);
}
} while (0);
return rv;
}
static int
cmd_info_dump (const char * argstr)
{
cprintf("Configuration memory:\n");
vBSP430consoleDisplayMemory((const uint8_t *)infoConnectParams, __info_segment_size, (uintptr_t)infoConnectParams);
return 0;
}
static sBSP430cliCommand dcmd_info_dump = {
.key = "dump",
.help = HELP_STRING("# display INFO_B contents"),
.next = NULL,
.param.simple_handler = cmd_info_dump
};
static sBSP430cliCommand dcmd_info_store = {
.key = "store",
.help = HELP_STRING("# store wlan AP params in INFO_B"),
.next = &dcmd_info_dump,
.param.simple_handler = cmd_info_store
};
static sBSP430cliCommand dcmd_info_erase = {
.key = "erase",
.help = HELP_STRING("# erase INFO_B"),
.next = &dcmd_info_store,
.param.simple_handler = cmd_info_erase
};
static sBSP430cliCommand dcmd_info_load = {
.key = "load",
.help = HELP_STRING("# load wlan AP params from INFO_B"),
.next = &dcmd_info_erase,
.param.simple_handler = cmd_info_load
};
static sBSP430cliCommand dcmd_info = {
.key = "info",
.next = LAST_COMMAND,
.child = &dcmd_info_load
};
#undef LAST_COMMAND
#define LAST_COMMAND &dcmd_info
#endif /* CMD_INFO */
static int
cmd_mdns (const char * argstr)
{
size_t argstr_len = strlen(argstr);
const char * name = "CC3000";
size_t name_len;
int rc;
name = xBSP430cliNextQToken(&argstr, &argstr_len, &name_len);
if (0 == name_len) {
rc = mdnsAdvertiser(0, "CC3000", strlen("CC3000"));
} else {
int i;
cprintf("Will advertize: '");
for (i = 0; i < name_len; ++i) {
cputchar(name[i]);
}
cprintf("'\n");
rc = mdnsAdvertiser(1, (char *)name, name_len);
}
cprintf("mdnsAdvertiser got %d\n", rc);
return 0;
}
static sBSP430cliCommand dcmd_mdns = {
.key = "mdns",
.help = HELP_STRING("[name] # enable/disable mDNS"),
.next = LAST_COMMAND,
.param.simple_handler = cmd_mdns
};
#undef LAST_COMMAND
#define LAST_COMMAND &dcmd_mdns
static int
cmd_uptime (const char * argstr)
{
unsigned long now_utt;
now_utt = ulBSP430uptime_ni();
cprintf("Time: %s\n", xBSP430uptimeAsText(now_utt, timebuf));
cprintf("Last Event %lx: %s\n", lastEventType, xBSP430uptimeAsText(lastCallback_utt, timebuf));
cprintf("Last KA: %s\n", xBSP430uptimeAsText(lastKeepAlive_utt, timebuf));
return 0;
}
static sBSP430cliCommand dcmd_uptime = {
.key = "uptime",
.next = LAST_COMMAND,
.param.simple_handler = cmd_uptime
};
#undef LAST_COMMAND
#define LAST_COMMAND &dcmd_uptime
static int
cmd_ghbn (const char * argstr)
{
size_t argstr_len = strlen(argstr);
const char * name;
size_t name_len;
uint32_t addr = -1;
int rc;
name = xBSP430cliNextQToken(&argstr, &argstr_len, &name_len);
if (0 == name_len) {
name = "ntp.pool.org";
name_len = strlen(name);
}
rc = gethostbyname((char*)name, name_len, &addr);
cprintf("gethostbyname(%s) returned %d, ip: %s\n", name, rc, ipv4AsText((const uint8_t*)&addr));
return 0;
}
static sBSP430cliCommand dcmd_ghbn = {
.key = "ghbn",
.next = LAST_COMMAND,
.param.simple_handler = cmd_ghbn
};
#undef LAST_COMMAND
#define LAST_COMMAND &dcmd_ghbn
static int
cmd_test (sBSP430cliCommandLink * chain,
void * param,
const char * command,
size_t command_len)
{
return 0;
}
static sBSP430cliCommand dcmd_test = {
.key = "test",
.next = LAST_COMMAND,
.handler = cmd_test
};
#undef LAST_COMMAND
#define LAST_COMMAND &dcmd_test
#if (CMD_HELP - 0)
static int
cmd_help (sBSP430cliCommandLink * chain,
void * param,
const char * command,
size_t command_len)
{
return 0;
}
static sBSP430cliCommand dcmd_help = {
.key = "help",
.next = LAST_COMMAND,
.handler = cmd_help
};
#undef LAST_COMMAND
#define LAST_COMMAND &dcmd_help
#endif /* CMD_HELP */
void main (void)
{
int rv;
const char * command;
int flags;
#if (BSP430_MODULE_SYS - 0)
unsigned long reset_causes = 0;
unsigned int reset_flags = 0;
#endif /* BSP430_MODULE_SYS */
#if (BSP430_MODULE_SYS - 0)
{
unsigned int sysrstiv;
/* Record all the reset causes */
while (0 != ((sysrstiv = uiBSP430sysSYSRSTGenerator_ni(&reset_flags)))) {
reset_causes |= 1UL << (sysrstiv / 2);
}
#ifdef BSP430_PMM_ENTER_LPMXp5_NI
/* If we woke from LPMx.5, we need to clear the lock in PM5CTL0.
* We'll do it early, since we're not really interested in
* retaining the current IFG settings. */
if (reset_flags & BSP430_SYS_FLAG_SYSRST_LPM5WU) {
PMMCTL0_H = PMMPW_H;
PM5CTL0 = 0;
PMMCTL0_H = 0;
}
#endif /* BSP430_PMM_ENTER_LPMXp5_NI */
}
#endif /* BSP430_MODULE_SYS */
cprintf("\ncc3000 " __DATE__ " " __TIME__ "\n");
#if (BSP430_MODULE_SYS - 0)
cprintf("System reset bitmask %lx; causes:\n", reset_causes);
{
int bit = 0;
while (bit < (8 * sizeof(reset_causes))) {
if (reset_causes & (1UL << bit)) {
}
++bit;
}
}
cputtext("System reset included:");
if (reset_flags) {
if (reset_flags & BSP430_SYS_FLAG_SYSRST_BOR) {
cputtext(" BOR");
}
if (reset_flags & BSP430_SYS_FLAG_SYSRST_LPM5WU) {
cputtext(" LPM5WU");
}
if (reset_flags & BSP430_SYS_FLAG_SYSRST_POR) {
cputtext(" POR");
}
if (reset_flags & BSP430_SYS_FLAG_SYSRST_PUC) {
cputtext(" PUC");
}
} else {
cputtext(" no data");
}
cputchar('\n');
#endif /* BSP430_MODULE_SYS */
#ifdef BSP430_RF_CC3000_PWR_EN_PORT_PERIPH_HANDLE
#else /* BSP430_RF_CC3000_PWR_EN_PORT_PERIPH_HANDLE */
cprintf("No PWR_EN control.\n");
#endif /* BSP430_RF_CC3000_PWR_EN_PORT_PERIPH_HANDLE */
#if BSP430_PLATFORM_PERIPHERAL_HELP
#endif /* BSP430_PLATFORM_PERIPHERAL_HELP */
cprintf("CC3000 host driver: %u\n", DRIVER_VERSION_NUMBER);
cprintf("RX buffer size %u, TX buffer size %u\n",
cprintf(__DATE__ " " __TIME__ "\n");
/* Initialization can be done with interrupts disabled, since the
* function does nothing but store callbacks. We use the same
* callback for all three update capabilities. */
rv = iBSP430cc3000spiInitialize(wlan_cb, NULL, NULL, NULL);
cprintf("%s Initialize returned %d\n", xBSP430uptimeAsText_ni(ulBSP430uptime_ni()), rv);
if (0 > rv) {
cprintf("Aborting due to failure to initialized\n");
return;
}
commandSet = LAST_COMMAND;
command = NULL;
/* wlan_start() MUST be invoked with interrupts enabled. Pass 0 for
* a normal startup. If the firmware is suspect, you need to pass 2
* which will cause the NVMEM firmware sections to be ignored. */
#if (BYPASS_SP_LOAD - 0)
cprintf("Bypassing service packs\n");
wlan_start(2);
#else
wlan_start(0);
#endif
cprintf("\nAnd wlan has been started.\n");
rv = wlan_set_event_mask(0);
cprintf("Unmask events returned %d\n", rv);
#if (CMD_INFO - 0)
if (0 == cmd_info_load("")) {
cmd_wlan_status("");
}
#endif
while (1) {
if (flags & eBSP430cliConsole_DO_COMPLETION) {
flags &= ~eBSP430cliConsole_DO_COMPLETION;
flags |= iBSP430cliConsoleBufferCompletion(commandSet, &command);
}
if (flags & eBSP430cliConsole_READY) {
int rv;
rv = iBSP430cliExecuteCommand(commandSet, 0, command);
if (0 != rv) {
cprintf("Command execution returned %d\n", rv);
}
/* Ensure prompt is rewritten, but not the command we just
* ran */
command = NULL;
}
if (flags & eBSP430cliConsole_REPAINT) {
/* Draw the prompt along with whatever's left in the command buffer */
cprintf("\r> %s", command ? command : "");
flags &= ~eBSP430cliConsole_REPAINT;
}
if (flags & eBSP430cliConsole_REPAINT_BEL) {
cputchar('\a');
flags &= ~eBSP430cliConsole_REPAINT_BEL;
}
if (flags & eBSP430cliConsole_READY) {
/* Clear the command we just completed */
flags &= ~eBSP430cliConsole_READY;
}
do {
/* Discard any pending escape sequence */
/* If no operations are pending, see if there is pending input. */
if (0 == flags) {
}
/* If still no operations pending wait for something to
* happen. */
if (0 == flags) {
}
} while (! flags);
/* Got something to do; get the command contents in place so
* we can update the screen. */
}
}

bsp430_config.h

/* Use a crystal if one is installed. Much more accurate timing
* results. */
#define BSP430_PLATFORM_BOOT_CONFIGURE_LFXT1 1
/* Application does output: support spin-for-jumper */
#define configBSP430_PLATFORM_SPIN_FOR_JUMPER 1
/* Support console output */
#define configBSP430_CONSOLE 1
/* Enable an 8-character rx buffer for the console */
#define BSP430_CONSOLE_RX_BUFFER_SIZE 8
/* Enable an 80-character command buffer */
#define BSP430_CLI_CONSOLE_BUFFER_SIZE 80
/* Enable completion */
#define configBSP430_CLI_COMMAND_COMPLETION 1
/* Monitor uptime and provide generic ACLK-driven timer */
#define configBSP430_UPTIME 1
/* Support for CC30000 BoosterPack. This conflicts with RFEM use. */
#ifndef configBSP430_RF_CC3000BOOST
#define configBSP430_RF_CC3000BOOST 0
#endif /* configBSP430_RF_CC3000BOOST */
#if ! (configBSP430_RF_CC3000BOOST - 0)
/* Request RFEM interface resources specific to the CC3000EM. NB:
* CCEM maps SPI_IRQ to P6.5 on EXP430F5529LP; since that port is not
* interrupt-enabled the CC3000 can't be used on that platform. */
#define configBSP430_RFEM_CCEM 1
#define configBSP430_RFEM 1
#define configBSP430_RF_CC3000EM 1
#endif /* RFEM */
/* Get platform defaults */
/* We use HAL for CSn, perhaps because it's a generic interface to the
* DIR and OUT registers regardless of IE or non-IE register
* layout. */
#define BSP430_WANT_CONFIG_HAL 1
#define BSP430_WANT_PERIPH_CPPID BSP430_RF_CC3000_CSn_PORT_PERIPH_CPPID
#undef BSP430_WANT_CONFIG_HAL

Makefile

PLATFORM ?= exp430f5438
TEST_PLATFORMS=exp430f5438 trxeb
MODULES=$(MODULES_PLATFORM)
MODULES += $(MODULES_UPTIME)
MODULES += $(MODULES_CONSOLE)
MODULES += periph/port
MODULES += periph/sys
MODULES += periph/flash
MODULES += utility/cli
# Add the rules to provide external library support for the CC3000
include $(BSP430_ROOT)/make/Makefile.cc3000
# Optionally enable the nvmem update infrastructure.
# This requires the presence of two files:
# wlan_drv_patch.inc # has patches to the CC3000 driver
# fw_patch.inc # has patches to the CC3000 firmware
# See the source for information on where to get these files.
# You may need to disable other commands to make room for
# these, or build with 20-bit support.
WITH_UPDATE ?=
ifneq (,$(WITH_UPDATE))
AUX_CPPFLAGS += -DWITH_UPDATE
endif # WITH_UPDATE
# Optionally enable radio module comparison
# This requires the presence of the following file:
# rm_param.inc # has radio module default parameters
# See the source for information on where to get these files.
WITH_RMPARAM ?=
ifneq (,$(WITH_RMPARAM))
AUX_CPPFLAGS += -DWITH_RMPARAM
endif # WITH_RMPARAM
# Optionally enable SmartConfig.
WITH_SMART ?=
ifneq (,$(WITH_SMART))
AUX_CPPFLAGS += -DBSP430_CC3000_ENABLE_SMART
endif # WITH_SMART
# Optionally read profiles from local file
WITH_PROFILES ?=
ifneq (,$(WITH_PROFILES))
AUX_CPPFLAGS += -DWITH_PROFILES
endif # WITH_PROFILES
SRC += main.c
include $(BSP430_ROOT)/make/Makefile.common