Tiny HTTP server controlling a DigitalOutput.

Turn LED1, or other digital output, on/off using a web browser.

In this example we create a HTTP server for the STM32F407VET6 black board that will serve a simple Web page to remotely turn LED1, or other digital output, on/off by using a web browser.

/media/uploads/hudakz/webswitch03.png/media/uploads/hudakz/webswitch_mobile01.jpg

Notice that DHCP is turned on by default. The IP address assigned to the WebSwitch server along with an instruction how to use it is printed to the connected PC's serial terminal window during program start up.
To use static IP address uncomment and adjust line #221 in main.cpp.

A DP83848 module is used as Ethernet interface.

/media/uploads/hudakz/dp83848_01.jpg

Wiring

DP83848 moduleSTM32F407VET6 board
VCC<=>+3.3V
GND<=>GND
MDIO<=>PA_2
MDC<=>PC_1
OSCIN<=>PA_1
CRS<=>PA_7
RX0<=>PC_4
RX1<=>PC_5
TX_EN<=>PB_11
TX0<=>PB_12
TX1<=>PB_13

Notice that because the RX_ER line is not used the DP83848 module doesn't have to be modified.

The project was inspired by the Tuxgraphics Web Switch. Thank you Guido!

Committer:
hudakz
Date:
Sun Nov 24 13:59:46 2019 +0000
Revision:
8:6f52a0c88bca
Parent:
7:482a6f018329
Child:
9:3716ffcf2f27
Updated.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:912fb893b03c 1 #include "mbed.h"
hudakz 0:912fb893b03c 2 #include "EthernetInterface.h"
hudakz 0:912fb893b03c 3 #include "TCPSocket.h"
hudakz 0:912fb893b03c 4 #include <stdio.h>
hudakz 0:912fb893b03c 5 #include <string>
hudakz 6:55e13e19bec3 6
hudakz 0:912fb893b03c 7 using namespace std;
hudakz 6:55e13e19bec3 8
hudakz 6:55e13e19bec3 9 #define IP "192.168.1.181"
hudakz 6:55e13e19bec3 10 #define GATEWAY "192.168.1.1"
hudakz 6:55e13e19bec3 11 #define NETMASK "255.255.255.0"
hudakz 6:55e13e19bec3 12 #define PORT 80
hudakz 0:912fb893b03c 13
hudakz 0:912fb893b03c 14 Serial pc(PC_6, PC_7);
hudakz 0:912fb893b03c 15 EthernetInterface* net;
hudakz 0:912fb893b03c 16 TCPSocket server;
hudakz 0:912fb893b03c 17 TCPSocket* clientSocket;
hudakz 0:912fb893b03c 18 SocketAddress clientAddress;
hudakz 0:912fb893b03c 19 char receiveBuf[1024] = { };
hudakz 0:912fb893b03c 20 const int OFF = 1;
hudakz 0:912fb893b03c 21 const int ON = 0;
hudakz 6:55e13e19bec3 22 DigitalOut sw(PA_6); // A switch
hudakz 6:55e13e19bec3 23 float roomTemp = 21.8; // A temperature sensor output
hudakz 6:55e13e19bec3 24 const string PASSWORD = "secret"; // change as you like
hudakz 6:55e13e19bec3 25 const string HTTP_OK = "HTTP/1.0 200 OK";
hudakz 6:55e13e19bec3 26 const string MOVED_PERM = "HTTP/1.0 301 Moved Permanently\r\nLocation: ";
hudakz 0:912fb893b03c 27 const string UNAUTHORIZED = "HTTP/1.0 401 Unauthorized";
hudakz 6:55e13e19bec3 28 string httpHeader; // HTTP header
hudakz 6:55e13e19bec3 29 string httpContent; // HTTP content
hudakz 6:55e13e19bec3 30
hudakz 0:912fb893b03c 31 /**
hudakz 7:482a6f018329 32 * @brief Defines a custom MAC address
hudakz 7:482a6f018329 33 * @note Uncomment the code below to define a unique MAC address.
hudakz 7:482a6f018329 34 * Modify the mac array items as needed.
hudakz 7:482a6f018329 35 * @param
hudakz 7:482a6f018329 36 * @retval
hudakz 7:482a6f018329 37 */
hudakz 8:6f52a0c88bca 38 //uint8_t mbed_otp_mac_address(char *mac)
hudakz 8:6f52a0c88bca 39 //{
hudakz 7:482a6f018329 40 // mac[0] = 0x00;
hudakz 7:482a6f018329 41 // mac[1] = 0x01;
hudakz 7:482a6f018329 42 // mac[2] = 0x02;
hudakz 7:482a6f018329 43 // mac[3] = 0x03;
hudakz 7:482a6f018329 44 // mac[4] = 0x04;
hudakz 7:482a6f018329 45 // mac[5] = 0x05;
hudakz 8:6f52a0c88bca 46
hudakz 8:6f52a0c88bca 47 // return 1;
hudakz 8:6f52a0c88bca 48 //}
hudakz 7:482a6f018329 49
hudakz 7:482a6f018329 50 /**
hudakz 0:912fb893b03c 51 * @brief Analyses the received URL
hudakz 0:912fb893b03c 52 * @note The string passed to this function will look like this:
hudakz 0:912fb893b03c 53 * GET /password HTTP/1.....
hudakz 0:912fb893b03c 54 * GET /password/ HTTP/1.....
hudakz 0:912fb893b03c 55 * GET /password/?sw=1 HTTP/1.....
hudakz 0:912fb893b03c 56 * GET /password/?sw=0 HTTP/1.....
hudakz 0:912fb893b03c 57 * @param url URL string
hudakz 0:912fb893b03c 58 * @retval -1 invalid password
hudakz 0:912fb893b03c 59 * -2 no command given but password valid
hudakz 0:912fb893b03c 60 * -3 just refresh page
hudakz 0:912fb893b03c 61 * 0 switch off
hudakz 0:912fb893b03c 62 * 1 switch on
hudakz 0:912fb893b03c 63 */
hudakz 6:55e13e19bec3 64 int8_t analyseURL(string& url)
hudakz 6:55e13e19bec3 65 {
hudakz 6:55e13e19bec3 66 if (url.length() < 5 + PASSWORD.size() + 1)
hudakz 5:92942d4f4ff6 67 return(-1);
hudakz 6:55e13e19bec3 68
hudakz 6:55e13e19bec3 69 if (url.substr(5, PASSWORD.size()) != PASSWORD)
hudakz 0:912fb893b03c 70 return(-1);
hudakz 6:55e13e19bec3 71
hudakz 0:912fb893b03c 72 uint8_t pos = 5 + PASSWORD.size();
hudakz 6:55e13e19bec3 73
hudakz 6:55e13e19bec3 74 if (url.substr(pos, 1) != "/")
hudakz 5:92942d4f4ff6 75 return(-1);
hudakz 5:92942d4f4ff6 76
hudakz 6:55e13e19bec3 77 if (url.substr(pos++, 1) == " ")
hudakz 0:912fb893b03c 78 return(-2);
hudakz 6:55e13e19bec3 79
hudakz 0:912fb893b03c 80 string cmd(url.substr(pos, 5));
hudakz 6:55e13e19bec3 81
hudakz 6:55e13e19bec3 82 if (cmd == "?sw=0")
hudakz 0:912fb893b03c 83 return(0);
hudakz 6:55e13e19bec3 84
hudakz 6:55e13e19bec3 85 if (cmd == "?sw=1")
hudakz 0:912fb893b03c 86 return(1);
hudakz 6:55e13e19bec3 87
hudakz 0:912fb893b03c 88 return(-3);
hudakz 0:912fb893b03c 89 }
hudakz 6:55e13e19bec3 90
hudakz 0:912fb893b03c 91 /**
hudakz 0:912fb893b03c 92 * @brief
hudakz 0:912fb893b03c 93 * @note
hudakz 0:912fb893b03c 94 * @param
hudakz 0:912fb893b03c 95 * @retval
hudakz 0:912fb893b03c 96 */
hudakz 6:55e13e19bec3 97 string& movedPermanently(uint8_t flag)
hudakz 6:55e13e19bec3 98 {
hudakz 6:55e13e19bec3 99 if (flag == 1)
hudakz 0:912fb893b03c 100 httpContent = "/" + PASSWORD + "/";
hudakz 0:912fb893b03c 101 else
hudakz 0:912fb893b03c 102 httpContent = "";
hudakz 6:55e13e19bec3 103
hudakz 0:912fb893b03c 104 httpContent += "<h1>301 Moved Permanently</h1>\r\n";
hudakz 6:55e13e19bec3 105
hudakz 0:912fb893b03c 106 return(httpContent);
hudakz 0:912fb893b03c 107 }
hudakz 6:55e13e19bec3 108
hudakz 0:912fb893b03c 109 /**
hudakz 0:912fb893b03c 110 * @brief
hudakz 0:912fb893b03c 111 * @note
hudakz 0:912fb893b03c 112 * @param
hudakz 0:912fb893b03c 113 * @retval
hudakz 0:912fb893b03c 114 */
hudakz 6:55e13e19bec3 115 string& showWebPage(uint8_t status)
hudakz 6:55e13e19bec3 116 {
hudakz 6:55e13e19bec3 117 char roomTempStr[5];
hudakz 6:55e13e19bec3 118
hudakz 0:912fb893b03c 119 //roomTemp = ds1820.read();
hudakz 0:912fb893b03c 120 sprintf(roomTempStr, "%3.1f", roomTemp);
hudakz 6:55e13e19bec3 121
hudakz 8:6f52a0c88bca 122 /*$off*/
hudakz 7:482a6f018329 123 httpContent =
hudakz 3:6edf142a16a8 124 "<head>"
hudakz 8:6f52a0c88bca 125 "<meta charset=\"utf-8\">"
hudakz 8:6f52a0c88bca 126 "<meta name=\"viewport\" content=\" initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=0;\"/>"
hudakz 8:6f52a0c88bca 127 "<title>Smart Home</title>"
hudakz 8:6f52a0c88bca 128 "<link href='http://fonts.googleapis.com/css?family=Droid+Sans&v1' rel='stylesheet' type='text/css'>"
hudakz 7:482a6f018329 129 "<style>"
hudakz 7:482a6f018329 130 ".switch {"
hudakz 7:482a6f018329 131 "position: relative;"
hudakz 7:482a6f018329 132 "display: inline-block;"
hudakz 7:482a6f018329 133 "width: 60px;"
hudakz 7:482a6f018329 134 "height: 34px;"
hudakz 7:482a6f018329 135 "}"
hudakz 7:482a6f018329 136 ".switch input {display:none;}"
hudakz 7:482a6f018329 137 ".slider {"
hudakz 7:482a6f018329 138 "position: absolute;"
hudakz 7:482a6f018329 139 "cursor: pointer;"
hudakz 7:482a6f018329 140 "top: 0;"
hudakz 7:482a6f018329 141 "left: 0;"
hudakz 7:482a6f018329 142 "right: 0;"
hudakz 7:482a6f018329 143 "bottom: 0;"
hudakz 7:482a6f018329 144 "border-radius: 34px;"
hudakz 7:482a6f018329 145 "background-color: #ccc;"
hudakz 7:482a6f018329 146 "-webkit-transition: .4s;"
hudakz 7:482a6f018329 147 "transition: .4s;"
hudakz 7:482a6f018329 148 "}"
hudakz 7:482a6f018329 149 ".slider:before {"
hudakz 7:482a6f018329 150 "position: absolute;"
hudakz 8:6f52a0c88bca 151 "content: \"\";"
hudakz 7:482a6f018329 152 "height: 26px;"
hudakz 7:482a6f018329 153 "width: 26px;"
hudakz 7:482a6f018329 154 "left: 4px;"
hudakz 7:482a6f018329 155 "bottom: 4px;"
hudakz 7:482a6f018329 156 "border-radius: 50%;"
hudakz 7:482a6f018329 157 "background-color: white;"
hudakz 7:482a6f018329 158 "-webkit-transition: .4s;"
hudakz 7:482a6f018329 159 "transition: .4s;"
hudakz 7:482a6f018329 160 "}"
hudakz 7:482a6f018329 161 "input:checked + .slider {"
hudakz 7:482a6f018329 162 "background-color: #8ce196;"
hudakz 7:482a6f018329 163 "}"
hudakz 7:482a6f018329 164 "input:focus + .slider {"
hudakz 7:482a6f018329 165 "box-shadow: 0 0 1px #8ce196;"
hudakz 7:482a6f018329 166 "}"
hudakz 7:482a6f018329 167 "input:checked + .slider:before {"
hudakz 7:482a6f018329 168 "-webkit-transform: translateX(26px);"
hudakz 7:482a6f018329 169 "-ms-transform: translateX(26px);"
hudakz 7:482a6f018329 170 "transform: translateX(26px);"
hudakz 7:482a6f018329 171 "}"
hudakz 7:482a6f018329 172 "</style>"
hudakz 7:482a6f018329 173 "</head>"
hudakz 6:55e13e19bec3 174
hudakz 3:6edf142a16a8 175 "<body>"
hudakz 7:482a6f018329 176 "<h2><a href=\".\" title=\"Click to refresh the page\">Smart Home</a></h2>"
hudakz 7:482a6f018329 177 "<pre>Temperature:\t" + string(roomTempStr) + "&deg;C</pre>"
hudakz 3:6edf142a16a8 178 "<pre>Heating:\t";
hudakz 6:55e13e19bec3 179
hudakz 8:6f52a0c88bca 180 if(status == ON) {
hudakz 7:482a6f018329 181 httpContent +=
hudakz 7:482a6f018329 182 "<a href=\"./?sw=0\" class=\"switch\"> "
hudakz 3:6edf142a16a8 183 "<input type=\"checkbox\" checked>";
hudakz 0:912fb893b03c 184 }
hudakz 0:912fb893b03c 185 else {
hudakz 7:482a6f018329 186 httpContent +=
hudakz 7:482a6f018329 187 "<a href=\"./?sw=1\" class=\"switch\"> "
hudakz 3:6edf142a16a8 188 "<input type=\"checkbox\">";
hudakz 6:55e13e19bec3 189 }
hudakz 6:55e13e19bec3 190
hudakz 7:482a6f018329 191 httpContent +=
hudakz 7:482a6f018329 192 "<div class=\"slider\"></div>"
hudakz 8:6f52a0c88bca 193 "</a>"
hudakz 8:6f52a0c88bca 194 "</pre>"
hudakz 7:482a6f018329 195 "<hr>"
hudakz 7:482a6f018329 196 "<pre>2017 ARMmbed</pre>"
hudakz 3:6edf142a16a8 197 "</body>";
hudakz 6:55e13e19bec3 198
hudakz 0:912fb893b03c 199 return httpContent;
hudakz 6:55e13e19bec3 200 /*$on*/
hudakz 0:912fb893b03c 201 }
hudakz 6:55e13e19bec3 202
hudakz 0:912fb893b03c 203 /**
hudakz 0:912fb893b03c 204 * @brief
hudakz 0:912fb893b03c 205 * @note
hudakz 0:912fb893b03c 206 * @param
hudakz 0:912fb893b03c 207 * @retval
hudakz 0:912fb893b03c 208 */
hudakz 6:55e13e19bec3 209 void sendHTTP(TCPSocket& client, string& header, string& content)
hudakz 6:55e13e19bec3 210 {
hudakz 6:55e13e19bec3 211 /*$off*/
hudakz 0:912fb893b03c 212 char content_length[5] = { };
hudakz 6:55e13e19bec3 213
hudakz 7:482a6f018329 214 header +=
hudakz 7:482a6f018329 215 "\r\nContent-Type: text/html\r\n"
hudakz 3:6edf142a16a8 216 "Content-Length: ";
hudakz 0:912fb893b03c 217 sprintf(content_length, "%d", content.length());
hudakz 7:482a6f018329 218 header +=
hudakz 7:482a6f018329 219 string(content_length) + "\r\n"
hudakz 7:482a6f018329 220 "Pragma: no-cache\r\n"
hudakz 3:6edf142a16a8 221 "Connection: About to close\r\n\r\n";
hudakz 6:55e13e19bec3 222
hudakz 0:912fb893b03c 223 string webpage = header + content;
hudakz 0:912fb893b03c 224 client.send((char*)webpage.c_str(), webpage.length());
hudakz 0:912fb893b03c 225 pc.printf("HTTP message sent to client.\n\r");
hudakz 6:55e13e19bec3 226 /*$on*/
hudakz 0:912fb893b03c 227 }
hudakz 6:55e13e19bec3 228
hudakz 0:912fb893b03c 229 /**
hudakz 0:912fb893b03c 230 * @brief
hudakz 0:912fb893b03c 231 * @note
hudakz 0:912fb893b03c 232 * @param
hudakz 0:912fb893b03c 233 * @retval
hudakz 0:912fb893b03c 234 */
hudakz 6:55e13e19bec3 235 int main(void)
hudakz 6:55e13e19bec3 236 {
hudakz 8:6f52a0c88bca 237 pc.baud(115200);
hudakz 0:912fb893b03c 238 pc.printf("Starting.. \r\n\r\n");
hudakz 6:55e13e19bec3 239
hudakz 0:912fb893b03c 240 net = new EthernetInterface();
hudakz 0:912fb893b03c 241
hudakz 0:912fb893b03c 242 if (!net) {
hudakz 0:912fb893b03c 243 pc.printf("Error! No network inteface found.\n");
hudakz 0:912fb893b03c 244 return 0;
hudakz 0:912fb893b03c 245 }
hudakz 0:912fb893b03c 246
hudakz 0:912fb893b03c 247 //net->set_network (IP, NETMASK, GATEWAY); // include this for using static IP address
hudakz 6:55e13e19bec3 248 nsapi_size_or_error_t r = net->connect();
hudakz 7:482a6f018329 249
hudakz 0:912fb893b03c 250 if (r != 0) {
hudakz 0:912fb893b03c 251 pc.printf("Error! net->connect() returned: %d\n", r);
hudakz 0:912fb893b03c 252 return r;
hudakz 0:912fb893b03c 253 }
hudakz 0:912fb893b03c 254
hudakz 6:55e13e19bec3 255 // Show the network address
hudakz 8:6f52a0c88bca 256 const char* mac = net->get_mac_address();
hudakz 8:6f52a0c88bca 257 const char* ip = net->get_ip_address();
hudakz 8:6f52a0c88bca 258 const char* netmask = net->get_netmask();
hudakz 8:6f52a0c88bca 259 const char* gateway = net->get_gateway();
hudakz 8:6f52a0c88bca 260
hudakz 8:6f52a0c88bca 261 pc.printf("MAC address: %s\r\n", mac ? mac : "None");
hudakz 0:912fb893b03c 262 pc.printf("IP address: %s\r\n", ip ? ip : "None");
hudakz 0:912fb893b03c 263 pc.printf("Netmask: %s\r\n", netmask ? netmask : "None");
hudakz 6:55e13e19bec3 264 pc.printf("Gateway: %s\r\n\r\n", gateway ? gateway : "None");
hudakz 0:912fb893b03c 265 pc.printf("Usage: Type %s/%s/ into your web browser and hit ENTER\r\n\r\n", ip, PASSWORD.c_str());
hudakz 6:55e13e19bec3 266
hudakz 0:912fb893b03c 267 /* Open the server on ethernet stack */
hudakz 0:912fb893b03c 268 server.open(net);
hudakz 6:55e13e19bec3 269
hudakz 0:912fb893b03c 270 /* Bind the HTTP port (TCP 80) to the server */
hudakz 0:912fb893b03c 271 server.bind(ip, PORT);
hudakz 6:55e13e19bec3 272
hudakz 0:912fb893b03c 273 /* Can handle 5 simultaneous connections */
hudakz 0:912fb893b03c 274 server.listen(5);
hudakz 6:55e13e19bec3 275
hudakz 0:912fb893b03c 276 //listening for http GET request
hudakz 6:55e13e19bec3 277 while (true) {
hudakz 0:912fb893b03c 278 pc.printf("=========================================\r\n");
hudakz 6:55e13e19bec3 279
hudakz 6:55e13e19bec3 280 nsapi_error_t error;
hudakz 7:482a6f018329 281
hudakz 0:912fb893b03c 282 clientSocket = server.accept(&error);
hudakz 0:912fb893b03c 283 if (error != 0) {
hudakz 0:912fb893b03c 284 pc.printf("Connection failed!\r\n");
hudakz 5:92942d4f4ff6 285 clientSocket->close();
hudakz 0:912fb893b03c 286 continue;
hudakz 0:912fb893b03c 287 }
hudakz 6:55e13e19bec3 288
hudakz 0:912fb893b03c 289 clientSocket->getpeername(&clientAddress);
hudakz 0:912fb893b03c 290 pc.printf("Client with IP address %s connected.\r\n\r\n", clientAddress.get_ip_address());
hudakz 0:912fb893b03c 291 clientSocket->recv(receiveBuf, 1023);
hudakz 0:912fb893b03c 292 pc.printf("Data received:\r\n%s\n\r", receiveBuf);
hudakz 6:55e13e19bec3 293
hudakz 0:912fb893b03c 294 string received(receiveBuf);
hudakz 6:55e13e19bec3 295
hudakz 6:55e13e19bec3 296 if (received.substr(0, 3) != "GET") {
hudakz 0:912fb893b03c 297 httpHeader = HTTP_OK;
hudakz 0:912fb893b03c 298 httpContent = "<h1>200 OK</h1>";
hudakz 0:912fb893b03c 299 sendHTTP(*clientSocket, httpHeader, httpContent);
hudakz 5:92942d4f4ff6 300 clientSocket->close();
hudakz 0:912fb893b03c 301 continue;
hudakz 0:912fb893b03c 302 }
hudakz 6:55e13e19bec3 303
hudakz 6:55e13e19bec3 304 if (received.substr(0, 6) == "GET / ") {
hudakz 0:912fb893b03c 305 httpHeader = HTTP_OK;
hudakz 0:912fb893b03c 306 httpContent = "<p>Usage: Type http://ip_address/password/ into your web browser and hit ENTER</p>\r\n";
hudakz 0:912fb893b03c 307 sendHTTP(*clientSocket, httpHeader, httpContent);
hudakz 5:92942d4f4ff6 308 clientSocket->close();
hudakz 0:912fb893b03c 309 continue;
hudakz 0:912fb893b03c 310 }
hudakz 6:55e13e19bec3 311
hudakz 0:912fb893b03c 312 int cmd = analyseURL(received);
hudakz 6:55e13e19bec3 313
hudakz 8:6f52a0c88bca 314 switch (cmd) {
hudakz 8:6f52a0c88bca 315 case -3:
hudakz 8:6f52a0c88bca 316 httpHeader = HTTP_OK;
hudakz 8:6f52a0c88bca 317 break;
hudakz 8:6f52a0c88bca 318
hudakz 8:6f52a0c88bca 319 case -2:
hudakz 8:6f52a0c88bca 320 // redirect to the right base url
hudakz 8:6f52a0c88bca 321 httpHeader = MOVED_PERM;
hudakz 8:6f52a0c88bca 322 break;
hudakz 8:6f52a0c88bca 323
hudakz 8:6f52a0c88bca 324 case -1:
hudakz 8:6f52a0c88bca 325 httpHeader = UNAUTHORIZED;
hudakz 8:6f52a0c88bca 326 httpContent = "<h1>401 Unauthorized</h1>";
hudakz 8:6f52a0c88bca 327 break;
hudakz 8:6f52a0c88bca 328
hudakz 8:6f52a0c88bca 329 case 0:
hudakz 8:6f52a0c88bca 330 httpHeader = HTTP_OK;
hudakz 8:6f52a0c88bca 331 sw = OFF; // turn the switch off
hudakz 8:6f52a0c88bca 332 break;
hudakz 8:6f52a0c88bca 333
hudakz 8:6f52a0c88bca 334 case 1:
hudakz 8:6f52a0c88bca 335 httpHeader = HTTP_OK;
hudakz 8:6f52a0c88bca 336 sw = ON; // turn the switch on
hudakz 8:6f52a0c88bca 337 break;
hudakz 0:912fb893b03c 338 }
hudakz 6:55e13e19bec3 339
hudakz 0:912fb893b03c 340 sendHTTP(*clientSocket, httpHeader, showWebPage(sw));
hudakz 0:912fb893b03c 341 clientSocket->close();
hudakz 0:912fb893b03c 342 }
hudakz 0:912fb893b03c 343 }