]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/chips/msp430/usci/Msp430UartP.nc
Fix up io pin restoration after Uart peripheral is released.
[tinyos-2.x.git] / tos / chips / msp430 / usci / Msp430UartP.nc
index a987e6d87576d8bda573e0d6f8e9404b7642dcfc..605c426960f5d926d10670ec8582a70dc76383f6 100644 (file)
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
 /**
  * Uart implementation using a USCI device.
  *
- * @author R. Steve McKown <smckown@gmail.com>
+ * TODO: Implement blocking like in Msp430UartSpiP.nc.
+ *       Implement error checking via UCAxSTAT.
+ *
+ * @author R. Steve McKown <rsmckown@gmail.com>
  */
+
 generic module Msp430UartP() {
   provides {
     interface UartStream;
     interface UartByte;
+    interface ResourceConfigure;
   }
   uses {
     interface HplMsp430UsciReg as Registers;
     interface HplMsp430UsciInt as Interrupts;
-    interface Msp430UsciUartConfigure; /* maybe just Msp430UsciConfigure */
-    interface Counter<T32khz,uint16_6>
+    interface HplMsp430GeneralIO as RXD;
+    interface HplMsp430GeneralIO as TXD;
+    interface AsyncConfigure<const msp430_usci_uart_t*> as Configure;
+    interface Counter<T32khz,uint16_t>;
     interface ArbiterInfo;
   }
 }
 implementation {
   enum {
-    CLIENT_ID = unique(MSP430_USCIA0_RESOURCE)
+    /* Bit positions in m_pins */
+    PINS_RXD = 0,
+    PINS_TXD
   };
 
-  components Msp430UartP as UartP;
-  UartStream = UartP;
-  UartByte = UartP;
-  Msp430UsciUartConfigure = UartP;
-
-  components new Msp430UsciA0C() as UsciC;
-  Resource = UsciC.Resource[CLIENT_ID];
-  ResourceRequested = UsciC.ResourceRequested[CLIENT_ID];
-  ArbiterInfo = UsciC.ArbiterInfo;
-  UartP -> UsciC.Registers;
-  UartP -> UsciC.Interrupts[CLIENT_ID];
-  UartP -> UsciC.ArbiterInfo;
-  UsciC.ResourceConfigure[CLIENT_ID] -> UartP;
+  uint8_t m_pins;
+  uint8_t* m_sobuf;    /* Original buffer ptr from UartStream.send() */
+  uint16_t m_solen;    /* Original buffer len from UartStream.send() */
+  uint8_t* m_sbuf;     /* Position of next char to send */
+  uint16_t m_slen;     /* Len of chars in m_sbuf to send */
+  bool m_rxie;         /* Set if rxie has been enabled to UartStream.receive() */
+  uint8_t* m_robuf;    /* Original receive buffer */
+  uint16_t m_rolen;    /* Original (maximum) receive len */
+  uint8_t* m_rbuf;     /* Position of next byte in which to receive a char */
+  uint16_t m_rlen;     /* Remaining length in receive buffer */
+
+  sfrb(MYBRX, 219U);
+
+  async command void ResourceConfigure.configure()
+  {
+    atomic {
+      const msp430_usci_uart_t* config = call Configure.get();
+
+      call Registers.setCtl1(UCSWRST);
+
+      /* Configure USCI registers */
+      call Registers.assignCtl0(config->ctl0 & ~UCSYNC);
+      call Registers.assignCtl1(config->ctl1 | UCSWRST);
+      call Registers.assignBr0(config->brx & 0xff);
+      call Registers.assignBr1(config->brx >> 8);
+      call Registers.assignMctl(config->mctl);
+      call Registers.assignIrtctl(config->irtctl);
+      call Registers.assignIrrctl(config->irrctl);
+      call Registers.assignAbctl(config->abctl);
+      if (config->uclisten)
+       call Registers.setStat(UCLISTEN);
+      else
+       call Registers.clrStat(UCLISTEN);
+
+      /* Configure pins for UART, saving prior pin states */
+      m_pins = 0;
+      if (call RXD.isIOFunc()) {
+       m_pins |= (1 << PINS_RXD);
+       call RXD.selectModuleFunc();
+      }
+      if (call TXD.isIOFunc()) {
+       m_pins |= (1 << PINS_TXD);
+       call TXD.selectModuleFunc();
+      }
+
+      /* Reset important state variables */
+      m_robuf = 0;
+      m_sobuf = 0;
+
+      /* Clear interrupts; we'll add them as needed */
+      call Registers.clrIeRx();
+      call Registers.clrIeTx();
+
+      /* Enable the device */
+      call Registers.clrCtl1(UCSWRST);
+
+      /* TOS convention is for receive interrupts on by default. */
+      call Registers.clrIfgRx();
+      call Registers.setIeRx();
+    }
+  }
+
+  async command void ResourceConfigure.unconfigure()
+  {
+    atomic {
+      /* Disable the device */
+      call Registers.setCtl1(UCSWRST);
+
+      /* Clear interrupts and interrupt flags */
+      call Registers.clrIeRx();
+      call Registers.clrIeTx();
+      call Registers.clrIfgRx();
+
+      /* Reset important state variables */
+      m_robuf = 0;
+      m_sobuf = 0;
+
+      /* Restore pins to their pre-configure state */
+      if (m_pins & (1 << PINS_RXD))
+       call RXD.selectIOFunc();
+      if (m_pins & (1 << PINS_TXD))
+       call TXD.selectIOFunc();
+    }
+  }
+
+  async command error_t UartByte.send(uint8_t byte)
+  {
+    atomic {
+      while (!call Registers.getIfgTx());
+      call Registers.setTxbuf(byte);
+      return SUCCESS;
+    }
+  }
+
+  async command error_t UartStream.send(uint8_t* buf, uint16_t len)
+  {
+    atomic {
+      if (m_sobuf || !buf || !len)
+       return FAIL;
+      m_sbuf = m_sobuf = buf;
+      m_slen = m_solen = len;
+      call Registers.setIeTx();
+      return SUCCESS;
+    }
+  }
+
+  async event void Interrupts.tx()
+  {
+    /* FIXME: this can cause an arbitrarily long ISR, if m_slen is large.
+     * But depending on timing, we may always only write 1 byte.
+     */
+    if (m_sobuf) {
+      while (!call Registers.getIfgTx()); /* in case interleaved UB.send */
+      while (m_slen && call Registers.getIfgTx()) {
+       call Registers.setTxbuf(*m_sbuf);
+       if (--m_slen)
+         m_sbuf++;
+      }
+      if (m_slen == 0) {
+       call Registers.clrIeTx();
+       m_sobuf = 0;
+       signal UartStream.sendDone(m_sobuf, m_solen, SUCCESS);
+      }
+    }
+  }
+
+  async command error_t UartStream.enableReceiveInterrupt()
+  {
+    atomic {
+      if (!m_robuf)
+       call Registers.clrIfgRx();
+      call Registers.setIeRx();
+      m_rxie = FALSE;
+      return SUCCESS;
+    }
+  }
+
+  async command error_t UartStream.disableReceiveInterrupt()
+  {
+    atomic {
+      if (!m_robuf) {
+       call Registers.clrIeRx();
+       call Registers.clrIfgRx();
+      } else
+       m_rxie = TRUE;
+      return SUCCESS;
+    }
+  }
+
+  async command error_t UartByte.receive(uint8_t* byte, uint8_t timeout)
+  {
+    atomic {
+      uint16_t t;
+
+      /* FIXME: race with UartStream.receive() */
+      if (m_robuf || !byte)
+       return FAIL;
+      /* TODO: implement timeout, byte-time units.  For now, 1-2 sec */
+      t = TBR;
+      while (t < TBR) {
+       if (call Registers.getIfgRx()) {
+         *byte = call Registers.getRxbuf();
+         return SUCCESS;
+       }
+      }
+      return FAIL;
+    }
+  }
+
+  async command error_t UartStream.receive(uint8_t* buf, uint16_t len)
+  {
+    atomic {
+      if (m_robuf || !buf || !len)
+       return FAIL;
+      m_robuf = m_rbuf = buf;
+      m_rolen = m_rlen = len;
+      if (!call Registers.getIeRx()) {
+       call Registers.clrIfgRx();
+       call Registers.setIeRx();
+       m_rxie = TRUE;
+      } else
+       m_rxie = FALSE;
+    }
+  }
+
+  async event void Interrupts.rx(uint8_t byte)
+  {
+    if (m_robuf) {
+      /* receive() takes precedence if active */
+      /* FIXME: an arbitrarily long ISR may occur if m_rlen is large.
+       * But depending on timing, we may always only read 1 byte.
+       */
+      while (m_rlen && call Registers.getIfgRx()) {
+       *m_rbuf = byte;
+       if (--m_rlen)
+         m_rbuf++;
+      }
+      if (m_rlen == 0 && m_robuf) {
+       if (m_rxie) {
+         call Registers.clrIeRx();
+         call Registers.clrIfgRx();
+       }
+       m_robuf = 0;
+       signal UartStream.receiveDone(m_robuf, m_rolen, SUCCESS);
+      }
+    } else
+      signal UartStream.receivedByte(byte);
+  }
+
+  default async command const msp430_usci_uart_t* Configure.get()
+  {
+    const static msp430_usci_uart_t def = {
+      ctl0: UCMODE_0,          /* async, lsb first, 8N1 */
+      ctl1: UCSWRST | UCSSEL_3,        /* clock uart from SMCLK */
+      brx: UBRX_1MHZ_115200,
+      mctl: UMCTL_1MHZ_115200,
+      irtctl: 0,
+      irrctl: 0,
+      abctl: 0,
+      uclisten: FALSE,
+      ren: USCI_REN_NONE
+    };
+
+    return &def;
+  }
+
+  async event void Interrupts.i2cStart() {}
+  async event void Interrupts.i2cStop() {}
+  async event void Interrupts.i2cCal() {}
+  async event void Interrupts.brk() {}
+  async event void Interrupts.i2cNak() {}
+  async event void Counter.overflow() {}
+
+  default async event void UartStream.sendDone( uint8_t* buf, uint16_t len,
+      error_t error ) {}
+  default async event void UartStream.receivedByte( uint8_t byte ) {}
+  default async event void UartStream.receiveDone( uint8_t* buf, uint16_t len,
+      error_t error ) {}
 }