 Good afternoon. My name is Andrei Imirchenko. I work at Intel with the Zephyr Operating System, including USB stack and other work. And in this presentation, I will tell you how to use Zephyr Operating System to write a simple USB gadget. In this presentation, I will talk about the problem we try to solve. Then we look at Zephyr Operating System and USB basics. Then we will talk about programming of USB devices, including implementation of standard classes in Zephyr. We talk about Ethernet over USB, about other USB classes supported by Zephyr. Then we will talk about programming custom devices in Zephyr and, for example, 15.4 over USB. Then I will talk about experimental USB features like web USB and virtual USB controller over USB IP protocol. And finally, I will talk about connecting our USB device in Zephyr to Linux host and to Linux host. And I will talk about drivers in operating systems for our gadget. Probably everyone was faced with a problem of connecting some non-standard device to a personal computer and usually some sort of tricky radio chips. They use SPI or other interface which is not found on ordinary computers. And for this problem, we can propose a solution using Zephyr device. It's an embedded device with a Zephyr operating system which has a right interface to connect to the complex hardware. And this gadget would have a USB controller which is supported by Zephyr and so we connected to our host PC. And now I will briefly talk about operating system in Zephyr. So probably everyone knows about this. I will briefly talk about it. So it's operating system for embedded devices hosted by Linux Foundation and supports more than 100 devices and it has Apache license to the zero. And the documentation and source code is available with the link provides. And now we look how we can write a very simple hello world application. For that, we only need to set up a development system and build environment and then we can use a vest tool to configure and build our sample. In this example, I built a hello world sample for QEMO x86 board. And for the QEMO board, we have a run target. We can run the sample in the QEMO emulator. And now we look at USB basics. To program USB device, we need to know the following information about USB. In USB protocol, the host connects to USB devices and host initiates all traffic. And when connected, USB devices identify themselves through a set of binary data called descriptors. Descriptors determine the functionality of the device, including device class, product ID, vendor ID, configurations, interfaces, and endpoints, where endpoints are communication channels between host and device. There are standard USB classes, which are defined by USB implementers for specifications. And they usually have drivers in operating systems. And in Zephyr, we implement USB device mode only. So our device can only be in the device mode. And now we look into the standard classes in Zephyr. And many standard classes are already implemented in the Zephyr device tech. Some classes, they provide API for applications. For example, human interface device, it provides special API application show use. If they want to implement some human interface device in Zephyr like a mouse or keyboard. Other classes, they just work if we enable them in the application configuration, or via menu config. Let's look at Bluetooth over USB sample, HCI USB. And this is the source code of Bluetooth over USB. It has only main functions, which brings some output to the console. And everything else is implemented in the USB stack. We can enable this stack with application configuration files, or via menu config. So we need to go to USB device stack. And then to select USB, Bluetooth device class driver. And now we look what other standard USB classes supported in Zephyr. We support also human interface device, device firmware upgrade, mouse storage over USB. There is support for serial port over USB. And with serial port, you can encapsulate any other protocol inside serial port. We have a sample, VPN serial, which actually implements 15.4 serial radio protocol. It sends 15.4 frames over USB with a little bit encoding. And the sample works with the Contiki native border router application. And more information about Contiki and native border router you can find with the links provided. We also support Bluetooth over USB, already mentioned. And we implement Bluetooth USB transportation, which is specified by Bluetooth.org specifications. There is also support for Ethernet over USB with standard protocols supported. And I will talk about Ethernet over USB in the following slides. And here we consider a use case of accessing our USB gadget from a personal computer. And the gadget is connected with USB to the host. At the lowest level, there are USB packets exchanged between host and device. Then USB packets are assembled to Ethernet frames and high level on both Zephyr and host. They work with Ethernet interfaces. Then comes transport layer and network layers with the protocols like IP, TCP, UDP. Then comes application layers with protocols like HTTP, MQTT, etc., which all those are implemented in Zephyr. And finally, we have application which can interact with application on a host, can interact with application on our Zephyr gadget. For example, we can run a browser on a host. And the browser would render a web page which is produced by HTTP server which is running on Zephyr gadget. And next, we will talk about standards. There are also many vendor-specific protocols I will not talk about then because we will implement open standards. And there are four types of protocols. They are Microsoft, remote-induced protocol, and the protocols included in the communication device class protocol group. They are Ethernet control model, Ethernet emulation model, and network control model protocols. And out of these protocols, Ethernet control model is the simplest protocol. It just takes Ethernet frames and just split it to USB packet and send over USB. And there is no floor control and to indicate that Ethernet has ended, it may send a zero-lens packet with USB. And then all other protocols, they implement floor control in some way. And now we see how Zephyr implements these protocols. Support for ECMEM and RNDs is implemented in the USB Zephyr networking stack. And it works out of the box. To enable protocol, we just enable them in the application configuration or we can enable them in the menu config of the application. So basically, there are many networking samples. In Zephyr, we can take any sample. Usually, samples work with a network interface and we just enable a net USB interface. It can be done with menu config, for example. So we go to USB device stack and we select USB device, networking support, and then we choose needed protocol. So in this case, we select ECM, Ethernet control model protocol. Next, we look to zero configuration which can help us to access our Zephyr with a short name. Zero configuration is the set of technologies that automatically creates workable network configuration. It includes obtaining IP address, name, resolution, and routing. This all works in Zephyr. And to obtain IPv4 address, we just make sure no one uses this address. And then we just start using this address. And LLMNR, it's a link local multicast name resolution protocol which basically kind of truncated DNS over multicast. And we have LLMNR responder which on DNS request with the host name Zephyr, this short name, it responds with its IP address. And after this, Zephyr can be used as a host name. And this works in Windows out of the box, at least in Windows 10 maybe some other also. And in Linux, it works with a system D result service. If you enable LLMNR in the system configuration file for the service. And now we see how we can enable all these technologies in the application. It's possible to build a simple HTTP server in Zephyr. For example, we look at dump HTTP server, sort of sample with a source and documentation available with the link provided. So as I already mentioned, we just need to enable USB Ethernet interface. It can be done with the overlay net USB configuration file. And then we enable zero configuration. It can be done with the overlay zero conf. And we are using this tool to configure and build application for some board. It can work with any board with the USB controller supported by Zephyr. And then we flash application to board, connect board to our PC. And on a host PC, we start the browser and just type name Zephyr and the port number which is specified by this dump HTTP server port. And the browser shows a web page which is produced by dump HTTP server sample. So after we have done this very simple sample, it's also obvious we can create a Zephyr very complex graphical user web interface. And we can have some button, for example, and from browser you can press on the button and we can execute some comment on our Zephyr board. Now we look at another use case with networking. Zephyr operating system is a fairly advanced IP stack and therefore one of the application can be to use Zephyr board as a board router which can road traffic between different IP networks. For example, between 15.4 and 6 low pan and between regular IP network. And the following Zephyr capability allows us to use to build a board router. It's a very advanced IP stack. It's a very advanced IP stack. It has multiple interfaces and support for routing. And now we look at drivers for operating systems for our other use being gadgets. So when we connect our gadgets, we want it to be recognized by operating system. Since all those protocols are open standards, we want it to be recognized by operating systems like Linux, Mac OS and Windows. In fact, Linux supports all interfaces. Mac OS supports ECM interface. And Windows supports RNGs. But it requires some tweaking of this in the system. So in Windows only, RNGs is supported. And after manipulation in the device manager. And we had a problem that our gadget was recognized in a different way for different Windows versions. For example, it can be recognized as a serial port, half working serial port. And we consider following our networking sample with RNGs supported and we connect it to Windows 10. So it's recognized as a device. What we need to do and to make it working, we go update drivers and select network adapters. And then we select driver from Microsoft for remote and disk compatible device. After this, our driver starts working. But it's not very convenient and there is a solution to make the driver working out of the box in the default Windows configuration. Windows developers come up with a special custom OS descriptors which helps automatically configure Windows drivers for USB. If you consider previous example with RNGs, without OS descriptors, we need to manually select our driver. If it's not, of course, if vendor ID and product ID are not in this file in Windows, which is our case. If we add OS descriptor to our gadget, Microsoft Windows recognize the technology support. When we connect first time our gadget to Windows, then it tries to read OS descriptors and it reads compatible ID, subcompatible ID parameters. And it tries to match these parameters with identifiers in the inf files in the driver collection of the Windows drivers. If the match is found, then Windows load correct driver. For the RNGs, you can select checkbox OS descriptors. I think it's called. And we have this OS descriptor with MS Comp RNGs and this magic number. I took from inf file. And after that, our gadget is working out of the box in the Windows. And this can also help, for example, if you want for some device to load general Windows USB driver in USB. And after that, it allows you to work with your USB device with some USB libraries or you can use web USB. And web USB, it access directly USB device. So if there is some driver loaded, it doesn't work. So I will talk about web USB later. And now we talk about custom class. The custom class, it's a USB class which is not covered by USB implement for specification. But still the basics of common part of all custom classes, they are implemented in the USB device stack. And basically application which wants to implement custom class. They just need to implement custom USB interface. And let's look at example with loopback custom class. So this custom class define custom interface, which basically has two end points and it's basically copies from one end point to another. And this is used in test USB application in Linux for the testing of USB. And for this custom class, we have a Linux kernel driver available. And if you look at code, there are two callbacks. One callback, it reads from end points to buffer. Another callback, it writes from buffer to the end point. And we also need to implement to define interface and end point descriptors. And here we define it's a custom class. It has two end points. Also we need to define end points configuration, which basically glues our callbacks I mentioned in the previous slide and end points addresses. We also need to define configuration data structure, which basically glues all previous structures. And it allows you to define a vendor handler for vendor requests or class requests, or you can override some standard USB requests. And this is basically all we need to know about programming in the custom class in USB. At least for this class, we have a Linux kernel driver for the loopback interface. But now we look at a more complex case when there is no driver. And we will write driver ourselves. So we consider a following use case. There is some radio, 15.4. We want to access it from our host PC. And it's actually a real case. We had a problem. We wanted to access 15.4 radio from a Linux and we couldn't find a suitable adapter. It was only one adapter available at USB. But it wasn't easy to buy it. You had to order those adapters. At the same time, there are lots of 15.4 SPI chips available on the market. And we have come up with the idea of using embedded board with the SPI interface to which we connect our radio. And the board has a USB controller. We can connect to our PC. And the main idea is described here. So 15.4 on Linux, we have Vipan USB Linux kernel driver which basically packs 15.4 frames to USB packets and sends packets to Zephyr USB gadget. On the Zephyr site, we have Vipan USB application. It actually unpacks 15.4 frames and sends it to 15.4 layer. And after some time, the packet comes to the driver of 15.4 and the driver makes physical transfer of the packet on the radio level. And so we have invented this protocol and how we have done it. So if you look at Linux 15.4 soft mark API, you can notice that it's very similar to 15.4 driver API. The operations and parameters are almost the same. And therefore, we can pack operations. We can invent opcode for operation. And we can pack all parameters to the Zephyr packet. And actually, we put opcode to be request field and parameters to data field. And now we can have a very simple protocol I call Vipan USB. So now we look at Zephyr implementation. So we obviously need a board with a 15.4 radio and USB controller and they need to be supported by Zephyr. Actually, I have tested this on a RAV based, like a real board from Fitec and a freedom board from NXP with a freedom shield. So Vipan USB sample is available with links to the source and documentation. And basically, this Vipan USB sample, it defines custom interface which implements this USB protocol, Vipan USB. And Vipan USB protocol is very similar to 80 USB protocol. The only difference is our protocol is vendor independent. So it's not tied to some chip. For example, for a third channel operation, we use a third channel opcode in Vipan USB. While 80 USB, it uses register write and it uses register write for many opcodes. Because it's actually, it's more like SPI USB, not like a 15.4 over USB. So since this is custom driver, custom device, we need to write a driver. And so there is a Vipan USB driver which basically uses SoftMaker Linux API. The driver is very similar to 80 USB driver. But it's the only difference. It works with our protocol, Vipan USB. The driver gets loaded when we plug device with a certain vendor product deeper. And the source code is available on the link provided. So for this custom device, we need to write a driver. And we have driver only for Linux. But there is a method you can use, you can use your custom devices without writing drivers for any operating systems. So it's WebUSB and WebUSB developers from Google introduced API that can simplify interaction with the custom non-standard device. And typical use case, we plug WebUSB device to our host. And on the host, we have notification with the links to the website. We click to the link. And the Chrome opens our website and it opens the device chooser. With the list of devices, you can connect to or reselect our device. For example, the WebUSB sample. And the connection established and the JavaScript on this website get an opportunity to work with our USB device. So the main advantage of this approach is that it works on any operating system. When there is a compatible browser, like a Chrome, I have tested it on Linux and Windows. And now we look at API and support in Zephyr. WebUSB has very simple API. And it works with recent Chrome and Opera browsers. And there is compatibility table. You can check for browser support. And basically, API allows direct access to USB device. For example, you can execute such operations like select configuration, claim interface. You can start data transfer. You can start control transfer. And the device announces support for WebUSB via a special descriptor. In Zephyr, we have support for WebUSB. We have WebUSB sample. It's a very simple device. It has two endpoints and basically it acquires data from one endpoint to another. And the link to the source code and documentation for our WebUSB sample is available. And now we look at another experimental feature. It's a virtual USB controller. There is a method for testing Zephyr USB application in the Linux host. As you know, Zephyr application can be built as a native Linux application, console application. And to do so, we just need to specify a board as native POSIX. For the native POSIX board, it's possible to include a virtual USB controller which works over USB IP protocol. From the Zephyr point of view, application on the Zephyr runs with a thing that it has a USB controller. And the Linux host, you just see that some peripheral device added to the host. And there is advantage of using this approach is that we can use Linux host tool like debuggers and profilers for debugging and profiling Zephyr application on the host. And next, it's an idea for this virtual USB controller over USB. So there is a virtual USB host controller driver on the client side. So there is a client and a server. And on the client, we have this virtual USB host controller driver. It's actually, it emulates a real host controller for virtual connection of the remote device. On the server side, we have a start driver and USB IP and they export a USB device over the network. And when connection is established, it's basically sends a USB request over the USB IP protocol. So if you put Zephyr to the picture, in our case, Zephyr is a server. It has a virtual USB controller driver which emulates a USB controller and it has a virtual controller adaptation layer which listens on the USB IP port. And it's the basic idea that we export a device which we implement in our Zephyr sample, Zephyr USB sample. So we can see how it works. This illustration shows example of attaching USB device which we have implemented in the Zephyr application to Linux host. So first we need to load USB IP virtual host controller driver with modprobe. Then we use WEST tool to build this USB heat sample for the native POSIX board. And we also use run target. So it also runs. And then we verify that that's our application is running and is licensed on the USB IP port. Then we can use USB IP list to list exportable USB devices. So we see that human interface device is available for export. And then we can use USB IP attach command to attach device to the Linux host. And after that device is attached and we can use LS USB and we can verify that the device is actually attached. And we can look at also at kernel logs. So there are kernel logs when we load virtual USB host controller driver and the logs when we attach our device. And you can see that from the logs the kernel doesn't see the difference. Is it a real device added to the Linux kernel or it's just our Zephyr gadget attached? So here's the Zephyr heat sample added. So it's a conclusion. I want to say again about the main idea is that we can use our Zephyr gadget to encapsulate some complexity of working with some interfaces. And hopefully when you connect this Zephyr gadget it can be automatically recognized by operating system. And all needed drivers for major operating systems would be loaded and it would be working out of the box. At least Ethernet could be done easily. Okay. That's all. Yes? So I have to admit that I did not look into USB on the firewalls far. And this is a very good introduction and overview quite complete. And the first question, I have the feeling the implementation of the stack is based on callbacks. Is this correct? The implementation of the USB stack in Zephyr, it's based on callbacks. Does this mean that the code is executed in interrupt context if we have callbacks? Because this, I relate this to another talk that we were seeing yesterday, another colleague from Nordic I think is not in the room, was talking about real time in Zephyr OS. And maybe this is a little bit conflicting. Okay, so you adjusted from priorities of different peripherals. Okay, I got it. And the next question, I've seen there is a fire vendor ID for USB devices. Are other companies allowed to use this in a product? No. Yeah, you mentioned there's a fire vendor ID already. I think this is... Yes, so you're talking about that Zephyr has a kind of registered USB vendor ID. Yes, and you have applications and they use different product IDs. You want to somehow to use it, some product ID? If I have a product idea, would I be allowed to use it? And then the next question comes, who is managing the product IDs? Because otherwise we're getting conflict with something which might be already done or available. Yeah, he's managing, he's managing. Okay, then I know this guy. I'll write to you. But in principle, you would allow companies to... You would give product IDs? Okay, for testing purposes I could use anything actually, isn't it? In the lab. Yeah, I get it, I know this. I'm asking because I think some years ago, I'm not up to date now, Microchip was offering something like that, so they have their Microchip vendor ID and they have a small range of product IDs which they can simply give to different companies. Yeah, might be a precondition. Yeah, clear. Good, thank you. Thank you.