EPICS RTEMS Initialization
The EPICS RTEMS Initialization effort provides a new way to initialize EPICS for RTEMS. The works is under review and can be found in the EPICS base PR #905.
Get the branch from my repo and add to your EPICS base local site configuration:
RTEMS_INIT = new
EPICS code or RTEMS code?
A key goal of this work is to move BSP related code from EPICS to the BSPs in RTEMS and to provide an API in RTEMS the RTEMS project is prepared to support.
RTEMS is a static linked executable that runs in a single address and if you have a header file with a call signature you can call any function. RTEMS provides a number of headers that form internal RTEMS APIs and EPCIS should not depend on them. BSP code is hard spread across projects as RTEMS does change internal interfaces BSPs depend on. The best approach is to add BSP code to RTEMS and to use a driver interface to get access.
Network Initialization
Network initialization has the following steps:
- Declare the network configuration
- Create the LibBSD
/etc/rc.confand optionally the/etc/resolv.conffiles - Initialize LibBSD
- Run
/etc/rc.conf - Wait for a valid network interface
Network Configuration
The network is configured using environment variables. Environment variables:
- Are supported via the standards base calls
getenv()andsetenv() - Can be easily checked using the RTEMS shell command
getenv -a - Simple means to export from a BSP any boot loader or boot monitor configurations in a standard way without a complex driver or set of calls.
Network Environment Variables
| Environment Variable | Description |
|---|---|
| RTEMS_NET_HOSTNAME | Name of this host |
| RTEMS_NET_IFACE_1 | Network interface 1 device label |
| RTEMS_NET_IFACE_2 | Network interface 2 device label |
| RTEMS_NET_IFACE_3 | Network interface 3 device label |
| RTEMS_NET_IFACE_4 | Network interface 4 device label |
| RTEMS_NET_IF_1_MAC | Network interface 1 MAC |
| RTEMS_NET_IF_2_MAC | Network interface 2 MAC |
| RTEMS_NET_IF_3_MAC | Network interface 3 MAC |
| RTEMS_NET_IF_4_MAC | Network interface 4 MAC |
| RTEMS_NET_IF_1_OPTS | Network interface 1 options |
| RTEMS_NET_IF_2_OPTS | Network interface 2 options |
| RTEMS_NET_IF_3_OPTS | Network interface 3 options |
| RTEMS_NET_IF_4_OPTS | Network interface 4 options |
| RTEMS_NET_IF_1_IP_ADDR | Network interface 1 static IP address |
| RTEMS_NET_IF_2_IP_ADDR | Network interface 2 static IP address |
| RTEMS_NET_IF_3_IP_ADDR | Network interface 3 static IP address |
| RTEMS_NET_IF_4_IP_ADDR | Network interface 4 static IP address |
| RTEMS_NET_IF_1_NETMASK | Network interface 1 static IP subnet mask |
| RTEMS_NET_IF_2_NETMASK | Network interface 2 static IP subnet mask |
| RTEMS_NET_IF_3_NETMASK | Network interface 3 static IP subnet mask |
| RTEMS_NET_IF_4_NETMASK | Network interface 4 static IP subnet mask |
| RTEMS_NET_SERVER_IP | Network Server IP address |
| RTEMS_NET_GATEWAY_IP | Network Gateway IP address |
| RTEMS_NET_NTP_IP | Network Time Protocol IP address |
| RTEMS_NET_DNS_IP | Network Domain Name Server IP address |
| RTEMS_NET_DOMAIN_NAME | Network Domain Name |
| RTEMS_NET_BOOT_FILE | Network Download Boot File |
| RTEMS_BOOT_CMD_LINE | Boot Command Line |
| RTEMS_BOOT_SCRIPT | Boot script |
| RTEMS_NFS_MOUNT_PATH | Network File System mount path |
| TZ | Timezone |
- Up to 4 interfaces can be configured and supported
- Interface specific options such as hardware check sums can be supported using the
RTEMS_NET_IS_1_OPTvariables. The options are passed to the LibBSDifconfigcommand so you can experiment with the options in an RTEMS shell first - DHCP is automatically support if no static data is provided
EPICS VME PowerPC BSP Support
This new initialization moves BSP specific probes and set up from EPICS base to the related RTEMS BSPs. If a BSP you use is not supported please ask on Discord about adding the support. The Beatnik and MVME2700 BSPs have been moved.
The BSPs read GEV data from the boot loader and populate the related network environment variables.
Custom Configurations
Some boot loaders and boards do not have a way to export a network set up so the application may have to provide a way. The new EPICS RTEMS Initialization supports this by adding a custom handler.
Custom Initialization Handlers
Customer handlers have the following parts:
- A function that is called at the stage of the initialization you specify
- A global static object linked to your IOC automatically registers your custom handler
- A domain and name to help you review and audit the initialization sequence
To access the types you need add to your IOC this include:
#ifdef __rtems__
#include <epicsRtemsInit.h>
#endif
Note: if this include is in common IOC code guard the include with the RTEMS define. You will also need to guard any code and objects else where in the file.
Custom Handler Function
The function has the type:
using epicsRtemsInitHandler = std::function<int()>;
The handler can be function:
static int myHandler() {
std::cout << "My handler function has been called" << std::endl;
return 0;
}
or a lambda:
auto myHandler = []() {
std::cout << "My handler lamdba has been called" << std::endl;
return 0;
};
Custom Handler Registration
The handler function is registered automatically by creating a global registration object of type epicsRtemsInitRegister. Global objects are constructed before EPICS runs registering your handler when the registration object’s constructs.
Note: Make sure you directly link the compiled object (.o) file to your executable or if in a library reference a global symbol in the same source file. If you do not do one of these things the linker will ignore the object file and the global object will not be in your executable.
A handler registration for a function is:
epicsRtemsInitRegister myHandlerInit(
"me", "init", rtemsInit_Order_early + 3, true, myHandler);
or for a lambda is:
epicsRtemsInitRegister myHandlerInit(
"me", "init", rtemsInit_Order_early + 3, true, myHandler);
In this case the lamdba variable is passed in and copied for you.
You can provide a domain and a name. These are printed during initialization to help you audit and debug any initialization issues. An example is:
] Init (15,1/12,enabled): my.init
My handler function has been called
] Init (200,3/12,enabled): system.log.reset
The start order is an absolute value so you can insert at any point your handler. A few standard blocks have been defined as:
enum epicsRtemsInit_bands {
rtemsInit_Order_early= 10,
rtemsInit_Order_filesystems = 200,
rtemsInit_Order_pre_net_services= 100,
rtemsInit_Order_net = 500,
rtemsInit_Order_net_filesystems = 600,
rtemsInit_Order_post_net_services= 800,
rtemsInit_Order_commands = 900,
rtemsInit_Order_ioc = 1000,
};
A handler can be enabled or disabled by default. You can also use the environment variables RTEMS_INIT_ENABLE and RTEMS_INIT_DISABLE to dynamically change what is initialized. For example to enabled the system debugger service:
setenv("RTEMS_INIT_ENABLE", "system.debugger", 1);
You can provide a list as comma (,) separated values:
setnv("RTEMS_INIT_ENABLE", "system.debugger,my.init", 1);
A disable overrides any enables.
DHCP Hook Function
The support for the DHCP hook function was removed. This is a fragile interface that depends heavly on the DHCP implementation in RTEMS and it may change or be removed in future RTEMS releases.
If you depend on parsing the DHCP data for a specific option you can implement a custom initialize handler to do this task. The handler can then update any network environment variables and support any functionality you need.
This approach is an improvement because you can add code you need and not depend on EPICS base changes.
An example is:
#ifdef __rtems__
#include <epicsRtemsInit.h>
#include <rtems/dhcpcd.h>
static void dhcpcd_hook_handler(rtems_dhcpcd_hook *hook, char *const *env) {
std::cout << "DHCP Hook:" << std::endl;
while (*env != nullptr) {
std::cout << ' ' << *env << std::endl;
++env;
}
}
static rtems_dhcpcd_hook dhcpcd_hook = {
.name = "ioc boot",
.handler = dhcpcd_hook_handler
};
static int DHCP_hook() {
rtems_dhcpcd_add_hook(&dhcpcd_hook);
return 0;
}
epicsRtemsInitRegister dhcpInit(
"test", "dhcp", rtemsInit_Order_early, true, DHCP_hook);
#endif /* __rtems__ */
The console output is:
] Init (10,1/12,enabled): bbb.dhcp
] Init (10,2/12,enabled): bbb.environ
] Init (200,3/12,enabled): system.log.reset
Startup
] Init (210,4/12,enabled): system.filesys.root
File System: root set up
[ snip ]
iocInit
Starting iocInit
############################################################################
## EPICS R7.0.10.1-DEV
## Rev. 8ae316147cffe5c42af8-dirty
## Rev. Date Git: 2026-09-30 10:18:09 +1000
############################################################################
iocRun: All initialization complete
## Start any sequence programs
#seq(sncExample, "user=chris")
myhost > err: cpsw0: ipv4_addroute: File exists
err: cpsw0: ipv4_addroute: Invalid argument
DHCP Hook:
interface=cpsw0
reason=RENEW
pid=1
ifmetric=201
ifwireless=0
ifflags=4294936643
ifmtu=1500
interface_order=cpsw0
if_up=true
if_down=false
old_ip_address=10.10.5.120
old_subnet_cidr=24
old_broadcast_address=10.10.5.255
old_network_number=10.10.5.0
old_subnet_mask=255.255.255.0
old_routers=10.10.5.1
old_dhcp_lease_time=6951
old_dhcp_message_type=5
old_dhcp_server_identifier=10.10.5.1
new_ip_address=10.10.5.120
new_subnet_cidr=24
new_broadcast_address=10.10.5.255
new_network_number=10.10.5.0
new_subnet_mask=255.255.255.0
new_routers=10.10.5.1
new_dhcp_lease_time=7200
new_dhcp_message_type=5
new_dhcp_server_identifier=10.10.5.1
Custom Network Configuration
This example is a DHCP network set up for a Beagle Bone Black BSP. This BSP does not support any boot loader configurations so you can manage the set up in a network wide configuration using DHCP. The IOC code is:
#ifdef __rtems__
#include <epicsRtemsInit.h>
#if RTEMS_BSP == beagleboneblack
static int set_BBB_Environment() {
setenv("RTEMS_NET_HOSTNAME", "myhost", 1);
setenv("RTEMS_NET_IFACE_1", "cpsw0", 1);
setenv("RTEMS_NFS_MOUNT_PATH",
"10.10.5.4:/opt/src:epics/ntp/ntp-test/iocBoot/iocntp/st.cmd",
1);
return 0;
}
epicsRtemsInitRegister bbbInit(
"bbb", "environ", rtemsInit_Order_early, true, set_BBB_Environment);
#endif /* beagleboneblack */
#endif /* __rtems__ */