W5200: Possible Gotcha & Fix
twc
Posts: 107
Hey Mike:
I've been experimenting & stress testing, came across an issue but think I have a fix.
In tens words or less it appears buff can overrun by a byte if the wiz buffer fills up. I discovered the problem when I was moving stuff around and using a variable for a website name. At some point I ended up with...
...and then I started experiencing intermittent failures with the DNS portion of REPEATed DHCP-DNS-TCP stress test. Looking closer I could see the first byte of the site variable getting clobbered...
Below is code I think you can use to confirm. It's essentially the TCSDDD demo modified to REPEAT the entire DHCP-DNS-TCP sequence.
On my setup the first byte of the site variable gets clobbered as above on the second iteration. If you look down in the code you can see the way I force it fail by inserting a pause after the GET insuring the wiz buffer fills with 2KB...
...note that, on my setup, taking out the pause will generally allow the loop to work but it eventually fails (I think depending whether the wiz buffer happens to fill). As well, reversing the order of the site and buff variable declaration allows the loop to run - in this case I think buff+1 may have been clobbering the next var in line (t1) but gone unnoticed.
I've tried this fix...
...and it seems to be working but don't know if it's as simple as that.
Otherwise software seems rock solid, I've run thousands of DHCP-DNS-TCP test cycles at this point.
I've been experimenting & stress testing, came across an issue but think I have a fix.
In tens words or less it appears buff can overrun by a byte if the wiz buffer fills up. I discovered the problem when I was moving stuff around and using a variable for a website name. At some point I ended up with...
buff byte $0[BUFFER_2K] site byte "finance.google.com", $0
...and then I started experiencing intermittent failures with the DNS portion of REPEATed DHCP-DNS-TCP stress test. Looking closer I could see the first byte of the site variable getting clobbered...
Getting network parameters Requesting IP.....10.0.0.157 Lease Time........86400 DNS...............10.0.0.1 DHCP Server.......10.0.0.1 Router............10.0.0.1 Gateway...........10.0.0.1 DNS Init (bool)...-1 DNS Lookup........finance.google.com Resolved IP(0)....74.125.224.64 Resolved IPs......11 Initialize Socket Begin Client Web Request Connecting to.....74.125.224.64 Sending HTTP Request Bytes Sent........99 Bytes Received....7066 Disconnect Getting network parameters Requesting IP.....10.0.0.157 Lease Time........86400 DNS...............10.0.0.1 DHCP Server.......10.0.0.1 Router............10.0.0.1 Gateway...........10.0.0.1 DNS Init (bool)...-1 DNS Lookup........ Resolved IP(0)....0.0.0.0 00 69 i 6E n 61 a 6E n 63 c 65 e 2E . 67 g
Below is code I think you can use to confirm. It's essentially the TCSDDD demo modified to REPEAT the entire DHCP-DNS-TCP sequence.
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 { Protocol } #0, CLOSED, TCP, UDP, IPRAW, MACRAW, PPPOE { PST Display } CR = $0D LF = $0A BUFFER_2K = $800 ATTEMPTS = 5 { Serial IO PINs } USB_Rx = 31 USB_Tx = 30 { Run time DHCP and DNS socket paramters } DHCP_SOCKET = 7 DNS_SOCKET = 6 VAR DAT request byte "GET /index.htm HTTP/1.1", CR, LF, { } byte "User-Agent: Wiz5200", CR, LF, CR, LF, $0 request2 byte "GET /default.aspx HTTP/1.1", CR, LF, { } byte "Host: agaverobotics.com", CR, LF, { } byte "User-Agent: Wiz5200", CR, LF, CR, LF, $0 google byte "GET /finance/historical?q=FB&output=csv HTTP/1.1", CR, LF, { } byte "Host: finance.google.com", CR, LF, { } byte "User-Agent: Wiz5200", CR, LF, CR, LF, $0 weather byte "GET / HTTP/1.1", CR, LF, { } byte "Host: [URL="http://www.weather.gov"]www.weather.gov[/URL]", CR, LF, { } byte "User-Agent: Wiz5200", CR, LF, CR, LF, $0 buff byte $0[BUFFER_2K] site byte "finance.google.com", $0 t1 long $0 null long $00 OBJ pst : "Parallax Serial Terminal" wiz : "W5200" sock : "Socket" dhcp : "Dhcp" dns : "Dns" PUB Main | bytesToRead, buffer, bytesSent, receiving, remoteIP, dnsServer, totalBytes, i, dnsInit if(ina[USB_Rx] == 0) '' Check to see if USB port is powered outa[USB_Tx] := 0 '' Force Propeller Tx line LOW if USB not connected else '' Initialize normal serial communication to the PC here pst.Start(115_200) '' [URL]http://forums.parallax.com/showthread.php?135067-Serial-Quirk&p=1043169&viewfull=1#post1043169[/URL] pause(500) pst.str(string("Initialize W5200", CR)) wiz.QS_Init 'Loop until we get the W5200 version 'This lets us know if the W5200 is ready to go i := 0 repeat until wiz.GetVersion > 0 pause(250) if(i++ > ATTEMPTS*5) pst.str(string(CR, "SPI communication failed!", CR)) return pst.str(string("WizNet 5200 Ver: ") ) pst.dec(wiz.GetVersion) pst.char(CR) wiz.SetMac($00, $08, $DC, $17, $62, $ca) REPEAT receiving := true bytesToRead := 0 dnsInit := 0 pst.str(string("Getting network parameters", CR)) dhcp.Init(@buff, DHCP_SOCKET) ' pst.str(string("--------------------------------------------------", CR)) 'SetRequestIp allows us to request a specific IP - No guarentee 'dhcp.SetRequestIp(192, 168, 1, 110) ' t1:=0 pst.str(string("Requesting IP.....")) repeat until dhcp.DoDhcp(true) if(++t1 > ATTEMPTS) quit if(t1 > ATTEMPTS) pst.char(CR) pst.str(string(CR, "DHCP Attempts: ")) pst.dec(t1) pst.str(string(CR, "Error Code: ")) pst.dec(dhcp.GetErrorCode) pst.char(CR) pst.str(dhcp.GetErrorMessage) pst.char(CR) return else PrintIp(dhcp.GetIp) { Stress test repeat pst.str(string("Requesting IP.....")) t1 := 0 'wiz.SetIp(0,0,0,0) repeat until dhcp.RenewDhcp if(++t1 > ATTEMPTS) quit if(t1 > ATTEMPTS) pst.char(CR) pst.str(string(CR, "DHCP Attempts: ")) pst.dec(t1) pst.str(string(CR, "Error Code: ")) pst.dec(dhcp.GetErrorCode) pst.char(CR) pst.str(dhcp.GetErrorMessage) pst.char(CR) return else PrintIp(dhcp.GetIp) 'pause(2000) } pst.str(string("Lease Time........")) pst.dec(dhcp.GetLeaseTime) pst.char(CR) pst.str(string("DNS...............")) dnsServer := wiz.GetDns PrintIp(wiz.GetDns) pst.str(string("DHCP Server.......")) printIp(dhcp.GetDhcpServer) pst.str(string("Router............")) printIp(dhcp.GetRouter) pst.str(string("Gateway...........")) printIp(wiz.GetGatewayIp) pst.char(CR) pst.str(string("DNS Init (bool)...")) pst.dec(dns.Init(@buff, DNS_SOCKET)) pst.char(CR) pst.str(string("DNS Lookup........")) pst.str(@site) pst.str(string(CR,"Resolved IP(0)....")) 'remoteIP := dns.ResolveDomain(string("[URL="http://www.agaverobotics.com"]www.agaverobotics.com[/URL]")) remoteIP := dns.ResolveDomain(@site) 'remoteIP := dns.ResolveDomain(string("[URL="http://www.weather.gov"]www.weather.gov[/URL]")) PrintIp(remoteIP) if (byte[remoteIP][0] + byte[remoteIP][1] + byte[remoteIP][2] + byte[remoteIP][3]) == 0 REPEAT i from 0 to 17 pst.hex(byte[@site][i],2) pst.char(" ") pst.char(byte[@site][i]) pst.char(CR) return pst.str(string("Resolved IPs......")) pst.dec(dns.GetIpCount) pst.char(13) pst.char(13) 'remoteIP := dns.GetResolvedIp(1) pst.str(string("Initialize Socket")) sock.Init(0, TCP, 8080) sock.RemoteIp(byte[remoteIP][0], byte[remoteIP][1], byte[remoteIP][2], byte[remoteIP][3]) sock.RemotePort(80) 'PrintIp(wiz.GetRemoteIP(0)) pst.str(string(CR, "Begin Client Web Request", CR)) 'wiz.setGateway(0,0,0,0) 'Client 'pst.str(string("Open Socket", CR)) sock.Open sock.Connect pst.str(string("Connecting to.....")) PrintIp(wiz.GetRemoteIP(0)) pst.char(CR) 'Connection? repeat until sock.Connected pause(100) pst.str(string("Sending HTTP Request", CR)) 'bytesSent := sock.Send(@request2, strsize(@request2)) bytesSent := sock.Send(@google, strsize(@google)) 'bytesSent := sock.Send(@weather, strsize(@weather)) pst.str(string("Bytes Sent........")) pst.dec(bytesSent) pst.char(13) pause(3000) 'wait for wiz buff to fill totalBytes := 0 repeat while receiving 'Data in the buffer? bytesToRead := sock.Available totalBytes += bytesToRead 'Check for a timeout if(bytesToRead < 0) receiving := false pst.str(string("Timeout", CR)) ' return if(bytesToRead == 0) receiving := false 'pst.str(string(CR, "Done Receiving Response", CR)) next if(bytesToRead > 0) 'Get the Rx buffer buffer := sock.Receive(@buff, bytesToRead) ' pst.str(buffer) bytesToRead~ pst.str(string("Bytes Received....")) pst.dec(totalBytes) pst.char(CR) pst.str(string("Disconnect", CR, CR)) sock.Disconnect pause(5000) PUB DisplayMemory(addr, len, isHex) | j pst.str(string(13,"-----------------------------------------------------",13)) pst.str(string(13, " ")) repeat j from 0 to $F pst.hex(j, 2) pst.char($20) pst.str(string(13, " ")) repeat j from 0 to $F pst.str(string("-- ")) pst.char(13) repeat j from 0 to len if(j == 0) pst.hex(0, 4) pst.char($20) pst.char($20) if(isHex) pst.hex(byte[addr + j], 2) else if(byte[addr+j] < $20 OR byte[addr+j] > $7E) if(byte[addr+j] == 0) pst.char($20) else pst.hex(byte[addr+j], 2) else pst.char($20) pst.char(byte[addr+j]) pst.char($20) if((j+1) // $10 == 0) pst.char($0D) pst.hex(j+1, 4) pst.char($20) pst.char($20) pst.char(13) pst.char(13) pst.str(string("Start: ")) pst.dec(addr) pst.str(string(" Len: ")) pst.dec(len) pst.str(string(13,"-----------------------------------------------------",13,13)) PUB PrintIp(addr) | i i := 0 repeat i from 0 to 3 pst.dec(byte[addr][i] & $FF) if(i < 3) pst.char($2E) else pst.char($0D) PRI pause(Duration) waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt) return
On my setup the first byte of the site variable gets clobbered as above on the second iteration. If you look down in the code you can see the way I force it fail by inserting a pause after the GET insuring the wiz buffer fills with 2KB...
pst.str(string("Sending HTTP Request", CR)) 'bytesSent := sock.Send(@request2, strsize(@request2)) bytesSent := sock.Send(@google, strsize(@google)) 'bytesSent := sock.Send(@weather, strsize(@weather)) pst.str(string("Bytes Sent........")) pst.dec(bytesSent) pst.char(13) pause(3000) 'make sure wiz buf fills totalBytes := 0 repeat while receiving
...note that, on my setup, taking out the pause will generally allow the loop to work but it eventually fails (I think depending whether the wiz buffer happens to fill). As well, reversing the order of the site and buff variable declaration allows the loop to run - in this case I think buff+1 may have been clobbering the next var in line (t1) but gone unnoticed.
I've tried this fix...
BUFFER_2K = $801
...and it seems to be working but don't know if it's as simple as that.
Otherwise software seems rock solid, I've run thousands of DHCP-DNS-TCP test cycles at this point.
Comments
Is the $800+1 byte always the same value?
1000 passes is not too shabby.