Beispiel #1
0
const volatile sBSP430eventTagRecord *
xBSP430eventRecordEvent_ni (unsigned char tag,
                            unsigned char flags,
                            const uBSP430eventAnyType * up)
{
    volatile sBSP430eventTagRecord * ep = xBSP430eventRecord + event_head;
    ep->tag = tag;
    ep->flags = flags;
    if (up) {
        ep->u = *up;
    } else {
        memset((unsigned char *)&ep->u, 0, sizeof(ep->u));
    }
    ep->timestamp_utt = ulBSP430uptime_ni();
    if (tag < nBSP430eventTagConfig_) {
        ep->seqno = xBSP430eventTagConfig_[tag].seqno++;
    }
    vBSP430eventFlagsSet_ni(uiBSP430eventFlag_EventRecord);
    EVENT_INCREMENT_PTR(event_head);
    if (event_head == event_tail) {
        EVENT_INCREMENT_PTR(event_tail);
        ++event_lost_count;
    }
    return ep;
}
Beispiel #2
0
long
lBSP430uptimeSleepUntil_ni (unsigned long setting_utt,
                            unsigned int lpm_bits)
{
  int rc;

  /* Exit immediately unless the alarm callback is registered. */
  if (! (DELAY_ALARM_REGISTERED & delayAlarm_.flags)) {
    return 0;
  }
  delayAlarm_.flags &= ~DELAY_ALARM_FIRED;
  rc = iBSP430timerAlarmSet_ni(H_delayAlarm, setting_utt);
  if (0 != rc) {
    return 0;
  }
  /* Sleep until the alarm goes off, or something else wakes us up.
   * Immediately disable the interrupts as that probably was not done
   * during wakeup. */
  BSP430_CORE_LPM_ENTER_NI(lpm_bits);
  BSP430_CORE_DISABLE_INTERRUPT();

  /* Cancel the alarm if it hasn't fired yet. */
  if (! (delayAlarm_.flags & DELAY_ALARM_FIRED)) {
    (void)iBSP430timerAlarmCancel_ni(H_delayAlarm);
  }
  return setting_utt - ulBSP430uptime_ni();
}
Beispiel #3
0
static void wlan_cb (long event_type,
                     char * data,
                     unsigned char length)
{
  int rv = BSP430_HAL_ISR_CALLBACK_EXIT_LPM;

  switch (event_type) {
    case HCI_EVNT_WLAN_UNSOL_CONNECT:
      event_flags_v |= EVENT_FLAG_WLANCONN;
      break;
    case HCI_EVNT_WLAN_UNSOL_DHCP:
      event_flags_v |= EVENT_FLAG_IPCONN;
      break;
    case HCI_EVNT_WLAN_UNSOL_DISCONNECT:
      event_flags_v |= EVENT_FLAG_DISCONN;
      break;
    case HCI_EVENT_CC3000_CAN_SHUT_DOWN:
      event_flags_v |= EVENT_FLAG_SHUTDOWN;
      ++can_shutdown;
      break;
    default:
      cprintf("%s wlan_cb evnt %#lx len %u at %p\n",
              xBSP430uptimeAsText_ni(ulBSP430uptime_ni()),
              event_type, length, data);
    /*FALLTHRU*/
    case HCI_EVNT_WLAN_KEEPALIVE:
      /* No wakeup for uninteresting events */
      rv = 0;
  }

  /* Wake up the main program to respond to whatever just happened. */
  iBSP430cc3000IRQrv = rv;
}
Beispiel #4
0
void main ()
{
  hBSP430halSERIAL console = NULL;
  hBSP430halSERIAL uart = NULL;
  unsigned long prep_utt = 0;
  unsigned long emit_utt = 0;
  unsigned long done_utt = 0;

  vBSP430platformInitialize_ni();
  iBSP430consoleInitialize();

  console = hBSP430console();
  cprintf("\ntxcb " __DATE__ " " __TIME__ "\n");

  cprintf("\nConsole %p is on %s: %s\n", console,
          xBSP430serialName(BSP430_CONSOLE_SERIAL_PERIPH_HANDLE),
          xBSP430platformPeripheralHelp(BSP430_CONSOLE_SERIAL_PERIPH_HANDLE, 0));

  uart = hBSP430serialLookup(UART_PERIPH_HANDLE);
  if (NULL == uart) {
    cprintf("Failed to resolve secondary\n");
    return;
  }
  cprintf("\nSecondary %p is on %s: %s\n", uart,
          xBSP430serialName(UART_PERIPH_HANDLE),
          xBSP430platformPeripheralHelp(UART_PERIPH_HANDLE, 0));

  tx_buffer_.head = tx_buffer_.tail = 0;
  BSP430_HAL_ISR_CALLBACK_LINK_NI(sBSP430halISRVoidChainNode, uart->tx_cbchain_ni, tx_buffer_.cb_node, next_ni);
  uart = hBSP430serialOpenUART(uart, 0, 0, 9600);
  if (NULL == uart) {
    cprintf("Secondary open failed\n");
  }

  /* Need to enable interrupts so timer overflow events are properly
   * acknowledged */
  BSP430_CORE_ENABLE_INTERRUPT();
  while (1) {
    unsigned long next_prep_utt;
    char * obp;
    char * ob_end;

    next_prep_utt = ulBSP430uptime();
    obp = tx_buffer_.buffer;
    ob_end = obp + sizeof(tx_buffer_.buffer);
    obp += snprintf(obp, ob_end - obp, "prep %lu emit %lu\r\n", emit_utt - prep_utt, done_utt - emit_utt);
    ob_end = obp;
    BSP430_CORE_DISABLE_INTERRUPT();
    emit_utt = ulBSP430uptime_ni();
    prep_utt = next_prep_utt;
    tx_buffer_.tail = 0;
    tx_buffer_.head = obp - tx_buffer_.buffer;
    vBSP430serialWakeupTransmit_ni(uart);
    BSP430_CORE_LPM_ENTER_NI(LPM0_bits);
    /* Expect tail == head otherwise should not have awoken */
    done_utt = ulBSP430uptime();
  }
}
Beispiel #5
0
static int
cmd_uptime (const char * argstr)
{
  BSP430_CORE_INTERRUPT_STATE_T istate;
  BSP430_CORE_SAVE_INTERRUPT_STATE(istate);
  BSP430_CORE_DISABLE_INTERRUPT();
  cprintf("Up %s\n", xBSP430uptimeAsText_ni(ulBSP430uptime_ni()));
  BSP430_CORE_RESTORE_INTERRUPT_STATE(istate);
  return 0;
}
Beispiel #6
0
void main ()
{
  hBSP430halSERIAL i2c;
  sBSP430bq24210 bq24210;
  union {
    sBQ27510 state;
    uint16_t raw[1];
  } u;
  const int nwords = sizeof(u.state)/sizeof(u.raw[0]);
  unsigned long resample_interval_utt;
  unsigned long resample_wake_utt;
  unsigned int flags;
  int rc;

  vBSP430platformInitialize_ni();
  (void)iBSP430consoleInitialize();

  cprintf("\nbattpack " __DATE__ " " __TIME__ "\n");

  bq24210.chg_port = xBSP430hplLookupPORT(APP_CHGn_PORT_PERIPH_HANDLE);
  bq24210.en_port = xBSP430hplLookupPORT(APP_ENn_PORT_PERIPH_HANDLE);
  bq24210.pg_port = xBSP430hplLookupPORT(APP_PGn_PORT_PERIPH_HANDLE);
  bq24210.chg_bit = APP_CHGn_PORT_BIT;
  bq24210.en_bit = APP_ENn_PORT_BIT;
  bq24210.pg_bit = APP_PGn_PORT_BIT;

  cprintf("CHGn on %s.%u\n",
          xBSP430portName(xBSP430periphFromHPL(bq24210.chg_port)),
          iBSP430portBitPosition(bq24210.chg_bit));
  cprintf("ENn on %s.%u\n",
          xBSP430portName(xBSP430periphFromHPL(bq24210.en_port)),
          iBSP430portBitPosition(bq24210.en_bit));
  cprintf("PGn on %s.%u\n",
          xBSP430portName(xBSP430periphFromHPL(bq24210.pg_port)),
          iBSP430portBitPosition(bq24210.pg_bit));
  if (! (bq24210.chg_port && bq24210.en_port && bq24210.pg_port)) {
    cprintf("One of the ports is missing\n");
    return;
  }

  /* Charge signal is an input (active low) to the MCU.  Configure as
   * input with internal pull-up. */
  bq24210.chg_port->dir &= ~bq24210.chg_bit;
  bq24210.chg_port->out |= bq24210.chg_bit;
  bq24210.chg_port->ren |= bq24210.chg_bit;

  /* Power-good signal is an input (active low) to the MCU.  Configure
   * as input with internal pull-up. */
  bq24210.pg_port->dir &= ~bq24210.pg_bit;
  bq24210.pg_port->out |= bq24210.pg_bit;
  bq24210.pg_port->ren |= bq24210.pg_bit;

  /* Enable signal is an output (active low) from the MCU.  Start
   * active. */
  bq24210.en_port->out &= ~bq24210.en_bit;
  bq24210.en_port->dir |= bq24210.en_bit;

  cprintf("I2C on %s at address 0x%02x\nPins: %s\n",
          xBSP430serialName(APP_BQ27510_I2C_PERIPH_HANDLE),
          APP_BQ27510_I2C_ADDRESS,
          xBSP430platformPeripheralHelp(APP_BQ27510_I2C_PERIPH_HANDLE, BSP430_PERIPHCFG_SERIAL_I2C));

  /* NOTE: At default BSP430_SERIAL_I2C_BUS_SPEED_HZ 400kHz this
   * devices supports only single-byte write operations.  Further,
   * ensure a 66us delay between packets. */
  i2c = hBSP430serialOpenI2C(hBSP430serialLookup(APP_BQ27510_I2C_PERIPH_HANDLE),
                             BSP430_SERIAL_ADJUST_CTL0_INITIALIZER(UCMST),
                             0, 0);
  if (! i2c) {
    cprintf("I2C open failed\n");
    return;
  }
  (void)iBSP430i2cSetAddresses_rh(i2c, -1, APP_BQ27510_I2C_ADDRESS);

  resample_interval_utt = BSP430_UPTIME_MS_TO_UTT(1000UL * RESAMPLE_INTERVAL_S);
  resample_wake_utt = ulBSP430uptime_ni();
  flags = FLG_DUMP_STATE | FLG_UPDATE_INTERVAL;

  BSP430_CORE_ENABLE_INTERRUPT();
  while (1) {
    char astext_buf[BSP430_UPTIME_AS_TEXT_LENGTH];
    uint16_t temperature_dC;

    if (FLG_DUMP_STATE & flags) {
      memset(&u, 0, sizeof(u));
      rc = readBQ27510(i2c, 0, nwords, u.raw);
      cprintf("Device ID %04x rc %d\n", u.state.device_id, rc);
      cprintf("%.30s = %d\n", "atRate_mA", u.state.atRate_mA);
      cprintf("%.30s = %u\n", "atRatetimeToEmpty_min", u.state.atRatetimeToEmpty_min);
      cprintf("%.30s = %u\n", "temperature_dK", u.state.temperature_dK);
      cprintf("%.30s = %u\n", "voltage_mV", u.state.voltage_mV);
      cprintf("%.30s = 0x%04x\n", "flags", u.state.flags);
      cprintf("%.30s = %u\n", "nominalAvailableCapacity_mAh", u.state.nominalAvailableCapacity_mAh);
      cprintf("%.30s = %u\n", "fullAvailableCapacity_mAh", u.state.fullAvailableCapacity_mAh);
      cprintf("%.30s = %u\n", "remainingCapacity_mAh", u.state.remainingCapacity_mAh);
      cprintf("%.30s = %u\n", "fullChargeCapacity_mAh", u.state.fullChargeCapacity_mAh);
      cprintf("%.30s = %d\n", "averageCurrent_mA", u.state.averageCurrent_mA);
      cprintf("%.30s = %u\n", "timeToEmpty_min", u.state.timeToEmpty_min);
      cprintf("%.30s = %d\n", "standbyCurrent_mA", u.state.standbyCurrent_mA);
      cprintf("%.30s = %u\n", "standbyTimeToEmpty_min", u.state.standbyTimeToEmpty_min);
      cprintf("%.30s = %u\n", "stateOfHealth_ppcpx", u.state.stateOfHealth_ppcpx);
      cprintf("%.30s = %u\n", "cycleCount", u.state.cycleCount);
      cprintf("%.30s = %u\n", "stateOfCharge_ppc", u.state.stateOfCharge_ppc);
      cprintf("%.30s = %d\n", "instantaneousCurrent_mA", u.state.instantaneousCurrent_mA);
      cprintf("%.30s = %u\n", "internalTemperature_dK", u.state.internalTemperature_dK);
      cprintf("%.30s = %u\n", "reistanceScale", u.state.reistanceScale);
      cprintf("%.30s = %u\n", "operationConfiguration", u.state.operationConfiguration);
      cprintf("%.30s = %u\n", "designCapacity_mAh", u.state.designCapacity_mAh);
      cprintf("flags %02x ; ENn state %d\n", flags, (bq24210.en_port->out & bq24210.en_bit));
      flags &= ~FLG_DUMP_STATE;
    }
    if (FLG_TOGGLE_ENABLE & flags) {
      bq24210.en_port->out ^= bq24210.en_bit;
      flags &= ~FLG_TOGGLE_ENABLE;
    }
    vBSP430ledSet(BSP430_LED_GREEN, !(bq24210.en_port->out & bq24210.en_bit));

    rc = readBQ27510(i2c, 0, nwords, u.raw);
    temperature_dC = u.state.temperature_dK - 2733;

    cprintf("%s: %c%c%c % 2d.%dC  %4dmV ; SoC %u%% ; Cap %4d / %4d ; %dmA ~ %dmA / %u\n",
            xBSP430uptimeAsText(ulBSP430uptime(), astext_buf),
            (bq24210.en_port->out & bq24210.en_bit) ? ' ' : 'E',
            (bq24210.chg_port->in & bq24210.chg_bit) ? ' ' : 'C',
            (bq24210.pg_port->in & bq24210.pg_bit) ? ' ' : 'P',
            (temperature_dC / 10), (temperature_dC % 10),
            u.state.voltage_mV,
            u.state.stateOfCharge_ppc,
            u.state.remainingCapacity_mAh,
            u.state.fullAvailableCapacity_mAh,
            u.state.instantaneousCurrent_mA,
            u.state.averageCurrent_mA,
            u.state.cycleCount
            );
    if (FLG_UPDATE_INTERVAL & flags) {
      resample_wake_utt += resample_interval_utt;
      flags &= ~FLG_UPDATE_INTERVAL;
    }
    flags = 0;
    while (! flags) {
      iBSP430consoleFlush();
      if (0 >= lBSP430uptimeSleepUntil(resample_wake_utt, LPM3_bits)) {
        flags |= FLG_UPDATE_INTERVAL;
      }
      while (0 <= ((rc = cgetchar()))) {
        if ('!' == rc) {
          flags |= FLG_TOGGLE_ENABLE;
        } else if (' ' == rc) {
          flags |= FLG_DUMP_STATE;
        }
      }
    }

  }
}
Beispiel #7
0
void main ()
{
  hBSP430timerMuxSharedAlarm map;
  tBSP430periphHandle uptime_periph;
  int arc[sizeof(mux_alarms)/sizeof(*mux_alarms)];
  unsigned long last_wake_utt;
  unsigned long last_sleep_utt;
  int rc = 0;

  vBSP430platformInitialize_ni();
  last_wake_utt = ulBSP430uptime_ni();
  (void)iBSP430consoleInitialize();
  BSP430_CORE_ENABLE_INTERRUPT();

  cprintf("\n\nevent demo " __DATE__ " " __TIME__ "\n");
  mux_tag = ucBSP430eventTagAllocate("MuxAlarm");
  stats_tag = ucBSP430eventTagAllocate("Statistics");
  mux_flag = uiBSP430eventFlagAllocate();

  uptime_periph = xBSP430periphFromHPL(hBSP430uptimeTimer()->hpl);

  map = hBSP430timerMuxAlarmStartup(&mux_alarm_base, uptime_periph, UPTIME_MUXALARM_CCIDX);
  cprintf("Mux tag %u, stats tag %u, flag %x, with alarm base %p on %s.%u\n",
          mux_tag, stats_tag, mux_flag, map,
          xBSP430timerName(uptime_periph), UPTIME_MUXALARM_CCIDX);
  if (! map) {
    cprintf("ERR initializing mux shared alarm\n");
    goto err_out;
  }

  /* Processing done entirely in mux callback.  No wakeup. */
  mux_alarms[0].alarm.callback_ni = mux_alarm_callback;
  mux_alarms[0].interval_utt = BSP430_UPTIME_MS_TO_UTT(150);

  /* Processing done by an event flag */
  mux_alarms[1].alarm.callback_ni = mux_alarm_callback;
  mux_alarms[1].interval_utt = BSP430_UPTIME_MS_TO_UTT(500);
  mux_alarms[1].flag = mux_flag;

  /* Processing done by a callback with a timestamped event */
  mux_alarms[2].alarm.callback_ni = mux_alarm_callback;
  mux_alarms[2].interval_utt = BSP430_UPTIME_MS_TO_UTT(700);
  mux_alarms[2].process_fn = process_timestamp;
  mux_alarms[2].tag = mux_tag;

  /* Processing done by a callback with a timestamped event */
  mux_alarms[3].alarm.callback_ni = mux_alarm_callback;
  mux_alarms[3].interval_utt = BSP430_UPTIME_MS_TO_UTT(10000);
  mux_alarms[3].process_fn = process_statistics;
  mux_alarms[3].tag = stats_tag;

  /* Enable the multiplexed alarms */
  BSP430_CORE_DISABLE_INTERRUPT();
  do {
    int i = 0;
    for (i = 0; (0 == rc) && (i < sizeof(mux_alarms)/sizeof(*mux_alarms)); ++i) {
      mux_alarms[i].alarm.setting_tck = ulBSP430uptime_ni();
      arc[i] = iBSP430timerMuxAlarmAdd_ni(map, &mux_alarms[i].alarm);
    }
  } while (0);
  BSP430_CORE_ENABLE_INTERRUPT();

  /* Display the results.  All values should be non-negative for success. */
  {
    int i;
    cprintf("Alarm installation got:");
    rc = 0;
    for (i = 0; i < sizeof(arc)/sizeof(*arc); ++i) {
      cprintf(" %d", arc[i]);
      if (0 > arc[i]) {
        rc = arc[i];
      }
    }
    cputchar('\n');
  }
  if (0 > rc) {
    goto err_out;
  }

  last_sleep_utt = ulBSP430uptime();
  while (1) {
    last_wake_utt = ulBSP430uptime();
    unsigned int events = process_events(uiBSP430eventFlagsGet());
    if (events) {
      cprintf("ERR: Unprocessed event flags %04x\n", events);
    }

    BSP430_CORE_DISABLE_INTERRUPT();
    /* Put back any unprocessed events */
    vBSP430eventFlagsSet_ni(events);
    if (iBSP430eventFlagsEmpty_ni()) {
      /* Nothing pending: go to sleep, then jump back to the loop head
       * when we get woken. */
      statistics_v.sleep_utt += last_wake_utt - last_sleep_utt;
      last_sleep_utt = ulBSP430uptime_ni();
      statistics_v.awake_utt += last_sleep_utt - last_wake_utt;
      statistics_v.sleep_ct += 1;
      BSP430_CORE_LPM_ENTER_NI(LPM4_bits | GIE);
      continue;
    }
    BSP430_CORE_ENABLE_INTERRUPT();
  }
err_out:
  (void)iBSP430consoleFlush();
  return;
}
Beispiel #8
0
void main ()
{
  int rc;
  unsigned long next_wake_utt;
  unsigned long delta_wake_utt;

  vBSP430platformInitialize_ni();
  (void)iBSP430consoleInitialize();

  cprintf("\n\nadc demo, " __DATE__ " " __TIME__ "\n");

  delta_wake_utt = 2 * ulBSP430uptimeConversionFrequency_Hz();

  rc = initializeADC();
  cprintf("%s initialized, returned %d, ADC cal at %p, REF cal at %p\n",
#if defined(__MSP430_HAS_ADC10__)
          "ADC10"
#elif defined(__MSP430_HAS_ADC10_A__)
          "ADC10_A"
#elif defined(__MSP430_HAS_ADC10_B__)
          "ADC10_B"
#elif defined(__MSP430_HAS_ADC10_B4__)
          "ADC10_B (FR4xx)"
#elif defined(__MSP430_HAS_ADC12__)
          "ADC12"
#elif defined(__MSP430_HAS_ADC12_B__)
          "ADC12_B"
#elif defined(__MSP430_HAS_ADC12_PLUS__)
          "ADC12_PLUS"
#endif /* ADC */
          , rc, cal_adc, cal_ref);

#if HAVE_REF
  if (cal_ref) {
    cprintf("Reference factors:\n"
            "\t" REF_1pX_STR "V %u (0x%04x)\n"
            "\t2.0V %u (0x%04x)\n"
            "\t2.5V %u (0x%04x)\n",
            cal_ref->cal_adc_15vref_factor, cal_ref->cal_adc_15vref_factor,
            cal_ref->cal_adc_20vref_factor, cal_ref->cal_adc_20vref_factor,
            cal_ref->cal_adc_25vref_factor, cal_ref->cal_adc_25vref_factor);
  }
#endif /* HAVE_REF */
  if (cal_adc) {
    cprintf("ADC gain factor %d (0x%04x), offset %d\n",
            cal_adc->cal_adc_gain_factor, cal_adc->cal_adc_gain_factor,
            cal_adc->cal_adc_offset);
    cprintf("Temperature ranges:\n");
    cprintf("\t" REF_1pX_STR "V T30 %u T85 %u\n", cal_adc->cal_adc_15t30, cal_adc->cal_adc_15t85);
#if BSP430_TLV_IS_5XX
    cprintf("\t2.0V T30 %u T85 %u\n", cal_adc->cal_adc_20t30, cal_adc->cal_adc_20t85);
#endif /* BSP430_TLV_IS_5XX */
    cprintf("\t2.5V T30 %u T85 %u\n", cal_adc->cal_adc_25t30, cal_adc->cal_adc_25t85);
  }

  cprintf("Vmid channel %u, Temp channel %u"
#ifdef INCH_AUX
          ", Aux channel %u"
#endif /* INCH_AUX */
          "\n",
          INCH_VMID / INCH_BASE, INCH_TEMP / INCH_BASE
#ifdef INCH_AUX
          , INCH_AUX / INCH_BASE
#endif /* INCH_AUX */
         );

  next_wake_utt = ulBSP430uptime_ni();
  while (1) {
    char timestamp[BSP430_UPTIME_AS_TEXT_LENGTH];
    static const int refv[] = { REF_1pX, REF_2p0, REF_2p5 };
    static const char * const refv_str[] = { REF_1pX_STR, "2.0", "2.5" };
    static const int const nrefv = sizeof(refv)/sizeof(*refv);
    static const int inch[] = { INCH_TEMP,
                                INCH_VMID,
#if defined(INCH_AUX)
                                INCH_AUX,
#endif /* INCH_AUX */
                              };
    static const int const ninch = sizeof(inch)/sizeof(*inch);
    int valid = 0;
    sSample sample[sizeof(refv)/sizeof(*refv)][sizeof(inch)/sizeof(*inch)];
    int ri;
    int ii;

#define VALID(_ri,_ii) ((1 << (_ii)) << ((_ri) * nrefv))
#define ANY_VALID(_ri) (((1 << nrefv)-1) << ((_ri) * nrefv))

    for (ri = 0; ri < nrefv; ++ri) {
      if (0 == setReferenceVoltage(refv[ri])) {
        for (ii = 0; ii < ninch; ++ii) {
          if (0 == getSample(sample[ri]+ii, refv[ri], inch[ii])) {
            valid |= VALID(ri, ii);
          }
        }
      }
    }
    cprintf("%s: valid %x", xBSP430uptimeAsText(ulBSP430uptime_ni(), timestamp), valid);
    for (ri = 0; ri < nrefv; ++ri) {
      if (valid & ANY_VALID(ri)) {
        cprintf("\n\t%sV: ", refv_str[ri]);
        for (ii = 0; ii < ninch; ++ii) {
          if (VALID(ri, ii) & valid) {
            if (INCH_TEMP == inch[ii]) {
              displayTemperature(sample[ri] + ii);
            } else if (INCH_VMID == inch[ii]) {
              displayVmid(sample[ri] + ii);
            } else {
              displayVoltage(sample[ri] + ii);
            }
          }
        }
      }
    }
    cputchar('\n');
    next_wake_utt += delta_wake_utt;
    while (0 < lBSP430uptimeSleepUntil(next_wake_utt, LPM3_bits)) {
      /* nop */
    }
  }
}
Beispiel #9
0
void main ()
{
  int rc;
  sBSP430m25p m25p_data;
  hBSP430m25p m25p;
  unsigned long addr;
  unsigned long t0;
  unsigned long t1;

  vBSP430platformInitialize_ni();
  (void)iBSP430consoleInitialize();

  cprintf("\nBuild " __DATE__ " " __TIME__ "\n");
  cprintf("SPI is %s: %s\n",
          xBSP430serialName(BSP430_PLATFORM_M25P_SPI_PERIPH_HANDLE),
          xBSP430platformPeripheralHelp(BSP430_PLATFORM_M25P_SPI_PERIPH_HANDLE, 0));

#ifdef BSP430_PLATFORM_M25P_PWR_PORT_PERIPH_HANDLE
  cprintf("PWR at %s.%u\n",
          xBSP430portName(BSP430_PLATFORM_M25P_PWR_PORT_PERIPH_HANDLE),
          iBSP430portBitPosition(BSP430_PLATFORM_M25P_PWR_PORT_BIT));
#else /* BSP430_PLATFORM_M25P_PWR_PORT_PERIPH_HANDLE */
  cprintf("PWR is hard-wired\n");
#endif /* BSP430_PLATFORM_M25P_PWR_PORT_PERIPH_HANDLE */

#ifdef BSP430_PLATFORM_M25P_RSTn_PORT_PERIPH_HANDLE
  cprintf("RSTn at %s.%u\n",
          xBSP430portName(BSP430_PLATFORM_M25P_RSTn_PORT_PERIPH_HANDLE),
          iBSP430portBitPosition(BSP430_PLATFORM_M25P_RSTn_PORT_BIT));
#else /* BSP430_PLATFORM_M25P_RSTn_PORT_PERIPH_HANDLE */
  cprintf("RSTn is hard-wired\n");
#endif /* BSP430_PLATFORM_M25P_RSTn_PORT_PERIPH_HANDLE */
  cprintf("CSn at %s.%u\n",
          xBSP430portName(BSP430_PLATFORM_M25P_CSn_PORT_PERIPH_HANDLE),
          iBSP430portBitPosition(BSP430_PLATFORM_M25P_CSn_PORT_BIT));

  memset(&m25p_data, 0, sizeof(m25p_data));
  m25p_data.spi = hBSP430serialLookup(BSP430_PLATFORM_M25P_SPI_PERIPH_HANDLE);
  m25p_data.csn_port = xBSP430hplLookupPORT(BSP430_PLATFORM_M25P_CSn_PORT_PERIPH_HANDLE);
  m25p_data.csn_bit = BSP430_PLATFORM_M25P_CSn_PORT_BIT;
#ifdef BSP430_PLATFORM_M25P_RSTn_PORT_PERIPH_HANDLE
  m25p_data.rstn_port = xBSP430hplLookupPORT(BSP430_PLATFORM_M25P_RSTn_PORT_PERIPH_HANDLE);
  m25p_data.rstn_bit = BSP430_PLATFORM_M25P_RSTn_PORT_BIT;
#endif /* BSP430_PLATFORM_M25P_RSTn_PORT_PERIPH_HANDLE */

  m25p = hBSP430m25pInitialize(&m25p_data,
                               BSP430_SERIAL_ADJUST_CTL0_INITIALIZER(UCCKPL | UCMSB | UCMST),
                               UCSSEL_2, 1);
  if (NULL == m25p) {
    cprintf("M25P device initialization failed.\n");
    return;
  }

#ifdef BSP430_PLATFORM_M25P_PWR_PORT_PERIPH_HANDLE
  {
    volatile sBSP430hplPORT * pwr_hpl;
    /* Turn on power, then wait 10 ms for chip to stabilize before releasing RSTn. */
    pwr_hpl = xBSP430hplLookupPORT(BSP430_PLATFORM_M25P_PWR_PORT_PERIPH_HANDLE);
    pwr_hpl->out &= ~BSP430_PLATFORM_M25P_PWR_PORT_BIT;
    pwr_hpl->dir |= BSP430_PLATFORM_M25P_PWR_PORT_BIT;
    pwr_hpl->out |= BSP430_PLATFORM_M25P_PWR_PORT_BIT;
    BSP430_CORE_DELAY_CYCLES(10 * (BSP430_CLOCK_NOMINAL_MCLK_HZ / 1000));
  }
#endif /* BSP430_PLATFORM_M25P_PWR_PORT_PERIPH_HANDLE */
  BSP430_M25P_RESET_CLEAR(m25p);

  cprintf("Status register %d\n", iBSP430m25pStatus_ni(m25p));
  rc = iBSP430m25pStrobeCommand_ni(m25p, BSP430_M25P_CMD_WREN);
  cprintf("WREN got %d, status register %d\n", rc, iBSP430m25pStatus_ni(m25p));
  rc = iBSP430m25pStrobeCommand_ni(m25p, BSP430_M25P_CMD_WRDI);
  cprintf("WRDI got %d, status register %d\n", rc, iBSP430m25pStatus_ni(m25p));

  rc = iBSP430m25pInitiateCommand_ni(m25p, BSP430_M25P_CMD_RDID);
  if (0 == rc) {
    rc = iBSP430m25pCompleteTxRx_ni(m25p, NULL, 0, 20, buffer);
  }

  BSP430_CORE_ENABLE_INTERRUPT();
  cprintf("READ_IDENTIFICATION got %d\n", rc);
  if (0 <= rc) {
    dumpMemory(buffer, rc, 0);
  }
  cprintf("Config identified %u sectors of %lu bytes each: %lu bytes total\n",
          BSP430_PLATFORM_M25P_SECTOR_COUNT,
          (unsigned long)BSP430_PLATFORM_M25P_SECTOR_SIZE,
          BSP430_PLATFORM_M25P_SECTOR_COUNT * (unsigned long)BSP430_PLATFORM_M25P_SECTOR_SIZE);
#if (BSP430_PLATFORM_M25P_SUBSECTOR_SIZE - 0)
  cprintf("Config supports access as %u sub-sectors of %u bytes each\n",
          (unsigned int)(BSP430_PLATFORM_M25P_SECTOR_COUNT * (BSP430_PLATFORM_M25P_SECTOR_SIZE / BSP430_PLATFORM_M25P_SUBSECTOR_SIZE)),
          (unsigned int)BSP430_PLATFORM_M25P_SUBSECTOR_SIZE);
#else /* BSP430_PLATFORM_M25P_SUBSECTOR_SIZE */
  cprintf("Config indicates device is not sub-sector addressable\n");
#endif /* BSP430_PLATFORM_M25P_SUBSECTOR_SIZE */
  cprintf("RDID identified %lu bytes total capacity\n", 0x1UL << buffer[2]);

  addr = 0;

  rc = readFromAddress(m25p, addr, sizeof(flashContents));
  if (sizeof(flashContents) != rc) {
    cprintf("ERROR %d reading initial block\n", rc);
  } else {
    dumpMemory(buffer, rc, addr);
    if (0 == memcmp(flashContents, buffer, rc)) {
      cprintf("Found expected contents.\n");
    }
  }

#if (BSP430_PLATFORM_M25P_SUPPORTS_PE - 0)
  rc = writeToAddress(m25p, BSP430_M25P_CMD_PE, addr, NULL, 0);
  cprintf("PAGE_ERASE got %d\n", rc);
#else /* BSP430_PLATFORM_M25P_SUPPORTS_PE */
  rc = writeToAddress(m25p, BSP430_M25P_CMD_SE, addr, NULL, 0);
  cprintf("SECTOR_ERASE got %d\n", rc);
#endif /* BSP430_PLATFORM_M25P_SUPPORTS_PE */
  rc = readFromAddress(m25p, addr, sizeof(buffer));
  if (0 < rc) {
    dumpMemory(buffer, rc, addr);
  }

  rc = writeToAddress(m25p, BSP430_M25P_CMD_PP, addr, flashContents, sizeof(flashContents));
  cprintf("PAGE_PROGRAM got %d\n", rc);
  rc = readFromAddress(m25p, addr, sizeof(buffer));
  if (0 < rc) {
    dumpMemory(buffer, rc, addr);
  }

  /* PAGE PROGRAM is the one that only clears 1s to 0s so needs a
   * prior page or sector erase */
  rc = writeToAddress(m25p, BSP430_M25P_CMD_PP, addr, flashContents + 4, 4);
  cprintf("PAGE_PROGRAM to %lx returned %d\n", addr, rc);
  rc = readFromAddress(m25p, 0, sizeof(flashContents));
  dumpMemory(buffer, rc, 0);
  /*
  Write 4 took 8
  PAGE_PROGRAM to 0 returned 4
  00000000  88 11 03 30 cc 33 c3 3c  01 23 45 67 89 ab cd ef  ...0.3.<.#Eg....
  */

  /* PAGE_WRITE is the one that does not need a prior erase cycle */
  addr = 8;
#if (BSP430_PLATFORM_M25P_SUPPORTS_PW - 0)
  rc = writeToAddress(m25p, BSP430_M25P_CMD_PW, addr, flashContents + 4, 4);
  cprintf("PAGE_WRITE to %lx returned %d\n", addr, rc);
#else
  rc = writeToAddress(m25p, BSP430_M25P_CMD_PP, addr, flashContents + 4, 4);
  cprintf("overwrite PAGE_PROGRAM to unerased %lx returned %d\n", addr, rc);
#endif
  rc = readFromAddress(m25p, 0, sizeof(flashContents));
  dumpMemory(buffer, rc, 0);
  /*
  Write 4 took 204
  PAGE_WRITE to 8 returned 4
  00000000  88 11 03 30 cc 33 c3 3c  cc 33 c3 3c 89 ab cd ef  ...0.3.<.3.<....
  */

  cprintf("Initiating bulk erase...");
  BSP430_CORE_DISABLE_INTERRUPT();
  do {
    t0 = t1 = 0;
    rc = iBSP430m25pStrobeCommand_ni(m25p, BSP430_M25P_CMD_WREN);
    if (0 == rc) {
      rc = iBSP430m25pStrobeCommand_ni(m25p, BSP430_M25P_CMD_BE);
    }
    if (0 == rc) {
      int sr;

      t0 = ulBSP430uptime_ni();
      do {
        sr = iBSP430m25pStatus_ni(m25p);
      } while ((0 <= sr) && (BSP430_M25P_SR_WIP & sr));
      t1 = ulBSP430uptime();
    }
  } while (0);
  BSP430_CORE_ENABLE_INTERRUPT();
  cprintf("\nBULK_ERASE got %d\n", rc);
  if (0 == rc) {
    char tstr[BSP430_UPTIME_AS_TEXT_LENGTH];
    cprintf("Bulk erase took %lu utt = %s\n", t1-t0, xBSP430uptimeAsText(t1 - t0, tstr));
  }
  rc = readFromAddress(m25p, 0, sizeof(flashContents));
  dumpMemory(buffer, rc, 0);

  rc = writeToAddress(m25p, BSP430_M25P_CMD_PP, 0, flashContents, sizeof(flashContents));
  cprintf("Restore got %d\n", rc);

  addr = 0;
  while (addr < (256 * 1025L)) {
    rc = readFromAddress(m25p, addr, sizeof(buffer));
    if (0 > rc) {
      break;
    }
    dumpMemory(buffer, rc, addr);
    addr += rc;
    break;
  }

}
Beispiel #10
0
void main ()
{
  int rc;
  unsigned long uptime_ticks_per_sec;
  const struct sBSP430onewireBus * bus = &ds18b20;

  vBSP430platformInitialize_ni();

  (void)iBSP430consoleInitialize();
  cprintf("\nHere we go...\n");

  uptime_ticks_per_sec = ulBSP430uptimeConversionFrequency_Hz_ni();
  cprintf("Uptime now %lu with frequency %lu Hz\n",
          ulBSP430uptime_ni(), uptime_ticks_per_sec);

  cprintf("Monitoring DS18xx on %s.%u bit %x\n",
          xBSP430portName(BSP430_PORT_HAL_GET_PERIPH_HANDLE(APP_DS18B20_PORT_HAL)) ?: "P?",
          iBSP430portBitPosition(APP_DS18B20_BIT),
          APP_DS18B20_BIT);

  do {
    rc = iBSP430onewireReadSerialNumber(bus, &serial);
    if (0 != rc) {
      cprintf("ERROR: Failed to read serial number from DS18B20: %d\n", rc);
      BSP430_CORE_DELAY_CYCLES(BSP430_CLOCK_NOMINAL_MCLK_HZ);
    }
  } while (0 != rc);
  cprintf("DS18B20 serial number: %02x%02x%02x%02x%02x%02x\n",
          serial.id[0], serial.id[1], serial.id[2],
          serial.id[3], serial.id[4], serial.id[5]);

  while (1) {
    int rc;
    unsigned long start_tck;
    unsigned long end_tck;
    unsigned int duration_ms;
    unsigned int delay_count = 0;
    int t_c;

    start_tck = ulBSP430uptime_ni();
    rc = -1;
    if (0 == iBSP430onewireRequestTemperature_ni(bus)) {
      /* Wait for read to complete.  Each read is nominally 61
       * microseconds.  Conversion time can be as long as 750 ms if
       * 12-bit resolution is used.  (12-bit resolution is the
       * default.) */
      while (! iBSP430onewireReadBit_ni(bus)) {
        ++delay_count;
      }
      rc = iBSP430onewireReadTemperature_ni(bus, &t_c);
    }
    end_tck = ulBSP430uptime_ni();
    duration_ms = 1000 * (end_tck - start_tck) / uptime_ticks_per_sec;

    if (0 == rc) {
      cprintf("Temperature %d dCel or %d d[degF] in %u ms\n",
              (10 * t_c) / 16, BSP430_ONEWIRE_xCel_TO_ddegF(t_c), duration_ms);
    } else {
      cprintf("Measurement failed in %u ms\n", duration_ms);
    }

    /* You'd want to do this if you were going to sleep here */
    vBSP430onewireShutdown_ni(bus);
  }
}
Beispiel #11
0
static int
nmea_rx_isr_ni (const struct sBSP430halISRVoidChainNode * cb,
                void * context)
{
  sRxState * sp = (sRxState *)cb;
  sBSP430halSERIAL * hal = (sBSP430halSERIAL *) context;
  sNMEAmessage * cp = &sp->curmsg;
  int rv = 0;

  switch (sp->state) {
    case SRX_unsync:
      if (NULL != cp->message) {
        if (NULL != serial_cb) {
          rv |= serial_cb(NULL, sp->message_idx, cp->timestamp_utt);
        }
        (void)fp_release(sp->pool, cp->message);
        cp->message = NULL;
      }
      if ('$' == hal->rx_byte) {
        sp->state = SRX_store_NMEA;
      } else if (0xA0 == hal->rx_byte) {
        sp->state = SRX_start_Binary;
      } else {
        break;
      }
      cp->timestamp_utt = ulBSP430uptime_ni();
      sp->message_idx = 0;
      sp->csum_calc = 0;
      cp->message = fp_request(sp->pool, 4, FP_MAX_FRAGMENT_SIZE, &cp->message_endp);
      if (NULL == cp->message) {
        sp->state = SRX_unsync;
        if (NULL != serial_cb) {
          rv |= serial_cb(NULL, 0, cp->timestamp_utt);
        }
      }
      break;
    case SRX_store_NMEA:
      if ('*' == hal->rx_byte) {
        if ((cp->message + sp->message_idx) == cp->message_endp) {
          sp->state = SRX_unsync;
          break;
        }
        cp->message[sp->message_idx] = 0;
        sp->message_idx += 1;
        sp->state = SRX_read_csum_NMEA;
        break;
      }
      /*FALLTHRU*/
    case SRX_store_Binary:
      /* If attempt to store would go beyond end, abort the message. */
      if ((cp->message + sp->message_idx) == cp->message_endp) {
        sp->state = SRX_unsync;
        break;
      }
      /* Add character to checksum and accumulated buffer */
      sp->csum_calc ^= hal->rx_byte;
      cp->message[sp->message_idx] = hal->rx_byte;
      sp->message_idx += 1;
      if ((SRX_store_Binary == sp->state) && (sp->message_idx == sp->length_rx)) {
        sp->state = SRX_read_csum_Binary;
      }
      break;
    case SRX_start_Binary:
      sp->length_rx = 0;
      sp->state = (0xA1 == hal->rx_byte) ? SRX_read_len_Binary : SRX_unsync;
      break;
    case SRX_read_csum_NMEA:
    case SRX_read_csum_NMEA_2:
      if (! IS_HEXDIGIT(hal->rx_byte)) {
        sp->state = SRX_unsync;
        break;
      }
      sp->csum_rx = (sp->csum_rx << 4) | HEXDIGIT_VALUE(hal->rx_byte);
      if (SRX_read_csum_NMEA == sp->state) {
        sp->state = SRX_read_csum_NMEA_2;
        break;
      }
      /*FALLTHRU*/
validate:
      if (sp->csum_rx == sp->csum_calc) {
        if (NULL != serial_cb) {
          uint8_t * msg = fp_resize(sp->pool, cp->message, sp->message_idx, &cp->message_endp);
          cp->message = NULL;
          rv |= serial_cb(msg, sp->message_idx, cp->timestamp_utt);
        }
      }
      sp->state = SRX_unsync;
      break;
    case SRX_read_csum_Binary:
      sp->csum_rx = hal->rx_byte;
      goto validate;
    case SRX_read_len_Binary:
      sp->length_rx = hal->rx_byte;
      sp->state = SRX_read_len_Binary_2;
      break;
    case SRX_read_len_Binary_2:
      sp->length_rx = (sp->length_rx << 8) | hal->rx_byte;
      sp->state = SRX_store_Binary;
      break;
  }
  return rv;
}
Beispiel #12
0
void main (void)
{
  unsigned long wake_utt;
  int rc;
  long lrc;
  char as_text[BSP430_UPTIME_AS_TEXT_LENGTH];
  uint32_u ntp_addr;
  uint32_u self_addr;

  vBSP430platformInitialize_ni();
  (void)iBSP430consoleInitialize();
  cprintf("\nntp " __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. */
  rc = iBSP430cc3000spiInitialize(wlan_cb, NULL, NULL, NULL);
  if (0 > rc) {
    cprintf("ERR: Initialization failed: %d\n", rc);
    return;
  }

  BSP430_CORE_ENABLE_INTERRUPT();

  /* Local addresses use all zeros for inet addr.  bind does not
   * support dynamic assignment of unused port through sin_port=0. */
  memset(&local_addr, 0, sizeof(local_addr));
  local_addr.sai.sin_family = AF_INET;
  local_addr.sai.sin_port = htons(60123);

  /* Remote server will be determined by DNS from the NTP pool once we
   * start. */
  remote_addr = local_addr;
  remote_addr.sai.sin_port = htons(123);

  ntp_addr.u32 = 0;
  self_addr.u32 = 0;

  cprintf("Remote: %s:%u\n", net_ipv4AsText(&remote_addr.sai.sin_addr), ntohs(remote_addr.sai.sin_port));
  rc = sizeof(sBSP430uptimeNTPPacketHeader);
  if (48 != rc) {
    cprintf("ERR: NTP header size %d\n", rc);
    return;
  }
  wake_utt = ulBSP430uptime();

  (void)rc;
  while (1) {
    unsigned long timeout_utt;

    do {
      tNetappIpconfigRetArgs ipc;
      unsigned long start_utt;
      unsigned long finished_utt;
      int sfd;
      int nfds;
      fd_set rfds;
      int servers_left;
      int retries_left;

      /* Clear everything as we're starting a cycle */
      BSP430_CORE_DISABLE_INTERRUPT();
      do {
        event_flags_v = 0;
        start_utt = ulBSP430uptime_ni();
      } while (0);
      BSP430_CORE_ENABLE_INTERRUPT();

      /* Start the WAN process.  This is asynchronous; wait up to 2
       * seconds for it to complete. */
      cprintf("%s: ", xBSP430uptimeAsText(start_utt, as_text));
      cputchar('W');
      wlan_start(0);
      vBSP430ledSet(BSP430_LED_RED, 1);
      (void)wlan_set_event_mask(0UL);
      lrc = BSP430_UPTIME_MS_TO_UTT(2000);
      timeout_utt = ulBSP430uptime() + lrc;
      while ((! (EVENT_FLAG_WLANCONN & event_flags_v))
             && (0 < ((lrc = lBSP430uptimeSleepUntil(timeout_utt, LPM0_bits))))) {
      }
      if (! (EVENT_FLAG_WLANCONN & event_flags_v)) {
        cprintf("WLAN start failed\n");
        break;
      }

      /* Wait for IP connectivity (signalled by a DHCP event).
       * Continue using the previous timeout. */
      cputchar('D');
      while ((! (EVENT_FLAG_IPCONN & event_flags_v))
             && (0 < ((lrc = lBSP430uptimeSleepUntil(timeout_utt, LPM0_bits))))) {
      }
      if (! (EVENT_FLAG_IPCONN & event_flags_v)) {
        cprintf("IP conn failed\n");
        break;
      }

      /* Inspect the IP configuration.  Sometimes we get the event,
       * but there's no IP assigned. */
      netapp_ipconfig(&ipc);
      memcpy(self_addr.u8, ipc.aucIP, sizeof(self_addr));
      if (! self_addr.u32) {
        cprintf("IP assignment failed\n");
        break;
      }
      vBSP430ledSet(BSP430_LED_GREEN, 1);

      /* Obtain a UDP socket and bind it for local operations. */
      cputchar('I');
      sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
      if (0 > sfd) {
        cprintf("socket() failed: %d\n", sfd);
        break;
      }
      cputchar('S');
      lrc = bind(sfd, &local_addr.sa, sizeof(local_addr.sa));
      if (0 > lrc) {
        cprintf("bind() failed: %ld\n", lrc);
        break;
      }
      cputchar('B');

      servers_left = NTP_SERVERS_PER_ATTEMPT;
      retries_left = NTP_REQUESTS_PER_SERVER;
      do {
        sBSP430uptimeNTPPacketHeader ntp0;
        sBSP430uptimeNTPPacketHeader ntp1;
        int have_invalid_epoch;
        struct timeval tv;
        sockaddr_u src;
        socklen_t slen = sizeof(src);
        unsigned long recv_utt;
        uint64_t recv_ntp;
        int64_t adjustment_ntp;
        long adjustment_ms;
        unsigned long rtt_us;

        have_invalid_epoch = 0 != iBSP430uptimeCheckEpochValidity();
        if (! remote_addr.sai.sin_addr.s_addr) {
          const char ntp_fqdn[] = "0.pool.ntp.org";
          ntp_addr.u32 = 0;
          rc = gethostbyname((char *)ntp_fqdn, sizeof(ntp_fqdn)-1, &ntp_addr.u32);
          cputchar('d');
          if (-95 == rc) { /* ARP request failed; retry usually works */
            rc = gethostbyname((char *)ntp_fqdn, sizeof(ntp_fqdn)-1, &ntp_addr.u32);
            cputchar('d');
          }
          if (0 == ntp_addr.u32) {
            cprintf("gethostbyname(%s) failed: %d\n", ntp_fqdn, rc);
            rc = -1;
            break;
          }
          remote_addr.sai.sin_addr.s_addr = htonl(ntp_addr.u32);
          cprintf("{%s}", net_ipv4AsText(&remote_addr.sai.sin_addr));
          retries_left = NTP_REQUESTS_PER_SERVER;
        }

        /* Configure the NTP request and send it */
        iBSP430uptimeInitializeNTPRequest(&ntp0);
        iBSP430uptimeSetNTPXmtField(&ntp0, NULL);
        BSP430_CORE_DISABLE_INTERRUPT();
        do {
          /* Clear the shutdown bit, so we know when it's ok to shut
           * down after this send */
          event_flags_v &= ~EVENT_FLAG_SHUTDOWN;
        } while (0);
        BSP430_CORE_ENABLE_INTERRUPT();
        rc = sendto(sfd, &ntp0, sizeof(ntp0), 0, &remote_addr.sa, sizeof(remote_addr.sai));
        if (sizeof(ntp0) != rc) {
          cprintf("sendto %s:%u failed: %d\n", net_ipv4AsText(&remote_addr.sai.sin_addr), ntohs(remote_addr.sai.sin_port), rc);
          rc = -1;
          break;
        }
        cputchar('s');

        /* If we get an answer it should be here in less than 100
         * ms, but give it 400 ms just to be kind. */
        tv.tv_sec = 0;
        tv.tv_usec = 400000UL;
        FD_ZERO(&rfds);
        FD_SET(sfd, &rfds);
        nfds = sfd+1;
        rc = select(nfds, &rfds, NULL, NULL, &tv);
        if (! FD_ISSET(sfd, &rfds)) {
          /* We didn't get an answer.  If there are any retries left, use them. */
          if (0 < retries_left--) {
            rc = 1;
            continue;
          }
          /* No retries left on this server: forget about it.  If
           * there are any servers left, try another. */
          cputchar('!');
          remote_addr.sai.sin_addr.s_addr = 0;
          if (0 < servers_left--) {
            rc = 1;
            continue;
          }
          /* No retries from all available servers.  Fail this attempt */
          cprintf("no responsive NTP server found\n");
          rc = -1;
          break;
        }

        /* Got a response.  Record the time it came in and then read
         * it (no high-resolution packet RX time available, but we
         * believe it's here already so set the RX time first).  The
         * message is unacceptable if it isn't an NTP packet. */
        recv_utt = ulBSP430uptime();
        rc = recvfrom(sfd, &ntp1, sizeof(ntp1), 0, &src.sa, &slen);
        if (sizeof(ntp1) != rc) {
          cprintf("recv failed: %d\n", rc);
          rc = -1;
          break;
        }
        cputchar('r');

        /* Convert the RX time to NTP, then process the message to
         * determine the offset. */
        rc = iBSP430uptimeAsNTP(recv_utt, &recv_ntp, have_invalid_epoch);
        if (0 != rc) {
          cprintf("NTP decode failed: %d\n", rc);
          continue;
        }
        rc = iBSP430uptimeProcessNTPResponse(&ntp0, &ntp1, recv_ntp, &adjustment_ntp, &adjustment_ms, &rtt_us);
        if (0 != rc) {
          cprintf("Process failed: %d\n", rc);
          continue;
        }
        if (have_invalid_epoch) {
          rc = iBSP430uptimeSetEpochFromNTP(BSP430_UPTIME_BYPASS_EPOCH_NTP + adjustment_ntp);
          cputchar('E');
          if (0 != rc) {
            cprintf("\nERR: SetEpoch failed: %d\n", rc);
          }
#if (NTP_ADJUST_EACH_ITER - 0)
        } else {
          rc = iBSP430uptimeAdjustEpochFromNTP(adjustment_ntp);
          cputchar('A');
          if (0 != rc) {
            cprintf("\nERR: AdjustEpoch failed: %d\n", rc);
          }
#endif
        }
        cprintf("[%s:%u adj %lld ntp = %ld ms, rtt %lu us]",
                net_ipv4AsText(&remote_addr.sai.sin_addr), ntohs(remote_addr.sai.sin_port),
                adjustment_ntp, adjustment_ms, rtt_us);
      } while (0 != rc);
      if (0 != rc) {
        cprintf("NTP query failed\n");
        break;
      }
#if 0
      /* The shutdown OK seems to arrive about 1000 ms after the last
       * transmit, which is unnecessarily long.  As we're not doing
       * TCP, there's no reason to wait for it. */
      lrc = BSP430_UPTIME_MS_TO_UTT(4000);
      timeout_utt = ulBSP430uptime() + lrc;
      while ((! (EVENT_FLAG_SHUTDOWN & event_flags_v))
             && (0 < ((lrc = lBSP430uptimeSleepUntil(timeout_utt, LPM0_bits))))) {
      }
      if (! (EVENT_FLAG_SHUTDOWN & event_flags_v)) {
        cprintf("SHUTDOWN ok never received\n");
        break;
      }
#endif
      finished_utt = ulBSP430uptime();
      cprintf("[%s]\n", xBSP430uptimeAsText(finished_utt - start_utt, as_text));
    } while (0);

    BSP430_CORE_DISABLE_INTERRUPT();
    do {
      event_flags_v = 0;
    } while (0);
    BSP430_CORE_ENABLE_INTERRUPT();
    wlan_stop();
    vBSP430ledSet(BSP430_LED_GREEN, 0);
    vBSP430ledSet(BSP430_LED_RED, 0);
    wake_utt += 60 * ulBSP430uptimeConversionFrequency_Hz();
    while (0 < lBSP430uptimeSleepUntil(wake_utt, LPM2_bits)) {
    }
  }
  cprintf("Fell off end\n");
}