I'm releasing a module for the low cost ESP8266 Uart to Wifi Bridge.
EDIT:*** POSSIBLY FIXED ***
{
Please be aware that this is still a work in progress; there is a major bug in the module somewhere, but I have spent far too long on this module already and cannot seem to get to the bottom of the bug.
If anyone else wants to take a look at this I would be most grateful. It appears to be a memory leak/trashing issue that occurs somewhere *i think* around the IP address checking. The module will work for a while, then jam up somewhere. There is a lot of string manipulation going on, it could be around there.
}
The demo program posts values to the Sparkfun data service (Phant), and would be a valuable core to an Internet Of Things type device. I have chosen sparkfun over my previous Pachube/Cosm/Xively services as it is much simpler to interact with, and they provide the source to run your own instance. My Demo stream is here.
In the code, you'll need to add your own PUBLICKEY & PRIVATEKEY, from the sparkfun instructions, plus your own Wifi SSID and PASSWORD.
This is tested with an ESP8266 module with Version: 00160901 firmware. I have not tested against anything else.
Module Code:
Code: Select all
Module ESP
#option RX_BUFFER_SIZE = 256 // Need to have a good sized buffer, 64 was too short.
#option RX_PRIORITY = ipLow
'#option RX_PRIORITY = ipHigh
Include "String.bas"
Include "Convert.bas"
Include "USART.bas"
Include "ISRRX.bas"
Public Dim
// Pass through some ISRRX routines
DataAvailable As ISRRX.DataAvailable,
ISRReset As ISRRX.Reset,
ISRStart As ISRRX.Start,
ISRStop As ISRRX.Stop,
ReadByte As ISRRX.ReadByte,
ReadWord As ISRRX.ReadWord,
ReadLongWord As ISRRX.ReadLongWord,
ReadFloat As ISRRX.ReadFloat,
ReadStr As ISRRX.ReadStr
Public Const
CR = #13,
LF = #10,
QU = #34
Public Structure TIPAddr
Val(4) As Byte
IP As Val(0).AsLongWord
End Structure
Public Dim
IPAddr As TIPAddr
{
****************************************************************************
* Name : ISRRXFind (BLOCKING W T/O) *
* Purpose : Finds pStr in the ISRRX buffer (blocking with timeout) *
****************************************************************************
}
Public Function ISRRXFind(pStr As String, pTimeout As Word) As Boolean
Dim Counter, StrIndex As Byte
Dim Timeout As Word
Dim Ch As Byte
Result = False
StrIndex = 0
Counter = 10
Repeat
Timeout = pTimeout
While Timeout > 0
Ch = pStr(StrIndex)
If Ch = 0 Then
result = True
Exit
ElseIf ISRRX.DataAvailable Then
If Ch = ISRRX.ReadByte() Then
Inc(StrIndex)
Else
StrIndex = 0
EndIf
EndIf
DelayUS(100)
Dec(Timeout)
Wend
Dec(Counter)
Until Counter = 0
End Function
{
****************************************************************************
* Name : ReadString (BLOCKING W T/O) *
* Purpose : Reads pText string from the ISRRX buffer (blocking with timeout)*
****************************************************************************
}
Function ReadString(ByRef pText As String, pTimeout As Word, count As Word, pTerminator As Char = null) As Byte
Dim Ch As Char
Dim tTimeout As LongWord
tTimeout = pTimeout * 4000
Result = 0
Repeat
Repeat
DelayUS(25)
Dec(tTimeout)
If tTimeout = 0 Then
result = 0
pText(0) = 0 // Null terminate whatever we have
Exit
EndIf
Until ISRRX.DataAvailable
Ch = ISRRX.ReadByte()
If Ch <> pTerminator Then
pText(result) = Ch
Inc(Result)
If result = Count - 2 Then
pText(result) = 0 // Null terminate whatever we have
Inc(Result)
Exit
EndIf
EndIf
Until Ch = pTerminator
pText(result) = 0
Inc(Result)
End Function
{
****************************************************************************
* Name : StrToIP *
* Purpose : Checks whether pString is an IP address, and formats it *
****************************************************************************
}
Public Function StrToIP(pString As String, ByRef IPaddress As TIPAddr) As Boolean
Dim
octno As Byte,
oct As String(10),
Pos As Byte,
split As Byte
result = false
Pos = 0
// Sensible size?
FSR0 = AddressOf(pString)
While POSTINC0 <> 0 And pos < 18
Inc(pos)
Wend
// Carry on...
If pos < 18 And pos > 0 Then
// Split into octlets
For octno = 3 To 0 Step -1
split = Position(".", pString)
If split > -1 Then
oct = Left(pString, split) // Get octlet
If IsDecValid(oct) Then // valid decimal number?
IPaddress.Val(octno) = Byte(StrToDec(oct))
Else
IPaddress.IP = $00000000
Exit // Nope. Exit false
EndIf
pString = Mid(pString, split + 1) // Get remainder
Else
IPaddress.IP = $00000000
Exit // Couldn't find split (.)
EndIf
Next
result = true
EndIf
End Function
{
****************************************************************************
* Name : Setup (PUBLIC) (BLOCKING W T/O) *
* Purpose : Sets ESP8266 to known state and configures peripherals *
****************************************************************************
}
Public Function Setup(Timeout As Word = 5000) As Boolean
USART.SetBaudrate(br115200)
ISRRX.Initialize()
DelayMS(100)
ISRRX.Reset()
USART.Write("AT+RST", CR, LF)
If ISRRXFind("ready", Timeout) Then
Result = true
Else
Result = false
EndIf
End Function
{
****************************************************************************
* Name : ConnectWifi (PUBLIC) (BLOCKING W T/O) *
* Purpose : Sets ESP to connect to an AP with the SSID and PASS credentials*
****************************************************************************
}
Public Function ConnectWifi(SSID As String, PASS As String, Timeout As Word = 5000) As Boolean
USART.Write("AT+CWMODE=1", CR, LF)
USART.Write("AT+CWJAP=")
USART.Write(QU, SSID, QU)
USART.Write(",", QU, PASS, QU, CR, LF)
If ISRRXFind("OK", Timeout) Then
result = true
Else
result = false
EndIf
End Function
{
****************************************************************************
* Name : CheckWifi (PUBLIC) (BLOCKING W T/O) *
* Purpose : Checks ESP for a valid IP (indicating connected) *
****************************************************************************
}
Public Function CheckWifi(Timeout As Word = 100) As TIPAddr
Dim IPstring As String
result.IP = $00000000
USART.Write("AT+CIFSR", CR, LF)
If ISRRXFind("AT+CIFSR" + CR + CR + LF, 100) Then
ReadString(IPstring, 500, 25, CR)
StrToIP(IPString, result)
EndIf
DelayMS(500)
End Function
{
****************************************************************************
* Name : GetVersion (PUBLIC) (BLOCKING W T/O) *
* Purpose : Checks ESP for version string *
****************************************************************************
}
Public Function GetVersion(ByRef pString As String, Timeout As Word = 100) As Boolean
result = false
USART.Write("AT+GMR", CR, LF)
If ISRRXFind("AT+GMR" + CR + CR + LF, 100) Then
ReadString(pString, 500, 20, CR)
result = true
EndIf
End Function
{
****************************************************************************
* Name : ConnectTCP (PUBLIC) (BLOCKING W T/O) *
* Purpose : ESP connects to given desthost; returns true if successful *
****************************************************************************
}
Public Function ConnectTCP(desthost As String, pPort As Word = 80, Timeout As Word = 1000) As Boolean
result = false
// Set single connection mode
USART.Write("AT+CIPMUX=0", CR, LF)
If Not ISRRXFind("OK", Timeout) Then
Exit
EndIf
USART.Write("AT+CIPSTART=", QU, "TCP", QU)
USART.Write(",", QU, desthost, QU, ",", DecToStr(pPort), CR, LF)
If ISRRXFind("Linked", Timeout) Then
result = true
EndIf
End Function
{
****************************************************************************
* Name : SendTCPData (PUBLIC) (BLOCKING W T/O) *
* Purpose : Sends tcpdata to previously connected host; returns true if successful*
****************************************************************************
}
Public Function SendTCPData(ByRef tcpdata As String, Timeout As Word = 5000) As Boolean
Dim strlen, i As Word
result = false
// Get length of tcpdata
strlen = 0
FSR0 = AddressOf(tcpdata)
While POSTINC0 <> 0
Inc(Strlen)
Wend
USART.Write("AT+CIPSEND=", DecToStr(strlen), CR, LF)
If ISRRXFind(">", Timeout) Then
For i = 0 To (strlen - 1) // Usart.write(tcpdata) as string seemed to have an issue.
USART.WriteByte(tcpdata(i))
Next
If ISRRXFind("SEND OK", timeout) Then
result = true
EndIf
EndIf
End Function
{
****************************************************************************
* Name : GetTCPDataMode (PUBLIC) (BLOCKING W T/O) *
* Purpose : Parses +IPD message and returns TCP data length *
****************************************************************************
}
Public Function GetTCPDataMode(Timeout As Word = 1000) As Integer
Dim CountString As String
Dim ChCount As Word
result = -1
If ISRRXFind("+IPD,", 500) Then // Look for IPD and Count
ReadString(CountString, 500, 10, ":") // Pull out Counter
If IsDecValid(CountString) Then // Turn into Word
ChCount = StrToDec(CountString)
Result = Integer(ChCount)
EndIf
EndIf
End Function
{
****************************************************************************
* Name : Disconnect (PUBLIC) *
* Purpose : Closes the TCP Connection *
****************************************************************************
}
Public Sub Disconnect()
USART.Write("AT+CIPCLOSE", CR, LF)
End Sub
Code: Select all
Device = 18F27J53
Clock = 48
Public Config
OSC = INTOSCPLL, ' internal osc 8MHz - No output on RA6
PLLDIV = 2, ' usb 48MHz
CPUDIV = OSC1, ' 48MHz cpu clock
FCMEN = Off,
IESO = Off,
WDTEN = Off,
WDTPS = 2048,
STVREN = On,
XINST = Off
'DEBUG = OFF
Include "SUART.bas"
Include "ESP8266.bas"
Include "String.bas"
Include "Convert.bas"
Include "setdigitalio.bas"
{
****************************************************************************
* Purpose : Enter your own keys here!! *
****************************************************************************
}
Const
// URL = http://data.sparkfun.com/streams/PUBLICKEY
PUBLICURL = "data.sparkfun.com",
PUBLICKEY = "ENTERYOURPUBLICKEYHERE",
PRIVATEKEY = "ENTERYOURPRIVATEKEYHERE",
SSID = "ENTERYOURWIFISSIDHERE",
PASSWORD = "ENTERYOURWIFIPASSWORDHERE"
{
****************************************************************************
* Name : Main *
* Purpose : Main loop *
****************************************************************************
}
Sub Main()
Dim lastIP As TIPAddr
Dim count As Integer
Dim DataString As String(150)
Dim Timer As Word
Dim UpCount As Word
SetAllDigital()
UART.SetTX(PORTB.7)
UART.SetRX(PORTB.6)
UART.SetBaudrate(sbr19200)
UART.SetMode(umTrue)
DelayMS(5000)
UART.Write("ESP8266 Sparkfun Demo ready!", CR , LF)
UART.Write("Once connected, Data will be posted to data.sparkfun.com", CR , LF)
UART.Write("at one minute intervals.", CR , LF)
UART.Write("========================================================", CR , LF)
// Run setup stuff on the ESP8266
ESP.Setup
// Get Module version number
If ESP.GetVersion(DataString) Then
UART.Write("Version: " + DataString + CR + LF)
EndIf
DelayMS(500)
// Clear IP addresses
IPAddr.IP = $00000000
lastIP.IP = $00000000
Timer = 0
Upcount = 0
// Loop forever
While true
// Are we connected to the AP? We have an IP address if we are.
If IPAddr.IP = $00000000 Then
// Nope, connect using these credentials
ISRReset ' for safety
ESP.ConnectWifi(SSID, PASSWORD)
UART.Write("Connecting Wifi...")
EndIf
// Wait for a connection (indicated by valid IP address, not $00000000)
Count = 100
Repeat
IPAddr = CheckWifi()
Dec(count)
Until IPAddr.IP <> $00000000 Or count = 0
// Display IP if its new
If IPAddr.IP <> lastIP.IP Then
UART.Write("New IP: ")
For count = 3 To 0 Step -1
UART.Write(DecToStr(IPAddr.Val(count)))
If count > 0 Then
UART.Write(".")
EndIf
Next
UART.Write(CR, LF)
lastIP = IPAddr
EndIf
// Don't go round the loop too quickly! Note: CheckWifi has 500mS delay too
DelayMS(500)
If Timer = 0 Then
Inc(upcount)
// Connect to data.sparkfun.com at port 80
UART.Write("Connecting...")
If ConnectTCP(PUBLICURL, 80) Then
UART.Write("Connected!", CR , LF)
UART.Write("Sending Data...")
// Format our data
DataString = "GET " + "/input/" + PUBLICKEY
DataString = DataString + "?private_key=" + PRIVATEKEY
// Heres where the Vars are - check Datastring is long enough and the var names match up to the webpage (vars are lowercase)
// These are jsut examples, you could use the ADC or read another sensor
DataString = DataString +"&ip=" + DecToStr(IPAddr.Val(3)) + "." + DecToStr(IPAddr.Val(2)) + "." + DecToStr(IPAddr.Val(1)) + "." + DecToStr(IPAddr.Val(0))
DataString = DataString +"&count=" + DecToStr(Upcount)
DataString = DataString +"&porta=" + BinToStr(PORTA,8)
// Finish the string
DataString = DataString + CR + LF + CR + LF + CR + LF
// Send it off
If SendTCPData(datastring) Then
Count = GetTCPDataMode() // If it worked, did we get something back?
If Count > -1 Then // yup
'' This is an Example to spew out what we receive on usart2 - caution: CDC or software serial are too slow bytewise.
'' CDC can be done as an array
'Repeat // Receive x no of chars
' Repeat
' Until ESP.DataAvailable
' USART2.Write(ESP.ReadByte)
' Dec(Count)
'Until Count = 0
// For this example we search the return for the message "1 success", waiting 1 second
If ISRRXFind("1 success", 1000) Then
UART.Write("Data posted OK.", CR , LF)
Else
UART.Write("Failed to post data!", CR , LF)
EndIf
EndIf
Else
UART.Write("Failed to send data.", CR , LF)
EndIf
// disconnect
ESP.Disconnect()
Else
UART.Write("Timeout.", CR , LF)
EndIf
// Don't come back for a minute
Timer = 60
EndIf
Dec(Timer)
Wend
End Sub
// No libraries need init, so can call this here, if not, put into a module and call first
'Config osc = INTIO2
OSCCON = %01110100
// 18F27J53 internal oscillator mode, set pll on.
OSCTUNE.bits(6) = 1
DelayMS(100)
Main()