2016-10-03 17:39:15 +02:00
/* 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/>.
*
*/
/** library to send data using ESP8266 WiFi SoC (code)
* @ file radio_esp8266 . c
* @ author King Kévin < kingkevin @ cuvoodoo . info >
* @ date 2016
* @ 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
2016-10-04 11:15:55 +02:00
# include <stdio.h> // string utilities
2016-10-03 17:39:15 +02:00
/* 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
* @ {
*/
# define RADIO_ESP8266_USART 2 /**< USART peripheral */
/** @} */
/* input and output buffers and used memory */
static uint8_t rx_buffer [ 24 ] = { 0 } ; /**< buffer for received data (we only expect AT responses) */
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 ;
2016-10-04 11:15: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)
radio_esp8266_activity = false ; // reset status because of new activity
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)
}
if ( tx_used ) {
usart_enable_tx_interrupt ( USART ( RADIO_ESP8266_USART ) ) ; // enable interrupt to send bytes
}
}
2016-10-03 17:39:15 +02:00
void radio_esp8266_setup ( void )
{
/* enable USART I/O peripheral */
rcc_periph_clock_enable ( RCC_AFIO ) ; // enable pin alternate function (USART)
rcc_periph_clock_enable ( USART_PORT_RCC ( RADIO_ESP8266_USART ) ) ; // enable clock for USART port peripheral
rcc_periph_clock_enable ( USART_RCC ( RADIO_ESP8266_USART ) ) ; // enable clock for USART peripheral
gpio_set_mode ( USART_PORT ( RADIO_ESP8266_USART ) , GPIO_MODE_OUTPUT_2_MHZ , GPIO_CNF_OUTPUT_ALTFN_PUSHPULL , USART_PIN_TX ( RADIO_ESP8266_USART ) ) ; // setup GPIO pin USART transmit
gpio_set_mode ( USART_PORT ( RADIO_ESP8266_USART ) , GPIO_MODE_INPUT , GPIO_CNF_INPUT_PULL_UPDOWN , USART_PIN_RX ( RADIO_ESP8266_USART ) ) ; // setup GPIO pin USART receive
gpio_set ( USART_PORT ( RADIO_ESP8266_USART ) , USART_PIN_RX ( RADIO_ESP8266_USART ) ) ; // pull up to avoid noise when not connected
/* setup USART parameters for ESP8266 AT firmware */
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 ) ;
nvic_enable_irq ( USART_IRQ ( RADIO_ESP8266_USART ) ) ; // enable the USART interrupt
usart_enable_rx_interrupt ( USART ( RADIO_ESP8266_USART ) ) ; // enable receive interrupt
usart_enable ( USART ( RADIO_ESP8266_USART ) ) ; // enable USART
/* reset buffer states */
rx_used = 0 ;
tx_used = 0 ;
radio_esp8266_activity = false ;
radio_esp8266_success = false ;
2016-10-04 11:15:55 +02:00
radio_esp8266_transmit ( ( uint8_t * ) " AT \r \n " , 4 ) ; // verify if module is present
2016-10-03 17:39:15 +02:00
while ( ! radio_esp8266_activity | | ! radio_esp8266_success ) { // wait for response
__WFI ( ) ; // sleep until something happened
}
2016-10-04 11:15:55 +02:00
radio_esp8266_transmit ( ( uint8_t * ) " AT+RST \r \n " , 8 ) ; // reset module
2016-10-03 17:39:15 +02:00
while ( ! radio_esp8266_activity | | ! radio_esp8266_success ) { // wait for response
__WFI ( ) ; // sleep until something happened
}
2016-10-04 11:15:55 +02:00
while ( rx_used < 13 | | memcmp ( ( char * ) & rx_buffer [ rx_used - 13 ] , " WIFI GOT IP \r \n " , 13 ) ! = 0 ) { // wait to have IP
__WFI ( ) ; // sleep until something happened
}
radio_esp8266_transmit ( ( uint8_t * ) " ATE0 \r \n " , 6 ) ; // disable echoing
2016-10-03 17:39:15 +02:00
while ( ! radio_esp8266_activity | | ! radio_esp8266_success ) { // wait for response
__WFI ( ) ; // sleep until something happened
}
}
2016-10-04 11:15:55 +02:00
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
if ( length > 0 ) {
radio_esp8266_transmit ( ( uint8_t * ) command , length ) ;
2016-10-03 17:39:15 +02:00
}
2016-10-04 11:15:55 +02:00
}
void radio_esp8266_send ( uint8_t * data , uint8_t length )
{
char command [ 16 + 1 ] = { 0 } ; // string to create command
int command_length = snprintf ( command , LENGTH ( command ) , " AT+CIPSEND=%u \r \n " , length ) ; // create AT command to send data
if ( command_length > 0 ) {
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
2016-10-03 17:39:15 +02:00
}
}
2016-10-04 11:15:55 +02:00
void radio_esp8266_close ( void )
{
radio_esp8266_transmit ( ( uint8_t * ) " AT+CIPCLOSE \r \n " , 13 ) ; // send AT command to close established connection
}
2016-10-03 17:39:15 +02:00
/** USART interrupt service routine called when data has been transmitted or received */
void USART_ISR ( RADIO_ESP8266_USART ) ( void )
{
if ( usart_get_interrupt_source ( USART ( RADIO_ESP8266_USART ) , USART_SR_TXE ) ) { // data has been transmitted
if ( tx_used ) { // there is still data in the buffer to transmit
usart_send ( USART ( RADIO_ESP8266_USART ) , tx_buffer [ tx_used - 1 ] ) ; // put data in transmit register
tx_used - - ; // update used size
} else { // no data in the buffer to transmit
usart_disable_tx_interrupt ( USART ( RADIO_ESP8266_USART ) ) ; // disable transmit interrupt
}
}
if ( usart_get_interrupt_source ( 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)
rx_used - - ; // update used buffer information
}
rx_buffer [ rx_used + + ] = usart_recv ( USART ( RADIO_ESP8266_USART ) ) ; // put character in buffer
2016-10-04 11:15: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)
if ( rx_used > = 4 & & memcmp ( ( char * ) & rx_buffer [ rx_used - 4 ] , " OK \r \n " , 4 ) = = 0 ) { // OK received
2016-10-03 17:39:15 +02:00
radio_esp8266_activity = true ; // response received
radio_esp8266_success = true ; // command succeeded
rx_used = 0 ; // reset buffer
2016-10-04 11:15:55 +02:00
} else if ( rx_used > = 7 & & memcmp ( ( char * ) & rx_buffer [ rx_used - 7 ] , " ERROR \r \n " , 7 ) = = 0 ) { // ERROR received
2016-10-03 17:39:15 +02:00
radio_esp8266_activity = true ; // response received
radio_esp8266_success = false ; // command failed
rx_used = 0 ; // reset buffer
}
}
}