+/*
+ * 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.
+ */
+
+/**
+ * Spi implementation using a USCI device.
+ *
+ * @author R. Steve McKown <smckown@gmail.com>
+ */
+
+generic module Msp430SpiP() {
+ provides {
+ interface SpiByte;
+ interface SpiPacket;
+ interface ResourceConfigure;
+ }
+ uses {
+ interface HplMsp430UsciReg as Registers;
+ interface HplMsp430UsciInt as Interrupts;
+ interface HplMsp430GeneralIO as STE;
+ interface HplMsp430GeneralIO as SIMO;
+ interface HplMsp430GeneralIO as SOMI;
+ interface HplMsp430GeneralIO as SCL;
+ interface Msp430UsciSpiConfigure; /* maybe just Msp430UsciConfigure */
+ interface Counter<T32khz,uint16_6>
+ interface ArbiterInfo;
+ }
+}
+implementation {
+ #define saveBits(pin, pos, dir, out, ren) { \
+ if (call pin.isOutput()) \
+ dir |= (1 << pos); \
+ if (call pin.getOut()) \
+ out |= (1 << pos); \
+ if (call pin.isRen()) \
+ ren |= (1 << pos); \
+ }
+
+ #define restoreBits(pin, pos, dir, out, ren) { \
+ if (ren & (1 << pos)) \
+ call pin.enableRen(); \
+ else \
+ call pin.disableRen(); \
+ if (out & (1 << pos)) \
+ call pin.set(); \
+ else \
+ call pin.clr(); \
+ if (dir & (1 << pos)) \
+ call pin.makeOutput(); \
+ else \
+ call pin.makeInput(); \
+ }
+
+ uint8_t dir; /* Pin state storage to allow for proper unconfiguration */
+ uint8_t out;
+ uint8_t ren;
+
+ async command void ResourceConfigure.configure();
+ {
+ call Registers.setCtl0(UCSYNC);
+ /* Save pin states */
+ dir = out = ren = 0;
+ saveBits(STE, 0, dir, out, ren);
+ saveBits(SIMO, 1, dir, out, ren);
+ saveBits(SOMI, 2, dir, out, ren);
+ saveBits(SCL, 3, dir, out, ren);
+ /* FIXME: use Msp430UsciConfig to configure ports */
+ /* FIXME: we may need to have REN/DIR stuff in the configuration... */
+ if (call Registers.getCtl1(UCMODE_3) != UCMODE_0) {
+ call STE.selectModuleFunc();
+ call SIMO.selectModuleFunc();
+ call SOMI.selectModuleFunc();
+ call SCL.selectModuleFunc();
+ /* Clear interrupts; we'll add them as needed */
+ call Registers.clrCtl1(UCRXEIE|UCBRKIE);
+ call Registers.clrIeRx();
+ call Registers.clrIeTx();
+ /* Enable the device */
+ call Registers.clrCtl0(UCSYNC);
+ }
+
+ async command void ResourceConfigure.unconfigure();
+ {
+ /* Disable the device */
+ call Registers.setCtl0(UCSYNC);
+ /* Clear interrupts and interrupt flags */
+ call Registers.clrIeRx();
+ call Registers.clrIeTx();
+ call Registers.clrIfgRx();
+ call Registers.clrIfgTx();
+ /* Restore pins to state just before configure() */
+ restoreBits(SIMO, 1, dir, out, ren);
+ restoreBits(SOMI, 2, dir, out, ren);
+ restoreBits(SCL, 3, dir, out, ren);
+ call SIMO.selectIOFunc();
+ call SOMI.selectIOFunc();
+ call SCL.selectIOFunc();
+ /* Restore more if we were using 4-pin SPI */
+ if (call Registers.getCtl1(UCMODE_3) != UCMODE_0) {
+ restoreBits(STE, 0, dir, out, ren);
+ call STE.selectIOFunc();
+ }
+ }
+
+
+ async event void Interrupts.tx()
+ {
+ while (slen && call Registers.getIfgTx()) {
+ call Registers.setTxbuf(*sbuf);
+ if (--slen)
+ sbuf++;
+ }
+ if (slen == 0 && sobuf) {
+ call Registers.clrIeTx();
+ call Registers.clrIfgTx();
+ sobuf = 0;
+ signal UartStream.sendDone(sobuf, solen, SUCCESS);
+ }
+ }
+
+ async event void Interrupts.rx(uint8_t byte)
+ {
+ if (robuf) {
+ /* receive() takes precedence if active */
+ while (rlen && call Registers.getIfgRx()) {
+ *rbuf = byte;
+ if (--rlen)
+ rbuf++;
+ }
+ if (rlen == 0 && robuf) {
+ if (rxie) {
+ call Registers.clrIeRx();
+ call Registers.clrIfgRx();
+ }
+ robuf = 0;
+ signal UartStream.receiveDone(robuf, rolen, SUCCESS);
+ }
+ } else
+ signal UartStream.receivedByte(byte);
+ }
+}