making a http server with mcu sdk (and a dhcp server too) todd mullanix
TRANSCRIPT
Making a HTTP Server with MCU SDK(and a DHCP Server too)
Todd Mullanix
2
TCP/IP Stack
Stack EventScheduler
NetworkInitialization
NetworkService
Manager
OSAdaptation
Layer
Hardware
EthernetPacketDriver
NAT
IFManager
RouteManager
SerialPort
Driver
TimerDriver
UserLED
Driver
Hardware Adaptation Layer
Ethernet IF
ARP
IP
TCP UDP ICMP IGMP
Standard BSD Sockets Interface
HTTP
TFTP
TELNET
DNS
DHCP
CONFIGURATION
Supports both IPv4 and IPv6
DHCP Client and Server
HTTP Server
Standard BSD Sockets interface
Zero-copy sockets interface available
Highly configurable to meet footprint constraints
Example on how to create daemon task required by TCP/IP stacks
TCP/IP Key Features
Let’s Make a WebServer!
Steps
• Create and build new “empty” project
• Load and debug the empty project
• Add in Networking stack
• Add HTTP pages
• Add in a DHCP Server
3
Creating an Empty Project
First let’s create an empty project via the CCS Project Wizard.
Doing “File->New->CCS Project” will start the wizard on the right.
You need to
1. Give the project a unique name
2. Select the Family and Variant
3. Select the Connection (optional, but we’ll use this later)
4. Select the MCU SDK Empty project for Concerto (TMDXDOCKH52C1)
Hit “Next”
4
Creating an Empty Project
This page shows which software is being used. Note: MCU SDK automatically includes SYS/BIOS, NDK, Ipc, UIA and *Ware. So you do not need to specify them.
Hit “Finish”
5
Creating an Empty Project
Once the new project is created, select “Properties” to get the following window.
This is the place to change compiler and linker options and other settings. The General page shows the product software configuration (again).
6
Building the httpServer Project
• Let’s look at the files in the new project – empty.c: main source file– empty.cfg: main configuration file– TMDXDOCKH52C1.c: board specific peripheral runtime
configuration– TMDXDOCKH52C1.h: header file for board specific peripheral
runtime configuration APIs– TMDXDOCKH52C1.cmd: Linker command file– Board.h: Small “shim” header file to make board specific APIs
generic.– F28M35H52C1.ccxml: Target Configuration file.
• Build project (right click, Project menu or build icon ) – Build output goes to the console window– One warning that we are working on removing for the GA release of MCU SDK.– After the build is successful, if asked, do not load the application yet.
7
Let’s Make a WebServer!
Steps
• Create and build new “empty” project
• Loading and debugging the empty project
• Add in Networking stack
• Add HTTP pages
• Add in a DHCP Server
8
Loading the Project
• Debug the application. This will do the following:– Launch the Debug session– Connect to the M3– Load the application
9
Run the project• Run.
You’ll probably halt in main(). This is configurable via the Tools->Debugger Options->Generic Debugger Options
• Open RTOS Object View (Tools->ROV)
Look at HeapMem and Task (shown below)
• Open System Anaylzer (Tools->System Analyzer->Live) and select Start
One event at this point. Notice that the Task handle address corresponds to the Idle Task shown in ROV above.
10
Debug Information
• Resume
• Suspend
• Look at System Analyzer’s Live Session
The LoggingSetup module is controlling what gets logged. We’ll look more at this later when there is more interesting data…
11
Let’s Make a WebServer!
Steps
• Create and build new “empty” project
• Loading and debugging the empty project
• Add in Networking stack
• Add HTTP pages
• Add in a DHCP Server
12
Adding Networking Stack
• Open up empty.cfg and view System Overview
• Add EMAC by right clicking and selecting “Use EMAC”
This will add the EMAC driver and allows you to configure it.Note: MCUSDK and GPIO are already there.
13
Adding Networking Stack
Currently there is not much configuration for the driver. This will be expanded in future releases.
The instrumented library includes assert checking and Log events to help in debugging.
14
Adding Networking Stack• Go back to the MCU SDK
System Overview and do a“Use” on the “TCP/IP” box.
• You can now deselect IPv6 (below the IP box).
• If you select the IP box, it goes to the IP configuration. You can specify whether to use a static IP address or DHCP. (We’ll play with this later)
15
Adding Networking Stack
• In Empty.c, add the following bolded line around line 53. This initializes the EMAC driver
Board_initGPIO();Board_initEMAC();
• In TMDXDOCKH52C1.c, you need to change the MAC address to match the sticker on your board. Note: there is a request to place the MAC address into a dedicated location in ROM.
UInt8 macAddress[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
Note: Once you have your company’s own custom board, you’ll need to make your own “board” source file.
16
Adding Networking Stack
• Navigate to include HTTP Server by left clicking TCP/IP box from MCU SDK System Overview.
• Right Click on HTTP and select “Use HTTP”. You should see the following now.
17
Adding Networking Stack• Select “Instance” and hit “Add”. We’ll leave the defaults.
• Save and build application.
18
Adding Networking Stack
• Before loading, Close System Analyzer Session.
• Load and halt at main().– Look at ROV’s Task, EMAC and Ndk windows
• Load and halt at main().
[Cortex_M3_0] 00000.000 mmBulkAlloc(): could not allocate memory.[Cortex_M3_0] 00000.000 out of memory: handle=0x20e375, size=10 [Cortex_M3_0] Service Status: DHCPC : Failed : : 000 [Cortex_M3_0] ti.sysbios.heaps.HeapMem: line 294: out of memory: handle=0x20009100, size=1804ti.sysbios.heaps.HeapMem: line 294: out of memory: handle=0x20009100, size=2048xdc.runtime.Error.raise: terminating execution
What happened!
Look at HeapMem in ROV. There is not enough memory. The default Networking settings are too big.
We are working to fix this for the next release. But let’s figure out how to fix this.
19
Fitting Networking Stack into Target
First, the default Memory heap is too small. Select the Memory page in the outline window and increase the heap to 25088 (0x6200)
20
Fitting Networking Stack into Target
Additionally, select the “Task” page and reduce the Idle Task size to 1024 (instead of 2048).
21
Fitting Networking Stack into Target
There are several other fields that need tweaking. Instead of doing this graphically, you can do this via a text file. Close the graphical configuration and right click on the empty.cfg file and select Open With-> Text Editor and add the following lines at the bottom. Save the file. (Again we are trying to make this easier for the next release)
Program.stack = 1024;var Udp = xdc.useModule('ti.ndk.config.Udp');Udp.receiveBufSize = 2048;var Tcp = xdc.useModule('ti.ndk.config.Tcp');Tcp.transmitBufSize = 2048;Tcp.receiveBufSize = 2048;Tcp.receiveBufLimit = 2048;Global.lowTaskStackSize = 1792;Global.normTaskStackSize = 1792;Global.highTaskStackSize = 1792;Global.ndkThreadStackSize = 1792;Global.pktSizeFrameBuf = 1552;Global.pktNumFrameBufs = 16;Global.memRawPageCount = 8;
22
Running HTTP Server• Make sure you have the Ethernet cable connection!
• Rebuild and load the application. Once you run it, you should see the following:
[Cortex_M3_0] Service Status: DHCPC : Enabled : : 000[Cortex_M3_0] Service Status: HTTP : Enabled : : 000 [Cortex_M3_0] Service Status: DHCPC : Enabled : Running : 000 [Cortex_M3_0] Network Added: If-1:146.252.161.8 [Cortex_M3_0] Service Status: DHCPC : Enabled : Running : 017
• Look at ROV’s Task, Ndk, and EMAC
• Open browser to IP Address…
What’s wrong! The reason is because we have no web content on the target.
23
Let’s Make a WebServer!
Steps
• Create and build new “empty” project
• Loading and debugging the empty project
• Add in Networking stack
• Add HTTP pages
• Add in a DHCP Server
24
Adding HTTP Server Content
The following slides are going to summarize the <mcusdk>/products/<ndk>/docs/spru524h.pdf’s “Appendix E: Web Programming with the HTTP Server” section…
25
Adding HTTP Server ContentLet’s add a simple index.html page for the target.
1. Create a simple default.html file that contains “Hello World” in the same directory as your project.
2. Convert this to a Char array that can be included into the application. Run the binsrc.exe that is in the <mcusdk>products\<ndk>\packages\ti\ndk\tools\binsrc directory. Add this directory to your path or use the full path name
>binsrc.exe default.html default.h DEFAULT
This creates a default.h file, which has the Char array representation of the webpage.
• Added the following header files into the empty.c file
#include <ti/ndk/inc/netmain.h>
#include "default.h"
26
Adding HTTP Server Content4. Add the following functions into empty.c
Void AddWebFiles(Void){ //Note: both DEFAULT_SIZE and DEFAULT are defined in default.h efs_createfile("index.html", DEFAULT_SIZE, (UINT8 *)DEFAULT);}
Void RemoveWebFiles(Void){ efs_destroyfile("index.html");}
5. Add the following into the empty.cfg fileGlobal.stackInitHook = '&AddWebFiles';Global.stackDeleteHook = '&RemoveWebFiles';
6. Rebuild, load, run and now point your browser at the IP address.
FYI: WireShark is a great free Network Analyzer that helps view the packets.
27
Adding HTTP Server ContentLet’s add a second page. Make an greetings.html file that contains “Greets Everyone” and a picture (e.g. dspchip.gif).
1. Run the binsrc.exe convertor on the page and the image.
>binsrc.exe greetings.html greetings.h GREETINGS>binsrc.exe dspchip.jpg dspchip.h DSPCHIP
2. Include the greetings.h and dspchip.h files into your project.#include "greetings.h"#include "dspchip.h"
3. Add greetings and dspchip into the AddWebFiles/RemoveWebFiles Void AddWebFiles(Void)
{ efs_createfile("index.html", DEFAULT_SIZE, (UINT8 *)DEFAULT); efs_createfile("greetings.html", GREETINGS_SIZE, (UINT8 *)GREETINGS); efs_createfile("dspchip.jpg", DSPCHIP_SIZE, (UINT8 *)DSPCHIP);}Void RemoveWebFiles(Void){ efs_destroyfile("index.html"); efs_destroyfile("greetings.html"); efs_destroyfile("dspchip.jpg");}
28
Adding HTTP Server ContentRebuild, load and run the target now. Point your browser at the IP address. It should still be the “Hello World” page.
Now point to <ipaddr>/greetings.html. You should see the greeting and the picture.
It is also possible to pull the pages from the network or from an SD card.
29
Adding HTTP Server Content: CGI
Pages are great, but how do you add “smarts” to the page? For example, how long has the target been up?
The NDK supports CGI scripts to be on the target. The basic idea is that you write a CGI function in ‘C’ that plugs into the EFS.
Let’s add the number of SYS/BIOS Clock ticks that have occurred since the system has started.
1. Add a getTicks.cgi command onto the default.html page.<body>Hello World<br><br>Get current Clock tick <a href="getTicks.cgi">getTick.cgi</a><br>
2. Convert the default.htm via binsrc
>binsrc.exe default.html default.h DEFAULT
30
Adding HTTP Server Content: CGINow add the following code into empty.c #include <ti/sysbios/knl/Clock.h>
Int getTicks(SOCKET s, int length){ Char buf[200]; static UInt scalar = 0;
if (scalar == 0) { scalar = 1000000u / Clock_tickPeriod; } httpSendStatusLine(s, HTTP_OK, CONTENT_TYPE_HTML); httpSendClientStr(s, CRLF); httpSendClientStr(s, "<html><head><title>SYS/BIOS Clock "\
"Time</title></head><body><h1>Time</h1>\n"); System_sprintf(buf, "<p>Up for %d seconds</p>\n", ((unsigned long)Clock_getTicks() / scalar)); httpSendClientStr(s, buf); httpSendClientStr(s, "</table></body></html>"); return (1);}
31
Adding HTTP Server Content: CGINow hook the cgi into the EFS in empty.cVoid AddWebFiles(Void){ Void *pFxn;
efs_createfile("index.html", DEFAULT_SIZE, (UINT8 *)DEFAULT); efs_createfile("greetings.html", GREETINGS_SIZE, (UINT8 *)GREETINGS); efs_createfile("dspchip.jpg", DSPCHIP_SIZE, (UINT8 *)DSPCHIP); pFxn = (Void*) &getTicks; efs_createfile("getTicks.cgi", 0, (UINT8 *) pFxn);}
Void RemoveWebFiles(Void){ efs_destroyfile("index.html"); efs_destroyfile("greetings.html"); efs_destroyfile("dspchip.jpg"); efs_destroyfile("getTicks.cgi");}
Rebuild, load and run. Point browser to the IP address.
32
Debug Information
• Start System Analyzer.
• Analyze the application(right-click in the LiveSession window)
– Open Execution Graph
Note: Hwi and Swi logging was not enabled, so you don’t see them. Hwi/Swi logging does impact performance (~2-3%).
33
Debug InformationOpen Task Load (both Graph and Summary)
34
Let’s Make a WebServer!
Steps
• Create and build new “empty” project
• Loading and debugging the empty project
• Add in Networking stack
• Add HTTP pages
• Add in a DHCP Server
35
Add in a DHCP ServerLet’s add in a DHCP Server into the application.
1. Move your PC and target to a private network.
2. Add DHCP Server into your application’s configuration
36
Add in a DHCP Server3. “Add” an instance and configure DHCP Server as needed.
37
Add in a DHCP Server4. Give the target a static IP address. Select IP and configure accordingly
38
Add in a DHCP Server5. Rebuild, load and run. Have you PC attempt to get an IP address now.
6. Future DHCP Server enhancements • Configurable lease time (currently 7 days)• Configurable Gateway (currently Gateway IP address is the target’s IP address)• API/ROV to display requests that have been serviced
39
Extra Material
• Using a different Software product
• printf vs System_printf
• CPU Load vs Task Load
• USB Logging
40
Creating an Empty Project
The “Order” page shows the order that the software packages are used (both for configuration and linking).
41
Using a different product version.
If you wanted to use a different sub-product version, select it on the RTSC page. Then on the “Order” page, move it up above the MCU SDK’s sub-product entry (see next slide).
42
Using a different product version.
When building now, the 1.1.00.04 UIA will be used instead of the MCU SDK’s UIA.
43
printf vs System_printfThe biggest question we have is “Why don’t I get output to the console”
First some background…
System_printf: This function behaves much like the ANSI C Standard printf but does not support the full range of format strings specified by the C Standard. In addition, several non-standard format specifiers are recognized.
You can plug in different implementations into the System module.
SysMin: Small implementation that stores output in an internal buffer. It is flushed to stdout when a System_flush is called or when the program exits.
SysStd: Basically sits on top of printf and other RTS functions.
SysFlex: Let’s the customer plug in different functions. MCU SDK ships a UART implementation.
Please refer to the MCU SDK User Guide for more details
44
CPU Load vs Task LoadWithin the SYS/BIOS Idle Task, there is a list of functions that are executed. These N functions are repeated executed while in Idle. The execution of all N functions is 1 idle loop. One of the function is placed there by the Load module.
For a time period (default 500ms) the number of loops completed by the Idle Task is counted. While this the counting is going on, the minimal time for a loop is also determined.
The product of the number of times through the loop and the minimal time is an approximation for the time spent in Idle. The CPU Load is determined in this manner.
An individual Task Load is determined by looking at the context switches.
The Task Load is a more accurate measure. So 100 - %Load of Idle is more accurate than %CPULoad. However, there is more of a performance overhead to manage Task Load.
Note: LoggerIdle plugs in an Idle function that messes up CPULoad, but not Task Load.
45
USB Logging
46
Some of the examples (demo and uartconsole) already show how to log via the USB peripheral instead of stop-mode.