/* * Copyright (c) 2021 ARM Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ---------------------------------------------------------------------- * * $Date: 1. March 2021 * $Revision: V1.0.0 * * Project: CMSIS-DAP Source * Title: UART.c CMSIS-DAP UART * *---------------------------------------------------------------------------*/ #include "DAP_config.h" #include "DAP.h" #if (DAP_UART != 0) #ifdef DAP_FW_V1 #error "UART Communication Port not supported in DAP V1!" #endif #include "Driver_USART.h" #include "cmsis_os2.h" #include #define UART_RX_BLOCK_SIZE 32U /* Uart Rx Block Size (must be 2^n) */ // USART Driver #define _USART_Driver_(n) Driver_USART##n #define USART_Driver_(n) _USART_Driver_(n) extern ARM_DRIVER_USART USART_Driver_(DAP_UART_DRIVER); #define pUSART (&USART_Driver_(DAP_UART_DRIVER)) // UART Configuration #if (DAP_UART_USB_COM_PORT != 0) static uint8_t UartTransport = DAP_UART_TRANSPORT_USB_COM_PORT; #else static uint8_t UartTransport = DAP_UART_TRANSPORT_NONE; #endif // UART Flags static uint8_t UartConfigured = 0U; static uint8_t UartReceiveEnabled = 0U; static uint8_t UartTransmitEnabled = 0U; static uint8_t UartTransmitActive = 0U; // UART TX Buffer static uint8_t UartTxBuf[DAP_UART_TX_BUFFER_SIZE]; static volatile uint32_t UartTxIndexI = 0U; static volatile uint32_t UartTxIndexO = 0U; // UART RX Buffer static uint8_t UartRxBuf[DAP_UART_RX_BUFFER_SIZE]; static volatile uint32_t UartRxIndexI = 0U; static volatile uint32_t UartRxIndexO = 0U; // Uart Errors static volatile uint8_t UartErrorRxDataLost = 0U; static volatile uint8_t UartErrorFraming = 0U; static volatile uint8_t UartErrorParity = 0U; // UART Transmit static uint32_t UartTxNum = 0U; // Function prototypes static uint8_t UART_Init (void); static void UART_Uninit (void); static uint8_t UART_Get_Status (void); static uint8_t UART_Receive_Enable (void); static uint8_t UART_Transmit_Enable (void); static void UART_Receive_Disable (void); static void UART_Transmit_Disable (void); static void UART_Receive_Flush (void); static void UART_Transmit_Flush (void); static void UART_Receive (void); static void UART_Transmit (void); // USART Driver Callback function // event: event mask static void USART_Callback (uint32_t event) { if (event & ARM_USART_EVENT_SEND_COMPLETE) { UartTxIndexO += UartTxNum; UartTransmitActive = 0U; UART_Transmit(); } if (event & ARM_USART_EVENT_RECEIVE_COMPLETE) { UartRxIndexI += UART_RX_BLOCK_SIZE; UART_Receive(); } if (event & ARM_USART_EVENT_RX_OVERFLOW) { UartErrorRxDataLost = 1U; } if (event & ARM_USART_EVENT_RX_FRAMING_ERROR) { UartErrorFraming = 1U; } if (event & ARM_USART_EVENT_RX_PARITY_ERROR) { UartErrorParity = 1U; } } // Init UART // return: DAP_OK or DAP_ERROR static uint8_t UART_Init (void) { int32_t status; uint8_t ret = DAP_ERROR; UartConfigured = 0U; UartReceiveEnabled = 0U; UartTransmitEnabled = 0U; UartTransmitActive = 0U; UartErrorRxDataLost = 0U; UartErrorFraming = 0U; UartErrorParity = 0U; UartTxIndexI = 0U; UartTxIndexO = 0U; UartRxIndexI = 0U; UartRxIndexO = 0U; UartTxNum = 0U; status = pUSART->Initialize(USART_Callback); if (status == ARM_DRIVER_OK) { status = pUSART->PowerControl(ARM_POWER_FULL); } if (status == ARM_DRIVER_OK) { ret = DAP_OK; } return (ret); } // Un-Init UART static void UART_Uninit (void) { UartConfigured = 0U; pUSART->PowerControl(ARM_POWER_OFF); pUSART->Uninitialize(); } // Get UART Status // return: status static uint8_t UART_Get_Status (void) { uint8_t status = 0U; if (UartReceiveEnabled != 0U) { status |= DAP_UART_STATUS_RX_ENABLED; } if (UartErrorRxDataLost != 0U) { UartErrorRxDataLost = 0U; status |= DAP_UART_STATUS_RX_DATA_LOST; } if (UartErrorFraming != 0U) { UartErrorFraming = 0U; status |= DAP_UART_STATUS_FRAMING_ERROR; } if (UartErrorParity != 0U) { UartErrorParity = 0U; status |= DAP_UART_STATUS_PARITY_ERROR; } if (UartTransmitEnabled != 0U) { status |= DAP_UART_STATUS_TX_ENABLED; } return (status); } // Enable UART Receive // return: DAP_OK or DAP_ERROR static uint8_t UART_Receive_Enable (void) { int32_t status; uint8_t ret = DAP_ERROR; if (UartReceiveEnabled == 0U) { // Flush Buffers UartRxIndexI = 0U; UartRxIndexO = 0U; UART_Receive(); status = pUSART->Control(ARM_USART_CONTROL_RX, 1U); if (status == ARM_DRIVER_OK) { UartReceiveEnabled = 1U; ret = DAP_OK; } } else { ret = DAP_OK; } return (ret); } // Enable UART Transmit // return: DAP_OK or DAP_ERROR static uint8_t UART_Transmit_Enable (void) { int32_t status; uint8_t ret = DAP_ERROR; if (UartTransmitEnabled == 0U) { // Flush Buffers UartTransmitActive = 0U; UartTxIndexI = 0U; UartTxIndexO = 0U; UartTxNum = 0U; status = pUSART->Control(ARM_USART_CONTROL_TX, 1U); if (status == ARM_DRIVER_OK) { UartTransmitEnabled = 1U; ret = DAP_OK; } } else { ret = DAP_OK; } return (ret); } // Disable UART Receive static void UART_Receive_Disable (void) { if (UartReceiveEnabled != 0U) { pUSART->Control(ARM_USART_CONTROL_RX, 0U); pUSART->Control(ARM_USART_ABORT_RECEIVE, 0U); UartReceiveEnabled = 0U; } } // Disable UART Transmit static void UART_Transmit_Disable (void) { if (UartTransmitEnabled != 0U) { pUSART->Control(ARM_USART_ABORT_SEND, 0U); pUSART->Control(ARM_USART_CONTROL_TX, 0U); UartTransmitActive = 0U; UartTransmitEnabled = 0U; } } // Flush UART Receive buffer static void UART_Receive_Flush (void) { pUSART->Control(ARM_USART_ABORT_RECEIVE, 0U); UartRxIndexI = 0U; UartRxIndexO = 0U; if (UartReceiveEnabled != 0U) { UART_Receive(); } } // Flush UART Transmit buffer static void UART_Transmit_Flush (void) { pUSART->Control(ARM_USART_ABORT_SEND, 0U); UartTransmitActive = 0U; UartTxIndexI = 0U; UartTxIndexO = 0U; UartTxNum = 0U; } // Receive data from target via UART static void UART_Receive (void) { uint32_t index; index = UartRxIndexI & (DAP_UART_RX_BUFFER_SIZE - 1U); pUSART->Receive(&UartRxBuf[index], UART_RX_BLOCK_SIZE); } // Transmit available data to target via UART static void UART_Transmit (void) { uint32_t count; uint32_t index; count = UartTxIndexI - UartTxIndexO; index = UartTxIndexO & (DAP_UART_TX_BUFFER_SIZE - 1U); if (count != 0U) { if ((index + count) <= DAP_UART_TX_BUFFER_SIZE) { UartTxNum = count; } else { UartTxNum = DAP_UART_TX_BUFFER_SIZE - index; } UartTransmitActive = 1U; pUSART->Send(&UartTxBuf[index], UartTxNum); } } // Process UART Transport command and prepare response // request: pointer to request data // response: pointer to response data // return: number of bytes in response (lower 16 bits) // number of bytes in request (upper 16 bits) uint32_t UART_Transport (const uint8_t *request, uint8_t *response) { uint8_t transport; uint8_t ret = DAP_ERROR; transport = *request; switch (transport) { case DAP_UART_TRANSPORT_NONE: switch (UartTransport) { case DAP_UART_TRANSPORT_NONE: ret = DAP_OK; break; case DAP_UART_TRANSPORT_USB_COM_PORT: #if (DAP_UART_USB_COM_PORT != 0) USB_COM_PORT_Activate(0U); UartTransport = DAP_UART_TRANSPORT_NONE; ret = DAP_OK; #endif break; case DAP_UART_TRANSPORT_DAP_COMMAND: UART_Receive_Disable(); UART_Transmit_Disable(); UART_Uninit(); UartTransport = DAP_UART_TRANSPORT_NONE; ret= DAP_OK; break; } break; case DAP_UART_TRANSPORT_USB_COM_PORT: switch (UartTransport) { case DAP_UART_TRANSPORT_NONE: #if (DAP_UART_USB_COM_PORT != 0) if (USB_COM_PORT_Activate(1U) == 0U) { UartTransport = DAP_UART_TRANSPORT_USB_COM_PORT; ret = DAP_OK; } #endif break; case DAP_UART_TRANSPORT_USB_COM_PORT: ret = DAP_OK; break; case DAP_UART_TRANSPORT_DAP_COMMAND: UART_Receive_Disable(); UART_Transmit_Disable(); UART_Uninit(); UartTransport = DAP_UART_TRANSPORT_NONE; #if (DAP_UART_USB_COM_PORT != 0) if (USB_COM_PORT_Activate(1U) == 0U) { UartTransport = DAP_UART_TRANSPORT_USB_COM_PORT; ret = DAP_OK; } #endif break; } break; case DAP_UART_TRANSPORT_DAP_COMMAND: switch (UartTransport) { case DAP_UART_TRANSPORT_NONE: ret = UART_Init(); if (ret == DAP_OK) { UartTransport = DAP_UART_TRANSPORT_DAP_COMMAND; } break; case DAP_UART_TRANSPORT_USB_COM_PORT: #if (DAP_UART_USB_COM_PORT != 0) USB_COM_PORT_Activate(0U); UartTransport = DAP_UART_TRANSPORT_NONE; #endif ret = UART_Init(); if (ret == DAP_OK) { UartTransport = DAP_UART_TRANSPORT_DAP_COMMAND; } break; case DAP_UART_TRANSPORT_DAP_COMMAND: ret = DAP_OK; break; } break; default: break; } *response = ret; return ((1U << 16) | 1U); } // Process UART Configure command and prepare response // request: pointer to request data // response: pointer to response data // return: number of bytes in response (lower 16 bits) // number of bytes in request (upper 16 bits) uint32_t UART_Configure (const uint8_t *request, uint8_t *response) { uint8_t control, status; uint32_t baudrate; int32_t result; if (UartTransport != DAP_UART_TRANSPORT_DAP_COMMAND) { status = DAP_UART_CFG_ERROR_DATA_BITS | DAP_UART_CFG_ERROR_PARITY | DAP_UART_CFG_ERROR_STOP_BITS; baudrate = 0U; // baudrate error } else { status = 0U; control = *request; baudrate = (uint32_t)(*(request+1) << 0) | (uint32_t)(*(request+2) << 8) | (uint32_t)(*(request+3) << 16) | (uint32_t)(*(request+4) << 24); result = pUSART->Control(control | ARM_USART_MODE_ASYNCHRONOUS | ARM_USART_FLOW_CONTROL_NONE, baudrate); if (result == ARM_DRIVER_OK) { UartConfigured = 1U; } else { UartConfigured = 0U; switch (result) { case ARM_USART_ERROR_BAUDRATE: status = 0U; baudrate = 0U; break; case ARM_USART_ERROR_DATA_BITS: status = DAP_UART_CFG_ERROR_DATA_BITS; break; case ARM_USART_ERROR_PARITY: status = DAP_UART_CFG_ERROR_PARITY; break; case ARM_USART_ERROR_STOP_BITS: status = DAP_UART_CFG_ERROR_STOP_BITS; break; default: status = DAP_UART_CFG_ERROR_DATA_BITS | DAP_UART_CFG_ERROR_PARITY | DAP_UART_CFG_ERROR_STOP_BITS; baudrate = 0U; break; } } } *response++ = status; *response++ = (uint8_t)(baudrate >> 0); *response++ = (uint8_t)(baudrate >> 8); *response++ = (uint8_t)(baudrate >> 16); *response = (uint8_t)(baudrate >> 24); return ((5U << 16) | 5U); } // Process UART Control command and prepare response // request: pointer to request data // response: pointer to response data // return: number of bytes in response (lower 16 bits) // number of bytes in request (upper 16 bits) uint32_t UART_Control (const uint8_t *request, uint8_t *response) { uint8_t control; uint8_t result; uint8_t ret = DAP_OK; if (UartTransport != DAP_UART_TRANSPORT_DAP_COMMAND) { ret = DAP_ERROR; } else { control = *request; if ((control & DAP_UART_CONTROL_RX_DISABLE) != 0U) { // Receive disable UART_Receive_Disable(); } else if ((control & DAP_UART_CONTROL_RX_ENABLE) != 0U) { // Receive enable if (UartConfigured != 0U) { result = UART_Receive_Enable(); if (result != DAP_OK) { ret = DAP_ERROR; } } else { ret = DAP_ERROR; } } if ((control & DAP_UART_CONTROL_RX_BUF_FLUSH) != 0U) { UART_Receive_Flush(); } if ((control & DAP_UART_CONTROL_TX_DISABLE) != 0U) { // Transmit disable UART_Transmit_Disable(); } else if ((control & DAP_UART_CONTROL_TX_ENABLE) != 0U) { // Transmit enable if (UartConfigured != 0U) { result = UART_Transmit_Enable(); if (result != DAP_OK) { ret = DAP_ERROR; } } else { ret = DAP_ERROR; } } if ((control & DAP_UART_CONTROL_TX_BUF_FLUSH) != 0U) { UART_Transmit_Flush(); } } *response = ret; return ((1U << 16) | 1U); } // Process UART Status command and prepare response // response: pointer to response data // return: number of bytes in response (lower 16 bits) // number of bytes in request (upper 16 bits) uint32_t UART_Status (uint8_t *response) { uint32_t rx_cnt, tx_cnt; uint32_t cnt; uint8_t status; if ((UartTransport != DAP_UART_TRANSPORT_DAP_COMMAND) || (UartConfigured == 0U)) { rx_cnt = 0U; tx_cnt = 0U; status = 0U; } else { rx_cnt = UartRxIndexI - UartRxIndexO; rx_cnt += pUSART->GetRxCount(); if (rx_cnt > (DAP_UART_RX_BUFFER_SIZE - (UART_RX_BLOCK_SIZE*2))) { // Overflow UartErrorRxDataLost = 1U; rx_cnt = (DAP_UART_RX_BUFFER_SIZE - (UART_RX_BLOCK_SIZE*2)); UartRxIndexO = UartRxIndexI - rx_cnt; } tx_cnt = UartTxIndexI - UartTxIndexO; cnt = pUSART->GetTxCount(); if (UartTransmitActive != 0U) { tx_cnt -= cnt; } status = UART_Get_Status(); } *response++ = status; *response++ = (uint8_t)(rx_cnt >> 0); *response++ = (uint8_t)(rx_cnt >> 8); *response++ = (uint8_t)(rx_cnt >> 16); *response++ = (uint8_t)(rx_cnt >> 24); *response++ = (uint8_t)(tx_cnt >> 0); *response++ = (uint8_t)(tx_cnt >> 8); *response++ = (uint8_t)(tx_cnt >> 16); *response = (uint8_t)(tx_cnt >> 24); return ((0U << 16) | 9U); } // Process UART Transfer command and prepare response // request: pointer to request data // response: pointer to response data // return: number of bytes in response (lower 16 bits) // number of bytes in request (upper 16 bits) uint32_t UART_Transfer (const uint8_t *request, uint8_t *response) { uint32_t rx_cnt, tx_cnt; uint32_t rx_num, tx_num; uint8_t *rx_data; const uint8_t *tx_data; uint32_t num; uint32_t index; uint8_t status; if (UartTransport != DAP_UART_TRANSPORT_DAP_COMMAND) { status = 0U; rx_cnt = 0U; tx_cnt = 0U; } else { // RX Data rx_cnt = ((uint32_t)(*(request+0) << 0) | (uint32_t)(*(request+1) << 8)); if (rx_cnt > (DAP_PACKET_SIZE - 6U)) { rx_cnt = (DAP_PACKET_SIZE - 6U); } rx_num = UartRxIndexI - UartRxIndexO; rx_num += pUSART->GetRxCount(); if (rx_num > (DAP_UART_RX_BUFFER_SIZE - (UART_RX_BLOCK_SIZE*2))) { // Overflow UartErrorRxDataLost = 1U; rx_num = (DAP_UART_RX_BUFFER_SIZE - (UART_RX_BLOCK_SIZE*2)); UartRxIndexO = UartRxIndexI - rx_num; } if (rx_cnt > rx_num) { rx_cnt = rx_num; } rx_data = (response+5); index = UartRxIndexO & (DAP_UART_RX_BUFFER_SIZE - 1U); if ((index + rx_cnt) <= DAP_UART_RX_BUFFER_SIZE) { memcpy( rx_data, &UartRxBuf[index], rx_cnt); } else { num = DAP_UART_RX_BUFFER_SIZE - index; memcpy( rx_data, &UartRxBuf[index], num); memcpy(&rx_data[num], &UartRxBuf[0], rx_cnt - num); } UartRxIndexO += rx_cnt; // TX Data tx_cnt = ((uint32_t)(*(request+2) << 0) | (uint32_t)(*(request+3) << 8)); tx_data = (request+4); if (tx_cnt > (DAP_PACKET_SIZE - 5U)) { tx_cnt = (DAP_PACKET_SIZE - 5U); } tx_num = UartTxIndexI - UartTxIndexO; num = pUSART->GetTxCount(); if (UartTransmitActive != 0U) { tx_num -= num; } if (tx_cnt > (DAP_UART_TX_BUFFER_SIZE - tx_num)) { tx_cnt = (DAP_UART_TX_BUFFER_SIZE - tx_num); } index = UartTxIndexI & (DAP_UART_TX_BUFFER_SIZE - 1U); if ((index + tx_cnt) <= DAP_UART_TX_BUFFER_SIZE) { memcpy(&UartTxBuf[index], tx_data, tx_cnt); } else { num = DAP_UART_TX_BUFFER_SIZE - index; memcpy(&UartTxBuf[index], tx_data, num); memcpy(&UartTxBuf[0], &tx_data[num], tx_cnt - num); } UartTxIndexI += tx_cnt; if (UartTransmitActive == 0U) { UART_Transmit(); } status = UART_Get_Status(); } *response++ = status; *response++ = (uint8_t)(tx_cnt >> 0); *response++ = (uint8_t)(tx_cnt >> 8); *response++ = (uint8_t)(rx_cnt >> 0); *response = (uint8_t)(rx_cnt >> 8); return (((4U + tx_cnt) << 16) | (5U + rx_cnt)); } #endif /* DAP_UART */