This tutorial was extracted from Erich Styger blog http://mcuoneclipse.wordpress.com with his agreement.
This is Part 3 of an ongoing tutorial to use the Arduino Ethernet Shield R3 with a Freescale FRDM-KL25Z board (or any other board you like).
In Part 1 I worked on the SD card, in Part 2 I have added basic network connection. Now time to run a web server with my FRDM-KL25ZFRDM-KL25Z . With this, I can get access to my board through the network, and the board will host a web page where I can do pretty much everything: showing status, or adding functions to turn on things like an LED.
List of Tutorials
- FRDM with Arduino Ethernet Shield R3, Part 1: SD Card
- FRDM with Arduino Ethernet Shield R3, Part 2: Ping
- FRDM with Arduino Ethernet Shield R3, Part 3: Embedded Web Server
W5100 as Web Server
The Wiznet W5100 Ethernet Chip on the Arduino Ethernet Shield R3Arduino Ethernet Shield R3 makes it easy to host a web server with a small microcontroller: the heavy protocol lifting is implemented in the W5100.
FRDM-KL25Z running Embedded Web Server with W5100
To make a web server, I need 3 things to do:
- Initialize the W5100
- Using Sockets
- Host an HTML web server
There are many good tutorials around this subject available. I recommend “Integrating Wiznet W5100, WIZ811MJ network module with Atmel AVR Microcontroller” as this article describes very nicely the features of the device and how the socket interface works. The example used in that article implements only one socket, while I have extended it to support up to four sockets of the device with the help of this article: “Wiznet 5100 library for ATmega devices“.
Initialization
First, the W5100 needs to be initialized:
- Reset the device
- Configure the network address and gateway
- Set up the total 8 KByte send and receive buffers for the 4 sockets
All the source files are available on GitHub.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Sockets
The W5100 supports up to 4 sockets. For this I have ‘sockets.h’ and ‘sockets.c’.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
|
The implementation uses the W5100 low-level driver I presented in Part 2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
|
Web Server
The web server ‘task’ gets called from the application main loop:
- It gets the status from the socket: If the socket is closed, it opens the socket with TCP protocol on the HTTP port (80), and then listens to the socket.
- Once a communication connection is established, it checks how many bytes has been received and reads them into a buffer. If there is data, it inspects the data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
Communication between Client and Server
To display a page from our web server in a client (a web browser, such as FireFox), the following happens:
- Enter the address of the board in the browser (e.g. http://192.168.0.12)
- The browser connects to the socket I have created with
SOCK_OpenSocket()
and which is listening to the incoming requests with SOCK_Listen(). By default it uses the standard TCP/IP port 80 (standard HTTP server port). - In the server, I get a
W5100_SOCK_ESTABLISHED
status. - The browser sends an HTTP “GET“or “POST” request to the server. With
SOCK_ReceivedSize()
the server knows the size of the request, and withSOCK_Receive()
the server can get the data from the socket.
GET Request
The client is sending a GET request to retrieve the HTML text to display.
HTTP GET Request
A GET is sent as well if I do a refresh in the web browser. The text of the GET request is what I get from the socket using SOCK_Receive()
, and looks like this, with a “GET /” at the beginning:
GET / HTTP/1.1 Host: 192.168.0.80 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Connection: keep-alive
The web server responds to this with the HTML code. And this is done in my server implementation with this function SendPage().
Because that source code contains HTML code, WordPress was not able to properly show the source code here. Have look in the Server.c on GitHub.
This constructs the HTML code for my page, which then looks like this:
Web Server with W5100 on FRDM-KL25Z
At the end, it performs a disconnect of the socket so other clients can connect to that socket.
POST Request
A POST request is sent by the client for that ‘Submit Query’ button: it will send me the state of the radio buttons so I can turn the red LED on or off.
HTTP Post
Such a POST message looks like this:
POST / HTTP/1.1 Host: 192.168.0.80 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Referer: http://192.168.0.80/ Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 7 radio=0
Depending on which radio button is selected, there is “radio=0″ or “radio=1″ in the message. So for such a POST message, the web server needs to
- Detect that it is a POST message (this is known by the “POST /” at the beginning)
- Find the “radio=” in the message.
strFind()
To find such substrings in the message, I have implemented a simple ‘search substring inside a string and return the position’. This function I have put into my utility component:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Checkin the HTML Data from the Client
The last piece of the server is the function to find the “GET” and “POST” messages, and then to send the result back to the client:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
For debugging purposes I print the received message to the console.
Putting everything together
Oh, one thing is missing: how to call the server processing function. I do this in my application inside a FreeRTOS task, but that can be done easily without an RTOS too:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | static portTASK_FUNCTION(Task1, pvParameters) {
|
With this I have a functional web server on my FRDM-KL25Z board. I can use it to give status, but with the POST commands I can do actions (e.g. turning on or off an LED, etc).
Summary
The combination of the Arduino Ethernet Shield with the FRDM-KL25Z makes a web server implementation very easy. With this, I can use and control the board through the network, a first and simple step into the IoT (Internet of Things)
The current project is available on GitHub here.
Other ideas for a continuation of this series:
- Having the HTML pages with Java scripts and images on the SD card
- Adding easier network integration, like using DHCP instead of static IP addresses