blob: 34cd8650472fe30a9477605da024eb5252ed8016 [file] [log] [blame]
/*
* Copyright (c) 2018, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*/
/**
* @file
* This file implements the OpenThread platform abstraction for UART communication.
*
*/
#include <openthread-core-config.h>
#include <openthread/config.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <openthread/platform/debug_uart.h>
#include <openthread/platform/logging.h>
#include <openthread/platform/uart.h>
#include "utils/code_utils.h"
#include <utils/code_utils.h>
#include <driverlib/ioc.h>
#include <driverlib/prcm.h>
#include <driverlib/sys_ctrl.h>
#include <driverlib/uart.h>
/**
* @note This will configure the uart for 115200 baud 8-N-1, no HW flow control
* RX pin IOID_2 TX pin IOID_3.
*
* If the DEBUG UART is enabled, IOID_0 = debug tx, IOID_1 = debug rx
*/
enum
{
CC1352_RECV_CIRC_BUFF_SIZE = 256,
};
static uint8_t const *sSendBuffer = NULL;
static uint16_t sSendLen = 0;
static uint8_t sReceiveBuffer[CC1352_RECV_CIRC_BUFF_SIZE];
static uint16_t sReceiveHeadIdx = 0;
static uint16_t sReceiveTailIdx = 0;
void UART0_intHandler(void);
static void uart_power_control(uint32_t who_base, int turnon)
{
uint32_t value;
if (turnon)
{
/* UART0 is in the SERIAL domain
* UART1 is in the PERIPH domain.
* See: ti/devices/cc13x2_cc26x2/driverlib/pcrm.h, line: 658
*/
value = (who_base == UART0_BASE) ? PRCM_DOMAIN_SERIAL : PRCM_DOMAIN_PERIPH;
PRCMPowerDomainOn(value);
while (PRCMPowerDomainStatus(value) != PRCM_DOMAIN_POWER_ON)
;
value = (who_base == UART0_BASE) ? PRCM_PERIPH_UART0 : PRCM_PERIPH_UART1;
PRCMPeripheralRunEnable(value);
PRCMPeripheralSleepEnable(value);
PRCMPeripheralDeepSleepEnable(value);
PRCMLoadSet();
while (!PRCMLoadGet())
;
}
else
{
if (who_base == UART0_BASE)
{
PRCMPeripheralRunDisable(PRCM_PERIPH_UART0);
PRCMPeripheralSleepDisable(PRCM_PERIPH_UART0);
PRCMPeripheralDeepSleepDisable(PRCM_PERIPH_UART0);
PRCMLoadSet();
PRCMPowerDomainOff(PRCM_DOMAIN_SERIAL);
}
else
{
/* we never turn the debug uart off */
}
}
}
/**
* Function documented in platform/uart.h
*/
otError otPlatUartEnable(void)
{
uart_power_control(UART0_BASE, true);
IOCPinTypeUart(UART0_BASE, IOID_12, IOID_13, IOID_UNUSED, IOID_UNUSED);
UARTConfigSetExpClk(UART0_BASE, SysCtrlClockGet(), 115200,
UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE);
/* Note: UART1 could use IRQs
* However, for reasons of debug simplicity
* we do not use IRQs for the debug uart
*/
UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);
UARTIntRegister(UART0_BASE, UART0_intHandler);
UARTEnable(UART0_BASE);
return OT_ERROR_NONE;
}
/**
* Function documented in platform/uart.h
*/
otError otPlatUartDisable(void)
{
UARTDisable(UART0_BASE);
UARTIntUnregister(UART0_BASE);
UARTIntDisable(UART0_BASE, UART_INT_RX | UART_INT_RT);
IOCPortConfigureSet(IOID_2, IOC_PORT_GPIO, IOC_STD_INPUT);
IOCPortConfigureSet(IOID_3, IOC_PORT_GPIO, IOC_STD_INPUT);
uart_power_control(UART0_BASE, false);
return OT_ERROR_NONE;
}
/**
* Function documented in platform/uart.h
*/
otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength)
{
otError error = OT_ERROR_NONE;
otEXPECT_ACTION(sSendBuffer == NULL, error = OT_ERROR_BUSY);
sSendBuffer = aBuf;
sSendLen = aBufLength;
exit:
return error;
}
/**
* @brief process the receive side of the buffers
*/
static void processReceive(void)
{
while (sReceiveHeadIdx != sReceiveTailIdx)
{
uint16_t tailIdx;
if (sReceiveHeadIdx < sReceiveTailIdx)
{
tailIdx = sReceiveTailIdx;
otPlatUartReceived(&(sReceiveBuffer[sReceiveHeadIdx]), tailIdx - sReceiveHeadIdx);
sReceiveHeadIdx = tailIdx;
}
else
{
tailIdx = CC1352_RECV_CIRC_BUFF_SIZE;
otPlatUartReceived(&(sReceiveBuffer[sReceiveHeadIdx]), tailIdx - sReceiveHeadIdx);
sReceiveHeadIdx = 0;
}
}
}
otError otPlatUartFlush(void)
{
otEXPECT(sSendBuffer != NULL);
for (; sSendLen > 0; sSendLen--)
{
UARTCharPut(UART0_BASE, *sSendBuffer);
sSendBuffer++;
}
sSendBuffer = NULL;
sSendLen = 0;
return OT_ERROR_NONE;
exit:
return OT_ERROR_INVALID_STATE;
}
/**
* @brief process the transmit side of the buffers
*/
static void processTransmit(void)
{
otPlatUartFlush();
otPlatUartSendDone();
}
/**
* Function documented in platform-cc1352.h
*/
void cc1352UartProcess(void)
{
processReceive();
processTransmit();
}
/**
* @brief the interrupt handler for the uart interrupt vector
*/
void UART0_intHandler(void)
{
while (UARTCharsAvail(UART0_BASE))
{
uint32_t c = UARTCharGet(UART0_BASE);
/* XXX process error flags for this character ?? */
sReceiveBuffer[sReceiveTailIdx] = (uint8_t)c;
sReceiveTailIdx++;
if (sReceiveTailIdx >= CC1352_RECV_CIRC_BUFF_SIZE)
{
sReceiveTailIdx = 0;
}
}
}
#if OPENTHREAD_CONFIG_ENABLE_DEBUG_UART
/*
* Documented in platform-cc1352.h
*/
void cc1352DebugUartInit(void)
{
uart_power_control(UART1_BASE, true);
/*
* LaunchPad Pin29 = tx, Pin 30 = rxd
*
* The function IOCPinTypeUart() is hard coded to
* only support UART0 - and does not support UART1.
*
* Thus, these pins are configured using a different way.
*/
IOCPortConfigureSet(IOID_0, IOC_PORT_MCU_UART1_TX, IOC_STD_INPUT);
IOCPortConfigureSet(IOID_1, IOC_PORT_MCU_UART1_RX, IOC_STD_INPUT);
UARTConfigSetExpClk(UART1_BASE, SysCtrlClockGet(), 115200,
UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE);
UARTEnable(UART1_BASE);
}
/* This holds the last key pressed */
static int debug_uart_ungetbuf;
/*
* Documented in "src/core/common/debug_uart.h"
*/
int otPlatDebugUart_getc(void)
{
int ch = -1;
if (otPlatDebugUart_kbhit())
{
/* get & clear 0x100 bit used below as flag */
ch = debug_uart_ungetbuf & 0x0ff;
debug_uart_ungetbuf = 0;
}
return ch;
}
/*
* Documented in "src/core/common/debug_uart.h"
*/
int otPlatDebugUart_kbhit(void)
{
int r;
/* if something is in the unget buf... */
r = !!debug_uart_ungetbuf;
if (!r)
{
/*
* Driverlib code returns "-1", or "char" on something
* but it comes with flags in upper bits
*/
r = (int)UARTCharGetNonBlocking(UART1_BASE);
if (r < 0)
{
r = 0; /* no key pressed */
}
else
{
/* key was pressed, mask flags
* and set 0x100 bit, to distinguish
* the value "0x00" from "no-key-pressed"
*/
debug_uart_ungetbuf = ((r & 0x0ff) | 0x0100);
r = 1; /* key pressed */
}
}
return r;
}
/*
* Documented in "src/core/common/debug_uart.h"
*/
void otPlatDebugUart_putchar_raw(int b)
{
UARTCharPut(UART1_BASE, b);
}
#endif /* OPENTHREAD_CONFIG_ENABLE_DEBUG_UART */