blob: f78362779d98eec39bb11dd736baeac1204e9e21 [file] [log] [blame]
/*
* 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 void errorCallback(UART_Handle handle, uintptr_t error);
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);
errorCallback((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;
/*
* Compute appropriate wait time for FIFO to empty out
* Total bits
* - 16 + 1: TX FIFO size + 1
* - 1 bit for start bit
* - 5+(object->dataLength) for total data length (5,6,7,or 8 bits)
* - 1+(object->stopBits) for total stop bit count (1 or 2 bits)
* mutiplied by 1000000 (bits / second)
* divided by object->baudRate (bits / second)
* divided by ClockP_getSystemTickPeriod() (bits (us) / SystemTick)
* In case of high baud rates, this tick count may be less than 1
* system ticks. Add 2 system ticks so that we can guarantee at
* least 1 system tick.
*/
object->writeEmptyClkTimeout = ((16 + 1) * (1 + 5 + object->dataLength +
1 + object->stopBits) * 1000000) / object->baudRate;
object->writeEmptyClkTimeout /= ClockP_getSystemTickPeriod();
object->writeEmptyClkTimeout += 2;
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);
}
/*
* ======== errorCallback ========
* Generic log function for when unexpected events occur.
*/
static void errorCallback(UART_Handle handle, uintptr_t error)
{
if (error & UART_RXERROR_OVERRUN) {
DebugP_log1("UART:(%p): OVERRUN ERROR",
((UARTCC32XX_HWAttrsV1 const *)handle->hwAttrs)->baseAddr);
}
if (error & UART_RXERROR_BREAK) {
DebugP_log1("UART:(%p): BREAK ERROR",
((UARTCC32XX_HWAttrsV1 const *)handle->hwAttrs)->baseAddr);
}
if (error & UART_RXERROR_PARITY) {
DebugP_log1("UART:(%p): PARITY ERROR",
((UARTCC32XX_HWAttrsV1 const *)handle->hwAttrs)->baseAddr);
}
if (error & UART_RXERROR_FRAMING) {
DebugP_log1("UART:(%p): FRAMING ERROR",
((UARTCC32XX_HWAttrsV1 const *)handle->hwAttrs)->baseAddr);
}
}
/*
* ======== 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) {
errorCallback(handle, (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) {
errorCallback(handle, (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) {
errorCallback(handle, (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) {
errorCallback(handle, (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);
}