// esp8266.c // Driver for ESP8266 module to act as a WiFi client or server // Currently restricted to one incoming or outgoing connection at a time // // Steven Prickett (steven.prickett@gmail.com) // Modified version by Dung Nguyen, Wally Guzman // Modified by Jonathan Valvano, March 28, 2017 // Consolidated by Andreas Gerstlauer, April 6, 2020 // Converted to MSPM0G3507 UART1 by Jonathan Valvano, Jan 19, 2026 // Added MSPM0G3507 UART2 by Jonathan Valvano, Jan 26, 2026 /* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. */ // NOTE: see ESP8266 files in datasheets folder /* Hardware connections Vcc is a separate regulated 3.3V supply with at least 215mA /------------------------------\ | chip 1 8 | | Ant 2 7 | | enna processor 3 6 | | 4 5 | \------------------------------/ Connects MSPM0 UART1 on (PA17/PA18) or UART2 on (PB17/PB18) Reset on PA25 Ok to not access PB19 because of the internal pullup in ESP8266 ESP8266 MSPM0 Motor board version 7 1 URxD PA17 UART1 out of MSPM0, into ESP8266 115200 baud 2 GPIO0 +3.3V for normal operation (ground to flash) 3 GPIO2 PB19 GPIO, high/float on startup, has internal pullup, can be used for I/O 4 GND Gnd GND (70mA) 5 UTxD PA18 UART out of ESP8266, UART1 into MSPM0 115200 baud 6 Ch_PD chip select, 10k resistor to 3.3V 7 Reset PA25 MSPM0 GPIO output, can issue output low to cause hardware reset 8 Vcc regulated 3.3V supply with at least 70mA ESP8266 MSPM0 Motor board version 7.1 1 URxD PB17 UART2 out of MSPM0, into ESP8266 115200 baud 2 GPIO0 +3.3V for normal operation (ground to flash) 3 GPIO2 PB19 GPIO, high/float on startup, has internal pullup, can be used for I/O 4 GND Gnd GND (70mA) 5 UTxD PB18 UART out of ESP8266, UART2 into MSPM0 115200 baud 6 Ch_PD chip select, 10k resistor to 3.3V 7 Reset PA25 MSPM0 GPIO output, can issue output low to cause hardware reset 8 Vcc regulated 3.3V supply with at least 70mA */ #include #include #include #include #include #include #include "../inc/UART.h" #include "../inc/Clock.h" #include "../inc/FIFO.h" #include "../RTOS_Labs_common/esp8266.h" #include "../RTOS_Labs_common/WifiSettings.h" // access point parameters #include "../RTOS_Labs_common/OS.h" #include "../inc/LaunchPad.h" /* =========================================================== ========== CONSTANTS ========== =========================================================== */ #define ESP8266_RST (1<<25) // PA25 //#define ESP8266_UART 1 // Motor board v7, UART1: U1Tx PA17, U1Rx PA18 #define ESP8266_UART 2 // Motor board v7.1, UART2: U2Tx PB17, U2Rx PB18 #if ESP8266_UART==1 #define ESP8266_RX PA18INDEX #define ESP8266_TX PA17INDEX #else #define ESP8266_RX PB18INDEX #define ESP8266_TX PB17INDEX #endif // defined in CriticalSection.s long StartCritical(void); void EndCritical(long); void OS_InitSemaphore(Sema4_t *semaPt, int32_t value); void OS_Signal(Sema4_t *semaPt); void OS_Wait(Sema4_t *semaPt); #define MAXTRY 1 // number of attempts to send command // ESP responses static const char ESP8266_READY_RESPONSE[] = "\r\nready\r\n"; static const char ESP8266_OK_RESPONSE[] = "\r\nOK\r\n"; static const char ESP8266_ERROR_RESPONSE[] = "\r\nERROR\r\n"; static const char ESP8266_FAIL_RESPONSE[] = "\r\nFAIL\r\n"; static const char ESP8266_SENDOK_RESPONSE[] = "\r\nSEND OK\r\n"; /* ============================================================= ========== GLOBAL VARIABLES ========== ============================================================= */ // Globals for UART driver bool ESP8266_EchoResponse = false; bool ESP8266_EchoCommand = false; void UART_OutCharNonBlock(char data){ if((TxFifo_Size() >= (TXFIFOSIZE-1))) return; UART_OutChar(data); } // UART receive control/data & transmit FIFOs (see FIFO.h) uint32_t LostData1; // prototypes for private functions void ESP8266TxFifo_Init(void); uint32_t ESP8266TxFifo_Put(char data); uint32_t ESP8266TxFifo_Get(char *datapt); uint32_t ESP8266TxFifo_Size(void); void ESP8266RxFifo_Init(void); uint32_t ESP8266RxFifo_Put(char data); uint32_t ESP8266RxFifo_Get(char *datapt); uint32_t ESP8266RxFifo_Size(void); void ESP8266Rx0Fifo_Init(void); uint32_t ESP8266Rx0Fifo_Put(char data); uint32_t ESP8266Rx0Fifo_Get(char *datapt); uint32_t ESP8266Rx0Fifo_Size(void); #define FIFOSIZE 1024 // size of the FIFOs (must be power of 2) #define FIFOSUCCESS 1 // return value on success #define FIFOFAIL 0 // return value on failure // ESP8266 state uint16_t ESP8266_Server = 0; // server port, if any uint16_t ESP8266_ConnectionMux = 0; uint16_t ESP8266_Segment = 0; // last segment ID for buffered send /* ======================================================================= ========== helper FUNCTIONS ========== ======================================================================= */ // make letter lower-case char lc(char letter){ if((letter>='A')&&(letter<='Z')) letter |= 0x20; return letter; } // ***** Receive buffer *** #define RECBUFMAX 16 char ReceiveSearch[16]; uint32_t ReceiveIndex=0; uint32_t ReceiveSize; uint32_t ReceiveMode; void ESP8266_StartReceiveSearch(char *search){ ReceiveIndex = 0; int i=0; while(search[i]){ ReceiveSearch[i] = search[i]; i++; } ReceiveSize = i; ReceiveMode = 1; // searching } char * ESP8266_GetReceiveBuffer(void){ if(ReceiveMode==3){ return ReceiveSearch; } return 0; } const char ReceiveDataSearchString[]="+IPD,"; static uint32_t ReceiveDataSearchIndex = 0; static uint32_t ReceiveDataState = 1; // 0 to disable filtering static uint32_t ReceiveDataStream = 0; // connection ID for received data static uint32_t ReceiveDataLen = 0; // receive data packet remaining size volatile uint32_t ESP8266_DataAvailable = 0; // received data (about to be) available volatile uint32_t ESP8266_DataLoss = 0; // lost data (for debugging) //-------------------ReceiveDataFilter ------------------- // State machine to filter out received data stream from UART Rx input // Inputs: character to check // Outputs: true if data was filtered out, false otherwise bool ReceiveDataFilter(char letter){ switch(ReceiveDataState) { // Filter FSM case 4: // filter out data and put it into the right receive FIFO if(ReceiveDataLen) { switch(ReceiveDataStream) { case 0: if(ESP8266Rx0Fifo_Put(letter) == FIFOFAIL){ // overflow, data loss ESP8266_DataAvailable--; ESP8266_DataLoss++; } break; // only one connection currently supported } ReceiveDataLen--; return true; } ReceiveDataState = 1; // restart // fall through to start searching again if data is done case 1: // Look for +IPD if (letter == ReceiveDataSearchString[ReceiveDataSearchIndex]){ // match letter? ReceiveDataSearchIndex++; if(ReceiveDataSearchString[ReceiveDataSearchIndex] == 0){ // end of match string? if(ESP8266_ConnectionMux) { ReceiveDataState = 2; } else { ReceiveDataState = 3; } ReceiveDataSearchIndex = 0; ReceiveDataStream = 0; ReceiveDataLen = 0; } } else { ReceiveDataSearchIndex = 0; // start over } return false; case 2: // look for connection ID (separated by comma) if(letter >= '0' && letter <= '9') { ReceiveDataStream = ReceiveDataStream * 10 + (letter - '0'); // add digit to ID } else if (letter == ',') { ReceiveDataState = 3; // ID completed, move on } else { ReceiveDataStream = 0; ReceiveDataState = 1; // error, start over } return false; case 3: // look for receive data size (separated by colon) if(letter >= '0' && letter <= '9') { ReceiveDataLen = ReceiveDataLen * 10 + (letter - '0'); // add digit to length } else if(letter == ':') { ReceiveDataState = 4; // size complete, move on ESP8266_DataAvailable += ReceiveDataLen; // mark as becoming available } else { ReceiveDataStream = 0; ReceiveDataLen = 0; ReceiveDataState = 1; // error, start over } return false; } return false; } /* ====================================================================== ========== UART and private FUNCTIONS ========== ====================================================================== */ // Preprocessor magic to construct UARTx_ identifiers #define STR(x) #x #define CONCAT(x,y,z) x ## y ## z #define UART_STR(uart) "UART" STR(uart) #define UART_NAME(uart,identifier) CONCAT(UART,uart,identifier) #define UART_ESP8266(identifier) UART_NAME(ESP8266_UART,identifier) // power Domain PD0 // for 80MHz bus clock, UART1/UART2 clocks are ULPCLK 40MHz //------------------- ESP8266InitUART------------------- // Intializes uart needed to communicate with esp8266 // Configure UART for 115200bps operation // Inputs: RX and/or TX echo for debugging // Outputs: none void ESP8266_InitUART(int rx_echo, int tx_echo){ ESP8266TxFifo_Init(); ESP8266RxFifo_Init(); ESP8266Rx0Fifo_Init(); ESP8266_EchoResponse = rx_echo; ESP8266_EchoCommand = tx_echo; #if ESP8266_UART==1 // do not reset or activate PortA, already done in LaunchPad_Init // RSTCLR to GPIOA and UART1 peripherals // bits 31-24 unlock key 0xB1 // bit 1 is Clear reset sticky bit // bit 0 is reset gpio port // GPIOA->GPRCM.RSTCTL = (uint32_t)0xB1000003; // called previously UART1->GPRCM.RSTCTL = 0xB1000003; // Enable power to GPIOA and UART1 peripherals // PWREN // bits 31-24 unlock key 0x26 // bit 0 is Enable Power // GPIOA->GPRCM.PWREN = (uint32_t)0x26000001; // called previously UART1->GPRCM.PWREN = 0x26000001; Clock_Delay(24); // time for uart to power up // the following code selects which pins to use IOMUX->SECCFG.PINCM[ESP8266_RX] = 0x00040082; //bit 18 INENA input enable //bit 7 PC connected //bits 5-0=2 for UART1_Rx // configure alternate UART1 transmit function IOMUX->SECCFG.PINCM[ESP8266_TX] = 0x00000082; //bit 7 PC connected //bits 5-0=2 for UART1_Tx UART1->CLKSEL = 0x08; // bus clock UART1->CLKDIV = 0x00; // no divide UART1->CTL0 &= ~0x01; // disable UART1 UART1->CTL0 = 0x00020018; // bit 17 FEN=1 enable FIFO // bits 16-15 HSE=00 16x oversampling // bit 14 CTSEN=0 no CTS hardware // bit 13 RTSEN=0 no RTS hardware // bit 12 RTS=0 not RTS // bits 10-8 MODE=000 normal // bits 6-4 TXE=001 enable TxD // bit 3 RXE=1 enable TxD // bit 2 LBE=0 no loop back // bit 0 ENABLE 0 is disable, 1 to enable if(Clock_Freq() == 40000000){ // 20000000/16 = 1,250,000 Hz // Baud = 115200 // 1,250,000/115200 = 10.8506944444 // divider = 10+54/64 = 10.84375 UART1->IBRD = 10; UART1->FBRD = 54; // baud =1,250,000/10.84375 = 115,273.77 }else if (Clock_Freq() == 32000000){ // 32000000/16 = 2,000,000 // Baud = 115200 // 2,000,000/115200 = 17.3611111 // divider = 21+23/64 = 17.359375 UART1->IBRD = 17; UART1->FBRD = 23; // 115,211.52 }else if (Clock_Freq() == 80000000){ // 40000000/16 = 2,500,000 Hz // Baud = 115200 // 2,500,000/115200 = 21.701388 // divider = 21+45/64 = 21.703125 UART1->IBRD = 21; UART1->FBRD = 45; // baud =2,500,000/21.703125 = 115,191 }else return; UART1->LCRH = 0x00000030; // bits 5-4 WLEN=11 8 bits // bit 3 STP2=0 1 stop // bit 2 EPS=0 parity select // bit 1 PEN=0 no parity // bit 0 BRK=0 no break UART1->CPU_INT.IMASK = 0x0C01; // bit 11 TXINT yes // bit 10 RXINT yes // bit 0 Receive timeout, yes UART1->IFLS = 0x0422; // bits 11-8 RXTOSEL receiver timeout select 4 (0xF highest) // bits 6-4 RXIFLSEL 2 is greater than or equal to half // bits 2-0 TXIFLSEL 2 is less than or equal to half UART1->CTL0 |= 0x01; // enable UART1 #else // do not reset or activate PortB, already done in LaunchPad_Init // RSTCLR to GPIOB and UART2 peripherals // bits 31-24 unlock key 0xB1 // bit 1 is Clear reset sticky bit // bit 0 is reset gpio port // GPIOB->GPRCM.RSTCTL = (uint32_t)0xB1000003; // called previously UART2->GPRCM.RSTCTL = 0xB1000003; // Enable power to GPIOB and UART2 peripherals // PWREN // bits 31-24 unlock key 0x26 // bit 0 is Enable Power // GPIOB->GPRCM.PWREN = (uint32_t)0x26000001; // called previously UART2->GPRCM.PWREN = 0x26000001; Clock_Delay(24); // time for uart to power up // the following code selects which pins to use IOMUX->SECCFG.PINCM[ESP8266_RX] = 0x00040082; //bit 18 INENA input enable //bit 7 PC connected //bits 5-0=2 for UART2_Rx // configure alternate UART2 transmit function IOMUX->SECCFG.PINCM[ESP8266_TX] = 0x00000082; //bit 7 PC connected //bits 5-0=2 for UART2_Tx UART2->CLKSEL = 0x08; // bus clock UART2->CLKDIV = 0x00; // no divide UART2->CTL0 &= ~0x01; // disable UART2 UART2->CTL0 = 0x00020018; // bit 17 FEN=1 enable FIFO // bits 16-15 HSE=00 16x oversampling // bit 14 CTSEN=0 no CTS hardware // bit 13 RTSEN=0 no RTS hardware // bit 12 RTS=0 not RTS // bits 10-8 MODE=000 normal // bits 6-4 TXE=001 enable TxD // bit 3 RXE=1 enable TxD // bit 2 LBE=0 no loop back // bit 0 ENABLE 0 is disable, 1 to enable if(Clock_Freq() == 40000000){ // 20000000/16 = 1,250,000 Hz // Baud = 115200 // 1,250,000/115200 = 10.8506944444 // divider = 10+54/64 = 10.84375 UART2->IBRD = 10; UART2->FBRD = 54; // baud =1,250,000/10.84375 = 115,273.77 }else if (Clock_Freq() == 32000000){ // 32000000/16 = 2,000,000 // Baud = 115200 // 2,000,000/115200 = 17.3611111 // divider = 21+23/64 = 17.359375 UART2->IBRD = 17; UART2->FBRD = 23; // 115,211.52 }else if (Clock_Freq() == 80000000){ // 40000000/16 = 2,500,000 Hz // Baud = 115200 // 2,500,000/115200 = 21.701388 // divider = 21+45/64 = 21.703125 UART2->IBRD = 21; UART2->FBRD = 45; // baud =2,500,000/21.703125 = 115,191 }else return; UART2->LCRH = 0x00000030; // bits 5-4 WLEN=11 8 bits // bit 3 STP2=0 1 stop // bit 2 EPS=0 parity select // bit 1 PEN=0 no parity // bit 0 BRK=0 no break UART2->CPU_INT.IMASK = 0x0C01; // bit 11 TXINT yes // bit 10 RXINT yes // bit 0 Receive timeout, yes UART2->IFLS = 0x0422; // bits 11-8 RXTOSEL receiver timeout select 4 (0xF highest) // bits 6-4 RXIFLSEL 2 is greater than or equal to half // bits 2-0 TXIFLSEL 2 is less than or equal to half UART2->CTL0 |= 0x01; // enable UART2 #endif } //--------ESP8266_EnableInterrupt-------- // Enables uart interrupt // Inputs: none // Outputs: none void ESP8266_EnableInterrupt(void){ #if ESP8266_UART==1 NVIC->ICPR[0] = 1<<13; // UART1 is IRQ 13 NVIC->ISER[0] = 1<<13; NVIC->IP[3] = (NVIC->IP[3]&(~0x0000FF00))|(1<<14); // set priority (bits 15,14) IRQ 13 #else NVIC->ICPR[0] = 1<<14; // UART2 is IRQ 14 NVIC->ISER[0] = 1<<14; NVIC->IP[3] = (NVIC->IP[3]&(~0x00FF0000))|(1<<22); // set priority (bits 23,22) IRQ 14 #endif } //--------ESP8266_DisableInterrupt-------- // Disables uart interrupt // Inputs: none // Outputs: none void ESP8266_DisableInterrupt(void){ #if ESP8266_UART==1 NVIC->ICER[0] = 1<<13; // UART1 is IRQ 13 #else NVIC->ICER[0] = 1<<14; // UART2 is IRQ 14 #endif } //----------ESP8266BufferToTx---------- // Copies TX buffer (software defined FIFO) to uart // Inputs: none // Outputs:none void static ESP8266BufferToTx(void){ char letter; #if ESP8266_UART==1 while(((UART1->STAT&0x80) == 0) && (ESP8266TxFifo_Size() > 0)){ ESP8266TxFifo_Get(&letter); if(ESP8266_EchoCommand){ UART_OutCharNonBlock(letter); // echo } UART1->TXDATA = letter; } #else while(((UART2->STAT&0x80) == 0) && (ESP8266TxFifo_Size() > 0)){ ESP8266TxFifo_Get(&letter); if(ESP8266_EchoCommand){ UART_OutCharNonBlock(letter); // echo } UART2->TXDATA = letter; } #endif } //----------ESP8266RxToBuffer---------- // Copies uart fifo to RX buffer (software defined FIFO) // Inputs: none // Outputs:none void static ESP8266RxToBuffer(void){ char letter; #if ESP8266_UART==1 while(((UART1->STAT&0x04) == 0)&&((ESP8266RxFifo_Size() < (FIFOSIZE - 1)))){ letter = UART1->RXDATA; if(ESP8266_EchoResponse){ UART_OutCharNonBlock(letter); // echo if(ReceiveBufferIndexSTAT&0x04) == 0)&&((ESP8266RxFifo_Size() < (FIFOSIZE - 1)))){ letter = UART2->RXDATA; if(ESP8266_EchoResponse){ UART_OutCharNonBlock(letter); // echo if(ReceiveMode==1){// searching if(ReceiveSearch[ReceiveIndex] == letter){ ReceiveIndex++; if(ReceiveIndex == ReceiveSize){ ReceiveMode=2; } }else{ ReceiveIndex = 0; // no match } }else{ if(ReceiveMode==2){ // found if(letter>='A'){ ReceiveSearch[ReceiveIndex] = letter; ReceiveIndex++; }else{ ReceiveMode = 3; // done ReceiveSearch[ReceiveIndex] = 0; } } } } if(!ReceiveDataFilter(letter)) { ESP8266RxFifo_Put(letter); } } #endif } //----------UART_Handler---------- // At least one of three things has happened: // hardware TX FIFO goes from 3 to 2 or less items // hardware RX FIFO goes from 1 to 2 or more items // UART receiver has timed out #if ESP8266_UART==1 void UART1_IRQHandler(void){ uint32_t status; status = UART1->CPU_INT.IIDX; // reading clears bit in RIS if(status == 0x01){ // 0x01 receive timeout ESP8266RxToBuffer(); }else if(status == 0x0B){ // 0x0B receive ESP8266RxToBuffer(); }else if(status == 0x0C){ // 0x0C transmit ESP8266BufferToTx(); if(ESP8266TxFifo_Size() == 0){ // software TX FIFO is empty UART1->CPU_INT.IMASK &= ~0x0800; // disable TX FIFO interrupt } } } #else void UART2_IRQHandler(void){ uint32_t status; status = UART2->CPU_INT.IIDX; // reading clears bit in RIS if(status == 0x01){ // 0x01 receive timeout ESP8266RxToBuffer(); }else if(status == 0x0B){ // 0x0B receive ESP8266RxToBuffer(); }else if(status == 0x0C){ // 0x0C transmit ESP8266BufferToTx(); if(ESP8266TxFifo_Size() == 0){ // software TX FIFO is empty UART2->CPU_INT.IMASK &= ~0x0800; // disable TX FIFO interrupt } } } #endif //--------ESP8266_OutChar-------- // Prints a character to the esp8226 via uart // Inputs: character to transmit // Outputs: none void ESP8266_OutChar(char data){ ESP8266TxFifo_Put(data); // blocks via semaphore if FIFO full #if ESP8266_UART==1 UART1->CPU_INT.IMASK &= ~0x0800; // disarm TX FIFO interrupt ESP8266BufferToTx(); UART1->CPU_INT.IMASK |= 0x0800; // rearm TX FIFO interrupt #else UART2->CPU_INT.IMASK &= ~0x0800; // disarm TX FIFO interrupt ESP8266BufferToTx(); UART2->CPU_INT.IMASK |= 0x0800; // rearm TX FIFO interrupt #endif } //--------ESP8266_InChar-------- // Read a character from the esp8226 via uart // Inputs: none // Outputs: character received char ESP8266_InChar(void){ char letter; ESP8266RxFifo_Get(&letter); // blocks via semaphore if FIFO empty return(letter); } //---------ESP8266_SendCommand----- // Sends a string to the esp8266 module // Inputs: string to send (null-terminated) // Outputs: none void ESP8266_SendCommand(const char* command){ int index = 0; while(command[index] != 0){ ESP8266_OutChar(command[index++]); } } //---------ESP8266_WaitForResponse----- // Busy-wait until response found // Inputs: Success or failure strings to search for // Outputs: 1 on success, 0 on failure int ESP8266_WaitForResponse(const char *success, const char* failure) { char d; const char *s = success; const char *f = failure; while((!s || *s) && (!f || *f)) { // end of search string reached? d = ESP8266_InChar(); if(s && (d == *s)) { s++; } else { s = success; // start over if(s && (d == *s)) s++; // match first char? } if(f && (d == *f)) { f++; } else { f = failure; // start over if(f && (d == *f)) f++; // match first char? } } if(failure && !(*f)) return FAILURE; return SUCCESS; } /* ======================================================================= ========== ESP8266 PUBLIC FUNCTIONS ========== ======================================================================= */ //-------------------ESP8266_Init -------------- // Initializes the module // Inputs: RX and/or TX echo for debugging // Outputs: 1 for success, 0 for failure (no ESP detected) int ESP8266_Init(int rx_echo, int tx_echo){ char c; const char* s; uint32_t timer = 1; // Disable interrupt during initialization ESP8266_DisableInterrupt(); // Initialize UART to communicate with ESP ESP8266_InitUART(rx_echo, tx_echo); // Initialize reset port on PA25 IOMUX->SECCFG.PINCM[PA25INDEX] = (uint32_t) 0x00000081; GPIOA->DOE31_0 |= (1<<25); // Hardware reset GPIOA->DOUTCLR31_0 = (1<<25); // reset low Clock_Delay1ms(10); GPIOA->DOUTSET31_0 = (1<<25); // reset high // Wait for ready status with timeout // Use low-level UART communication, interrupts disabled s = ESP8266_READY_RESPONSE; timer = 5000000; // around a 1-2s total timeout while(*s) { #if ESP8266_UART==1 while(timer && ((UART1->STAT&0x04) == 0x04)) { timer--; } if(!timer) break; c = (char)UART1->RXDATA; #else while(timer && ((UART2->STAT&0x04) == 0x04)) { timer--; } if(!timer) break; c = (char)UART2->RXDATA; #endif if(rx_echo) UART_OutCharNonBlock(c); // echo, requires UART0 to be operational, will print garbage if(c == *s) { s++; } else { s = ESP8266_READY_RESPONSE; if(c == *s) s++; } } // Finally enable interrupt ESP8266_EnableInterrupt(); if(!timer) return FAILURE; return SUCCESS; } //-------------------ESP8266_Connect -------------- // Bring interface up and connect to Wifi // Inputs: enable debug output // Outputs: 1 on success, 0 on failure int ESP8266_Connect(int verbose){ if(ESP8266_Reset()==FAILURE) return FAILURE; if(verbose) // debug output: MAC address oF ESP8266 ESP8266_GetMACAddress(); #if SOFTAP if(ESP8266_SoftAccessPoint(SSID_NAME,PASSKEY)==FAILURE) return FAILURE; if(ESP8266_SetWifiMode(ESP8266_WIFI_MODE_AP)==FAILURE) return FAILURE; #else if(ESP8266_SetWifiMode(ESP8266_WIFI_MODE_CLIENT)==FAILURE) return FAILURE; if(verbose) // debug output: see APs in area ESP8266_ListAccessPoints(); if(ESP8266_JoinAccessPoint(SSID_NAME,PASSKEY)==FAILURE) return FAILURE; #endif if(verbose) // debug output: our IP address ESP8266_GetIPAddress(); return SUCCESS; } //-------------------ESP8266_StartServer -------------- // Start server on specific port // Inputs: port and server timeout // Outputs: 1 on success, 0 on failure int ESP8266_StartServer(uint16_t port, uint16_t timeout){ if(ESP8266_SetConnectionMux(1)==FAILURE) return FAILURE; if(ESP8266_EnableServer(port)==FAILURE) return FAILURE; if(ESP8266_SetServerTimeout(timeout)==FAILURE) return FAILURE; return SUCCESS; } //-------------------ESP8266_StopServer -------------- // Stop server and set to single-client mode // Inputs: none // Outputs: 1 on success, 0 on failure int ESP8266_StopServer(void){ if(ESP8266_DisableServer()==FAILURE) return FAILURE; if(ESP8266_SetConnectionMux(0)==FAILURE) return FAILURE; return SUCCESS; } //----------ESP8266_Reset------------ // Soft resets the esp8266 module // Input: none // Output: 1 if success, 0 if fail int ESP8266_Reset(void){ int try=MAXTRY; while(try){ ESP8266_SendCommand("AT+RST\r\n"); if(ESP8266_WaitForResponse(ESP8266_READY_RESPONSE,0)) return SUCCESS; try--; } return FAILURE; } //---------ESP8266_Restore----- // Restore the ESP8266 module to default values // Inputs: none // Outputs: 1 if success, 0 if fail int ESP8266_Restore(void) { int try=MAXTRY; while(try){ ESP8266_SendCommand("AT+RESTORE\r\n"); if(ESP8266_WaitForResponse(ESP8266_READY_RESPONSE,0)) return SUCCESS; try--; } return FAILURE; } //---------ESP8266_GetVersionNumber---------- // Get status // Input: none // Output: 1 if success, 0 if fail int ESP8266_GetVersionNumber(void){ int try=MAXTRY; while(try){ ESP8266_SendCommand("AT+GMR\r\n"); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,0)) return SUCCESS; try--; } return FAILURE; // fail } //---------ESP8266_GetMACAddress---------- // Get MAC address // Input: none // Output: 1 if success, 0 if fail int ESP8266_GetMACAddress(void){ int try=MAXTRY; while(try){ ESP8266_SendCommand("AT+CIPSTAMAC?\r\n"); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,0)) return SUCCESS; try--; } return FAILURE; // fail } //---------ESP8266_SetWifiMode---------- // Configures the esp8266 to operate as a wifi client, access point, or both // Input: mode accepts ESP8266_WIFI_MODE constants // Output: 1 if success, 0 if fail int ESP8266_SetWifiMode(uint8_t mode){ int try=MAXTRY; char TXBuffer[32]; while(try){ sprintf(TXBuffer, "AT+CWMODE=%d\r\n", mode); ESP8266_SendCommand(TXBuffer); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,0)) return SUCCESS; try--; } return FAILURE; } //---------ESP8266_SetConnectionMux---------- // Enables the esp8266 connection mux, required for starting tcp server // Input: 0 (single) or 1 (multiple) // Output: 1 if success, 0 if fail int ESP8266_SetConnectionMux(uint8_t enabled){ int try=MAXTRY; //char TXBuffer[32]; while(try){ if(enabled){ //sprintf(TXBuffer, "AT+CIPMUX=%d\r\n", enabled); ESP8266_SendCommand("AT+CIPMUX=1\r\n"); }else{ ESP8266_SendCommand("AT+CIPMUX=0\r\n"); } if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,0)) { ESP8266_ConnectionMux = enabled; return SUCCESS; } try--; } return FAILURE; } //---------ESP8266_ListAccessPoints---------- // Lists available wifi access points // Input: none // Output: 1 if success, 0 if fail int ESP8266_ListAccessPoints(void){ int try=MAXTRY; while(try){ ESP8266_SendCommand("AT+CWLAP\r\n"); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,ESP8266_ERROR_RESPONSE)) return SUCCESS; try--; } return FAILURE; } //----------ESP8266_JoinAccessPoint------------ // Joins a wifi access point using specified ssid and password // Input: SSID and PASSWORD // Output: 1 if success, 0 if fail int ESP8266_JoinAccessPoint(const char* ssid, const char* password){ int try=MAXTRY; while(try){ ESP8266_SendCommand("AT+CWJAP=\""); ESP8266_SendCommand(ssid); ESP8266_SendCommand("\",\""); ESP8266_SendCommand(password); ESP8266_SendCommand("\"\r\n"); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,ESP8266_FAIL_RESPONSE)) return SUCCESS; try--; } return FAILURE; } // ----------ESP8266_QuitAccessPoint------------- // Disconnects from currently connected wifi access point // Inputs: none // Outputs: 1 if success, 0 if fail int ESP8266_QuitAccessPoint(void){ int try=MAXTRY; while(try){ ESP8266_SendCommand("AT+CWQAP\r\n"); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,0)) return SUCCESS; try--; } return FAILURE; } //----------ESP8266_ConfigureAccessPoint------------ // Configures esp8266 wifi soft access point settings // Use this function only when in AP mode (and not in client mode) // Input: SSID, Password, channel, security // Output: 1 if success, 0 if fail int ESP8266_ConfigureAccessPoint(const char* ssid, const char* password, uint8_t channel, uint8_t encryptMode){ int try=MAXTRY; char TXBuffer[32]; while(try){ ESP8266_SendCommand("AT+CWSAP=\""); ESP8266_SendCommand(ssid); ESP8266_SendCommand("\",\""); ESP8266_SendCommand(password); sprintf(TXBuffer, "\",%d,%d\r\n", channel, encryptMode); ESP8266_SendCommand(TXBuffer); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,ESP8266_ERROR_RESPONSE)) return SUCCESS; try--; } return FAILURE; } //---------ESP8266_GetIPAddress---------- // Get local IP address // Input: none // Output: 1 if success, 0 if fail int ESP8266_GetIPAddress(void){ int try=MAXTRY; while(try){ ESP8266_SendCommand("AT+CIFSR\r\n"); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,ESP8266_ERROR_RESPONSE)) return SUCCESS; try--; } return FAILURE; } //---------ESP8266_SetSSLClientConfiguration---------- // Set SSL client configuration // Requires certificates to be flashed into the ESP firmware // Inputs: enable/disable client/server certificate checks // output: 1 if success, 0 if fail int ESP8266_SetSSLClientConfiguration(int verifyClient, int verifyServer){ int try=MAXTRY; char TXBuffer[32]; while(try){ sprintf(TXBuffer, "AT+CIPSSLCCONF=%d\r\n", (verifyClient? 1 : 0) + (verifyServer? 2 : 0)); ESP8266_SendCommand(TXBuffer); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,ESP8266_ERROR_RESPONSE)) return SUCCESS; try--; } return FAILURE; } //---------ESP8266_SetSSLBufferSize---------- // Set SSL buffer size // Inputs: buffer size between 2048 and 4096 // output: 1 if success, 0 if fail int ESP8266_SetSSLBufferSize(uint16_t bufferSize){ int try=MAXTRY; char TXBuffer[32]; while(try){ sprintf(TXBuffer, "AT+CIPSSLSIZE=%d\r\n", bufferSize); ESP8266_SendCommand(TXBuffer); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,ESP8266_ERROR_RESPONSE)) return SUCCESS; try--; } return FAILURE; } //---------ESP8266_MakeTCPConnection---------- // Establish TCP or SSL connection // The ESP only seems to have limited SSL support, does not work with all servers // Inputs: IP address or web page as a string, port, and keepalive time (0 if none) // output: 1 if success, 0 if fail int ESP8266_MakeTCPConnection(char *IPaddress, uint16_t port, uint16_t keepalive, int ssl){ int try=MAXTRY; char TXBuffer[32]; while(try){ if(ssl){ ESP8266_SendCommand("AT+CIPSTART=\"SSL\",\""); } else { ESP8266_SendCommand("AT+CIPSTART=\"TCP\",\""); } ESP8266_SendCommand(IPaddress); if(keepalive) { sprintf(TXBuffer, "\",%d,%d\r\n", port, keepalive); } else { sprintf(TXBuffer, "\",%d\r\n", port); } ESP8266_SendCommand(TXBuffer); // open and connect to a socket if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,ESP8266_ERROR_RESPONSE)) return SUCCESS; try--; } return FAILURE; } //---------ESP8266_Send---------- // Send a string to server // Input: payload to send // Output: 1 if success, 0 if fail int ESP8266_Send(const char* fetch){ char TXBuffer[32]; if(ESP8266_ConnectionMux) { sprintf(TXBuffer, "AT+CIPSEND=%d,%d\r\n", 0, strlen(fetch)); } else { sprintf(TXBuffer, "AT+CIPSEND=%d\r\n", strlen(fetch)); } ESP8266_SendCommand(TXBuffer); if(!ESP8266_WaitForResponse(">",ESP8266_ERROR_RESPONSE)) return FAILURE; ESP8266_SendCommand(fetch); if(ESP8266_WaitForResponse(ESP8266_SENDOK_RESPONSE,ESP8266_ERROR_RESPONSE)) return SUCCESS; return FAILURE; } //---------ESP8266_SendBuffered---------- // Send a string to server using ESP TCP-send buffer // Input: payload to send // Output: 1 if success, 0 if fail int ESP8266_SendBuffered(const char* fetch){ char TXBuffer[32]; if(ESP8266_ConnectionMux) { sprintf(TXBuffer, "AT+CIPSENDBUF=%d,%d\r\n", 0, strlen(fetch)); } else { sprintf(TXBuffer, "AT+CIPSENDBUF=%d\r\n", strlen(fetch)); } ESP8266_SendCommand(TXBuffer); if(!ESP8266_WaitForResponse(">",ESP8266_ERROR_RESPONSE)) return FAILURE; ESP8266_Segment++; ESP8266_SendCommand(fetch); sprintf(TXBuffer, "Recv %d bytes", strlen(fetch)); if(ESP8266_WaitForResponse(TXBuffer,ESP8266_ERROR_RESPONSE)) return SUCCESS; return FAILURE; } //---------ESP8266_SendBufferedStatus---------- // Check status of last buffered segment // Input: none // Output: 1 if success, 0 if fail int ESP8266_SendBufferedStatus(void){ char OKBuffer[16]; char FailBuffer[24]; if(ESP8266_ConnectionMux) { sprintf(OKBuffer, "\n%d,%d,SEND OK\r\n", 0, ESP8266_Segment); sprintf(FailBuffer, "\n%d,%d,SEND FAIL\r\n", 0, ESP8266_Segment); } else { sprintf(OKBuffer, "\n%d,SEND OK\r\n", ESP8266_Segment); sprintf(FailBuffer, "\n%d,SEND FAIL\r\n", ESP8266_Segment); } if(ESP8266_WaitForResponse(OKBuffer,FailBuffer)) return SUCCESS; return FAILURE; } //---------ESP8266_Receive---------- // Receive a string from server // Reads from data input until end of line or max length is reached // Input: buffer and max length // Output: 1 and null-terminated string if success, 0 if fail (disconnected) int ESP8266_Receive(char* fetch, uint32_t max){ long sr; const char* s; char letter; while(max > 1) { if(ESP8266Rx0Fifo_Size() || ESP8266_DataAvailable) { // data (about to be) available? ESP8266Rx0Fifo_Get(&letter); // blocks via semaphore if FIFO empty // ESP8266_DisableInterrupt(); // critical section sr = StartCritical(); if(ESP8266_DataAvailable) ESP8266_DataAvailable--; EndCritical(sr); // ESP8266_EnableInterrupt(); if(letter == '\r') continue; if(letter == '\n') break; *fetch = letter; fetch++; max--; } else { // wait for next packet or connection close if(ESP8266_ConnectionMux) { s = "0,CLOSED"; } else { s = "CLOSED"; } if(!ESP8266_WaitForResponse(ReceiveDataSearchString,s)){ *fetch = 0; // connection closed return FAILURE; } while(ESP8266_InChar() != ':') {} // wait for DataAvailable to be updated } } *fetch = 0; // terminate with null character return SUCCESS; } //---------ESP8266_CloseTCPConnection---------- // Close TCP connection // Input: none // Output: 1 if success, 0 if fail int ESP8266_CloseTCPConnection(void){ int try=MAXTRY; while(try){ if(ESP8266_ConnectionMux) { ESP8266_SendCommand("AT+CIPCLOSE=0\r\n"); } else { ESP8266_SendCommand("AT+CIPCLOSE\r\n"); } if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,ESP8266_ERROR_RESPONSE)) { ESP8266Rx0Fifo_Init(); // Discard any data return SUCCESS; } try--; } ESP8266Rx0Fifo_Init(); // Discard any data return FAILURE; } //---------ESP8266_SetDataTransmissionMode---------- // Set data transmission passthrough mode // Input: 0 not data mode, 1 data mode; return "Link is builded" // Output: 1 if success, 0 if fail int ESP8266_SetDataTransmissionMode(uint8_t mode){ int try=MAXTRY; char TXBuffer[32]; while(try){ sprintf(TXBuffer, "AT+CIPMODE=%d\r\n", mode); ESP8266_SendCommand(TXBuffer); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,0)) return SUCCESS; try--; } return FAILURE; } //---------ESP8266_GetStatus---------- // Get network connection status // Input: none // Output: 1 if success, 0 if fail int ESP8266_GetStatus(void){ int try=MAXTRY; while(try){ ESP8266_SendCommand("AT+CIPSTATUS\r\n"); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,0)) return SUCCESS; try--; } return FAILURE; } // --------ESP8266_EnableServer------------------ // Enables tcp server on specified port // Inputs: port number // Outputs: 1 if success, 0 if fail int ESP8266_EnableServer(uint16_t port){ int try=MAXTRY; char TXBuffer[32]; while(try){ sprintf(TXBuffer, "AT+CIPSERVER=1,%d\r\n", port); ESP8266_SendCommand(TXBuffer); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,0)) { ESP8266_Server = port; return SUCCESS; } try--; } return FAILURE; } // ----------ESP8266_SetServerTimeout-------------- // Set connection timeout for tcp server, 0-28800 seconds // Inputs: timeout parameter // Outputs: 1 if success, 0 if fail int ESP8266_SetServerTimeout(uint16_t timeout){ int try=MAXTRY; char TXBuffer[32]; while(try){ sprintf(TXBuffer, "AT+CIPSTO=%d\r\n", timeout); ESP8266_SendCommand(TXBuffer); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,ESP8266_ERROR_RESPONSE)) return SUCCESS; try--; } return FAILURE; } // ----------ESP8266_WaitForConnection-------------- // Wait for incoming connection on server // must ensure that no other ESP calls are done while waiting // this should really be done in the background interrupt handler // using a mailbox to communicate with this function // Inputs: none // Outputs: 1 if success, 0 if fail int ESP8266_WaitForConnection(void){ if(!ESP8266_ConnectionMux) return FAILURE; if(!ESP8266_Server) return FAILURE; if(ESP8266_WaitForResponse("0,CONNECT\r\n",0)) return SUCCESS; return FAILURE; } //---------ESP8266_DisableServer---------- // Disables tcp server // Input: none // Output: 1 if success, 0 if fail int ESP8266_DisableServer(void){ int try=MAXTRY; while(try){ ESP8266_SendCommand("AT+CIPSERVER=0\r\n"); if(ESP8266_WaitForResponse(ESP8266_OK_RESPONSE,0)) { ESP8266_Server = 0; return SUCCESS; } try--; } return FAILURE; } // Declare state variables for FiFo // size, buffer, put and get indexes // Lab 6 change: Added semaphores for OS synchronization. // TxFifo: foreground threads Put (block if full), ISR Gets (signals space available) // RxFifo: ISR Puts (signals data available), foreground threads Get (block if empty) // Rx0Fifo: ISR Puts (signals data available), foreground threads Get (block if empty) int32_t static ESP8266TxPutI; // Index to put new int32_t static ESP8266TxGetI; // Index of oldest char static ESP8266TxFifo[FIFOSIZE]; Sema4_t ESP8266TxSpaceAvailable; // Lab 6: counting semaphore for free space // *********** ESP8266TxFifo_Init********** // Initializes a software ESP8266TxFIFO of a // fixed size and sets up indexes for // put and get operations // Lab 6 change: Also initializes TxSpaceAvailable semaphore to FIFOSIZE-1 void ESP8266TxFifo_Init(void){ ESP8266TxPutI = ESP8266TxGetI = 0; OS_InitSemaphore(&ESP8266TxSpaceAvailable, FIFOSIZE-1); } // *********** ESP8266TxFifo_Put********** // Adds an element to the ESP8266TxFIFO // Input: data is character to be inserted // Output: 1 for success, data properly saved // 0 for failure, TxFIFO is full // Lab 6 change: Now blocks via OS_Wait if FIFO is full (called by foreground thread) uint32_t ESP8266TxFifo_Put(char data){ OS_Wait(&ESP8266TxSpaceAvailable); ESP8266TxFifo[ESP8266TxPutI] = data; ESP8266TxPutI = (ESP8266TxPutI+1)&(FIFOSIZE-1); return SUCCESS; } // *********** ESP8266TxFifo_Get********** // Gets an element from the ESP8266TxFIFO // Input: pointer to empty 8-bit variable // Output: If the ESP8266TxFIFO is empty return 0 // If the ESP8266TxFIFO has data, remove it, and put in *datapt, return 1 // Lab 6 change: Calls OS_Signal after removing element to wake blocked Put callers (called by ISR) uint32_t ESP8266TxFifo_Get(char *datapt){ if(ESP8266TxGetI == ESP8266TxPutI){ return FAILURE; } *datapt = ESP8266TxFifo[ESP8266TxGetI]; ESP8266TxGetI = (ESP8266TxGetI+1)&(FIFOSIZE-1); OS_Signal(&ESP8266TxSpaceAvailable); return SUCCESS; } //------------ESP8266TxFifo_Size------------ // Returns how much data available for reading from Tx1 FIFO // Input: none // Output: number of elements in receive FIFO uint32_t ESP8266TxFifo_Size(void){ return ((ESP8266TxPutI - ESP8266TxGetI)&(FIFOSIZE-1)); } int32_t static ESP8266RxPutI; // Index to put new int32_t static ESP8266RxGetI; // Index of oldest char static ESP8266RxFifo[FIFOSIZE]; Sema4_t ESP8266RxDataAvailable; // Lab 6: counting semaphore for available data // *********** ESP8266RxFifo_Init********** // Initializes a software RxFIFO of a // fixed size and sets up indexes for // put and get operations // Lab 6 change: Also initializes RxDataAvailable semaphore to 0 void ESP8266RxFifo_Init(void){ ESP8266RxPutI = ESP8266RxGetI = 0; OS_InitSemaphore(&ESP8266RxDataAvailable, 0); } // *********** ESP8266RxFifo_Put********** // Adds an element to the ESP8266RxFIFO // Input: data is character to be inserted // Output: 1 for success, data properly saved // 0 for failure, RxFIFO is full // Lab 6 change: Calls OS_Signal after adding element to wake blocked Get callers (called by ISR) uint32_t ESP8266RxFifo_Put(char data){ if(((ESP8266RxPutI+1)&(FIFOSIZE-1)) == ESP8266RxGetI){ return FAILURE; } ESP8266RxFifo[ESP8266RxPutI] = data; ESP8266RxPutI = (ESP8266RxPutI+1)&(FIFOSIZE-1); OS_Signal(&ESP8266RxDataAvailable); return SUCCESS; } // *********** ESP8266RxFifo_Get********** // Gets an element from the ESP8266RxFIFO // Input: pointer to empty 8-bit variable // Output: If the ESP8266RxFIFO is empty return 0 // If the ESP8266RxFIFO has data, remove it, and put in *datapt, return 1 // Lab 6 change: Now blocks via OS_Wait if FIFO is empty (called by foreground thread) uint32_t ESP8266RxFifo_Get(char *datapt){ OS_Wait(&ESP8266RxDataAvailable); *datapt = ESP8266RxFifo[ESP8266RxGetI]; ESP8266RxGetI = (ESP8266RxGetI+1)&(FIFOSIZE-1); return SUCCESS; } //------------ESP8266RxFifo_Size------------ // Returns how much data available for reading from Rx FIFO // Input: none // Output: number of elements in receive FIFO uint32_t ESP8266RxFifo_Size(void){ return ((ESP8266RxPutI - ESP8266RxGetI)&(FIFOSIZE-1)); } int32_t static ESP8266Rx0PutI; // Index to put new int32_t static ESP8266Rx0GetI; // Index of oldest char static ESP8266Rx0Fifo[FIFOSIZE]; Sema4_t ESP8266Rx0DataAvailable; // Lab 6: counting semaphore for available data // *********** ESP8266Rx0Fifo_Init********** // Initializes a software RxFIFO of a // fixed size and sets up indexes for // put and get operations // Lab 6 change: Also initializes Rx0DataAvailable semaphore to 0 void ESP8266Rx0Fifo_Init(void){ ESP8266Rx0PutI = ESP8266Rx0GetI = 0; OS_InitSemaphore(&ESP8266Rx0DataAvailable, 0); } // *********** ESP8266Rx0Fifo_Put********** // Adds an element to the ESP8266Rx0FIFO // Input: data is character to be inserted // Output: 1 for success, data properly saved // 0 for failure, RxFIFO is full // Lab 6 change: Calls OS_Signal after adding element to wake blocked Get callers (called by ISR) uint32_t ESP8266Rx0Fifo_Put(char data){ if(((ESP8266Rx0PutI+1)&(FIFOSIZE-1)) == ESP8266Rx0GetI){ return FAILURE; } ESP8266Rx0Fifo[ESP8266Rx0PutI] = data; ESP8266Rx0PutI = (ESP8266Rx0PutI+1)&(FIFOSIZE-1); OS_Signal(&ESP8266Rx0DataAvailable); return SUCCESS; } // *********** ESP8266Rx0Fifo_Get********** // Gets an element from the ESP8266Rx0FIFO // Input: pointer to empty 8-bit variable // Output: If the ESP8266Rx0FIFO is empty return 0 // If the ESP8266Rx0FIFO has data, remove it, and put in *datapt, return 1 // Lab 6 change: Now blocks via OS_Wait if FIFO is empty (called by foreground thread) uint32_t ESP8266Rx0Fifo_Get(char *datapt){ OS_Wait(&ESP8266Rx0DataAvailable); *datapt = ESP8266Rx0Fifo[ESP8266Rx0GetI]; ESP8266Rx0GetI = (ESP8266Rx0GetI+1)&(FIFOSIZE-1); return SUCCESS; } //------------ESP8266Rx0Fifo_Size------------ // Returns how much data available for reading from Rx0 FIFO // Input: none // Output: number of elements in receive FIFO uint32_t ESP8266Rx0Fifo_Size(void){ return ((ESP8266Rx0PutI - ESP8266Rx0GetI)&(FIFOSIZE-1)); }