bldc/applications/app_uartcomm.c

254 lines
8.7 KiB
C

/*
Copyright 2016 - 2019 Benjamin Vedder benjamin@vedder.se
This file is part of the VESC firmware.
The VESC firmware 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.
The VESC firmware 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/>.
*/
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "app.h"
#include "ch.h"
#include "hal.h"
#include "hw.h"
#include "packet.h"
#include "commands.h"
// Settings
// By default 7/8 pin uart is index 0, builtin BLE is index 1, and third uart is index 2
#define BAUDRATE 115200
#ifndef UART_NUMBER
#ifdef HW_UART_3_DEV
#define UART_NUMBER 3
#else
#ifdef HW_UART_P_DEV
#define UART_NUMBER 2
#else
#define UART_NUMBER 1
#endif
#endif
#endif
// Threads
static THD_FUNCTION(packet_process_thread, arg);
static THD_WORKING_AREA(packet_process_thread_wa, 2048);
// Variables
static volatile bool thread_is_running = false;
static volatile bool uart_is_running[UART_NUMBER] = {false};
static mutex_t send_mutex[UART_NUMBER];
static bool send_mutex_init_done[UART_NUMBER] = {false};
static SerialConfig uart_cfg[UART_NUMBER] = {{
BAUDRATE,
0,
USART_CR2_LINEN,
0
}};
// Different for Rx and Tx because it is possible for hardware to use different UART driver
// for Rx and Tx, feature not a bug XD
static SerialDriver *serialPortDriverTx[UART_NUMBER];
static SerialDriver *serialPortDriverRx[UART_NUMBER];
static stm32_gpio_t * TxGpioPort[UART_NUMBER];
static stm32_gpio_t * RxGpioPort[UART_NUMBER];
static uint8_t TxGpioPin[UART_NUMBER], RxGpioPin[UART_NUMBER], gpioAF[UART_NUMBER];
static PACKET_STATE_t packet_state[UART_NUMBER];
static bool pins_enabled[UART_NUMBER];
// Private functions
static void process_packet(unsigned char *data, unsigned int len, unsigned int port_number);
static void write_packet(unsigned char *data, unsigned int len, unsigned int port_number);
static void process_packet_1(unsigned char *data, unsigned int len) {process_packet(data,len,UART_PORT_COMM_HEADER);}
static void write_packet_1(unsigned char *data, unsigned int len) {write_packet(data,len,UART_PORT_COMM_HEADER);}
static void send_packet_1(unsigned char *data, unsigned int len) {app_uartcomm_send_packet(data,len,UART_PORT_COMM_HEADER);}
static void process_packet_2(unsigned char *data, unsigned int len) {process_packet(data,len,UART_PORT_BUILTIN);}
static void write_packet_2(unsigned char *data, unsigned int len) {write_packet(data,len,UART_PORT_BUILTIN);}
static void send_packet_2(unsigned char *data, unsigned int len) {app_uartcomm_send_packet(data,len,UART_PORT_BUILTIN);}
static void process_packet_3(unsigned char *data, unsigned int len) {process_packet(data,len,UART_PORT_EXTRA_HEADER);}
static void write_packet_3(unsigned char *data, unsigned int len) {write_packet(data,len,UART_PORT_EXTRA_HEADER);}
static void send_packet_3(unsigned char *data, unsigned int len) {app_uartcomm_send_packet(data,len,UART_PORT_EXTRA_HEADER);}
typedef void (*data_func) (unsigned char *data, unsigned int len);
static data_func write_functions[3] = {write_packet_1, write_packet_2, write_packet_3};
static data_func process_functions[3] = {process_packet_1, process_packet_2, process_packet_3};
static data_func send_functions[3] = {send_packet_1, send_packet_2, send_packet_3};
static void write_packet(unsigned char *data, unsigned int len, unsigned int port_number) {
if (port_number >= UART_NUMBER) {
return;
}
if (uart_is_running[port_number]) {
sdWrite(serialPortDriverTx[port_number], data, len);
}
}
static void process_packet(unsigned char *data, unsigned int len, unsigned int port_number) {
if (port_number >= UART_NUMBER) {
return;
}
commands_process_packet(data, len, send_functions[port_number]);
}
void app_uartcomm_initialize(void) {
serialPortDriverTx[0] = &HW_UART_DEV;
serialPortDriverRx[0] = &HW_UART_DEV;
uart_cfg[0].speed = BAUDRATE;
RxGpioPort[0] = HW_UART_RX_PORT; RxGpioPin[0] = HW_UART_RX_PIN;
TxGpioPort[0] = HW_UART_TX_PORT; TxGpioPin[0] = HW_UART_TX_PIN;
gpioAF[0] = HW_UART_GPIO_AF;
#ifdef HW_UART_P_DEV
#ifdef HW_UART_P_DEV_TX
serialPortDriverTx[1] = &HW_UART_P_DEV_TX;
#else
serialPortDriverTx[1] = &HW_UART_P_DEV;
#endif
serialPortDriverRx[1] = &HW_UART_P_DEV;
uart_cfg[1].speed = HW_UART_P_BAUD;
RxGpioPort[1] = HW_UART_P_RX_PORT; RxGpioPin[1] = HW_UART_P_RX_PIN;
TxGpioPort[1] = HW_UART_P_TX_PORT; TxGpioPin[1] = HW_UART_P_TX_PIN;
gpioAF[1] = HW_UART_P_GPIO_AF;
#endif
#ifdef HW_UART_3_DEV
serialPortDriverTx[2] = &HW_UART_3_DEV;
serialPortDriverRx[2] = &HW_UART_3_DEV;
uart_cfg[2].speed = HW_UART_3_BAUD;
RxGpioPort[2] = HW_UART_3_RX_PORT; RxGpioPin[2] = HW_UART_3_RX_PIN;
TxGpioPort[2] = HW_UART_3_TX_PORT; TxGpioPin[2] = HW_UART_3_TX_PIN;
gpioAF[2] = HW_UART_3_GPIO_AF;
#endif
}
void app_uartcomm_start(UART_PORT port_number) {
if(port_number >= UART_NUMBER){
return;
}
packet_init(write_functions[port_number], process_functions[port_number], &packet_state[port_number]);
if (!thread_is_running) {
chThdCreateStatic(packet_process_thread_wa, sizeof(packet_process_thread_wa),
NORMALPRIO, packet_process_thread, NULL);
thread_is_running = true;
}
sdStart(serialPortDriverRx[port_number], &uart_cfg[port_number]);
sdStart(serialPortDriverTx[port_number], &uart_cfg[port_number]);
uart_is_running[port_number] = true;
palSetPadMode(TxGpioPort[port_number], TxGpioPin[port_number], PAL_MODE_ALTERNATE(gpioAF[port_number]) |
PAL_STM32_OSPEED_HIGHEST | PAL_STM32_PUDR_PULLUP);
palSetPadMode(RxGpioPort[port_number], RxGpioPin[port_number], PAL_MODE_ALTERNATE(gpioAF[port_number]) |
PAL_STM32_OSPEED_HIGHEST | PAL_STM32_PUDR_PULLUP);
pins_enabled[port_number] = true;
}
void app_uartcomm_stop(UART_PORT port_number) {
if(port_number >= UART_NUMBER) {
return;
}
if (uart_is_running[port_number]) {
sdStop(serialPortDriverRx[port_number]);
sdStop(serialPortDriverTx[port_number]);
palSetPadMode(TxGpioPort[port_number], TxGpioPin[port_number], PAL_MODE_INPUT_PULLUP);
palSetPadMode(RxGpioPort[port_number], RxGpioPin[port_number], PAL_MODE_INPUT_PULLUP);
uart_is_running[port_number] = false;
}
// Notice that the processing thread is kept running in case this call is made from it.
}
void app_uartcomm_send_packet(unsigned char *data, unsigned int len, UART_PORT port_number) {
if (port_number >= UART_NUMBER) {
return;
}
if (!send_mutex_init_done[port_number]) {
chMtxObjectInit(&send_mutex[port_number]);
send_mutex_init_done[port_number] = true;
}
chMtxLock(&send_mutex[port_number]);
packet_send_packet(data, len, &packet_state[port_number]);
chMtxUnlock(&send_mutex[port_number]);
}
void app_uartcomm_configure(uint32_t baudrate, bool enabled, UART_PORT port_number) {
if (port_number >= UART_NUMBER) {
return;
}
if (baudrate > 0) {
uart_cfg[port_number].speed = baudrate;
}
if (thread_is_running && uart_is_running[port_number]) {
sdStart(serialPortDriverRx[port_number], &uart_cfg[port_number]);
if (enabled && !pins_enabled[port_number]) {
palSetPadMode(TxGpioPort[port_number], TxGpioPin[port_number], PAL_MODE_ALTERNATE(gpioAF[port_number]) |
PAL_STM32_OSPEED_HIGHEST |
PAL_STM32_PUDR_PULLUP);
palSetPadMode(RxGpioPort[port_number], RxGpioPin[port_number], PAL_MODE_ALTERNATE(gpioAF[port_number]) |
PAL_STM32_OSPEED_HIGHEST |
PAL_STM32_PUDR_PULLUP);
pins_enabled[port_number] = true;
} else if (!enabled && pins_enabled[port_number]) {
palSetPadMode(TxGpioPort[port_number], TxGpioPin[port_number], PAL_MODE_INPUT);
palSetPadMode(RxGpioPort[port_number], RxGpioPin[port_number], PAL_MODE_INPUT);
pins_enabled[port_number] = false;
}
}
}
static THD_FUNCTION(packet_process_thread, arg) {
(void)arg;
chRegSetThreadName("uartcomm proc");
event_listener_t el[UART_NUMBER];
for(int port_number = 0; port_number < UART_NUMBER; port_number++) {
chEvtRegisterMaskWithFlags(&(*serialPortDriverRx[port_number]).event, &el[port_number], EVENT_MASK(0), CHN_INPUT_AVAILABLE);
}
for(;;) {
chEvtWaitAnyTimeout(ALL_EVENTS, ST2MS(10));
bool rx = true;
while (rx) {
rx = false;
for(int port_number = 0; port_number < UART_NUMBER; port_number++) {
if (uart_is_running[port_number]) {
msg_t res = sdGetTimeout(serialPortDriverRx[port_number], TIME_IMMEDIATE);
if (res != MSG_TIMEOUT) {
packet_process_byte(res, &packet_state[port_number]);
rx = true;
}
}
}
}
}
}
#pragma GCC pop_options