Exemple #1
0
// Called from startup() after some initial setup has been done.
// Can abort with panic() if need be.
void POSTalt()
  {


#ifdef USE_MODULE_RFM22RADIOSIMPLE
#if !defined(RFM22_IS_ACTUALLY_RFM23) && defined(DEBUG)
  DEBUG_SERIAL_PRINTLN_FLASHSTRING("(Using RFM22.)");
#endif
  // Initialise the radio, if configured, ASAP because it can suck a lot of power until properly initialised.
  RFM22PowerOnInit();
  // Check that the radio is correctly connected; panic if not...
  if(!RFM22CheckConnected()) { panic(); }
  // Configure the radio.
  RFM22RegisterBlockSetup(FHT8V_RFM22_Reg_Values);
  // Put the radio in low-power standby mode.
  RFM22ModeStandbyAndClearState();
#endif

  DEBUG_SERIAL_PRINTLN_FLASHSTRING("Setting up interrupts");
  cli();
  PCICR = 0x05;
  PCMSK0 = 0b00000011; // PB; PCINT  0--7    (LEARN1 and Radio)
  PCMSK1 = 0b00000000; // PC; PCINT  8--15
  PCMSK2 = 0b00101001; // PD; PCINT 16--24   (LEARN2 and MODE, RX)
  sei();
  }
Exemple #2
0
// Clears the RFM22 TX FIFO and queues up ready to send via the TXFIFO the 0xff-terminated bytes starting at bptr.
// This routine does not change the command area.
// This uses an efficient burst write.
// For DEBUG can abort after (over-)filling the 64-byte FIFO at no extra cost with a check before spinning waiting for SPI byte to be sent.
void RFM22QueueCmdToFF(const uint8_t *bptr)
  {
#if 0 && defined(DEBUG)
  if(0 == *bptr) { DEBUG_SERIAL_PRINTLN_FLASHSTRING("RFM22QueueCmdToFF: buffer uninitialised"); panic(); } 
#endif
  const bool neededEnable = powerUpSPIIfDisabled();
  // Clear the TX FIFO.
  _RFM22ClearTXFIFO();
  _RFM22_SELECT();
  _RFM22_wr(RFM22REG_FIFO | 0x80); // Start burst write to TX FIFO.
  uint8_t val;
#if 1 && defined(DEBUG)
  for(int8_t i = 64; ((uint8_t)0xff) != (val = *bptr++); )
    {
    // DEBUG_SERIAL_PRINTFMT(val, HEX); DEBUG_SERIAL_PRINTLN();
    SPDR = val;
    if(--i < 0) { DEBUG_SERIAL_PRINTLN_FLASHSTRING("RFM22QueueCmdToFF: buffer unterminated"); panic(); }
    while (!(SPSR & _BV(SPIF))) { }
    //val = SPDR; // Not clear if SPDR has to be read...
    }
#else
  while((uint8_t)0xff != (val = *bptr++)) { _RFM22_wr(val); }
#endif
  _RFM22_DESELECT();
  if(neededEnable) { powerDownSPI(); }
  }
Exemple #3
0
// Returns true iff RFM22 (or RFM23) appears to be correctly connected.
bool RFM22CheckConnected()
  {
  const bool neededEnable = powerUpSPIIfDisabled();
  bool isOK = false;
  const uint8_t rType = _RFM22ReadReg8Bit(0); // May read as 0 if not connected at all.
  if(RFM22_SUPPORTED_DEVICE_TYPE == rType)
    {
    const uint8_t rVersion = _RFM22ReadReg8Bit(1);
    if(RFM22_SUPPORTED_DEVICE_VERSION == rVersion)
      { isOK = true; }
#if 0 && defined(DEBUG)
    else
      {
      DEBUG_SERIAL_PRINT_FLASHSTRING("RFM22 bad version: ");
      DEBUG_SERIAL_PRINTFMT(rVersion, HEX);
      DEBUG_SERIAL_PRINTLN();
      }
#endif
    }
#if 0 && defined(DEBUG)
  else
    {
    DEBUG_SERIAL_PRINT_FLASHSTRING("RFM22 bad type: ");
    DEBUG_SERIAL_PRINTFMT(rType, HEX);
    DEBUG_SERIAL_PRINTLN();
    }
#endif
#if 1 && defined(DEBUG)
  if(!isOK) { DEBUG_SERIAL_PRINTLN_FLASHSTRING("RFM22 bad"); }
#endif
  if(neededEnable) { powerDownSPI(); }
  return(isOK);
  }
Exemple #4
0
// Enter receive mode.
// SPI must already be configured and running.
static void _RFM22ModeRX()
  {
  _RFM22WriteReg8Bit(RFM22REG_OP_CTRL1, 5);
#if 0 && defined(DEBUG)
  DEBUG_SERIAL_PRINTLN_FLASHSTRING("Rx");
#endif
  } // RXON | XTON
Exemple #5
0
// Minimal set-up of I/O (etc) after system power-up.
// Performs a software reset and leaves the radio deselected and in a low-power and safe state.
// Will power up SPI if needed.
void RFM22PowerOnInit()
  {
#if 0 && defined(DEBUG)
  DEBUG_SERIAL_PRINTLN_FLASHSTRING("RFM22 reset...");
#endif
  const bool neededEnable = powerUpSPIIfDisabled();
  _RFM22WriteReg8Bit(RFM22REG_OP_CTRL1, RFM22REG_OP_CTRL1_SWRES);
  _RFM22ModeStandby();
  if(neededEnable) { powerDownSPI(); }
  }
Exemple #6
0
// Called from loop().
void loopAlt()
  {

  // Sleep in low-power mode (waiting for interrupts) until seconds roll.
  // NOTE: sleep at the top of the loop to minimise timing jitter/delay from Arduino background activity after loop() returns.
  // DHD20130425: waking up from sleep and getting to start processing below this block may take >10ms.
#if 0 && defined(DEBUG)
  DEBUG_SERIAL_PRINTLN_FLASHSTRING("*E"); // End-of-cycle sleep.
#endif
  powerDownSerial(); // Ensure that serial I/O is off.
  // Power down most stuff (except radio for hub RX).
  minimisePowerWithoutSleep();
  static uint_fast8_t TIME_LSD; // Controller's notion of seconds within major cycle.
  uint_fast8_t newTLSD;
  while(TIME_LSD == (newTLSD = getSecondsLT()))
    {
    sleepUntilInt(); // Normal long minimal-power sleep until wake-up interrupt.
    }
  TIME_LSD = newTLSD;
#if 0 && defined(DEBUG)
  DEBUG_SERIAL_PRINTLN_FLASHSTRING("*S"); // Start-of-cycle wake.
#endif


  // START LOOP BODY
  // ===============
 
  DEBUG_SERIAL_PRINTLN_FLASHSTRING("tick...");



  DEBUG_SERIAL_PRINTLN_FLASHSTRING("int count: ");
  DEBUG_SERIAL_PRINT(interruptCount);
  DEBUG_SERIAL_PRINTLN();





  }
// Get approximate internal temperature in nominal C/16.
// Only accurate to +/- 10C uncalibrated.
// May set sleep mode to SLEEP_MODE_ADC, and disables sleep on exit.
int readInternalTemperatureC16()
  {
  // Measure internal temperature sensor against internal voltage source.
  // Response is ~1mv/C with 0C at ~289mV according to the data sheet.
  const uint16_t raw = OTV0P2BASE::_analogueNoiseReducedReadM(_BV(REFS1) | _BV(REFS0) | _BV(MUX3), 1);
#if 0 && defined(DEBUG)
  DEBUG_SERIAL_PRINT_FLASHSTRING("Int temp raw: ");
  DEBUG_SERIAL_PRINT(raw);
  DEBUG_SERIAL_PRINTLN_FLASHSTRING("");
#endif
  //const int degC = (raw - 328) ; // Crude fast adjustment for one sensor at ~20C (DHD20130429).
  const int degC = ((((int)raw) - 324) * 210) >> 4; // Slightly less crude adjustment, see http://playground.arduino.cc//Main/InternalTemperatureSensor
  return(degC);
  }
Exemple #8
0
// Send the underlying stats binary/text 'whitened' message.
// This must be terminated with an 0xff (which is not sent),
// and no longer than STATS_MSG_MAX_LEN bytes long in total (excluding the terminating 0xff).
// This must not contain any 0xff and should not contain long runs of 0x00 bytes.
// The message to be sent must be written at an offset of STATS_MSG_START_OFFSET from the start of the buffer.
// This routine will alter the content of the buffer for transmission,
// and the buffer should not be re-used as is.
//   * doubleTX  double TX to increase chance of successful reception
//   * RFM23BfriendlyPremable  if true then add an extra preamble
//     to allow RFM23B-based receiver to RX this
// This will use whichever transmission medium/carrier/etc is available.
//#define STATS_MSG_START_OFFSET (RFM22_PREAMBLE_BYTES + RFM22_SYNC_MIN_BYTES)
//#define STATS_MSG_MAX_LEN (64 - STATS_MSG_START_OFFSET)
void RFM22RawStatsTXFFTerminated(uint8_t * const buf, const bool doubleTX, bool RFM23BFramed)
  {
  if(RFM23BFramed) RFM22RXPreambleAdd(buf);	// Only needed for RFM23B. This should be made more clear when refactoring
  const uint8_t buflen = OTRadioLink::frameLenFFTerminated(buf);
#if 0 && defined(DEBUG)
    DEBUG_SERIAL_PRINT_FLASHSTRING("buflen=");
    DEBUG_SERIAL_PRINT(buflen);
    DEBUG_SERIAL_PRINTLN();
#endif // DEBUG
  if(!PrimaryRadio.queueToSend(buf, buflen, 0, (doubleTX ? OTRadioLink::OTRadioLink::TXmax : OTRadioLink::OTRadioLink::TXnormal)))
    {
#if 0 && defined(DEBUG)
    DEBUG_SERIAL_PRINTLN_FLASHSTRING("!TX failed");
#endif
    } // DEBUG
  //DEBUG_SERIAL_PRINTLN_FLASHSTRING("RS");
  }
Exemple #9
0
// Called from startup() after some initial setup has been done.
// Can abort with panic() if need be.
void POSTalt()
  {
#ifdef USE_MODULE_RFM22RADIOSIMPLE
#if !defined(RFM22_IS_ACTUALLY_RFM23) && defined(DEBUG)
  DEBUG_SERIAL_PRINTLN_FLASHSTRING("(Using RFM22.)");
#endif
  // Initialise the radio, if configured, ASAP, because it can suck a lot of power until properly initialised.
  RFM22PowerOnInit();
  // Check that the radio is correctly connected; panic if not...
  if(!RFM22CheckConnected()) { panic(); }
  // Configure the radio.
  RFM22RegisterBlockSetup(FHT8V_RFM22_Reg_Values);
  // Put the radio in low-power standby mode.
  RFM22ModeStandbyAndClearState();
#endif
  // Force initialisation into low-power state.
  const int heat = TemperatureC16.read();
#if 1 && defined(DEBUG)
  DEBUG_SERIAL_PRINT_FLASHSTRING("temp: ");
  DEBUG_SERIAL_PRINT(heat);
  DEBUG_SERIAL_PRINTLN();
#endif
  const int light = AmbLight.read();
#if 1 && defined(DEBUG)
  DEBUG_SERIAL_PRINT_FLASHSTRING("light: ");
  DEBUG_SERIAL_PRINT(light);
  DEBUG_SERIAL_PRINTLN();
#endif



  // Trailing setup for the run
  // --------------------------




//  const bool foundSlaves = MinOW.reset();
  }
// Initialise the device (if any) before first use.
// Returns true iff successful.
// Uses specified order DS18B20 found on bus.
// May need to be reinitialised if precision changed.
bool TemperatureC16_DS18B20::init()
  {
//  DEBUG_SERIAL_PRINTLN_FLASHSTRING("DS18B20 init...");
  bool found = false;

  // Ensure no bad search state.
  minOW.reset_search();

  for( ; ; )
    {
    if(!minOW.search(address))
      {
      minOW.reset_search(); // Be kind to any other OW search user.
      break;
      }

#if 0 && defined(DEBUG)
    // Found a device.
    DEBUG_SERIAL_PRINT_FLASHSTRING("addr:");
    for(int i = 0; i < 8; ++i)
      {
      DEBUG_SERIAL_PRINT(' ');
      DEBUG_SERIAL_PRINTFMT(address[i], HEX);
      }
    DEBUG_SERIAL_PRINTLN();
#endif

    if(0x28 != address[0])
      {
#if 0 && defined(DEBUG)
      DEBUG_SERIAL_PRINTLN_FLASHSTRING("Not a DS18B20, skipping...");
#endif
      continue;
      }

#if 0 && defined(DEBUG)
    DEBUG_SERIAL_PRINTLN_FLASHSTRING("Setting precision...");
#endif
    minOW.reset();
    // Write scratchpad/config
    minOW.select(address);
    minOW.write(0x4e);
    minOW.write(0); // Th: not used.
    minOW.write(0); // Tl: not used.
//    MinOW.write(DS1820_PRECISION | 0x1f); // Config register; lsbs all 1.
    minOW.write(((precision - 9) << 6) | 0x1f); // Config register; lsbs all 1.

    // Found one and configured it!
    found = true;
    }

  // Search has been run (whether DS18B20 was found or not).
  initialised = true;

  if(!found)
    {
//    DEBUG_SERIAL_PRINTLN_FLASHSTRING("DS18B20 not found");
    address[0] = 0; // Indicate that no DS18B20 was found.
    }
  return(found);
  }
Exemple #11
0
// Called from loop().
void loopAlt()
{
    // Sleep in low-power mode (waiting for interrupts) until seconds roll.
    // NOTE: sleep at the top of the loop to minimise timing jitter/delay from Arduino background activity after loop() returns.
    // DHD20130425: waking up from sleep and getting to start processing below this block may take >10ms.
#if 0 && defined(DEBUG)
    DEBUG_SERIAL_PRINTLN_FLASHSTRING("*E"); // End-of-cycle sleep.
#endif

#if !defined(ENABLE_MIN_ENERGY_BOOT)
    OTV0P2BASE::powerDownSerial(); // Ensure that serial I/O is off.
    // Power down most stuff (except radio for hub RX).
    minimisePowerWithoutSleep();
#endif
    static uint_fast8_t TIME_LSD; // Controller's notion of seconds within major cycle.
    uint_fast8_t newTLSD;
    while(TIME_LSD == (newTLSD = OTV0P2BASE::getSecondsLT()))
    {
        // Poll I/O and process message incrementally (in this otherwise idle time)
        // before sleep and on wakeup in case some IO needs further processing now,
        // eg work was accrued during the previous major slow/outer loop
        // or the in a previous orbit of this loop sleep or nap was terminated by an I/O interrupt.
        // Come back and have another go if work was done, until the next tick at most.
        if(handleQueuedMessages(&Serial, true, &PrimaryRadio)) {
            continue;
        }

// If missing h/w interrupts for anything that needs rapid response
// then AVOID the lowest-power long sleep.
#if defined(ENABLE_CONTINUOUS_RX) && !defined(PIN_RFM_NIRQ)
#define MUST_POLL_FREQUENTLY true
#else
#define MUST_POLL_FREQUENTLY false
#endif
        if(MUST_POLL_FREQUENTLY /** && in hub mode */ )
        {
            // No h/w interrupt wakeup on receipt of frame,
            // so can only sleep for a short time between explicit poll()s,
            // though allow wake on interrupt anyway to minimise loop timing jitter.
            OTV0P2BASE::nap(WDTO_15MS, true);
        }
        else
        {
            // Normal long minimal-power sleep until wake-up interrupt.
            // Rely on interrupt to force fall through to I/O poll() below.
            OTV0P2BASE::sleepUntilInt();
        }
//    DEBUG_SERIAL_PRINTLN_FLASHSTRING("w"); // Wakeup.

//    idle15AndPoll(); // Attempt to crash the board!

    }
    TIME_LSD = newTLSD;

#if 0 && defined(DEBUG)
    DEBUG_SERIAL_PRINTLN_FLASHSTRING("*S"); // Start-of-cycle wake.
#endif


    // START LOOP BODY
    // ===============

//  DEBUG_SERIAL_PRINTLN_FLASHSTRING("*");

//  // Power up serial for the loop body.
//  // May just want to turn it on in POSTalt() and leave it on...
//  const bool neededWaking = powerUpSerialIfDisabled();




//#if defined(ENABLE_FHT8VSIMPLE)
//  // Try for double TX for more robust conversation with valve?
//  const bool doubleTXForFTH8V = false;
//  // FHT8V is highest priority and runs first.
//  // ---------- HALF SECOND #0 -----------
//  bool useExtraFHT8VTXSlots = localFHT8VTRVEnabled() && FHT8VPollSyncAndTX_First(doubleTXForFTH8V); // Time for extra TX before UI.
////  if(useExtraFHT8VTXSlots) { DEBUG_SERIAL_PRINTLN_FLASHSTRING("ES@0"); }
//#endif



    switch(TIME_LSD)
    {
#ifdef ENABLE_STATS_TX
    // Regular transmission of stats if NOT driving a local valve (else stats can be piggybacked onto that).
    case 10:
    {
//      if((OTV0P2BASE::getMinutesLT() & 0x3) == 0) // Send once every 4 minutes.
        {
            // Send it!
            // Try for double TX for extra robustness unless:
            //   * this is a speculative 'extra' TX
            //   * battery is low
            //   * this node is a hub so needs to listen as much as possible
            // This doesn't generally/always need to send binary/both formats
            // if this is controlling a local FHT8V on which the binary stats can be piggybacked.
            // Ie, if doesn't have a local TRV then it must send binary some of the time.
            // Any recently-changed stats value is a hint that a strong transmission might be a good idea.
            const bool doBinary = false; // !localFHT8VTRVEnabled() && OTV0P2BASE::randRNG8NextBoolean();
            bareStatsTX(false, false, false);
        }
        break;
    }
#endif

    // Poll ambient light level at a fixed rate.
    // This allows the unit to respond consistently to (eg) switching lights on (eg TODO-388).
    case 20: {
        AmbLight.read();
        break;
    }

#if defined(ENABLE_PRIMARY_TEMP_SENSOR_DS18B20)
    case 30: {
        TemperatureC16.read();
        break;
    }
#endif // ENABLE_PRIMARY_TEMP_SENSOR_DS18B20

#if defined(ENABLE_VOICE_SENSOR)
    // read voice sensor
    case 40: {
        Voice.read();
        break;
    }
#endif // (ENABLE_VOICE_SENSOR)

#ifdef ENABLE_OCCUPANCY_SUPPORT
    case 50: {
        Occupancy.read();    // Needs regular poll.
        break;
    }
#endif // ENABLE_OCCUPANCY_SUPPORT
    }


    PrimaryRadio.poll();



//#if defined(ENABLE_FHT8VSIMPLE)
//  if(useExtraFHT8VTXSlots)
//    {
//    // Time for extra TX before other actions, but don't bother if minimising power in frost mode.
//    // ---------- HALF SECOND #1 -----------
//    useExtraFHT8VTXSlots = localFHT8VTRVEnabled() && FHT8VPollSyncAndTX_Next(doubleTXForFTH8V);
////    if(useExtraFHT8VTXSlots) { DEBUG_SERIAL_PRINTLN_FLASHSTRING("ES@1"); }
//    }
//#endif





//#if defined(ENABLE_FHT8VSIMPLE) && defined(V0P2BASE_TWO_S_TICK_RTC_SUPPORT)
//  if(useExtraFHT8VTXSlots)
//    {
//    // ---------- HALF SECOND #2 -----------
//    useExtraFHT8VTXSlots = localFHT8VTRVEnabled() && FHT8VPollSyncAndTX_Next(doubleTXForFTH8V);
////    if(useExtraFHT8VTXSlots) { DEBUG_SERIAL_PRINTLN_FLASHSTRING("ES@2"); }
//    }
//#endif





//#if defined(ENABLE_FHT8VSIMPLE) && defined(V0P2BASE_TWO_S_TICK_RTC_SUPPORT)
//  if(useExtraFHT8VTXSlots)
//    {
//    // ---------- HALF SECOND #3 -----------
//    useExtraFHT8VTXSlots = localFHT8VTRVEnabled() && FHT8VPollSyncAndTX_Next(doubleTXForFTH8V);
////    if(useExtraFHT8VTXSlots) { DEBUG_SERIAL_PRINTLN_FLASHSTRING("ES@3"); }
//    }
//#endif


//#ifdef HAS_DORM1_VALVE_DRIVE
//  // Move valve to new target every minute to try to upset it!
//  // Targets at key thresholds and random.
//  if(0 == TIME_LSD)
//    {
//    switch(OTV0P2BASE::randRNG8() & 1)
//      {
//      case 0: ValveDirect.set(OTRadValve::DEFAULT_VALVE_PC_MIN_REALLY_OPEN-1); break; // Nominally shut.
//      case 1: ValveDirect.set(OTRadValve::DEFAULT_VALVE_PC_MODERATELY_OPEN); break; // Nominally open.
//      // Random.
////      default: ValveDirect.set(OTV0P2BASE::randRNG8() % 101); break;
//      }
//    }
//
//  // Simulate human doing the right thing after fitting valve when required.
//  if(ValveDirect.isWaitingForValveToBeFitted()) { ValveDirect.signalValveFitted(); }
//
//  // Provide regular poll to motor driver.
//  // May take significant time to run
//  // so don't call when timing is critical or not much left,
//  // eg around critical TXes.
//  const uint8_t pc = ValveDirect.read();
//  DEBUG_SERIAL_PRINT_FLASHSTRING("Pos%: ");
//  DEBUG_SERIAL_PRINT(pc);
//  DEBUG_SERIAL_PRINTLN();
//#endif



//  // Reading shaft encoder.
//  // Measure motor count against (fixed) internal reference.
//  power_intermittent_peripherals_enable(true);
//  const uint16_t mc = analogueNoiseReducedRead(MOTOR_DRIVE_MC_AIN, INTERNAL);
//  void power_intermittent_peripherals_disable();
//  DEBUG_SERIAL_PRINT_FLASHSTRING("Count input: ");
//  DEBUG_SERIAL_PRINT(mc);
//  DEBUG_SERIAL_PRINTLN();














//  // Force any pending output before return / possible UART power-down.
//  flushSerialSCTSensitive();
//  if(neededWaking) { OTV0P2BASE::powerDownSerial(); }
}
Exemple #12
0
// Called from loop().
void loopAlt()
  {
  // Sleep in low-power mode (waiting for interrupts) until seconds roll.
  // NOTE: sleep at the top of the loop to minimise timing jitter/delay from Arduino background activity after loop() returns.
  // DHD20130425: waking up from sleep and getting to start processing below this block may take >10ms.
#if 0 && defined(DEBUG)
  DEBUG_SERIAL_PRINTLN_FLASHSTRING("*E"); // End-of-cycle sleep.
#endif

#if defined(WAKEUP_32768HZ_XTAL) // Normal 32768Hz crystal driving main timing.
  powerDownSerial(); // Ensure that serial I/O is off.
  // Power down most stuff (except radio for hub RX).
  minimisePowerWithoutSleep();
//  RFM22ModeStandbyAndClearState();
  static uint_fast8_t TIME_LSD; // Controller's notion of seconds within major cycle.
  uint_fast8_t newTLSD;
  while(TIME_LSD == (newTLSD = getSecondsLT()))
    {
    sleepUntilInt(); // Normal long minimal-power sleep until wake-up interrupt.
//    DEBUG_SERIAL_PRINTLN_FLASHSTRING("w"); // Wakeup.
    }
  TIME_LSD = newTLSD;
#else // Keep running on main RC clock, simulating normal-ish sleep length.
  delay(2000);
#endif

#if 0 && defined(DEBUG)
  DEBUG_SERIAL_PRINTLN_FLASHSTRING("*S"); // Start-of-cycle wake.
#endif


  // START LOOP BODY
  // ===============

  DEBUG_SERIAL_PRINTLN_FLASHSTRING("*");



//  const bool neededWaking = powerUpSerialIfDisabled();


//  const int heat = TemperatureC16.read();
//#if 1 && defined(DEBUG)
//  DEBUG_SERIAL_PRINT_FLASHSTRING("temp: ");
//  DEBUG_SERIAL_PRINT(heat);
//  DEBUG_SERIAL_PRINTLN();
//#endif


//#if defined(DIRECT_MOTOR_DRIVE_V1) && defined(ALT_MAIN_LOOP) && defined(DEBUG)
//  // Ensure that end-stop current-sense feedback is enabled before starting the motor.
//  cb.hitEndStop = false;
//  hd.enableFeedback(true, cb);
//  // Ensure that the motor is running...
//  static bool open = true;
//  if(open) { DEBUG_SERIAL_PRINTLN_FLASHSTRING("opening"); } else { DEBUG_SERIAL_PRINTLN_FLASHSTRING("closing"); }
//  hd.motorRun(open ? HardwareMotorDriverInterface::motorDriveOpening : HardwareMotorDriverInterface::motorDriveClosing);
//  // Try to ride through any start-up transients...
//  nap(WDTO_120MS);
//  nap(WDTO_120MS);
//  nap(WDTO_120MS);
//  nap(WDTO_120MS);
//  // Spin the motor for up to about 1.5s polling for end-stop hit, etc.
//  while(!cb.hitEndStop && (getSubCycleTime() < 0xc0))
//    {
//    hd.enableFeedback(true, cb);
//    }
//  // Stop motor.
//  hd.motorRun(HardwareMotorDriverInterface::motorOff);
//  // Iff the end-stop was hit then reverse the motor.
//  if(cb.hitEndStop)
//    {
//    DEBUG_SERIAL_PRINTLN_FLASHSTRING("Hit end stop; reversing...");
//    open = !open;
//    }
//#endif

//  static bool boilerOut;
//  boilerOut = !boilerOut;
//  if(boilerOut) { LED_HEATCALL_ON() } else { LED_HEATCALL_OFF(); }
//  fastDigitalWrite(OUT_HEATCALL, boilerOut ? HIGH : LOW);
//#if defined(LED_UI2_L)
//  if(boilerOut) { LED_UI2_OFF() } else { LED_UI2_ON(); }
//#endif



//  uint8_t addr[8];
//
//  if(!MinOW.search(addr))
//    {
//    Serial.println("No more slaves found...");
//    MinOW.reset_search();
//    return;
//    }
//
//  // Found a device.
//  Serial.print("addr:");
//  for(int i = 0; i < 8; ++i)
//    {
//    Serial.write(' ');
//    Serial.print(addr[i], HEX);
//    }
//  Serial.println();
//
//  if(0x28 != addr[0])
//    {
//    Serial.println("Not a DS18B20...");
//    return;
//    }
//
//#define DS1820_PRECISION_MASK 0x60
//#define DS1820_PRECISION_9 0x00
//#define DS1820_PRECISION_10 0x20
//#define DS1820_PRECISION_11 0x40 // 1/8C @ 375ms.
//#define DS1820_PRECISION_12 0x60 // 1/16C @ 750ms.
//
//#define DS1820_PRECISION DS1820_PRECISION_11 // 1/8C @ 375ms.
//
//
//  // Force any pending output before return / possible UART power-down.
//  flushSerialSCTSensitive();
//  if(neededWaking) { powerDownSerial(); }
//
//  DEBUG_SERIAL_PRINTLN_FLASHSTRING("Setting precision...");
//  MinOW.reset();
//  // Write scratchpad/config
//  MinOW.select(addr);
//  MinOW.write(0x4e);
//  MinOW.write(0); // Th: not used.
//  MinOW.write(0); // Tl: not used.
//  MinOW.write(DS1820_PRECISION | 0x1f); // Config register; lsbs all 1.
//
//  const unsigned long usStart = micros();
//
//  // Start a temperature reading.
//  MinOW.reset();
//  MinOW.select(addr);
//  MinOW.write(0x44); // Start conversion without parasite power.
//  //delay(1000); // 750ms should be enough.
//  while(MinOW.read_bit() == 0) { /*nap(WDTO_30MS);*/ } // Poll for conversion complete (bus released)...
//
//  // Fetch temperature (scratchpad read).
//  MinOW.reset();
//  MinOW.select(addr);    
//  MinOW.write(0xbe);
//  byte data[2]; // Read first two bytes of 9 available.
//  for(uint8_t i = 0; i < sizeof(data); ++i)
//    { 
//    data[i] = MinOW.read();
////    Serial.print(data[i], HEX);
////    Serial.print(" ");
//    }
//  Serial.println();
//  MinOW.reset();
//
//  const unsigned long usEnd = micros();
//  // Nominal loop time should be 2s x 1MHz clock, ie 2,000,000 if CPU running all the time.
//  // Should generally be <2000 (<0.1%) for leaf, <20000 (<1%) for hub.
//  const unsigned long usApparentTaken = usEnd - usStart;
//#if 1 && defined(DEBUG)
//  DEBUG_SERIAL_PRINT_FLASHSTRING("us apparent: ");
//  DEBUG_SERIAL_PRINT(usApparentTaken);
//  DEBUG_SERIAL_PRINTLN();
//#endif
//
//  if(neededWaking) { powerUpSerialIfDisabled(); }
//
//  // Extract raw temperature, masking any undefined lsbits.
//  const int16_t rawC16 = (data[1] << 8) | (data[0] & ~1);
//  Serial.print("C16=");
//  Serial.print(rawC16);
////  Serial.print(" = ");
////  Serial.print(rawC16 / 16.0f);
//  Serial.println();

//  // Force any pending output before return / possible UART power-down.
//  flushSerialSCTSensitive();
//
//  if(neededWaking) { powerDownSerial(); }
  }