.NET MF code:
using System;
using Microsoft.SPOT;
using GHI.Networking;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Text;
using GHI.Processor;
using System.Diagnostics;
namespace G120E_Ethernet_Test
{
public class Program
{
public static void Main()
{
// Open ethernet interface
EthernetBuiltIn eth = new EthernetBuiltIn();
eth.Open();
eth.EnableDhcp();
eth.EnableDynamicDns();
// Setup registers that we will look at later
uint base_address = 0x20084000;
Register IntStatus = new Register(base_address + 0xFE0);
Register TxDescriptor = new Register(base_address + 0x11C);
Register TxStatus = new Register(base_address + 0x120);
Register TxProduceIndex = new Register(base_address + 0x128);
Register TxConsumeIndex = new Register(base_address + 0x12C);
Register TxDescriptorNumber = new Register(base_address + 0x124);
uint N_Tx_descriptors = TxDescriptorNumber.Value + 1; // TXDESCRIPTORNUMBER uses minus 1 encoding
Register[] Tx_StatusInfo = new Register[N_Tx_descriptors];
for (uint i = 0; i < N_Tx_descriptors; i++)
{
Tx_StatusInfo[i] = new Register(TxStatus.Value + i * 4); // Every 4 bytes, starting at value of TXSTATUS
}
// Wait for DHCP address
while (eth.IPAddress == "0.0.0.0")
{
Debug.Print("Waiting for DHCP");
Thread.Sleep(250);
}
Debug.Print(DateTime.Now.Ticks + "\tUsing IP address " + eth.IPAddress);
// Listen for connections on TCP port 23
Socket listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listen.Bind(new IPEndPoint(IPAddress.Any, 23));
listen.Listen(1);
Socket conversation = listen.Accept();
Debug.Print(DateTime.Now.Ticks + "\tConnection from " + conversation.RemoteEndPoint);
// Conversation
conversation.ReceiveTimeout = 1000;
int N_bytes;
byte[] receive_buffer = new byte[80];
byte[] send_buffer;
uint IntStatus_value;
uint TxProduceIndex_value;
uint TxConsumeIndex_value;
uint[] Tx_StatusInfo_value = new uint[N_Tx_descriptors];
while (true)
{
try
{
// Receive command from PC
N_bytes = conversation.Receive(receive_buffer);
string text = new String(Encoding.UTF8.GetChars(receive_buffer, 0, N_bytes));
Debug.Print(DateTime.Now.Ticks + "\tReceived \"" + text.Trim() + "\"");
// Send response to PC
text = "Response to " + text;
send_buffer = Encoding.UTF8.GetBytes(text);
conversation.Send(send_buffer);
Debug.Print(DateTime.Now.Ticks + "\tSent \"" + text.Trim() + "\"");
}
catch (SocketException x)
{
if (x.ErrorCode == 10060)
{
// Quickly get the values of the registers
IntStatus_value = IntStatus.Value;
TxProduceIndex_value = TxProduceIndex.Value;
TxConsumeIndex_value = TxConsumeIndex.Value;
for (int i = 0; i < N_Tx_descriptors; i++)
{
Tx_StatusInfo_value[i] = Tx_StatusInfo[i].Value;
}
// Print out a message to console
string message = DateTime.Now.Ticks + "\tTimeout receiving next command" +
"\r\n\tIntStatus\t" + IntStatus_value +
"\r\n\tTxConsumeIndex\t"+ TxConsumeIndex_value;
for (int i = 0; i < N_Tx_descriptors; i++)
{
message += "\r\n\tTx_StatusInfo[" + i + "]\t" + Tx_StatusInfo_value[i];
}
Debug.Print(message);
; // Can set breakpoint here for further investigation
}
else
{
Debug.Print(DateTime.Now.Ticks + "\t" + x.Message);
}
}
catch (Exception x)
{
Debug.Print(DateTime.Now.Ticks + "\t" + x.Message);
}
}
}
}
}
PC code:
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace G120_Ethernet_Test_PC
{
class Program
{
static void Main(string[] args)
{
// Connect to G120E
IPAddress remote_ip = new IPAddress(new byte[] { 192, 168, 0, 3 });
IPEndPoint remote_endpoint = new IPEndPoint(remote_ip, 23);
TcpClient client = new TcpClient();
client.Connect(remote_endpoint);
Console.WriteLine(DateTime.Now.Ticks + "\tConnected to " + remote_endpoint);
// Network stream
NetworkStream stream = client.GetStream();
StreamWriter Out = new StreamWriter(stream) { AutoFlush = true };
StreamReader In = new StreamReader(stream);
// Conversation
for (int i = 0; i < 1000; i++)
{
// Send request
string text = "Request " + i;
Out.WriteLine(text);
Console.WriteLine(DateTime.Now.Ticks + "\tSent \"" + text + "\"");
// Receive response
text = In.ReadLine();
Console.WriteLine(DateTime.Now.Ticks + "\tReceived \"" + text + "\"");
}
}
}
}
When the issue occurs, the G120E will have sent the response and be waiting for the next request. The PC will still be waiting for the previous response before sending the next request.
The output from the programs will look something like this (I added the time deltas in parenthesis in post-processing):
PC:
636465214035412000 Sent "Request 480" (+ 0 ms)
636465214038490000 Received "Response to Request 480" (+ 308 ms)
636465214038490000 Sent "Request 481" (+ 0 ms)
636465214038605000 Received "Response to Request 481" (+ 12 ms)
636465214038605000 Sent "Request 482" (+ 0 ms)
<timeout messages, see below>
636465214078911000 Received "Response to Request 482" (+ 4,031 ms)
636465214078911000 Sent "Request 483" (+ 0 ms)
636465214078986000 Received "Response to Request 483" (+ 8 ms)
636465214078986000 Sent "Request 484" (+ 0 ms)
636465214082069000 Received "Response to Request 484" (+ 308 ms)
G120E:
129513680755275000 Received "Request 480" (+ 303 ms)
129513680755324000 Sent "Response to Request 480" (+ 5 ms)
129513680755395000 Received "Request 481" (+ 7 ms)
129513680755442000 Sent "Response to Request 481" (+ 5 ms)
129513680755513000 Received "Request 482" (+ 7 ms)
129513680755562000 Sent "Response to Request 482" (+ 5 ms)
129513680795774000 Received "Request 483" (+ 4,021 ms)
129513680795823000 Sent "Response to Request 483" (+ 5 ms)
129513680798856000 Received "Request 484" (+ 303 ms)
129513680798905000 Sent "Response to Request 484" (+ 5 ms)
Wireshark:
Relative Time Source Destination Telnet
33.349484 192.168.0.2 192.168.0.3 Request 480\\r\\n (+ 0 ms)
33.657255 192.168.0.3 192.168.0.2 Response to Request 480\\r\\n (+ 308 ms)
33.657354 192.168.0.2 192.168.0.3 Request 481\\r\\n (+ 0 ms)
33.669035 192.168.0.3 192.168.0.2 Response to Request 481\\r\\n (+ 12 ms)
33.669096 192.168.0.2 192.168.0.3 Request 482\\r\\n (+ 0 ms)
37.699325 192.168.0.3 192.168.0.2 Response to Request 482\\r\\n (+ 4,030 ms)
37.699451 192.168.0.2 192.168.0.3 Request 483\\r\\n (+ 0 ms)
37.706969 192.168.0.3 192.168.0.2 Response to Request 483\\r\\n (+ 8 ms)
37.70705 192.168.0.2 192.168.0.3 Request 484\\r\\n (+ 0 ms)
38.015173 192.168.0.3 192.168.0.2 Response to Request 484\\r\\n (+ 308 ms)
In this case, it took the G120E only 5 ms to send response #482, but over 4 seconds for it to appear on the network and for the PC program to receive it.
When the long delay happened, the G120E additionally wrote out the following register values:
129513680767124827 Timeout receiving next command
IntStatus 98
TxConsumeIndex 0
Tx_StatusInfo[0] 0
Tx_StatusInfo[1] 0
Tx_StatusInfo[2] 2684354560
A value of 98 in the IntStatus register means that the TXERRORINT bit (bit 5) is set, meaning “Interrupt trigger on transmit errors: LateCollision, ExcessiveCollision and ExcessiveDefer, NoDescriptor or Underrun.” (see Table 189 on page 236 of the LPC1788 User Manual, UM10470, Rev. 3.1 — 15 September 2014)
The last Tx descriptor to be sent was #2, and it TxConsumeIndex wrapped around to the current value of 0. The StatusInfo value for Tx descriptor 2 was 2684354560, meaning that UNDERRUN (bit 29) and ERROR (bit 31) are set. (see Table 202 on page 245)
The UNDERRUN means “A Tx underrun occurred due to the adapter not producing transmit data.”
ERROR is simply a logical or of several error conditions, including the underrun.