<commit_before>/** This file is in the public domain.
 *
 * This program is an example; see detailed discussion within the
 * BSP430 documentation.
 *
 * @homepage http://github.com/pabigot/bsp430
 */

#include <bsp430/platform.h>
#include <bsp430/clock.h>
#include <bsp430/periph/port.h>
#include <bsp430/periph/sys.h>
#include <bsp430/periph/flash.h>
#include <sys/crtld.h>
#include <bsp430/utility/uptime.h>
#include <bsp430/utility/console.h>
#include <bsp430/utility/led.h>
#include <bsp430/utility/cli.h>
#include "cc3000spi.h"
#include <cc3000/wlan.h>
#include <cc3000/nvmem.h>
#include <cc3000/netapp.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

/* 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
 * EXP430F5438 the total application size is just over 20 kB. */
#define CMD_WLAN 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_NVMEM 1
#define CMD_NVMEM_SP 1
#define CMD_NVMEM_READ 1
#define CMD_NVMEM_MAC 1
#define CMD_INFO 1
#define CMD_HELP 1

#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

typedef struct sConnectParams {
  unsigned int magic;
  int security_type;
  size_t ssid_len;
  size_t passphrase_len;
  char ssid[33];
  unsigned char passphrase[65];
} sConnectParams;

static void wlan_cb (long event_type,
                     char * data,
                     unsigned char length)
{
  cprintf("%s wlan_cb %#lx %u at %p SR %#x\n",
          xBSP430uptimeAsText_ni(ulBSP430uptime_ni()),
          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,
  .handler = iBSP430cliHandlerSimple,
  .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,
  .handler = iBSP430cliHandlerSimple,
  .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)
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;
}

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,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_wlan_ipconfig
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_ipconfig
#endif /* CMD_WLAN_IPCONFIG */

#if (CMD_WLAN_CONNECT - 0)
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" },
#if 0
  /* WPA2 is not implemented.  Unit will transmit unsecured auth request */
  { WLAN_SEC_WPA2, "wpa2" },
#endif /* 0 */
};
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;
}

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, 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", 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, connectParams.passphrase_len);
  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);
  t[0] = ulBSP430uptime_ni();
  rl = wlan_connect(connectParams.security_type,
                    connectParams.ssid, connectParams.ssid_len,
                    NULL,
                    connectParams.passphrase, connectParams.passphrase_len);
  t[1] = ulBSP430uptime_ni();
  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,
  .handler = iBSP430cliHandlerSimple,
  .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,
  .handler = iBSP430cliHandlerSimple,
  .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,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_wlan_sectype
};
static sBSP430cliCommand dcmd_wlan_connect = {
  .key = "connect",
  .help = HELP_STRING("# connect to specified access point using AP config"),
  .next = &dcmd_wlan_sectype,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_wlan_connect
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_connect
#endif /* CMD_WLAN_CONNECT */

#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,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_wlan_status
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_status
#endif /* CMD_WLAN_STATUS */

#if (CMD_WLAN_START - 0)
static int
cmd_wlan_start (const char * argstr)
{
  unsigned long t[2];
  t[0] = ulBSP430uptime_ni();
  wlan_start(0);
  t[1] = ulBSP430uptime_ni();
  cprintf("wlan_start() took %s\n", xBSP430uptimeAsText_ni(t[1]-t[0]));
  return 0;
}
static sBSP430cliCommand dcmd_wlan_start = {
  .key = "start",
  .help = HELP_STRING("# power-up CC3000"),
  .next = LAST_SUB_COMMAND,
  .handler = iBSP430cliHandlerSimple,
  .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_NVMEM - 0) && (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]);
  return 0;
}
static sBSP430cliCommand dcmd_nvmem_sp = {
  .key = "sp",
  .help = HELP_STRING("# read firmware service pack level"),
  .next = LAST_SUB_COMMAND,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_nvmem_sp
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_nvmem_sp
#endif /* CMD_NVMEM_SP */

#if (CMD_NVMEM - 0) && (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[32];
  char asciiz[17];
  char * ap;
  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;
  memset(asciiz, 0, sizeof(asciiz));
  ap = asciiz;
  rc = 0;
  while ((0 == rc) && (ofs < end_read)) {
    unsigned char * dp;
    unsigned char * dpe;
    nb = (end_read - ofs);
    if (sizeof(data) < nb) {
      nb = sizeof(data);
    }
    rc = nvmem_read(fileid, nb, ofs, data);
    if (0 == rc) {
      dp = data;
      dpe = dp + nb;
      while (dp < dpe) {
        if (0 == (ofs % 16)) {
          cprintf("    %s\n%x.%04x ", asciiz, fileid, ofs);
          memset(asciiz, 0, sizeof(asciiz));
          ap = asciiz;
        } else if (0 == (ofs % 8)) {
          cprintf(" ");
        }
        ++ofs;
        *ap++ = isprint(*dp) ? *dp : '.';
        cprintf(" %02x", *dp++);
      }
      len -= nb;
    }
  }
  if (0 == rc) {
    cprintf("    %s\n", asciiz);
  } else {
    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,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_nvmem_read
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_nvmem_read
#endif /* CMD_NVMEM_READ */

#if (CMD_NVMEM - 0) && (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,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_nvmem_mac
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_nvmem_mac
#endif /* CMD_NVMEM_MAC */

#if (CMD_NVMEM - 0)
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)
{
  BSP430_CORE_SAVED_INTERRUPT_STATE(istate);
  int rv;

  BSP430_CORE_DISABLE_INTERRUPT();
  do {
    rv = cmd_info_erase_ni();
  } while (0);
  BSP430_CORE_RESTORE_INTERRUPT_STATE(istate);
  return rv;
}

static int
cmd_info_store (const char * argstr)
{
  BSP430_CORE_SAVED_INTERRUPT_STATE(istate);
  int rv;

  BSP430_CORE_DISABLE_INTERRUPT();
  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);
  BSP430_CORE_RESTORE_INTERRUPT_STATE(istate);
  return rv;
}
static sBSP430cliCommand dcmd_info_store = {
  .key = "store",
  .help = HELP_STRING("# store wlan AP params in INFO_B"),
  .next = NULL,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_info_store
};
static sBSP430cliCommand dcmd_info_erase = {
  .key = "erase",<commit_msg>cc3000: refactor to share memory display<commit_after>/** This file is in the public domain.
 *
 * This program is an example; see detailed discussion within the
 * BSP430 documentation.
 *
 * @homepage http://github.com/pabigot/bsp430
 */

#include <bsp430/platform.h>
#include <bsp430/clock.h>
#include <bsp430/periph/port.h>
#include <bsp430/periph/sys.h>
#include <bsp430/periph/flash.h>
#include <sys/crtld.h>
#include <bsp430/utility/uptime.h>
#include <bsp430/utility/console.h>
#include <bsp430/utility/led.h>
#include <bsp430/utility/cli.h>
#include "cc3000spi.h"
#include <cc3000/wlan.h>
#include <cc3000/nvmem.h>
#include <cc3000/netapp.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

/* 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
 * EXP430F5438 the total application size is just over 20 kB. */
#define CMD_WLAN 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_NVMEM 1
#define CMD_NVMEM_SP 1
#define CMD_NVMEM_READ 1
#define CMD_NVMEM_MAC 1
#define CMD_INFO 1
#define CMD_HELP 1

#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

typedef struct sConnectParams {
  unsigned int magic;
  int security_type;
  size_t ssid_len;
  size_t passphrase_len;
  char ssid[33];
  unsigned char passphrase[65];
} sConnectParams;

static void wlan_cb (long event_type,
                     char * data,
                     unsigned char length)
{
  cprintf("%s wlan_cb %#lx %u at %p SR %#x\n",
          xBSP430uptimeAsText_ni(ulBSP430uptime_ni()),
          event_type, length, data, __read_status_register());
}

static void
displayMemory (const uint8_t * dp,
               size_t len,
               size_t offset)
{
  char asciiz[17];
  const uint8_t * const dpe = dp + len;
  char * ap;

  ap = asciiz;
  while (1) {
    if (0 == (offset % 16)) {
      if (asciiz < ap) {
        *ap = 0;
        cprintf("    %s\n", asciiz);
      }
      if (dp >= dpe) {
        break;
      }
      cprintf("%04x ", offset);
      ap = asciiz;
    } else if (0 == (offset % 8)) {
      cprintf(" ");
    }
    ++offset;
    if (dp < dpe) {
      *ap++ = isprint(*dp) ? *dp : '.';
      cprintf(" %02x", *dp);
    } else {
      cprintf("   ");
    }
    ++dp;
  }
}

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,
  .handler = iBSP430cliHandlerSimple,
  .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,
  .handler = iBSP430cliHandlerSimple,
  .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)
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;
}

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,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_wlan_ipconfig
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_ipconfig
#endif /* CMD_WLAN_IPCONFIG */

#if (CMD_WLAN_CONNECT - 0)
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" },
#if 0
  /* WPA2 is not implemented.  Unit will transmit unsecured auth request */
  { WLAN_SEC_WPA2, "wpa2" },
#endif /* 0 */
};
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;
}

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, 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", 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, connectParams.passphrase_len);
  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);
  t[0] = ulBSP430uptime_ni();
  rl = wlan_connect(connectParams.security_type,
                    connectParams.ssid, connectParams.ssid_len,
                    NULL,
                    connectParams.passphrase, connectParams.passphrase_len);
  t[1] = ulBSP430uptime_ni();
  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,
  .handler = iBSP430cliHandlerSimple,
  .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,
  .handler = iBSP430cliHandlerSimple,
  .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,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_wlan_sectype
};
static sBSP430cliCommand dcmd_wlan_connect = {
  .key = "connect",
  .help = HELP_STRING("# connect to specified access point using AP config"),
  .next = &dcmd_wlan_sectype,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_wlan_connect
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_connect
#endif /* CMD_WLAN_CONNECT */

#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,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_wlan_status
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_wlan_status
#endif /* CMD_WLAN_STATUS */

#if (CMD_WLAN_START - 0)
static int
cmd_wlan_start (const char * argstr)
{
  unsigned long t[2];
  t[0] = ulBSP430uptime_ni();
  wlan_start(0);
  t[1] = ulBSP430uptime_ni();
  cprintf("wlan_start() took %s\n", xBSP430uptimeAsText_ni(t[1]-t[0]));
  return 0;
}
static sBSP430cliCommand dcmd_wlan_start = {
  .key = "start",
  .help = HELP_STRING("# power-up CC3000"),
  .next = LAST_SUB_COMMAND,
  .handler = iBSP430cliHandlerSimple,
  .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_NVMEM - 0) && (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]);
  return 0;
}
static sBSP430cliCommand dcmd_nvmem_sp = {
  .key = "sp",
  .help = HELP_STRING("# read firmware service pack level"),
  .next = LAST_SUB_COMMAND,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_nvmem_sp
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_nvmem_sp
#endif /* CMD_NVMEM_SP */

#if (CMD_NVMEM - 0) && (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[32];
  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);
    }
    rc = nvmem_read(fileid, nb, ofs, data);
    if (0 == rc) {
      displayMemory(data, nb, ofs);
      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,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_nvmem_read
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_nvmem_read
#endif /* CMD_NVMEM_READ */

#if (CMD_NVMEM - 0) && (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,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_nvmem_mac
};
#undef LAST_SUB_COMMAND
#define LAST_SUB_COMMAND &dcmd_nvmem_mac
#endif /* CMD_NVMEM_MAC */

#if (CMD_NVMEM - 0)
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)
{
  BSP430_CORE_SAVED_INTERRUPT_STATE(istate);
  int rv;

  BSP430_CORE_DISABLE_INTERRUPT();
  do {
    rv = cmd_info_erase_ni();
  } while (0);
  BSP430_CORE_RESTORE_INTERRUPT_STATE(istate);
  return rv;
}

static int
cmd_info_store (const char * argstr)
{
  BSP430_CORE_SAVED_INTERRUPT_STATE(istate);
  int rv;

  BSP430_CORE_DISABLE_INTERRUPT();
  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);
  BSP430_CORE_RESTORE_INTERRUPT_STATE(istate);
  return rv;
}


static int
cmd_info_dump (const char * argstr)
{
  cprintf("Configuration memory:\n");
  displayMemory((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,
  .handler = iBSP430cliHandlerSimple,
  .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,
  .handler = iBSP430cliHandlerSimple,
  .param.simple_handler = cmd_info_store
};
static sBSP430cliCommand dcmd_info_erase = {
  .key = "erase",
{'fraction_non_alphanumeric': 0.13231932209589417, 'fraction_numerical': 0.025299478769774744, 'mean_word_length': 3.804217308537121, 'pattern_counts': {'":': 2, '<': 66, '<?xml version=': 0, '>': 60, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5077272', 'n_tokens_mistral': 13308, 'n_tokens_neox': 12748, 'n_words': 2935}