The Xedge C Code for Embedded Devices

Xedge transforms the Barracuda App Server into a versatile Lua development tool, offering an optimal starting point for anyone using the Barracuda App Server in an RTOS environment. Beyond development, the strength of Xedge lies in its adaptability for production systems. Keeping Xedge as part of your production system not only simplifies the end product, but also enhances its capabilities, allowing it to take advantage of the plethora of services Xedge provides. The Xedge Lua code can optionally be replaced with your own specialized Lua bootloader and final application as needed, while the Xedge's C code can typically be used 'as is' for your final product, but note that using Xedge in a production system adds value by offering seamless, integrated functionalities.


Xedge's Lua application, which is embedded in the executable, is best visualized as Lua firmware. The Lua firmware is a compressed ZIP file stored inside the executable and made available to the Lua Virtual Machine via the ZipIo.

This document explains how to build the Xedge C code. Using Xedge is explained in a separate document.

Compiling Xedge

The following section includes generic build instructions. We provide two ready to use RTOS build projects you may download and use:

Include the following files in your build:

The file XedgeZip.c must be created by running barracuda/examples/xedge/make/BuildXedgeZip.cmd.

The file XedgeZip.c is a C array containing the zipped Xedge's resource files ( and is mounted by the C startup code as a ZipIo and used by the Lua VM's required 'vmio'. We recommend studying the content of the produced ZIP file to get an understanding of the various resource files.

In addition to including the above files in your IDE/Makefile, add the required include path and #define directives as required by your platform. See the readme file barracuda/builds/[platform]/readme.txt for details.

The file system plugin barracuda/xrc/DiskIo/[platform]/BaFile.c is optional and may be included if you have a file system in the device and if a suitable plugin is found in barracuda/xrc/DiskIo/ directory. You must add #define NO_BAIO_DISK in your IDE/Makefile if you do not plan on using a file system. See the DiskIo documentation for details.

Enabling Additional Features

BAS Amalgamated (BAS.c) includes features that are by default not compiled. These features can be enabled by the following macros. The macros can be enabled on any platform, including RTOS, unless stated otherwise.

The following macros are required if you plan on using the Let's Encrypt plugin. The macros are pre-set for the following ports: POSIX (Linux/QNX), Windows, VxWorks, and INtime.

All porting layers, except POSIX and Windows, have the following pre-set:

The above construction makes Lua use integer only and excludes floating point numbers. To re-enable floating point, compile the code with:

See inc/arch/XXX/luaconf.h for details.

Xedge's Configuration File

Xedge keeps the configured application(s) and their state in a JSON file. This file is stored on the embedded file system if Xedge is compiled with file system support or in the browser using Web Storage if Xedge is compiled with #define NO_BAIO_DISK.

The LSP application(s) startup state differs between a device with and without file system support:

Note: When using the NetIo, make sure to start a Web File Server on your host computer prior to booting the embedded device.

Adding Lua Bindings

To access the device hardware via the embedded system's C code, custom Lua bindings must be added. See the getting started guide and advanced Lua bindings for how to create Lua bindings automatically or manually.


When using a secure TLS client connection, such as HTTPS, or enabling the Automatic Certificate Management feature, the device must either have a clock with the correct time or fetch the time from the Internet using SNTP. The Barracuda App Server relies on the time returned by the platform-dependent function baGetUnixTime() defined in TargConfig.h. This header may also include baSetUnixTime(), which SNTP code can use when updating the time on a device without a clock. When updating the clock using SNTP, send the "sntp" event upon setting the time. See the Events below for details.


Xedge features an event mechanism that allows simple events to be sent asynchronously from C code to Lua code. The Xedge Lua code includes the following global Lua function, which the C code can call to distribute events throughout the system:

function _XedgeEvent(...)

Lua code can subscribe to events, and the Lua callbacks are triggered when the C code calls _XedgeEvent. The arguments can be any value, with one exception: Xedge requires the "sntp" event to activate Automatic Certificate Management if the device does not include a clock. To activate the certificate management, the C code must call _XedgeEvent("sntp"); see time above for details.

See Send Events Via The Lua Thread Library for more information on how to call _XedgeEvent from C code.

Creating a Custom Release Build

This section applies to developers that want to avoid including Xedge's UI in the production system. You may create the final custom release when the development is complete.

The recommended release method is to ZIP all resources together and then convert the ZIP file to a C array using the bin2c tool. Your web application stored in the ZIP file may then be compiled and linked with your firmware. If you have a file system, you may optionally store the ZIP file on the file system. In any event, our recommendation is to always use the ZipIo for deployed applications and not to store web pages directly on the embedded file system. The ZipIo is in most cases faster than fetching resources directly from an embedded file system.

Xedge's startup code xedge.c is designed for mounting an embedded ZIP file and to initially run the .config Lua startup script. You may use the file xedge.c "as is" for your release if you add the .config script we have prepared to the root of your application. The .config script opens the server's listening ports and loads the optional .preload script.

  1. Copy the .config script as explained above.
  2. Modify the .config script as needed.
  3. ZIP all files together and include any additional resources from the Barracuda App Server's resource directory or copy the resources from the original file. Note, the ZIP file must not include the name of the top directory.
  4. Convert the ZIP file to a C array as follows: bin2c -z getLspZipReader XedgeZip.c.
  5. Replace the original XedgeZip.c (Xedge's Lua code) with the file produced in step 4.
  6. Compile and link.

You may want to study the content of the original prior to creating your own ZIP file.

Note that you may create any number of ZIP files and associate each ZIP file with a Barracuda Resource Reader, thus effectively creating an app for each ZIP file. You may also have part of your application read resources via a DiskIo if you, for example, want your customers to be able to modify or add LSP code. The Barracuda App Server is extremely configurable and you may assemble a server anyway you want.

NetIo Details

You may use the Mako Server as the file server, but you must then configure a Mako Server Web File Server instance.

Note that you may get severe performance degradation when using the NetIo since the NetIo generates multiple requests for each resource fetched. The NetIo speed is directly proportional to the speed of the TCP/IP stack being used in the embedded system. The faster the TCP/IP stack, the faster the NetIo will respond. The following diagram illustrates a page request using the NetIo:

Browser        Embedded System         Web File Server
  |                   |                       |
  |    get page       |                       |
  | --------------->  |                       |
  |                   |  stat (file exists?)  |
  |                   | --------------------> |
  |                   |         yes           |
  |                   | <-------------------  |
  |                   |                       |
  |                   |   get fragment 1      |
  |                   | --------------------> |
  |                   |    fragment 1         |
  |     response      | <-------------------  |
  | <---------------  |                       |
  |                   |                       |
  |                   |   get fragment 2      |
  |                   | --------------------> |
  |                   |    fragment 2         |
  |     response      | <-------------------  |
  | <---------------  |                       |
  |                   |                       |
  |                   |                       |

Figure 6: Browser to Device to WFS Sequence Diagram