You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
362 lines
8.9 KiB
362 lines
8.9 KiB
/*
|
|
* This file is part of the Trezor project, https://trezor.io/
|
|
*
|
|
* Copyright (c) SatoshiLabs
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include STM32_HAL_H
|
|
#include TREZOR_BOARD
|
|
|
|
#include "comm.h"
|
|
#include <string.h>
|
|
#include "buffers.h"
|
|
#include "dma.h"
|
|
#include "int_comm_defs.h"
|
|
#include "state.h"
|
|
|
|
#define SPI_QUEUE_SIZE 10
|
|
|
|
static UART_HandleTypeDef urt;
|
|
static uint8_t last_init_byte = 0;
|
|
|
|
static SPI_HandleTypeDef spi = {0};
|
|
static DMA_HandleTypeDef spi_dma = {0};
|
|
|
|
typedef struct {
|
|
uint8_t buffer[BLE_PACKET_SIZE];
|
|
bool used;
|
|
bool ready;
|
|
} spi_buffer_t;
|
|
|
|
BUFFER_SECTION spi_buffer_t spi_queue[SPI_QUEUE_SIZE];
|
|
static int head = 0, tail = 0;
|
|
static bool overrun = false;
|
|
volatile uint16_t overrun_count = 0;
|
|
volatile uint16_t msg_cntr = 0;
|
|
volatile uint16_t first_overrun_at = 0;
|
|
|
|
void ble_comm_init(void) {
|
|
GPIO_InitTypeDef GPIO_InitStructure;
|
|
|
|
__HAL_RCC_USART1_CLK_ENABLE();
|
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
|
|
|
GPIO_InitStructure.Pin = GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;
|
|
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
|
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
|
GPIO_InitStructure.Alternate = GPIO_AF7_USART1;
|
|
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
|
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
|
|
|
|
urt.Init.Mode = UART_MODE_TX_RX;
|
|
urt.Init.BaudRate = 1000000;
|
|
urt.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS;
|
|
urt.Init.OverSampling = UART_OVERSAMPLING_16;
|
|
urt.Init.Parity = UART_PARITY_NONE, urt.Init.StopBits = UART_STOPBITS_1;
|
|
urt.Init.WordLength = UART_WORDLENGTH_8B;
|
|
urt.Instance = USART1;
|
|
|
|
HAL_UART_Init(&urt);
|
|
|
|
__HAL_RCC_DMA2_CLK_ENABLE();
|
|
__HAL_RCC_SPI4_CLK_ENABLE();
|
|
__HAL_RCC_GPIOE_CLK_ENABLE();
|
|
|
|
GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6;
|
|
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
|
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
|
GPIO_InitStructure.Alternate = GPIO_AF5_SPI4;
|
|
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;
|
|
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
|
|
|
|
dma_init(&spi_dma, &dma_SPI_4_RX, DMA_PERIPH_TO_MEMORY, &spi);
|
|
|
|
spi.Instance = SPI4;
|
|
spi.Init.Mode = SPI_MODE_SLAVE;
|
|
spi.Init.Direction = SPI_DIRECTION_2LINES; // rx only?
|
|
spi.Init.DataSize = SPI_DATASIZE_8BIT;
|
|
spi.Init.CLKPolarity = SPI_POLARITY_LOW;
|
|
spi.Init.CLKPhase = SPI_PHASE_1EDGE;
|
|
spi.Init.NSS = SPI_NSS_HARD_INPUT;
|
|
spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
|
|
spi.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
|
spi.Init.TIMode = SPI_TIMODE_DISABLE;
|
|
spi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
|
spi.Init.CRCPolynomial = 0;
|
|
spi.hdmarx = &spi_dma;
|
|
|
|
spi_dma.Parent = &spi;
|
|
|
|
HAL_SPI_Init(&spi);
|
|
|
|
set_initialized(false);
|
|
|
|
HAL_SPI_Receive_DMA(&spi, spi_queue[0].buffer, BLE_PACKET_SIZE);
|
|
spi_queue[0].used = true;
|
|
|
|
tail = 0;
|
|
}
|
|
|
|
void ble_comm_send(uint8_t *data, uint32_t len) {
|
|
HAL_UART_Transmit(&urt, data, len, 30);
|
|
}
|
|
|
|
uint32_t ble_comm_receive(uint8_t *data, uint32_t len) {
|
|
if (urt.Instance->SR & USART_SR_RXNE) {
|
|
HAL_StatusTypeDef result = HAL_UART_Receive(&urt, data, len, 30);
|
|
|
|
if (result == HAL_OK) {
|
|
return len;
|
|
} else {
|
|
if (urt.RxXferCount == len) {
|
|
return 0;
|
|
}
|
|
return len - urt.RxXferCount - 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void ble_int_comm_send(uint8_t *data, uint32_t len, uint8_t message_type) {
|
|
uint16_t msg_len = len + OVERHEAD_SIZE;
|
|
uint8_t len_hi = msg_len >> 8;
|
|
uint8_t len_lo = msg_len & 0xFF;
|
|
uint8_t eom = EOM;
|
|
|
|
HAL_UART_Transmit(&urt, &message_type, 1, 1);
|
|
HAL_UART_Transmit(&urt, &len_hi, 1, 1);
|
|
HAL_UART_Transmit(&urt, &len_lo, 1, 1);
|
|
|
|
HAL_UART_Transmit(&urt, data, len, 10);
|
|
HAL_UART_Transmit(&urt, &eom, 1, 1);
|
|
}
|
|
|
|
void process_poll(uint8_t *data, uint32_t len) {
|
|
uint8_t cmd = data[0];
|
|
|
|
switch (cmd) {
|
|
case INTERNAL_EVENT_INITIALIZED: {
|
|
set_connected(false);
|
|
set_initialized(true);
|
|
break;
|
|
}
|
|
case INTERNAL_EVENT_CONNECTED: {
|
|
set_connected(true);
|
|
set_initialized(true);
|
|
break;
|
|
}
|
|
case INTERNAL_EVENT_DISCONNECTED: {
|
|
set_connected(false);
|
|
set_initialized(true);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void flush_line(void) {
|
|
while (urt.Instance->SR & USART_SR_RXNE) {
|
|
(void)urt.Instance->DR;
|
|
}
|
|
}
|
|
|
|
uint32_t ble_int_comm_poll(void) {
|
|
uint8_t data[64] = {0};
|
|
if (urt.Instance->SR & USART_SR_RXNE) {
|
|
uint8_t init_byte = 0;
|
|
|
|
if (last_init_byte != 0) {
|
|
if (last_init_byte == INTERNAL_EVENT) {
|
|
init_byte = last_init_byte;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else {
|
|
HAL_UART_Receive(&urt, &init_byte, 1, 1);
|
|
}
|
|
|
|
if (init_byte == INTERNAL_EVENT) {
|
|
uint8_t len_hi = 0;
|
|
uint8_t len_lo = 0;
|
|
HAL_UART_Receive(&urt, &len_hi, 1, 1);
|
|
HAL_UART_Receive(&urt, &len_lo, 1, 1);
|
|
|
|
uint16_t act_len = (len_hi << 8) | len_lo;
|
|
|
|
if (act_len > sizeof(data) + OVERHEAD_SIZE) {
|
|
last_init_byte = 0;
|
|
flush_line();
|
|
return 0;
|
|
}
|
|
|
|
HAL_StatusTypeDef result =
|
|
HAL_UART_Receive(&urt, data, act_len - OVERHEAD_SIZE, 5);
|
|
|
|
if (result != HAL_OK) {
|
|
last_init_byte = 0;
|
|
flush_line();
|
|
return 0;
|
|
}
|
|
|
|
uint8_t eom = 0;
|
|
HAL_UART_Receive(&urt, &eom, 1, 1);
|
|
|
|
if (eom == EOM) {
|
|
process_poll(data, act_len - OVERHEAD_SIZE);
|
|
last_init_byte = 0;
|
|
return act_len - OVERHEAD_SIZE;
|
|
}
|
|
return 0;
|
|
|
|
} else if (init_byte == INTERNAL_MESSAGE) {
|
|
last_init_byte = init_byte;
|
|
} else {
|
|
flush_line();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (!ble_initialized()) {
|
|
uint8_t cmd = INTERNAL_CMD_SEND_STATE;
|
|
ble_int_comm_send(&cmd, sizeof(cmd), INTERNAL_EVENT);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t ble_int_comm_receive(uint8_t *data, uint32_t len) {
|
|
if (urt.Instance->SR & USART_SR_RXNE) {
|
|
uint8_t init_byte = 0;
|
|
|
|
if (last_init_byte != 0) {
|
|
if (last_init_byte == INTERNAL_MESSAGE) {
|
|
init_byte = last_init_byte;
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
} else {
|
|
HAL_UART_Receive(&urt, &init_byte, 1, 1);
|
|
}
|
|
|
|
if (init_byte == INTERNAL_MESSAGE) {
|
|
uint8_t len_hi = 0;
|
|
uint8_t len_lo = 0;
|
|
HAL_UART_Receive(&urt, &len_hi, 1, 1);
|
|
HAL_UART_Receive(&urt, &len_lo, 1, 1);
|
|
|
|
uint16_t act_len = (len_hi << 8) | len_lo;
|
|
|
|
if (act_len > len + OVERHEAD_SIZE) {
|
|
last_init_byte = 0;
|
|
flush_line();
|
|
return 0;
|
|
}
|
|
|
|
HAL_StatusTypeDef result =
|
|
HAL_UART_Receive(&urt, data, act_len - OVERHEAD_SIZE, 5);
|
|
|
|
if (result != HAL_OK) {
|
|
last_init_byte = 0;
|
|
flush_line();
|
|
return 0;
|
|
}
|
|
|
|
uint8_t eom = 0;
|
|
HAL_UART_Receive(&urt, &eom, 1, 1);
|
|
|
|
if (eom == EOM) {
|
|
last_init_byte = 0;
|
|
return act_len - OVERHEAD_SIZE;
|
|
}
|
|
return 0;
|
|
|
|
} else if (init_byte == INTERNAL_EVENT) {
|
|
last_init_byte = init_byte;
|
|
} else {
|
|
flush_line();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool start_spi_dma(void) {
|
|
int tmp_tail = (tail + 1) % SPI_QUEUE_SIZE;
|
|
if (spi_queue[tmp_tail].used || spi_queue[tmp_tail].ready) {
|
|
overrun = true;
|
|
overrun_count++;
|
|
if (first_overrun_at == 0) {
|
|
first_overrun_at = msg_cntr;
|
|
}
|
|
return false;
|
|
}
|
|
spi_queue[tmp_tail].used = true;
|
|
HAL_SPI_Receive_DMA(&spi, spi_queue[tmp_tail].buffer, BLE_PACKET_SIZE);
|
|
|
|
tail = tmp_tail;
|
|
return true;
|
|
}
|
|
|
|
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {
|
|
spi_queue[tail].ready = true;
|
|
msg_cntr++;
|
|
start_spi_dma();
|
|
}
|
|
|
|
#include "supervise.h"
|
|
|
|
uint32_t ble_ext_comm_receive(uint8_t *data, uint32_t len) {
|
|
svc_disableIRQ(DMA2_Stream0_IRQn);
|
|
if (spi_queue[head].ready) {
|
|
uint8_t *buffer = (uint8_t *)spi_queue[head].buffer;
|
|
memcpy(data, buffer, len > BLE_PACKET_SIZE ? BLE_PACKET_SIZE : len);
|
|
|
|
spi_queue[head].used = false;
|
|
spi_queue[head].ready = false;
|
|
head = (head + 1) % SPI_QUEUE_SIZE;
|
|
|
|
if (overrun && start_spi_dma()) {
|
|
// overrun was before, need to restart the DMA
|
|
overrun = false;
|
|
}
|
|
|
|
if (data[0] != '?') {
|
|
// bad packet, restart the DMA
|
|
HAL_SPI_Abort(&spi);
|
|
|
|
memset(spi_queue, 0, sizeof(spi_queue));
|
|
head = 0;
|
|
tail = 0;
|
|
overrun = false;
|
|
HAL_SPI_Receive_DMA(&spi, spi_queue[0].buffer, BLE_PACKET_SIZE);
|
|
spi_queue[0].used = true;
|
|
// todo return error?
|
|
svc_enableIRQ(DMA2_Stream0_IRQn);
|
|
|
|
return 0;
|
|
}
|
|
|
|
svc_enableIRQ(DMA2_Stream0_IRQn);
|
|
return len > BLE_PACKET_SIZE ? BLE_PACKET_SIZE : len;
|
|
}
|
|
|
|
svc_enableIRQ(DMA2_Stream0_IRQn);
|
|
return 0;
|
|
}
|