text: /*
   * Copyright (c) 2014-2017, Texas Instruments Incorporated
   * 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 Texas Instruments Incorporated 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.
   */
  
  #include <stdint.h>
  #include <stdbool.h>
  #include <ti/drivers/Power.h>
  #include <ti/drivers/power/PowerCC32XX.h>
  
  /*
   * By default disable both asserts and log for this module.
   * This must be done before DebugP.h is included.
   */
  #ifndef DebugP_ASSERT_ENABLED
  #define DebugP_ASSERT_ENABLED 0
  #endif
  #ifndef DebugP_LOG_ENABLED
  #define DebugP_LOG_ENABLED 0
  #endif
  
  #include <ti/drivers/dpl/ClockP.h>
  #include <ti/drivers/dpl/DebugP.h>
  #include <ti/drivers/dpl/HwiP.h>
  #include <ti/drivers/dpl/SemaphoreP.h>
  
  #include <ti/drivers/uart/UARTCC32XX.h>
  
  /* driverlib header files */
  #include <ti/devices/cc32xx/inc/hw_memmap.h>
  #include <ti/devices/cc32xx/inc/hw_ocp_shared.h>
  #include <ti/devices/cc32xx/inc/hw_ints.h>
  #include <ti/devices/cc32xx/inc/hw_types.h>
  #include <ti/devices/cc32xx/driverlib/rom.h>
  #include <ti/devices/cc32xx/driverlib/rom_map.h>
  #include <ti/devices/cc32xx/driverlib/uart.h>
  #include <ti/devices/cc32xx/driverlib/pin.h>
  
  /* Pad configuration defines */
  #define PAD_CONFIG_BASE (OCP_SHARED_BASE + OCP_SHARED_O_GPIO_PAD_CONFIG_0)
  #define PAD_RESET_STATE 0xC61
  
  /* UARTCC32XX functions */
  void         UARTCC32XX_close(UART_Handle handle);
  int_fast16_t UARTCC32XX_control(UART_Handle handle, uint_fast16_t cmd,
                  void *arg);
  void         UARTCC32XX_init(UART_Handle handle);
  UART_Handle  UARTCC32XX_open(UART_Handle handle, UART_Params *params);
  int_fast32_t UARTCC32XX_read(UART_Handle handle, void *buffer, size_t size);
  void         UARTCC32XX_readCancel(UART_Handle handle);
  int_fast32_t UARTCC32XX_readPolling(UART_Handle handle, void *buffer,
                  size_t size);
  int_fast32_t UARTCC32XX_write(UART_Handle handle, const void *buffer,
                  size_t size);
  void         UARTCC32XX_writeCancel(UART_Handle handle);
  int_fast32_t UARTCC32XX_writePolling(UART_Handle handle, const void *buffer,
                  size_t size);
  
  /* Static functions */
  static unsigned int getPowerMgrId(unsigned int baseAddr);
  static void initHw(UART_Handle handle);
  static int  postNotifyFxn(unsigned int eventType, uintptr_t eventArg,
      uintptr_t clientArg);
  static void readBlockingTimeout(uintptr_t arg);
  static bool readIsrBinaryBlocking(UART_Handle handle);
  static bool readIsrBinaryCallback(UART_Handle handle);
  static bool readIsrTextBlocking(UART_Handle handle);
  static bool readIsrTextCallback(UART_Handle handle);
  static void readSemCallback(UART_Handle handle, void *buffer, size_t count);
  static int readTaskBlocking(UART_Handle handle);
  static int readTaskCallback(UART_Handle handle);
  static void releasePowerConstraint(UART_Handle handle);
  static void writeData(UART_Handle handle, bool inISR);
  static void writeSemCallback(UART_Handle handle, void *buffer, size_t count);
  
  /*
   * Function for checking whether flow control is enabled.
   */
  static inline bool isFlowControlEnabled(UARTCC32XX_HWAttrsV1 const  *hwAttrs) {
      return ((hwAttrs->flowControl == UARTCC32XX_FLOWCTRL_HARDWARE) &&
          (hwAttrs->ctsPin != UARTCC32XX_PIN_UNASSIGNED) &&
              (hwAttrs->rtsPin != UARTCC32XX_PIN_UNASSIGNED));
  }
  
  /* UART function table for UARTCC32XX implementation */
  const UART_FxnTable UARTCC32XX_fxnTable = {
      UARTCC32XX_close,
      UARTCC32XX_control,
      UARTCC32XX_init,
      UARTCC32XX_open,
      UARTCC32XX_read,
      UARTCC32XX_readPolling,
      UARTCC32XX_readCancel,
      UARTCC32XX_write,
      UARTCC32XX_writePolling,
      UARTCC32XX_writeCancel
  };
  
  static const uint32_t dataLength[] = {
      UART_CONFIG_WLEN_5,     /* UART_LEN_5 */
      UART_CONFIG_WLEN_6,     /* UART_LEN_6 */
      UART_CONFIG_WLEN_7,     /* UART_LEN_7 */
      UART_CONFIG_WLEN_8      /* UART_LEN_8 */
  };
  
  static const uint32_t stopBits[] = {
      UART_CONFIG_STOP_ONE,   /* UART_STOP_ONE */
      UART_CONFIG_STOP_TWO    /* UART_STOP_TWO */
  };
  
  static const uint32_t parityType[] = {
      UART_CONFIG_PAR_NONE,   /* UART_PAR_NONE */
      UART_CONFIG_PAR_EVEN,   /* UART_PAR_EVEN */
      UART_CONFIG_PAR_ODD,    /* UART_PAR_ODD */
      UART_CONFIG_PAR_ZERO,   /* UART_PAR_ZERO */
      UART_CONFIG_PAR_ONE     /* UART_PAR_ONE */
  };
  
  /*
   *  ======== staticFxnTable ========
   *  This is a function lookup table to simplify the UART driver modes.
   */
  static const UARTCC32XX_FxnSet staticFxnTable[2][2] = {
      {/* UART_MODE_BLOCKING */
          {/* UART_DATA_BINARY */
              .readIsrFxn  = readIsrBinaryBlocking,
              .readTaskFxn = readTaskBlocking
          },
          {/* UART_DATA_TEXT */
              .readIsrFxn  = readIsrTextBlocking,
              .readTaskFxn = readTaskBlocking
          }
      },
      {/* UART_MODE_CALLBACK */
          {/* UART_DATA_BINARY */
              .readIsrFxn  = readIsrBinaryCallback,
              .readTaskFxn = readTaskCallback
  
          },
          {/* UART_DATA_TEXT */
              .readIsrFxn  = readIsrTextCallback,
              .readTaskFxn = readTaskCallback,
          }
      }
  };
  
  /*
   *  ======== UARTCC32XX_close ========
   */
  void UARTCC32XX_close(UART_Handle handle)
  {
      UARTCC32XX_Object           *object = handle->object;
      UARTCC32XX_HWAttrsV1 const  *hwAttrs = handle->hwAttrs;
      uint_fast16_t               retVal;
      uint32_t                    padRegister;
  
      /* Disable UART and interrupts. */
      MAP_UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX | UART_INT_RX |
          UART_INT_RT | UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE);
      MAP_UARTDisable(hwAttrs->baseAddr);
  
      if (object->hwiHandle) {
          HwiP_delete(object->hwiHandle);
      }
      if (object->writeSem) {
          SemaphoreP_delete(object->writeSem);
      }
      if (object->readSem) {
          SemaphoreP_delete(object->readSem);
      }
      if (object->timeoutClk) {
          ClockP_delete(object->timeoutClk);
      }
  
      if (object->state.txEnabled) {
          retVal = Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
          DebugP_assert(retVal == Power_SOK);
          object->state.txEnabled = false;
      }
  
      Power_unregisterNotify(&object->postNotify);
      if (object->state.rxEnabled) {
          retVal = Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
          DebugP_assert(retVal == Power_SOK);
          object->state.rxEnabled = false;
  
          DebugP_log1("UART:(%p) UART_close released read power constraint",
              hwAttrs->baseAddr);
      }
      Power_releaseDependency(object->powerMgrId);
  
      if (object->txPin != (uint16_t)-1) {
          PowerCC32XX_restoreParkState((PowerCC32XX_Pin)object->txPin,
              object->prevParkTX);
          object->txPin = (uint16_t)-1;
      }
  
      if (object->rtsPin != (uint16_t)-1) {
          PowerCC32XX_restoreParkState((PowerCC32XX_Pin)object->rtsPin,
              object->prevParkRTS);
          object->rtsPin = (uint16_t)-1;
      }
  
      /* Restore pin pads to their reset states */
      padRegister = (PinToPadGet((hwAttrs->rxPin) & 0xff)<<2) + PAD_CONFIG_BASE;
      HWREG(padRegister) = PAD_RESET_STATE;
      padRegister = (PinToPadGet((hwAttrs->txPin) & 0xff)<<2) + PAD_CONFIG_BASE;
      HWREG(padRegister) = PAD_RESET_STATE;
      if (isFlowControlEnabled(hwAttrs)) {
          padRegister = (PinToPadGet((hwAttrs->ctsPin) & 0xff)<<2)
              + PAD_CONFIG_BASE;
          HWREG(padRegister) = PAD_RESET_STATE;
          padRegister = (PinToPadGet((hwAttrs->rtsPin) & 0xff)<<2)
              + PAD_CONFIG_BASE;
          HWREG(padRegister) = PAD_RESET_STATE;
      }
  
      object->state.opened = false;
  
      DebugP_log1("UART:(%p) closed", hwAttrs->baseAddr);
  
      (void)retVal;
  }
  
  /*
   *  ======== UARTCC32XX_control ========
   *  @pre    Function assumes that the handle is not NULL
   */
  int_fast16_t UARTCC32XX_control(UART_Handle handle, uint_fast16_t cmd,
          void *arg)
  {
      UARTCC32XX_Object          *object = handle->object;
      UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
      unsigned char               data;
      int                         bufferCount;
      uint_fast16_t               retVal;
  
      bufferCount = RingBuf_peek(&object->ringBuffer, &data);
  
      switch (cmd) {
          /* Common UART CMDs */
          case (UART_CMD_PEEK):
              *(int *)arg = (bufferCount) ? data : UART_ERROR;
              DebugP_log2("UART:(%p) UART_CMD_PEEK: %d", hwAttrs->baseAddr,
                  *(uintptr_t*)arg);
              return (UART_STATUS_SUCCESS);
  
          case (UART_CMD_ISAVAILABLE):
              *(bool *)arg = (bufferCount != 0);
              DebugP_log2("UART:(%p) UART_CMD_ISAVAILABLE: %d", hwAttrs->baseAddr,
                  *(uintptr_t*)arg);
              return (UART_STATUS_SUCCESS);
  
          case (UART_CMD_GETRXCOUNT):
              *(int *)arg = bufferCount;
              DebugP_log2("UART:(%p) UART_CMD_GETRXCOUNT: %d", hwAttrs->baseAddr,
                  *(uintptr_t*)arg);
              return (UART_STATUS_SUCCESS);
  
          case (UART_CMD_RXENABLE):
              if (!object->state.rxEnabled) {
                  Power_setConstraint(PowerCC32XX_DISALLOW_LPDS);
                  MAP_UARTIntEnable(hwAttrs->baseAddr, UART_INT_RX | UART_INT_RT);
                  object->state.rxEnabled = true;
                  DebugP_log1("UART:(%p) UART_CMD_RXENABLE: Enabled",
                      hwAttrs->baseAddr);
                  DebugP_log1("UART:(%p) UART_control set read power constraint",
                      hwAttrs->baseAddr);
                  return (UART_STATUS_SUCCESS);
              }
              DebugP_log1("UART:(%p) UART_CMD_RXENABLE: Already enabled",
                  hwAttrs->baseAddr);
              return (UART_STATUS_ERROR);
  
          case (UART_CMD_RXDISABLE):
              if (object->state.rxEnabled) {
                  MAP_UARTIntDisable(hwAttrs->baseAddr, UART_INT_RX | UART_INT_RT);
                  retVal = Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
                  DebugP_assert(retVal == Power_SOK);
                  object->state.rxEnabled = false;
                  DebugP_log1("UART:(%p) UART_CMD_RXDISABLE: Disabled",
                      hwAttrs->baseAddr);
                  DebugP_log1("UART:(%p) UART_control released read power "
                      "constraint", hwAttrs->baseAddr);
  
                  (void)retVal;
                  return (UART_STATUS_SUCCESS);
              }
              DebugP_log1("UART:(%p) UART_CMD_RXDISABLE: Already disabled",
                  hwAttrs->baseAddr);
              return (UART_STATUS_ERROR);
  
          /* Specific UART CMDs */
          case (UARTCC32XX_CMD_IS_BUSY):
              *(bool *)arg = MAP_UARTBusy(hwAttrs->baseAddr);
              return (UART_STATUS_SUCCESS);
  
          case (UARTCC32XX_CMD_IS_RX_DATA_AVAILABLE):
              *(bool *)arg = MAP_UARTCharsAvail(hwAttrs->baseAddr);
              return (UART_STATUS_SUCCESS);
  
          case (UARTCC32XX_CMD_IS_TX_SPACE_AVAILABLE):
              *(bool *)arg = MAP_UARTSpaceAvail(hwAttrs->baseAddr);
              return (UART_STATUS_SUCCESS);
  
          default:
              DebugP_log2("UART:(%p) UART CMD undefined: %d",
                  hwAttrs->baseAddr, cmd);
              return (UART_STATUS_UNDEFINEDCMD);
      }
  }
  
  /*
   *  ======== UARTCC32XX_hwiIntFxn ========
   *  Hwi function that processes UART interrupts.
   *
   *  @param(arg)         The UART_Handle for this Hwi.
   */
  static void UARTCC32XX_hwiIntFxn(uintptr_t arg)
  {
      uint32_t                     status;
      UARTCC32XX_Object           *object = ((UART_Handle)arg)->object;
      UARTCC32XX_HWAttrsV1 const  *hwAttrs = ((UART_Handle)arg)->hwAttrs;
      uint32_t                     rxErrors;
  
      /* Clear interrupts */
      status = MAP_UARTIntStatus(hwAttrs->baseAddr, true);
      MAP_UARTIntClear(hwAttrs->baseAddr, status);
  
      if (status & (UART_INT_RX | UART_INT_RT | UART_INT_OE | UART_INT_BE |
              UART_INT_PE | UART_INT_FE)) {
          object->readFxns.readIsrFxn((UART_Handle)arg);
      }
  
      /* Reading the data from the FIFO doesn't mean we caught an overrrun! */
      rxErrors = MAP_UARTRxErrorGet(hwAttrs->baseAddr);
      if (rxErrors) {
          MAP_UARTRxErrorClear(hwAttrs->baseAddr);
          if (hwAttrs->errorFxn) {
              hwAttrs->errorFxn((UART_Handle)arg, rxErrors);
          }
      }
  
      if (status & UART_INT_TX) {
          writeData((UART_Handle)arg, true);
      }
  }
  
  /*
   *  ======== UARTCC32XX_init ========
   */
  void UARTCC32XX_init(UART_Handle handle)
  {
  }
  
  /*
   *  ======== UARTCC32XX_open ========
   */
  UART_Handle UARTCC32XX_open(UART_Handle handle, UART_Params *params)
  {
      uintptr_t                    key;
      UARTCC32XX_Object           *object = handle->object;
      UARTCC32XX_HWAttrsV1 const  *hwAttrs = handle->hwAttrs;
      SemaphoreP_Params            semParams;
      HwiP_Params                  hwiParams;
      ClockP_Params                clockParams;
      uint16_t                     pin;
      uint16_t                     mode;
  
      /* Check for callback when in UART_MODE_CALLBACK */
      DebugP_assert((params->readMode != UART_MODE_CALLBACK) ||
                    (params->readCallback != NULL));
      DebugP_assert((params->writeMode != UART_MODE_CALLBACK) ||
                    (params->writeCallback != NULL));
  
      key = HwiP_disable();
  
      if (object->state.opened == true) {
          HwiP_restore(key);
  
          DebugP_log1("UART:(%p) already in use.", hwAttrs->baseAddr);
          return (NULL);
      }
      object->state.opened = true;
  
      HwiP_restore(key);
  
      object->state.readMode       = params->readMode;
      object->state.writeMode      = params->writeMode;
      object->state.readReturnMode = params->readReturnMode;
      object->state.readDataMode   = params->readDataMode;
      object->state.writeDataMode  = params->writeDataMode;
      object->state.readEcho       = params->readEcho;
      object->readTimeout          = params->readTimeout;
      object->writeTimeout         = params->writeTimeout;
      object->readCallback         = params->readCallback;
      object->writeCallback        = params->writeCallback;
      object->baudRate             = params->baudRate;
      object->stopBits             = params->stopBits;
      object->dataLength           = params->dataLength;
      object->parityType           = params->parityType;
      object->readFxns =
          staticFxnTable[object->state.readMode][object->state.readDataMode];
  
      /* Set UART variables to defaults. */
      object->writeBuf             = NULL;
      object->readBuf              = NULL;
      object->writeCount           = 0;
      object->readCount            = 0;
      object->writeSize            = 0;
      object->readSize             = 0;
      object->state.txEnabled      = false;
      object->txPin                = (uint16_t)-1;
      object->rtsPin               = (uint16_t)-1;
  
      RingBuf_construct(&object->ringBuffer, hwAttrs->ringBufPtr,
          hwAttrs->ringBufSize);
  
      /* Get the Power resource Id from the base address */
      object->powerMgrId = getPowerMgrId(hwAttrs->baseAddr);
      if (object->powerMgrId == (unsigned int)-1) {
          DebugP_log1("UART:(%p) Failed to determine Power resource id",
                  hwAttrs->baseAddr);
          return (NULL);
      }
  
      /*
       *  Register power dependency. Keeps the clock running in SLP
       *  and DSLP modes.
       */
      Power_setDependency(object->powerMgrId);
  
      pin = (hwAttrs->rxPin) & 0xff;
      mode = (hwAttrs->rxPin >> 8) & 0xff;
  
      MAP_PinTypeUART((unsigned long)pin, (unsigned long)mode);
  
      pin = (hwAttrs->txPin) & 0xff;
      mode = (hwAttrs->txPin >> 8) & 0xff;
  
      MAP_PinTypeUART((unsigned long)pin, (unsigned long)mode);
  
      /*
       * Read and save TX pin park state; set to "don't park" while UART is
       * open as device default is logic '1' during LPDS
       */
      object->prevParkTX =
          (PowerCC32XX_ParkState) PowerCC32XX_getParkState((PowerCC32XX_Pin)pin);
      PowerCC32XX_setParkState((PowerCC32XX_Pin)pin, ~1);
      object->txPin = pin;
  
      if (isFlowControlEnabled(hwAttrs)) {
          pin = (hwAttrs->ctsPin) & 0xff;
          mode = (hwAttrs->ctsPin >> 8) & 0xff;
          MAP_PinTypeUART((unsigned long)pin, (unsigned long)mode);
  
          pin = (hwAttrs->rtsPin) & 0xff;
          mode = (hwAttrs->rtsPin >> 8) & 0xff;
          MAP_PinTypeUART((unsigned long)pin, (unsigned long)mode);
  
          /*
           * Read and save RTS pin park state; set to "don't park" while UART is
           * open as device default is logic '1' during LPDS
           */
          object->prevParkRTS = (PowerCC32XX_ParkState)PowerCC32XX_getParkState(
              (PowerCC32XX_Pin)pin);
          PowerCC32XX_setParkState((PowerCC32XX_Pin)pin, ~1);
          object->rtsPin = pin;
  
          /* Flow control will be enabled in initHw() */
      }
  
      Power_registerNotify(&object->postNotify, PowerCC32XX_AWAKE_LPDS,
          postNotifyFxn, (uintptr_t)handle);
  
      Power_setConstraint(PowerCC32XX_DISALLOW_LPDS);
      object->state.rxEnabled = true;
  
      DebugP_log1("UART:(%p) UART_open set read power constraint",
          hwAttrs->baseAddr);
  
      HwiP_Params_init(&hwiParams);
      hwiParams.arg = (uintptr_t)handle;
      hwiParams.priority = hwAttrs->intPriority;
      object->hwiHandle = HwiP_create(hwAttrs->intNum, UARTCC32XX_hwiIntFxn,
          &hwiParams);
      if (object->hwiHandle == NULL) {
          DebugP_log1("UART:(%p) HwiP_create() failed", hwAttrs->baseAddr);
          UARTCC32XX_close(handle);
          return (NULL);
      }
  
      SemaphoreP_Params_init(&semParams);
      semParams.mode = SemaphoreP_Mode_BINARY;
  
      /* If write mode is blocking create a semaphore and set callback. */
      if (object->state.writeMode == UART_MODE_BLOCKING) {
          if ((object->writeSem = SemaphoreP_create(0, &semParams)) == NULL) {
              DebugP_log1("UART:(%p) SemaphoreP_create() failed.",
                  hwAttrs->baseAddr);
              UARTCC32XX_close(handle);
              return (NULL);
          }
          object->writeCallback = &writeSemCallback;
      }
  
      ClockP_Params_init(&clockParams);
      clockParams.arg = (uintptr_t)handle;
  
      /* If read mode is blocking create a semaphore and set callback. */
      if (object->state.readMode == UART_MODE_BLOCKING) {
          object->readSem = SemaphoreP_create(0, &semParams);
          if (object->readSem == NULL) {
              DebugP_log1("UART:(%p) SemaphoreP_create() failed.",
                  hwAttrs->baseAddr);
              UARTCC32XX_close(handle);
              return (NULL);
          }
          object->readCallback = &readSemCallback;
          object->timeoutClk =
              ClockP_create((ClockP_Fxn)&readBlockingTimeout,
                      0 /* timeout */, &(clockParams));
          if (object->timeoutClk == NULL) {
              DebugP_log1("UART:(%p) ClockP_create() failed.",
                  hwAttrs->baseAddr);
              UARTCC32XX_close(handle);
              return (NULL);
          }
      }
      else {
          object->state.drainByISR = false;
      }
  
      /* Initialize the hardware */
      initHw(handle);
  
      DebugP_log1("UART:(%p) opened", hwAttrs->baseAddr);
  
      /* Return the handle */
      return (handle);
  }
  
  /*
   *  ======== UARTCC32XX_read ========
   */
  int_fast32_t UARTCC32XX_read(UART_Handle handle, void *buffer, size_t size)
  {
      uintptr_t           key;
      UARTCC32XX_Object  *object = handle->object;
  
      key = HwiP_disable();
  
      if ((object->state.readMode == UART_MODE_CALLBACK) && object->readSize) {
          HwiP_restore(key);
  
          DebugP_log1("UART:(%p) Could not read data, uart in use.",
                  ((UARTCC32XX_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr);
          return (UART_ERROR);
      }
  
      /* Save the data to be read and restore interrupts. */
      object->readBuf = buffer;
      object->readSize = size;
      object->readCount = size;
  
      HwiP_restore(key);
  
      return (object->readFxns.readTaskFxn(handle));
  }
  
  /*
   *  ======== UARTCC32XX_readCancel ========
   */
  void UARTCC32XX_readCancel(UART_Handle handle)
  {
      uintptr_t             key;
      UARTCC32XX_Object    *object = handle->object;
  
      if ((object->state.readMode != UART_MODE_CALLBACK) ||
          (object->readSize == 0)) {
          return;
      }
  
      key = HwiP_disable();
  
      object->state.drainByISR = false;
      /*
       * Indicate that what we've currently received is what we asked for so that
       * the existing logic handles the completion.
       */
      object->readSize -= object->readCount;
      object->readCount = 0;
  
      HwiP_restore(key);
  
      object->readFxns.readTaskFxn(handle);
  }
  
  /*
   *  ======== UARTCC32XX_readPolling ========
   */
  int_fast32_t UARTCC32XX_readPolling(UART_Handle handle, void *buf, size_t size)
  {
      int32_t                      count = 0;
      UARTCC32XX_Object           *object = handle->object;
      UARTCC32XX_HWAttrsV1 const  *hwAttrs = handle->hwAttrs;
      unsigned char               *buffer = (unsigned char *)buf;
  
      /* Read characters. */
      while (size) {
          /* Grab data from the RingBuf before getting it from the RX data reg */
          MAP_UARTIntDisable(hwAttrs->baseAddr, UART_INT_RX | UART_INT_RT);
          if (RingBuf_get(&object->ringBuffer, buffer) == -1) {
              *buffer = MAP_UARTCharGet(hwAttrs->baseAddr);
          }
          if (object->state.rxEnabled) {
              MAP_UARTIntEnable(hwAttrs->baseAddr, UART_INT_RX | UART_INT_RT);
          }
  
          DebugP_log2("UART:(%p) Read character 0x%x", hwAttrs->baseAddr,
              *buffer);
          count++;
          size--;
  
          if (object->state.readDataMode == UART_DATA_TEXT && *buffer == '\r') {
              /* Echo character if enabled. */
              if (object->state.readEcho) {
                  MAP_UARTCharPut(hwAttrs->baseAddr, '\r');
              }
              *buffer = '\n';
          }
  
          /* Echo character if enabled. */
          if (object->state.readDataMode == UART_DATA_TEXT &&
                  object->state.readEcho) {
              MAP_UARTCharPut(hwAttrs->baseAddr, *buffer);
          }
  
          /* If read return mode is newline, finish if a newline was received. */
          if (object->state.readDataMode == UART_DATA_TEXT &&
                  object->state.readReturnMode == UART_RETURN_NEWLINE &&
                  *buffer == '\n') {
              return (count);
          }
  
          buffer++;
      }
  
      DebugP_log2("UART:(%p) Read polling finished, %d bytes read",
          hwAttrs->baseAddr, count);
  
      return (count);
  }
  
  /*
   *  ======== UARTCC32XX_write ========
   */
  int_fast32_t UARTCC32XX_write(UART_Handle handle, const void *buffer,
          size_t size)
  {
      unsigned int                 key;
      UARTCC32XX_Object           *object = handle->object;
      UARTCC32XX_HWAttrsV1 const  *hwAttrs = handle->hwAttrs;
  
      if (!size) {
          return 0;
      }
  
      key = HwiP_disable();
  
      if (object->writeCount) {
          HwiP_restore(key);
          DebugP_log1("UART:(%p) Could not write data, uart in use.",
              hwAttrs->baseAddr);
  
          return (UART_ERROR);
      }
  
      /* Save the data to be written and restore interrupts. */
      object->writeBuf = buffer;
      object->writeSize = size;
      object->writeCount = size;
  
      if (object->state.txEnabled == false){
          object->state.txEnabled = true;
          Power_setConstraint(PowerCC32XX_DISALLOW_LPDS);
          DebugP_log1("UART:(%p) UART_write set write power constraint",
              hwAttrs->baseAddr);
      }
  
      HwiP_restore(key);
  
      if (!(MAP_UARTIntStatus(hwAttrs->baseAddr, false) & UART_INT_TX)) {
          /*
           *  Start the transfer going if the raw interrupt status TX bit
           *  is 0.  This will cause the ISR to fire when we enable
           *  UART_INT_TX.  If the RIS TX bit is not cleared, we don't
           *  need to call writeData(), since the ISR will fire once we
           *  enable the interrupt, causing the transfer to start.
           */
          writeData(handle, false);
      }
      if (object->writeCount) {
          MAP_UARTTxIntModeSet(hwAttrs->baseAddr, UART_TXINT_MODE_FIFO);
          MAP_UARTIntEnable(hwAttrs->baseAddr, UART_INT_TX);
      }
  
      /* If writeMode is blocking, block and get the state. */
      if (object->state.writeMode == UART_MODE_BLOCKING) {
          /* Pend on semaphore and wait for Hwi to finish. */
          if (SemaphoreP_OK != SemaphoreP_pend(object->writeSem,
                      object->writeTimeout)) {
              /* Semaphore timed out, make the write empty and log the write. */
              MAP_UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX);
              MAP_UARTIntClear(hwAttrs->baseAddr, UART_INT_TX);
              object->writeCount = 0;
  
              DebugP_log2("UART:(%p) Write timed out, %d bytes written",
                  hwAttrs->baseAddr, object->writeCount);
          }
          return (object->writeSize - object->writeCount);
      }
  
      return (0);
  }
  
  /*
   *  ======== UARTCC32XX_writeCancel ========
   */
  void UARTCC32XX_writeCancel(UART_Handle handle)
  {
      uintptr_t                    key;
      UARTCC32XX_Object           *object = handle->object;
      UARTCC32XX_HWAttrsV1 const  *hwAttrs = handle->hwAttrs;
      unsigned int                 written;
      uint_fast16_t                retVal;
  
      key = HwiP_disable();
  
      /* Return if there is no write. */
      if (!object->writeCount) {
          HwiP_restore(key);
          return;
      }
  
      /* Set size = 0 to prevent writing and restore interrupts. */
      written = object->writeCount;
      object->writeCount = 0;
      MAP_UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX);
      MAP_UARTIntClear(hwAttrs->baseAddr, UART_INT_TX);
  
      retVal = Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
      DebugP_assert(retVal == Power_SOK);
      object->state.txEnabled = false;
  
      HwiP_restore(key);
  
      /* Reset the write buffer so we can pass it back */
      object->writeCallback(handle, (void *)object->writeBuf,
          object->writeSize - written);
  
      DebugP_log2("UART:(%p) Write canceled, %d bytes written",
          hwAttrs->baseAddr, object->writeSize - written);
  
      (void)retVal;
  }
  
  /*
   *  ======== UARTCC32XX_writePolling ========
   */
  int_fast32_t UARTCC32XX_writePolling(UART_Handle handle, const void *buf,
          size_t size)
  {
      int32_t                    count = 0;
      UARTCC32XX_Object         *object = handle->object;
      UARTCC32XX_HWAttrsV1 const  *hwAttrs = handle->hwAttrs;
      unsigned char             *buffer = (unsigned char *)buf;
  
      /* Write characters. */
      while (size) {
          if (object->state.writeDataMode == UART_DATA_TEXT && *buffer == '\n') {
              MAP_UARTCharPut(hwAttrs->baseAddr, '\r');
              count++;
          }
          MAP_UARTCharPut(hwAttrs->baseAddr, *buffer);
  
          DebugP_log2("UART:(%p) Wrote character 0x%x", hwAttrs->baseAddr,
              *buffer);
          buffer++;
          count++;
          size--;
      }
  
      while (MAP_UARTBusy(hwAttrs->baseAddr)) {
          ;
      }
  
      DebugP_log2("UART:(%p) Write polling finished, %d bytes written",
          hwAttrs->baseAddr, count);
  
      return (count);
  }
  
  /*
   *  ======== getPowerMgrId ========
   */
  static unsigned int getPowerMgrId(unsigned int baseAddr)
  {
      switch (baseAddr) {
          case UARTA0_BASE:
              return (PowerCC32XX_PERIPH_UARTA0);
          case UARTA1_BASE:
              return (PowerCC32XX_PERIPH_UARTA1);
          default:
              return ((unsigned int)-1);
      }
  }
  
  /*
   *  ======== initHw ========
   */
  static void initHw(UART_Handle handle)
  {
      ClockP_FreqHz                 freq;
      UARTCC32XX_Object            *object = handle->object;
      UARTCC32XX_HWAttrsV1 const   *hwAttrs = handle->hwAttrs;
  
      /* Enable UART and its interrupt. */
      MAP_UARTIntClear(hwAttrs->baseAddr, UART_INT_TX | UART_INT_RX |
              UART_INT_RT);
      MAP_UARTEnable(hwAttrs->baseAddr);
  
      /* Set the FIFO level to 7/8 empty and 4/8 full. */
      MAP_UARTFIFOLevelSet(hwAttrs->baseAddr, UART_FIFO_TX1_8, UART_FIFO_RX1_8);
  
      if (isFlowControlEnabled(hwAttrs)) {
          /* Set flow control */
          MAP_UARTFlowControlSet(hwAttrs->baseAddr,
                  UART_FLOWCONTROL_TX | UART_FLOWCONTROL_RX);
      }
      else {
          MAP_UARTFlowControlSet(hwAttrs->baseAddr, UART_FLOWCONTROL_NONE);
      }
  
      ClockP_getCpuFreq(&freq);
      MAP_UARTConfigSetExpClk(hwAttrs->baseAddr, freq.lo, object->baudRate,
          dataLength[object->dataLength] | stopBits[object->stopBits] |
          parityType[object->parityType]);
  
      MAP_UARTIntEnable(hwAttrs->baseAddr, UART_INT_RX | UART_INT_RT |
          UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE);
  }
  
  /*
   *  ======== postNotifyFxn ========
   *  Called by Power module when waking up from LPDS.
   */
  static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg,
          uintptr_t clientArg)
  {
      initHw((UART_Handle)clientArg);
  
      return (Power_NOTIFYDONE);
  }
  
  /*
   *  ======== readBlockingTimeout ========
   */
  static void readBlockingTimeout(uintptr_t arg)
  {
      UARTCC32XX_Object *object = ((UART_Handle)arg)->object;
      object->state.bufTimeout = true;
      SemaphoreP_post(object->readSem);
  }
  
  /*
   *  ======== readIsrBinaryBlocking ========
   *  Function that is called by the ISR
   */
  static bool readIsrBinaryBlocking(UART_Handle handle)
  {
      UARTCC32XX_Object           *object = handle->object;
      UARTCC32XX_HWAttrsV1 const  *hwAttrs = handle->hwAttrs;
      int                          readIn;
  
      readIn = MAP_UARTCharGetNonBlocking(hwAttrs->baseAddr);
      while (readIn != -1) {
          if (readIn > 0xFF) {
              if (hwAttrs->errorFxn) {
                  hwAttrs->errorFxn(handle, (uint32_t)((readIn >> 8) & 0xF));
              }
              MAP_UARTRxErrorClear(hwAttrs->baseAddr);
              return (false);
          }
  
          if (RingBuf_put(&object->ringBuffer, (unsigned char)readIn) == -1) {
              DebugP_log1("UART:(%p) Ring buffer full!!", hwAttrs->baseAddr);
              return (false);
          }
          DebugP_log2("UART:(%p) buffered '0x%02x'", hwAttrs->baseAddr,
              (unsigned char)readIn);
  
          if (object->state.callCallback) {
              object->state.callCallback = false;
              object->readCallback(handle, NULL, 0);
          }
          readIn = MAP_UARTCharGetNonBlocking(hwAttrs->baseAddr);
      }
      return (true);
  }
  
  /*
   *  ======== readIsrBinaryCallback ========
   */
  static bool readIsrBinaryCallback(UART_Handle handle)
  {
      UARTCC32XX_Object           *object = handle->object;
      UARTCC32XX_HWAttrsV1 const  *hwAttrs = handle->hwAttrs;
      int                          readIn;
      bool                         ret = true;
  
      readIn = MAP_UARTCharGetNonBlocking(hwAttrs->baseAddr);
      while (readIn != -1) {
          if (readIn > 0xFF) {
              if (hwAttrs->errorFxn) {
                  hwAttrs->errorFxn(handle, (uint32_t)((readIn >> 8) & 0xF));
              }
              MAP_UARTRxErrorClear(hwAttrs->baseAddr);
              ret = false;
              break;
          }
  
          if (RingBuf_put(&object->ringBuffer, (unsigned char)readIn) == -1) {
              DebugP_log1("UART:(%p) Ring buffer full!!", hwAttrs->baseAddr);
              ret = false;
              break;
          }
          DebugP_log2("UART:(%p) buffered '0x%02x'", hwAttrs->baseAddr,
              (unsigned char)readIn);
          readIn = MAP_UARTCharGetNonBlocking(hwAttrs->baseAddr);
      }
  
      /*
       * Check and see if a UART_read in callback mode told use to continue
       * servicing the user buffer...
       */
      if (object->state.drainByISR) {
          readTaskCallback(handle);
      }
  
      return (ret);
  }
  
  /*
   *  ======== readIsrTextBlocking ========
   */
  static bool readIsrTextBlocking(UART_Handle handle)
  {
      UARTCC32XX_Object           *object = handle->object;
      UARTCC32XX_HWAttrsV1 const  *hwAttrs = handle->hwAttrs;
      int                          readIn;
  
      readIn = MAP_UARTCharGetNonBlocking(hwAttrs->baseAddr);
      while (readIn != -1) {
          if (readIn > 0xFF) {
              if (hwAttrs->errorFxn) {
                  hwAttrs->errorFxn(handle, (uint32_t)((readIn >> 8) & 0xF));
              }
              MAP_UARTRxErrorClear(hwAttrs->baseAddr);
              return (false);
          }
  
          if (readIn == '\r') {
              /* Echo character if enabled. */
              if (object->state.readEcho) {
                  MAP_UARTCharPut(hwAttrs->baseAddr, '\r');
              }
              readIn = '\n';
          }
          if (RingBuf_put(&object->ringBuffer, (unsigned char)readIn) == -1) {
              DebugP_log1("UART:(%p) Ring buffer full!!", hwAttrs->baseAddr);
              return (false);
          }
          DebugP_log2("UART:(%p) buffered '0x%02x'", hwAttrs->baseAddr,
              (unsigned char)readIn);
  
          if (object->state.readEcho) {
              MAP_UARTCharPut(hwAttrs->baseAddr, (unsigned char)readIn);
          }
          if (object->state.callCallback) {
              object->state.callCallback = false;
              object->readCallback(handle, NULL, 0);
          }
          readIn = MAP_UARTCharGetNonBlocking(hwAttrs->baseAddr);
      }
      return (true);
  }
  
  /*
   *  ======== readIsrTextCallback ========
   */
  static bool readIsrTextCallback(UART_Handle handle)
  {
      UARTCC32XX_Object           *object = handle->object;
      UARTCC32XX_HWAttrsV1 const  *hwAttrs = handle->hwAttrs;
      int                          readIn;
      bool                         ret = true;
  
      readIn = MAP_UARTCharGetNonBlocking(hwAttrs->baseAddr);
      while (readIn != -1) {
          if (readIn > 0xFF) {
              if (hwAttrs->errorFxn) {
                  hwAttrs->errorFxn(handle, (uint32_t)((readIn >> 8) & 0xF));
              }
              MAP_UARTRxErrorClear(hwAttrs->baseAddr);
              ret = false;
              break;
          }
  
          if (readIn == '\r') {
              /* Echo character if enabled. */
              if (object->state.readEcho) {
                  MAP_UARTCharPut(hwAttrs->baseAddr, '\r');
              }
              readIn = '\n';
          }
          if (RingBuf_put(&object->ringBuffer, (unsigned char)readIn) == -1) {
              DebugP_log1("UART:(%p) Ring buffer full!!", hwAttrs->baseAddr);
              ret = false;
              break;
          }
          DebugP_log2("UART:(%p) buffered '0x%02x'", hwAttrs->baseAddr,
              (unsigned char)readIn);
  
          if (object->state.readEcho) {
              MAP_UARTCharPut(hwAttrs->baseAddr, (unsigned char)readIn);
          }
          readIn = MAP_UARTCharGetNonBlocking(hwAttrs->baseAddr);
      }
  
      /*
       * Check and see if a UART_read in callback mode told use to continue
       * servicing the user buffer...
       */
      if (object->state.drainByISR) {
          readTaskCallback(handle);
      }
  
      return (ret);
  }
  
  /*
   *  ======== readSemCallback ========
   *  Simple callback to post a semaphore for the blocking mode.
   */
  static void readSemCallback(UART_Handle handle, void *buffer, size_t count)
  {
      UARTCC32XX_Object *object = handle->object;
  
      SemaphoreP_post(object->readSem);
  }
  
  /*
   *  ======== readTaskBlocking ========
   */
  static int readTaskBlocking(UART_Handle handle)
  {
      unsigned char              readIn;
      uintptr_t                  key;
      UARTCC32XX_Object         *object = handle->object;
      unsigned char             *buffer = object->readBuf;
  
      object->state.bufTimeout = false;
      /*
       * It is possible for the object->timeoutClk and the callback function to
       * have posted the object->readSem Semaphore from the previous UART_read
       * call (if the code below didn't get to stop the clock object in time).
       * To clear this, we simply do a NO_WAIT pend on (binary) object->readSem
       * so that it resets the Semaphore count.
       */
      SemaphoreP_pend(object->readSem, SemaphoreP_NO_WAIT);
  
      if ((object->readTimeout != 0) &&
                  (object->readTimeout != UART_WAIT_FOREVER)) {
          ClockP_setTimeout(object->timeoutClk, object->readTimeout);
          ClockP_start(object->timeoutClk);
      }
  
      while (object->readCount) {
          key = HwiP_disable();
  
          if (RingBuf_get(&object->ringBuffer, &readIn) < 0) {
              object->state.callCallback = true;
              HwiP_restore(key);
  
              if (object->readTimeout == 0) {
                  break;
              }
  
              SemaphoreP_pend(object->readSem, SemaphoreP_WAIT_FOREVER);
              if (object->state.bufTimeout == true) {
                  break;
              }
              RingBuf_get(&object->ringBuffer, &readIn);
          }
          else {
              HwiP_restore(key);
          }
  
          DebugP_log2("UART:(%p) read '0x%02x'",
              ((UARTCC32XX_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr,
              (unsigned char)readIn);
  
          *buffer = readIn;
          buffer++;
          /* In blocking mode, readCount doesn't not need a lock */
          object->readCount--;
  
          if (object->state.readDataMode == UART_DATA_TEXT &&
                  object->state.readReturnMode == UART_RETURN_NEWLINE &&
                  readIn == '\n') {
              break;
          }
      }
  
      ClockP_stop(object->timeoutClk);
      return (object->readSize - object->readCount);
  }
  
  /*
   *  ======== readTaskCallback ========
   *  This function is called the first time by the UART_read task and tries to
   *  get all the data it can get from the ringBuffer. If it finished, it will
   *  perform the user supplied callback. If it didn't finish, the ISR must handle
   *  the remaining data. By setting the drainByISR flag, the UART_read function
   *  handed over the responsibility to get the remaining data to the ISR.
   */
  static int readTaskCallback(UART_Handle handle)
  {
      unsigned int               key;
      UARTCC32XX_Object         *object = handle->object;
      unsigned char              readIn;
      unsigned char             *bufferEnd;
      bool                       makeCallback = false;
      size_t                     tempCount;
  
      object->state.drainByISR = false;
      bufferEnd = (unsigned char*) object->readBuf + object->readSize;
  
      while (object->readCount) {
          if (RingBuf_get(&object->ringBuffer, &readIn) < 0) {
              break;
          }
  
          DebugP_log2("UART:(%p) read '0x%02x'",
              ((UARTCC32XX_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr,
              (unsigned char)readIn);
  
          *(unsigned char *) (bufferEnd - object->readCount *
              sizeof(unsigned char)) = readIn;
  
          key = HwiP_disable();
  
          object->readCount--;
  
          HwiP_restore(key);
  
          if ((object->state.readDataMode == UART_DATA_TEXT) &&
              (object->state.readReturnMode == UART_RETURN_NEWLINE) &&
              (readIn == '\n')) {
              makeCallback = true;
              break;
          }
      }
  
      if (!object->readCount || makeCallback) {
          tempCount = object->readSize;
          object->readSize = 0;
          object->readCallback(handle, object->readBuf,
              tempCount - object->readCount);
      }
      else {
          object->state.drainByISR = true;
      }
  
      return (0);
  }
  
  /*
   *  ======== releasePowerConstraint ========
   */
  static void releasePowerConstraint(UART_Handle handle)
  {
      UARTCC32XX_Object *object = handle->object;
      uint_fast16_t      retVal;
  
      retVal = Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
      DebugP_assert(retVal == Power_SOK);
      object->state.txEnabled = false;
  
      DebugP_log1("UART:(%p) UART released write power constraint",
          ((UARTCC32XX_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr);
  
      (void)retVal;
  }
  
  /*
   *  ======== writeData ========
   */
  static void writeData(UART_Handle handle, bool inISR)
  {
      UARTCC32XX_Object           *object = handle->object;
      UARTCC32XX_HWAttrsV1 const  *hwAttrs = handle->hwAttrs;
      unsigned char               *writeOffset;
  
      writeOffset = (unsigned char *)object->writeBuf +
          object->writeSize * sizeof(unsigned char);
      while (object->writeCount) {
          if (!MAP_UARTCharPutNonBlocking(hwAttrs->baseAddr,
                  *(writeOffset - object->writeCount))) {
              /* TX FIFO is FULL */
              break;
          }
          if ((object->state.writeDataMode == UART_DATA_TEXT) &&
              (*(writeOffset - object->writeCount) == '\n')) {
              MAP_UARTCharPut(hwAttrs->baseAddr, '\r');
          }
          object->writeCount--;
      }
  
      if (!object->writeCount) {
          MAP_UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX);
          MAP_UARTIntClear(hwAttrs->baseAddr, UART_INT_TX);
  
          /*
           *  Set TX interrupt for end of transmission mode.
           *  The TXRIS bit will be set only when all the data
           *  (including stop bits) have left the serializer.
           */
          MAP_UARTTxIntModeSet(hwAttrs->baseAddr, UART_TXINT_MODE_EOT);
  
          if (!UARTBusy(hwAttrs->baseAddr)) {
              object->writeCallback(handle, (void *)object->writeBuf,
                      object->writeSize);
              releasePowerConstraint(handle);
          }
          else {
              UARTIntEnable(hwAttrs->baseAddr, UART_INT_TX);
          }
  
          DebugP_log2("UART:(%p) Write finished, %d bytes written",
              hwAttrs->baseAddr, object->writeSize - object->writeCount);
      }
  }
  
  /*
   *  ======== writeSemCallback ========
   *  Simple callback to post a semaphore for the blocking mode.
   */
  static void writeSemCallback(UART_Handle handle, void *buffer, size_t count)
  {
      UARTCC32XX_Object *object = handle->object;
  
      SemaphoreP_post(object->writeSem);
  }
  