2016-10-23 17:42:55 +02:00
/** library to send data using ESP8266 WiFi SoC (code)
2020-06-06 14:35:55 +02:00
* @ file
2016-10-23 17:42:55 +02:00
* @ author King Kévin < kingkevin @ cuvoodoo . info >
2020-06-06 14:35:55 +02:00
* @ copyright SPDX - License - Identifier : GPL - 3.0 - or - later
2022-07-14 18:54:06 +02:00
* @ date 2016 - 2022
2016-10-23 17:42:55 +02:00
* @ note peripherals used : USART @ ref radio_esp8266_usart
*/
/* standard libraries */
# include <stdint.h> // standard integer types
# include <stdlib.h> // general utilities
# include <string.h> // string and memory utilities
# include <stdio.h> // string utilities
/* STM32 (including CM3) libraries */
# include <libopencm3/stm32/rcc.h> // real-time control clock library
# include <libopencm3/stm32/gpio.h> // general purpose input output library
# include <libopencm3/stm32/usart.h> // universal synchronous asynchronous receiver transmitter library
# include <libopencm3/cm3/nvic.h> // interrupt handler
# include <libopencmsis/core_cm3.h> // Cortex M3 utilities
# include "radio_esp8266.h" // radio header and definitions
# include "global.h" // common methods
/** @defgroup radio_esp8266_usart USART peripheral used for communication with radio
* @ {
*/
2022-07-14 18:54:06 +02:00
# define RADIO_ESP8266_USART 1 /**< USART peripheral */
# define RADIO_ESP8266_TX PA9 /**< pin used for USART TX */
# define RADIO_ESP8266_RX PA10 /**< pin used for USART RX */
# define RADIO_ESP8266_AF GPIO_AF7 /**< alternate function for UART pins */
2016-10-23 17:42:55 +02:00
/** @} */
/* input and output buffers and used memory */
2022-07-14 18:56:56 +02:00
static uint8_t rx_buffer [ 24 + 530 ] = { 0 } ; /**< buffer for received data */
2016-10-23 17:42:55 +02:00
static volatile uint16_t rx_used = 0 ; /**< number of byte in receive buffer */
static uint8_t tx_buffer [ 256 ] = { 0 } ; /**< buffer for data to transmit */
static volatile uint16_t tx_used = 0 ; /**< number of bytes used in transmit buffer */
volatile bool radio_esp8266_activity = false ;
volatile bool radio_esp8266_success = false ;
2022-07-14 18:56:56 +02:00
uint8_t radio_esp8266_received [ 512 + 18 ] ;
uint16_t radio_esp8266_received_len = 0 ;
2016-10-23 17:42:55 +02:00
/** transmit data to radio
* @ param [ in ] data data to transmit
* @ param [ in ] length length of data to transmit
*/
static void radio_esp8266_transmit ( uint8_t * data , uint8_t length ) {
while ( tx_used | | ! usart_get_flag ( USART ( RADIO_ESP8266_USART ) , USART_SR_TXE ) ) { // wait until ongoing transmission completed
usart_enable_tx_interrupt ( USART ( RADIO_ESP8266_USART ) ) ; // enable transmit interrupt
__WFI ( ) ; // sleep until something happened
}
usart_disable_tx_interrupt ( USART ( RADIO_ESP8266_USART ) ) ; // ensure transmit interrupt is disable to prevent index corruption (the ISR should already have done it)
2022-08-11 14:03:15 +02:00
rx_used = 0 ; // reset receive buffer
2016-10-23 17:42:55 +02:00
radio_esp8266_activity = false ; // reset status because of new activity
2022-07-14 18:56:04 +02:00
for ( tx_used = 0 ; tx_used < length & & tx_used < LENGTH ( tx_buffer ) ; tx_used + + ) { // copy data
tx_buffer [ tx_used ] = data [ length - 1 - tx_used ] ; // put character in buffer (in reverse order)
2016-10-23 17:42:55 +02:00
}
if ( tx_used ) {
usart_enable_tx_interrupt ( USART ( RADIO_ESP8266_USART ) ) ; // enable interrupt to send bytes
}
}
2022-08-11 14:05:22 +02:00
/** transmit string to radio
* @ param [ in ] data data to transmit
* @ param [ in ] length length of data to transmit
*/
static void radio_esp8266_transmits ( char * str ) {
if ( NULL = = str ) {
return ;
}
const uint16_t length = strlen ( str ) ;
radio_esp8266_transmit ( ( uint8_t * ) str , length ) ;
}
/** transmit string to radio
* @ param [ in ] data data to transmit
* @ param [ in ] length length of data to transmit
*/
static void radio_esp8266_transmit_at ( char * at ) {
if ( NULL = = at ) {
return ;
}
radio_esp8266_transmits ( " AT " ) ;
radio_esp8266_transmits ( at ) ;
radio_esp8266_transmits ( " \r \n " ) ;
}
2016-10-23 17:42:55 +02:00
void radio_esp8266_setup ( void )
{
2022-07-14 18:54:06 +02:00
// configure pins
rcc_periph_clock_enable ( GPIO_RCC ( RADIO_ESP8266_TX ) ) ; // enable clock for USART TX pin port peripheral
gpio_mode_setup ( GPIO_PORT ( RADIO_ESP8266_TX ) , GPIO_MODE_AF , GPIO_PUPD_NONE , GPIO_PIN ( RADIO_ESP8266_TX ) ) ; // set TX pin to alternate function
gpio_set_output_options ( GPIO_PORT ( RADIO_ESP8266_TX ) , GPIO_OTYPE_PP , GPIO_OSPEED_25MHZ , GPIO_PIN ( RADIO_ESP8266_TX ) ) ; // set TX pin output as push-pull
gpio_set_af ( GPIO_PORT ( RADIO_ESP8266_TX ) , RADIO_ESP8266_AF , GPIO_PIN ( RADIO_ESP8266_TX ) ) ; // set alternate function to USART
rcc_periph_clock_enable ( GPIO_RCC ( RADIO_ESP8266_RX ) ) ; // enable clock for USART RX pin port peripheral
gpio_mode_setup ( GPIO_PORT ( RADIO_ESP8266_RX ) , GPIO_MODE_AF , GPIO_PUPD_PULLUP , GPIO_PIN ( RADIO_ESP8266_RX ) ) ; // set GPIO to alternate function, with pull up to avoid noise in case it is not connected
gpio_set_af ( GPIO_PORT ( RADIO_ESP8266_RX ) , RADIO_ESP8266_AF , GPIO_PIN ( RADIO_ESP8266_RX ) ) ; // set alternate function to USART
2016-10-23 17:42:55 +02:00
2022-07-14 18:54:06 +02:00
// configure USART for ESP8266 AT firmware
rcc_periph_clock_enable ( RCC_USART ( RADIO_ESP8266_USART ) ) ; // enable clock for USART peripheral
rcc_periph_reset_pulse ( RST_USART ( RADIO_ESP8266_USART ) ) ; // reset peripheral
2016-10-23 17:42:55 +02:00
usart_set_baudrate ( USART ( RADIO_ESP8266_USART ) , 115200 ) ; // AT firmware 0.51 (SDK 1.5.0) uses 115200 bps
usart_set_databits ( USART ( RADIO_ESP8266_USART ) , 8 ) ;
usart_set_stopbits ( USART ( RADIO_ESP8266_USART ) , USART_STOPBITS_1 ) ;
usart_set_mode ( USART ( RADIO_ESP8266_USART ) , USART_MODE_TX_RX ) ;
usart_set_parity ( USART ( RADIO_ESP8266_USART ) , USART_PARITY_NONE ) ;
usart_set_flow_control ( USART ( RADIO_ESP8266_USART ) , USART_FLOWCONTROL_NONE ) ;
2022-07-14 18:54:06 +02:00
nvic_enable_irq ( USART_IRQ ( RADIO_ESP8266_USART ) ) ; // enable the UART interrupt
2016-10-23 17:42:55 +02:00
usart_enable_rx_interrupt ( USART ( RADIO_ESP8266_USART ) ) ; // enable receive interrupt
2022-07-14 18:54:06 +02:00
usart_enable ( USART ( RADIO_ESP8266_USART ) ) ; // enable UART
2016-10-23 17:42:55 +02:00
/* reset buffer states */
rx_used = 0 ;
tx_used = 0 ;
radio_esp8266_activity = false ;
radio_esp8266_success = false ;
2022-08-11 14:05:22 +02:00
radio_esp8266_transmit_at ( " " ) ; // verify if module is present
2016-10-23 17:42:55 +02:00
while ( ! radio_esp8266_activity | | ! radio_esp8266_success ) { // wait for response
__WFI ( ) ; // sleep until something happened
}
2022-08-11 14:06:22 +02:00
radio_esp8266_transmit_at ( " E0 " ) ; // disable echoing
while ( ! radio_esp8266_activity | | ! radio_esp8266_success ) { // wait for response
__WFI ( ) ; // sleep until something happened
}
}
void radio_esp8266_reset ( void )
{
radio_esp8266_transmit_at ( " +RST " ) ; // reset module
while ( ! radio_esp8266_activity | | ! radio_esp8266_success ) { // wait for response
__WFI ( ) ; // sleep until something happened
}
radio_esp8266_transmit_at ( " E0 " ) ; // disable echoing
2016-10-23 17:42:55 +02:00
while ( ! radio_esp8266_activity | | ! radio_esp8266_success ) { // wait for response
__WFI ( ) ; // sleep until something happened
}
2022-07-14 18:56:04 +02:00
while ( rx_used < 13 | | memcmp ( ( char * ) & rx_buffer [ rx_used - 13 ] , " WIFI GOT IP \r \n " , 13 ) ! = 0 ) { // wait to have IP
2016-10-23 17:42:55 +02:00
__WFI ( ) ; // sleep until something happened
}
2022-07-14 18:56:04 +02:00
radio_esp8266_transmit ( ( uint8_t * ) " ATE0 \r \n " , 6 ) ; // disable echoing
2016-10-23 17:42:55 +02:00
while ( ! radio_esp8266_activity | | ! radio_esp8266_success ) { // wait for response
__WFI ( ) ; // sleep until something happened
}
}
void radio_esp8266_tcp_open ( char * host , uint16_t port )
{
char command [ 256 ] = { 0 } ; // string to create command
int length = snprintf ( command , LENGTH ( command ) , " AT+CIPSTART= \" TCP \" , \" %s \" ,%u \r \n " , host , port ) ; // create AT command to establish a TCP connection
2022-07-14 18:56:04 +02:00
if ( length > 0 ) {
2016-10-23 17:42:55 +02:00
radio_esp8266_transmit ( ( uint8_t * ) command , length ) ;
}
}
2022-07-14 18:56:36 +02:00
bool radio_esp8266_listen ( bool udp , uint16_t port )
{
char command [ 256 ] = { 0 } ; // string to create command
int length = snprintf ( command , LENGTH ( command ) , " AT+CIPSTART= \" %s \" , \" 0.0.0.0 \" ,0,%u \r \n " , udp ? " UDP " : " TCP " , port ) ; // create AT command to establish a listening connection
if ( ! length ) {
return false ;
}
radio_esp8266_transmit ( ( uint8_t * ) command , length ) ;
while ( ! radio_esp8266_activity | | ! radio_esp8266_success ) { // wait for response
__WFI ( ) ; // sleep until something happened
}
if ( ! radio_esp8266_success ) { // send AT command did not succeed
return false ;
}
return true ;
}
2016-10-23 17:42:55 +02:00
void radio_esp8266_send ( uint8_t * data , uint8_t length )
{
2022-07-14 18:56:04 +02:00
char command [ 16 + 1 ] = { 0 } ; // string to create command
2016-10-23 17:42:55 +02:00
int command_length = snprintf ( command , LENGTH ( command ) , " AT+CIPSEND=%u \r \n " , length ) ; // create AT command to send data
2022-07-14 18:56:04 +02:00
if ( command_length > 0 ) {
2016-10-23 17:42:55 +02:00
radio_esp8266_transmit ( ( uint8_t * ) command , command_length ) ; // transmit AT command
while ( ! radio_esp8266_activity | | ! radio_esp8266_success ) { // wait for response
__WFI ( ) ; // sleep until something happened
}
if ( ! radio_esp8266_success ) { // send AT command did not succeed
return ; // don't transmit data
}
radio_esp8266_transmit ( data , length ) ; // transmit data
}
}
void radio_esp8266_close ( void )
{
2022-08-11 14:05:22 +02:00
radio_esp8266_transmit_at ( " +CIPCLOSE " ) ; // send AT command to close established connection
2016-10-23 17:42:55 +02:00
}
/** USART interrupt service routine called when data has been transmitted or received */
void USART_ISR ( RADIO_ESP8266_USART ) ( void )
{
2022-07-14 18:56:04 +02:00
if ( usart_get_flag ( USART ( RADIO_ESP8266_USART ) , USART_SR_TXE ) ) { // data has been transmitted
2016-10-23 17:42:55 +02:00
if ( tx_used ) { // there is still data in the buffer to transmit
2022-07-14 18:56:04 +02:00
usart_send ( USART ( RADIO_ESP8266_USART ) , tx_buffer [ tx_used - 1 ] ) ; // put data in transmit register
2016-10-23 17:42:55 +02:00
tx_used - - ; // update used size
} else { // no data in the buffer to transmit
usart_disable_tx_interrupt ( USART ( RADIO_ESP8266_USART ) ) ; // disable transmit interrupt
}
}
2022-07-14 18:56:04 +02:00
if ( usart_get_flag ( USART ( RADIO_ESP8266_USART ) , USART_SR_RXNE ) ) { // data has been received
while ( rx_used > = LENGTH ( rx_buffer ) ) { // if buffer is full
memmove ( rx_buffer , & rx_buffer [ 1 ] , LENGTH ( rx_buffer ) - 1 ) ; // drop old data to make space (ring buffer are more efficient but harder to handle)
2016-10-23 17:42:55 +02:00
rx_used - - ; // update used buffer information
}
rx_buffer [ rx_used + + ] = usart_recv ( USART ( RADIO_ESP8266_USART ) ) ; // put character in buffer
2022-08-11 14:03:15 +02:00
/*
if ( ' \n ' = = rx_buffer [ rx_used - 1 ] ) {
rx_buffer [ rx_used ] = ' \0 ' ;
printf ( ( char * ) rx_buffer ) ;
printf ( " \n " ) ;
}
*/
2016-10-23 17:42:55 +02:00
// if the used send a packet with these strings during the commands detection the AT command response will break (AT commands are hard to handle perfectly)
2022-07-14 18:56:04 +02:00
if ( rx_used > = 4 & & memcmp ( ( char * ) & rx_buffer [ rx_used - 4 ] , " OK \r \n " , 4 ) = = 0 ) { // OK received
2016-10-23 17:42:55 +02:00
radio_esp8266_activity = true ; // response received
radio_esp8266_success = true ; // command succeeded
2022-07-14 18:56:04 +02:00
} else if ( rx_used > = 7 & & memcmp ( ( char * ) & rx_buffer [ rx_used - 7 ] , " ERROR \r \n " , 7 ) = = 0 ) { // ERROR received
2016-10-23 17:42:55 +02:00
radio_esp8266_activity = true ; // response received
radio_esp8266_success = false ; // command failed
2022-07-14 18:56:56 +02:00
} else if ( rx_used > = 7 & & memcmp ( ( char * ) & rx_buffer [ 0 ] , " \r \n +IPD, " , 7 ) = = 0 ) { // IP data being received
// find if we received the length
int32_t data_length = 0 ;
uint32_t data_start = 0 ;
for ( uint16_t i = 7 ; i < rx_used ; i + + ) {
if ( ' : ' = = rx_buffer [ i ] ) {
data_start = i + 1 ;
data_length = atoi ( ( char * ) & rx_buffer [ 7 ] ) ;
break ;
}
}
if ( data_length > 0 & & rx_used > = data_start + data_length ) {
if ( ( uint32_t ) data_length < = LENGTH ( radio_esp8266_received ) ) {
memcpy ( radio_esp8266_received , & rx_buffer [ data_start ] , data_length ) ;
radio_esp8266_received_len = data_length ;
}
rx_used = 0 ; // reset buffer
}
2016-10-23 17:42:55 +02:00
}
}
}