]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/chips/bq2403x/BQ2403XP.nc
Implement support for the BQ2403x charge controller family. Only tested with
[tinyos-2.x.git] / tos / chips / bq2403x / BQ2403XP.nc
diff --git a/tos/chips/bq2403x/BQ2403XP.nc b/tos/chips/bq2403x/BQ2403XP.nc
new file mode 100644 (file)
index 0000000..77ed42c
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2008, Titanium Mirror, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - Neither the name of the Technische Universität Berlin nor the names
+ *   of its contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * HIL implementation for the BQ2403X charge controller chip family.
+ * 
+ * @author R. Steve McKown <smckown@gmail.com>
+ */
+#include "BQ2403X.h"
+
+module BQ2403XP {
+  provides {
+    interface BQ2403X;
+    interface Init;
+  }
+  uses {
+    interface GeneralIO as BQstat1;
+    interface GeneralIO as BQstat2;
+    interface GeneralIO as ACPGn;
+    interface GeneralIO as USBPGn;
+
+    interface GpioInterrupt as IntBQstat1;
+    interface GpioInterrupt as IntBQstat2;
+    interface GpioInterrupt as IntACPGn;
+    interface GpioInterrupt as IntUSBPGn;
+
+    interface Timer<TMilli>;
+  }
+}
+implementation {
+  const static unsigned DELAY = 256; /* 1/4 sec in binary milliseconds */
+  bool enabled;
+  uint8_t state;
+  uint8_t lastState;
+
+  uint8_t bits2charge()
+  {
+    /* Conversion table:
+     *    Name       BQstat1  BQstat2  Value  Desired
+     * ----------------------------------------------
+     * Not charging    1        1        3      0
+     * Precharge       0        0        0      1
+     * Fast charge     0        1        1      2
+     * Charge done     1        0        2      3
+     */
+    return ((call BQstat1.get() << 1) + call BQstat2.get() + 1) & 0x3;
+  }
+
+  uint8_t bits2power()
+  {
+    /* Conversion table:
+     *    Name    ACPGn  USBPGn  Value  Desired
+     * ----------------------------------------
+     * On Battery   1      1       3      0
+     * USB power    1      0       2      1
+     * AC power     0      1       1      2
+     * Both AC+USB  0      0       0      3
+     */
+    return ~((call ACPGn.get() << 5) + (call USBPGn.get() << 4)) & 0x30;
+  }
+
+  void setInt()
+  {
+    /* Too many race conditions.  Implement IO pins as toggles w/deglitch.
+     * Or, poll.  Best solution is probably to interrupt on state change then
+     * poll a bit later to deal with deglitch.
+     */
+    if (call BQstat1.get())
+      call IntBQstat1.enableFallingEdge();
+    else
+      call IntBQstat1.enableRisingEdge();
+    if (call BQstat2.get())
+      call IntBQstat2.enableFallingEdge();
+    else
+      call IntBQstat2.enableRisingEdge();
+    if (call ACPGn.get())
+      call IntACPGn.enableFallingEdge();
+    else
+      call IntACPGn.enableRisingEdge();
+    if (call USBPGn.get())
+      call IntUSBPGn.enableFallingEdge();
+    else
+      call IntUSBPGn.enableRisingEdge();
+  }
+
+  void unsetInt()
+  {
+    call IntBQstat1.disable();
+    call IntBQstat2.disable();
+    call IntACPGn.disable();
+    call IntUSBPGn.disable();
+  }
+
+  void update()
+  {
+    atomic {
+      state = bits2power() + bits2charge();
+      setInt();
+    }
+  }
+
+  command error_t Init.init()
+  {
+    update();
+    lastState = state;
+    return SUCCESS;
+  }
+
+  async command void BQ2403X.enable()
+  {
+    atomic {
+      enabled = TRUE;
+      setInt();
+    }
+  }
+
+  async command void BQ2403X.disable()
+  {
+    atomic {
+      enabled = FALSE;
+      unsetInt();
+    }
+  }
+
+  async command bq2403x_state_t BQ2403X.getState()
+  {
+    return state;
+  }
+
+  async command bq2403x_state_t BQ2403X.getCharge()
+  {
+    return state & BQ2403X_CHG_MASK;
+  }
+
+  async command bq2403x_state_t BQ2403X.getPower()
+  {
+    return state & BQ2403X_PWR_MASK;
+  }
+
+  async command bool BQ2403X.isCharging()
+  {
+    return (state + 1) & 0x2;
+  }
+
+  async command bool BQ2403X.battOnly()
+  {
+    return call BQ2403X.getPower() == 0;
+  }
+
+  task void signalChange()
+  {
+    bq2403x_state_t cstate;
+    
+    atomic cstate = state;
+    signal BQ2403X.change(cstate, lastState);
+    lastState = cstate;
+  }
+
+  task void startTimer()
+  {
+    call Timer.startOneShot(DELAY);
+  }
+
+  async event void IntBQstat1.fired()
+  {
+    post startTimer();
+  }
+
+  async event void IntBQstat2.fired()
+  {
+    post startTimer();
+  }
+
+  async event void IntACPGn.fired()
+  {
+    post startTimer();
+  }
+
+  async event void IntUSBPGn.fired()
+  {
+    post startTimer();
+  }
+
+  event void Timer.fired()
+  {
+    atomic {
+      update();
+      if (enabled)
+       post signalChange();
+    }
+  }
+
+  default async event void BQ2403X.change(bq2403x_state_t current,
+      bq2403x_state_t last) {}
+}