📜 ⬆️ ⬇️

STM32F4 USB RNDIS driver (device control via web interface)

Good time of day, dear friends!

First of all, I would like to wish you all the best wishes on the past New Year holidays.

Earlier in the article was announced the development of RNDIS USB driver for STM32F4 series controllers. Since then, the library has gradually evolved and has now grown to the first release version. The library called LRNDIS (LWIP + RNDIS) allows us to create, on the basis of the STM32F4 controller, both a USB device of the “modem” class and any other devices that are controlled through a web interface. An example of managing the stm32f4-discovery card from a web browser on an Android tablet is shown in the video:
')


On the video page there is a link to the source codes and the HEX-file of the firmware for the discovery card, with which you can repeat this experiment. The article describes how and when the technology of access via the WEB interface is useful, as well as how the LRNDIS library works for STM32F4 controllers. Also there is a training material on the operation of USB and the device Ethernet-networks.

Prehistory of the library
image

The background of the project is very typical. It was a warm summer day. Ghm ... For the customer there was a task to develop a device with a service management interface.

Details
As the firmware was developed, several control commands for the VCP interface were entered. This means that after connecting a USB device to the OS, a virtual COM port was created. Using it, control and diagnostic commands were transmitted from the user terminal. In response, the status of the device and its current state were received from the device.

The system is quite typical from a service point of view: there is a serial port and a set of commands for control and diagnostics.

Everything changed in a short time. For objective reasons, the required set of commands has grown. Interactivity of the output was also needed: some parameters became necessary to be displayed in dynamics. As, for example, the testimony of a magnetic sensor when a ferromagnet is carried past it. For this, additional commands were introduced, which, using control sequences , printed information in the user terminal with high periodicity. This created the necessary sense of real-time observation. Interactive teams were so convenient for engineers that some of the teams were later added in accordance with the concept. And then there was a crash. It was necessary to support several teams at once: interactive, diagnostic, control commands. In this case, periodic code refactoring was associated with time-consuming editing in a large number of processed commands. It became clear that there still needs to be a user group of teams - for less qualified personnel who will simply follow the operating instructions. For them, the idea of ​​writing a client terminal with buttons and checkboxes arose ... And here doubts arose: it became clear that we are engaged in the service part, paying less attention to functionality! But the user program running on the client computer must also have its own requirements: cross-platform and LTS (support duration).

Suppose we’ve finished the device, and we have to port and test the custom software with each version of the operating systems being released! How long?

So the question was born - how to get rid of additional labor costs?

It was decided to use standards of guaranteed long-term support. Those standards that will allow us to create a client device management program that will be supported by the fullest possible set of operating systems in the present and future tense. In the first couple were found the flaws of popular cross-platform frameworks:
- java: the need for a JVM OS, and the consequent assumption about the need to distribute a virtual machine
- qt: the periodic need for versioned porting and launch nuances for Android.

No, these difficulties should not scare. The question, perhaps, is only in labor hours, which we sometimes underestimate, taking into account the factor of long-term support.

So the idea was born to make a WEB-interface to control the device. It does not require the development of third-party software, browsers to display the control page is in all required OS. The interface design potential is huge. The duration of support in terms of http / html / js standards is also beyond doubt.

According to the plan, the management was supposed to work as follows.
1. USB connected device represented by network card
2. The client computer (PC or gadget) gets an IP address to work on the network of our device
3. At the request of the web browser on the client computer, our device gives the page
4. The page contains information on the current status and available controls.
5. When the client activates the controls, the corresponding HTTP requests are transmitted from the browser.
In fact, between the browser and the device, the same text commands go, but only in the format of the HTTP protocol.
We must understand that this is just one of the options from a large set of possible solutions. It has its pros and cons. It so happened that now manufacturers use mostly network devices to use web-interfaces: setting up modems and routers. The promise of this article - let's apply what is really convenient. And let's not be afraid of difficulties on the way: overcoming them now will save us much more time in the future!

Library Scope
image

Unfortunately, the first announcement was not fully successful, because The story of the scope has been missed.
Let's try to catch up a little and open this topic.
If we are at the system design stage of the device, then the following considerations may lead us to use web interfaces (regardless of the physical channel, Ethernet or USB):
1. The device must have a control and / or diagnostic interface
2. Controls can be used not only at the development stage, but also at the operation stage (user software)
3. User qualification may not be high enough, which requires a friendly management interface.
4. The method of "friendly" management should be accessible from under different platforms and operating systems.
5. Relevant funds need to be maintained for a long time.
An additional criterion may be whether we initially develop a network device. And also: would not (otherwise) the addition of a network stack and a web server to the firmware be redundant against the background of much less rich device functionality? In other words, adding a web interface to a light bulb controller is obviously a redundant solution.

If we believed in a web interface, the following considerations may help us in choosing a physical communication channel (from an Ethernet and USB perspective).
Type ofIn-Circuit ConnectionTypical application
EthernetEthernet PHY controller- Industrial devices
- Home appliances with network function and add. nutrition
USBULPI controller or direct connection to the MKHousehold and part of industrial devices. In particular, if:
- devices do not have a guaranteed power source (battery power, for example)
- devices potentially connected to the host only with a USB interface (for example, a tablet)
- miniature device class

I'd add on my own - in spite of all the delights, I would not advise using USB in industrial hubs with the requirement of increased reliability: negative experience is often encountered. If there is no alternative, then the issue of sustainability needs to be studied thoroughly.
Based on the above points, it becomes clear the scope of the library: household and part of industrial devices, which:
- work on the basis of MK STM32F4
- must have a friendly management interface
- should be controlled from under different hardware and software set
- may not have a guaranteed power source
- must have a long period of management software support
There are many possible examples of using technology even outside the realm of purely network devices.
For example, at the moment there are plans to turn the stm32f4-discovery into an amateur development tool with the functions of a portable generator / signal analyzer and an oscilloscope. Connect such an assistant to the phone and look in the dynamics of what is happening in the circuit of interest to you. From free advantages - it is not required to build or install software; it is enough to flash the HEX file and open the browser - all the charms of the GUI interface will be present in it. In my picky taste - what you need. Of course, the tool is not for professional development, but there is a known interest in it.

So, I hope, understood. And now about how the library works.

How does it work
image

When answering this question we will not be in a hurry. A person who has little experience of interacting with networks can quite rightly be embarrassed. Therefore, referring to one or another interaction protocol, I will also give its brief technical description at that level ... which I once lacked myself.

Step 1. Connect the USB device.
As mentioned earlier, at this stage our device says to the host “I am a network card!”.
Host (i.e. client computer) after connecting our crafts to it, begins to send requests.
The host needs the following information.
- as the product is called
- what is the product's VID and PID (manufacturer and product identifiers, see list )
- what class and subclass is the device
- on which endpoint points and which blocks should be exchanged
Well, and some other information. Configuration packets are transmitted via endpoint 0. Response packets from the device with information about themselves are usually called “USB device descriptors”.

Read more about the survey process (enumeration) here .

In general, the USB protocol is quite rich ... sometimes it even seems to be redundant. However, this wealth for many years now allows you to connect completely different devices, makes it possible to transfer isochronous streams, data blocks, interrupts. In general, everything you need that may require a wide range of modern devices. The flip side of the coin is a high threshold for entry into the development of USB devices.

After receiving information about the device, the host OS searches for a suitable driver for interaction. In a typical case, like flash-carriers (USB class MSC) or keyboard with a mouse (HID class), the standard driver for the class is loaded. In a more "heavy" case, like our USB network card (CDC class with an RNDIS subclass), the operating system comes in discretion:
- linux / android / mac OS, as a rule, successfully tries to establish a typical exchange
- windows asks to install an external driver
Our device in the first case works immediately.
In the case of windows OS (later XP), you can install the standard Microsoft driver . For Windows XP, you need to put the inf file that is available in the LRNDIS library repository .

Step 2. The driver initializes the RNDIS device.
This picture shows the principle of communication with the RNDIS device (Windows OS).

image

You can read more about it here and there .

In short, the RNDIS protocol is an extension of NDIS for external devices. The role of the protocol is to provide PnP support and network packet exchange. In essence, RNDIS is an independent network interface, the information load of which is channel / network layer frames (Ethernet or IP frames, optional).

In the diagram below, this implements the “Miniport Remote NDIS” cube, which is responsible for:
- communication service (ask the network device for its MAC address, packet size, operation speed, etc.)
- wraps network-sent host packets in the RNDIS header
- transmits packets received from the device, discarding the RNDIS header
The Miniport Remote NDIS USB cube is responsible for the transit of RNDIS parcels by working with the USB bus driver.
On the side of the STM32 controller, the usbd_rndis_core.c file is responsible for supporting the RNDIS protocol and working with USB. He does the same thing as the "cube" of the host "Miniport Remote NDIS" - deals with sticking / unstitching headers, and also answers driver questions. Answers, such as the MAC address and speed, it takes from the usbd_rndis_core.h file.
After successful initialization of RNDIS, the Windows driver creates a network interface, which is subsequently displayed in the "Network Control Center" and in the tray indicator area.

Step 3. Obtaining an IP Address
So, why do we need a service for obtaining a dynamic address? This service is called DHCP (Dynamic Host Configuration Protocol).
After the host initializes our device, it creates a network interface.

Network interface (if anyone knows)
A network interface is a software entity that provides access to physical or virtual network resources.
Most often, each network interface host corresponds to a specific network adapter. But there are many other interfaces, such as the local loop or those that are used to interact with the virtual machine. In their case, in a signal form from the host "nothing comes out" - the exchange is programmed.

Each host network interface must have at least one IP address associated with it. According to it, "network residents" can refer to the host.

If several networks are addressed “on the wire” (for example, devices with IP addresses 10.4.1.xx and 192.168.1.xx), then the interface can be assigned two “personal” IP addresses. They may look like this: 10.4.1.151 and 192.168.1.200. You can find out the set of network interfaces and their associated IP addresses in Windows OS using the ipconfig command and using ifconfig in Linux OS.

A mask is used to describe networks / subnets. For example, the correct description of the network 10.4.1.xx is: network 10.4.1.0, mask 255.255.255.0. Or, if the 4-byte number of the mask is represented in binary form and the number of the leading units is calculated, then the value is 24. Then the network can be described as: 10.4.1.0/24.

More information about this can be found in the relevant sources .

There are two main strategies for assigning an IP address to an interface: a static method (when the user enrolls an address to an interface) and a dynamic method (using a DHCP service).

The last is that when creating an interface on the host, the DHCP client service is activated. It begins sending broadcast packets using UDP to the network (the configuration of which is not yet known), in the hope that there is a DHCP server on the network.

image

The function of the DHCP server in general, and in particular on our controller, is to respond to the client. In response, the controller “says”: client, you are in such and such a network, keep such and such an IP address, and we also have a DNS server with such and such address.

After that, the host “feels better”: it assigns the issued IP address to the interface and remembers the IP address of the DNS server.

Initialization is over, now you can enter the name of the page (run.stm) in the host browser.

It must be said that the behavior of the LRNDIS library is configurable. The DHCP server service can be excluded from the assembly. Then the host will have to register any address belonging to the range 192.168.7. (2-254). Such a network is created by default. Its parameters (192.168.7.0/24) are also configured. In the example, the client is given addresses in the range 192.168.7.2 ... 192.168.7.4 with a leasing time of 24 hours.
More details on the library settings can be found in the previous article .

Step 4. Loading page
To download the page, the user can enter the address of our device 192.168.7.1 directly.
However, remembering the numbers is not required, because in addition to the DHCP server, it is possible to build a library with the support of a DNS server, the function of which is to resolve network names. In the published example, the DNS server is trained to resolve the resource name “run.stm”.

Therefore, if we write run.stm in the browser, the host’s network service will send to our (and not only) DNS server a request in response to which the server will helpfully report: the domain name “run.stm” corresponds to the IP address 192.168.7.1 . Next, the host browser at a known address will make a TCP connection in order to send an HTTP request to get the root page.

Request and response between the Firefox browser and the controller:



Request history when loading the page:



From the history we see that, after loading the root HTML document, the browser also loads the other two files from the controller: discovery.svg and zepto.min.js. The first is the image of the discovery board. The SVG format is chosen, since, being an image of vector graphics, it occupies little space in the ROM of the microcontroller. The script file zepto.min.js is included because is a stripped-down counterpart of the famous JQUERY . It should be noted that there was no scrupulous saving of space in the ROM, because in spite of the sacrifice of 35 Kb for all static resources, the memory of the controller is still quite enough. In addition, this size with a further increase in the complexity of the interface promises to grow much slower. If the interface has grown significantly - there is always a way to store and distribute static resources in compressed form - all known browsers currently support decompression on the fly.

Another request that the browser sends is the /state.cgi request. It is formed by the script from the root HTML-document with a frequency of 5 times per second. We need a request to obtain the dynamics of the current state of the device.
When receiving this request, the controller generates and responds with the following line in JSON format:

{ "systick": 9528746, "button": 0, "acc": [54, -288, 936], "leds": { "g": 0, "o": 0, "r": 0 } } 

It contains all the data about the current state of the device, which are subsequently displayed on the page using JavaScript code.

Well, and perhaps the last moment in communicating with the browser - a way to control.

In the example, three LEDs are controlled. For example, when you click on the red LED flag with JavaScript tools, an HTTP GET request is sent with the “r” parameter and the value 0 or 1. The complete request looks like this: /ctl.cgi?r=1

In this or alternative ways, you can send any data set, whether it is a logical 0/1 state, or a text field value, or a push button notification. The beauty of the approach lies in the fact that the program logic may not be aware of the controls at all, because it receives strictly formalized control messages. You can also change and debug the interface part (HTML + JS) locally with all conveniences, and then upload it once to the controller as part of the firmware. Local web-development, which is important, can be handled by the appropriate specialist.

About the LWIP stack
No network exchange would have been possible if it were not for this network stack, which was built into the library.
Since the library works under the “bare” hardware (without the OS and dynamic memory allocation), the add-in in the form of sockets is not available for use. Writing network applications therefore occurs using the raw stack API. Fortunately, there is a lot of information on this topic.

Also in the package of contributions there are many ready-made solutions. Including from there and was used HTTP-server.

In the last article I gave a brief description of the stack and its settings. At the moment, the set of important definitions for the stack in the file has been clarified:

lwipopts.h
 #define NO_SYS 1 #define MEM_ALIGNMENT 4 #define LWIP_RAW 1 #define LWIP_NETCONN 0 #define LWIP_SOCKET 0 #define LWIP_DHCP 0 #define LWIP_ICMP 1 #define LWIP_UDP 1 #define LWIP_TCP 1 #define ETH_PAD_SIZE 0 #define LWIP_IP_ACCEPT_UDP_PORT(p) ((p) == PP_NTOHS(67)) #define MEM_SIZE 10000 #define TCP_MSS (1500 /*mtu*/ - 20 /*iphdr*/ - 20 /*tcphhr*/) #define TCP_SND_BUF (2 * TCP_MSS) #define ETHARP_SUPPORT_STATIC_ENTRIES 1 #define LWIP_HTTPD_CGI 1 #define LWIP_HTTPD_SSI 1 #define LWIP_HTTPD_SSI_INCLUDE_TAG 0 

Also the problem with mem_malloc was solved. Although the current firmware version does not use dynamic allocation, the hardware crash kept a watchful when calling mem_malloc. It was resolved by adding the definition of MEM_ALIGNMENT, which was previously ignored.

For the same reason, the HTTP-server supported by the community has steadily earned, which prompted them to abandon plans to create their own.

Unsolved Issues
1. Newns relicensing stack lwip, which may have its own conditions for inclusion in the other software;
2. Refinement of the DNS server for processing "multi-query" packets;

Instead of conclusion
I thank the reader for his patience and hope that this article will be useful to him. The source code library LRNDIS is available for use under the MIT license. I think it is wonderful if the work, for which considerable time and spare time was devoted, will be useful to someone else. At worst, without the use of open libraries, this would not have been possible.

The library is currently planned to be supported, therefore you can contact the e-mail address fsenok@gmail.com for questions.

Source: https://habr.com/ru/post/274663/


All Articles