Content area
This paper presents a framework that enables programmers to deploy embedded real-time firmware of Internet of Things (IoT) devices more conveniently than using plain C/C++-language programming, by abstracting away from low-level details and the ad hoc management of multiple, diverse network technologies. Moreover, unlike other proposals, the framework is able to accommodate both time and event-driven applications. Experimental results show that for Modbus-CAN communication, the worst-case time overhead of the framework is less than 6% of the total combined processing and communication time. Its memory requirement is less than 5% and 4% of the Flash memory and RAM available on a typical IoT microcontroller. The framework also compares favorably with respect to two other approaches in terms of the sustainable minimum cycle time, memory overhead, and level of programming abstraction when tested on a simple real-time algorithm.
Full text
1. Introduction
Most consumer products, including relatively inexpensive ones like kitchen appliances [1], contain at least one embedded processor that engages in some real-time activities. Moreover, those processors evolved from having no networking capabilities at all to a wide range of wired and wireless connectivity options, characterized by a very small hardware cost. In the past decade, this has led to the creation of smart devices and smart homes [2,3] and, more generally, a widespread diffusion of the Internet of Things (IoT) concept [4,5] that still continues unabated today, especially for applications with real-time execution requirements [6,7]. As a consequence, the challenge has become to develop embedded firmware more efficiently than in the past [8], further reducing its production cost and time to market without sacrificing quality and without resorting to higher-level design methods like, for instance, Model-Based Design (MBD).
The main contribution of this paper is the proposal of a novel firmware development framework called
The main goal of
The paper is organized as follows: Section 2 compares
2. Related Work
Among design methods standing at a higher level of abstraction with respect to plain C-language programming, MBD has been used successfully in multiple application domains, ranging from databases [13] to firmware for electricity distribution grids [14]. It offers unquestionable advantages, especially for large and mid-size systems with strong reliability and software certification requirements. However, it also forces embedded programmers to embrace a new design and programming paradigm and become familiar with new languages and tools. In some cases, especially for C-language programmers, the associated learning curve can be quite steep, like in the case of synchronous languages [15], even in their most recent evolution [16]. Similarly, approaches like the one discussed in [17,18] entail the adoption of an event-driven design paradigm and UML statecharts.
In the case of the CPAL language [19], language design aims at finding the best possible trade-off between staying as close as possible to the C language [20] (which most embedded programmers are likely to be proficient in), while incorporating all the features needed to model, simulate, and program embedded systems, as well as thoroughly scrutinize their behavior. This approach makes the language very versatile and has enabled its application to multiple case studies, like communication protocol analysis [21], fault tolerance [22], and more recently, the verification of an aerial video tracking system [23]. Nevertheless, programmers are still required to learn the CPAL language anew, as well as its specific tools and development environment.
Programming environments for Programmable Logic Controllers (PLCs) [24], either proprietary [25] or open-source [26], are also very powerful, especially when confronted with typical industrial automation applications. They are undoubtedly popular [27,28] but, like the previously mentioned ones, they are also tightly associated with dedicated Domain-Specific Languages (DSLs), such as the ones defined in [29], and the cost of PLC hardware is typically much higher than the cost of a microcontroller-based board of comparable processing power.
Arduino-based systems [30] have their own software development framework that adopts a simplified dialect of the C++ language, but the programming model consists of a single main loop that contains the code to be executed. As a consequence, over the years, it has been extended in various non-native ways to suitably support multitasking, in either a cooperative [31] or pre-emptive [32,33] way since such a feature becomes mandatory as the complexity of real-time embedded applications grows. A downside of cooperative approaches is that task execution is indeed cooperative. Hence, task switches are under the control of the running task and are executed in a timely manner only if tasks have been implemented correctly. At the same time, pre-emptive approaches make the underlying programming model more complex and introduce a new set of potential pitfalls, like race conditions, which Arduino programmers may or may not be aware of.
Other proposals, like the one described in [34,35] succeeded in speeding up firmware development by leveraging a variety of sophisticated, open-source firmware components, such as real-time operating systems (RTOSs) [36], filesystems [37], and TCP/IP protocol stacks [38]. Besides being quite sophisticated, those components have the additional advantage of being portable, and hence, readily available on many embedded platforms. However, even though those proposals effectively support modular embedded system construction and allow programmers to use the C language, they still lack much needed abstraction. As an example, if a programmer wants to read a process variable available on a sensor connected to the processor by means of a field bus like the Controller Area Network (CAN) [39] or via Ethernet, they still need to know all the details about this connection and call the appropriate library functions. Even more importantly, the corresponding code needs to be updated whenever the connection method changes as hardware technology evolves.
As discussed in the following, the framework proposed in this paper addresses the shortcomings just discussed, striving to reach a more favorable trade-off between abstraction, flexibility, use of a widespread programming language, and suitability for IoT systems with limited computing and memory capacity.
3. System Architecture
Figure 1 depicts the typical system architecture an
An additional feature of
Internet communication typically takes place through a dedicated, best-effort network, as shown in Figure 1. Although
As a real-time execution model,
To make
4. Core Framework Components
All core framework components, whose internal structure is shown in Figure 2, reside on the main controller card. Generally speaking,
Of all those components, only the timer task (Section 4.2) has been taken from [9]. The control task (Section 4.3) and the event subsystem have been significantly extended to accommodate event-driven programming, which was previously unsupported. Proxy tasks (Section 4.5) have been completely redesigned according to a new Internet access model, and the event management task (Section 5) did not previously exist.
A configuration system allows programmers to set up local and remote I/O points and access them through ordinary C-language variables, while
4.1. Real-Time Tasks and Control Cycle
The first group of tasks implements the cyclic executive and consists of a control task and a timer task. Within these tasks, the only user-provided code is a control function, depicted as a gray block in Figure 2. This function is invoked by the
4.2. Implementation Description
The timer task consists entirely of
The event system consists of a
Considering that cyclic events must be given higher priority than sporadic events to bound control cycle jitter, cyclic events are always inserted at the front of Q. Instead, sporadic events are appended to its back, to be processed in a first-in, first-out (FIFO) fashion. This is consistent with the message queue primitives
By itself, prioritizing the way events are enqueued is insufficient to grant cyclic events expedited handling, unless there is a way to guarantee that Q is never completely full when a cyclic event occurs. Otherwise, any enqueue operation—no matter if it is directed to the front or the back of the queue—would block the caller.
The counting semaphore R is used exactly for this purpose. More specifically, it keeps a record of free elements in Q that are available for sporadic events at the moment, and blocks sporadic event sources as needed, to exert back pressure on them. Accordingly, sporadic event insertions are preceded by a potentially blocking
4.3. Data Exchange Mechanism
The control task activates whenever there is an incoming event by waiting to receive a message from Q through data flow ➈. Upon receiving a cyclic event, it implements most of the control cycle, except for the control algorithm, which the control function is still responsible for. Figure 3 shows the structure of the control cycle in more detail. Each cycle consists of three mandatory phases, followed by one optional phase: During the computation phase (C phase), the control task executes the time-triggered portion of the real-time algorithms by invoking the control function. The control function operates on input data and stores results into the output data held in abstract process image (PI) variables through the bi-directional data flow ➁ shown in Figure 2. These variables are stored in their own memory area, denoted as [A] in the figure and are mapped to local or remote I/O points by the system configuration to be discussed in Section 6. In the output phase (O phase), the control task commits the value of all output PI variables to the corresponding output points, possibly going through a data format conversion stage specified by the configuration system. The conversion is transparent to the control function and adapts the CPU-dependent representation of memory-resident data to the format required by each specific I/O device. All I/O activities are performed by a real-time communication module, assisted by a set of real-time I/O libraries that provide I/O functions specific to each communication medium Finally, in the input phase (I phase), the control task queries input points and stores their values into the corresponding input PI variables, which are ready to be used during the C phase of the next cycle. In this case, data format conversions are performed as required, and I/O activities are coordinated by the communication module. During both the O and I phases, input and output data are transferred through data flow ➀, and the control function is kept inactive to avoid race conditions.
Real-time control cycle and sporadic event handling.
[Figure omitted. See PDF]
The reasons for using this unconventional order, instead of the usual I, C, O, are clarified later in the text. After completing these three phases, the control task starts the S phase, in which it checks whether there are sporadic events waiting in the queue. If there is none, the control task remains idle until a sporadic event arrives or the next cycle is due to begin, as signaled by the arrival of a new cyclic event. If some sporadic events are pending, the control task dispatches them, one at a time, to the control function. Therefore, as also shown in Figure 3, the S phase is composed of zero or more sporadic event handling intervals interleaved with idle time.
Although the handling of further sporadic events stops as soon as a cyclic event is inserted into Q—thanks to the prioritization mechanism discussed previously—the processing of the current sporadic event is allowed to complete before starting the next cycle. This event serialization approach simplifies synchronization within the control task and control function—because, in fact, there is no internal concurrency. However, it may introduce jitter at control cycle boundaries. Namely, the processing of the last sporadic event in the S phase of cycle k may delay the beginning of cycle . However, the amount of jitter is upper-bounded and, denoting the processing time of sporadic event i as , the upper bound is , regardless of the number of sporadic events in Q.
For sporadic events generated by UI and proxy tasks, the internal structure of the corresponding consists only of activities internal to the controller card performed by the control function. On the contrary, the handling of events coming from a real-time network involves I/O operations to properly refresh PI variables. They are performed by the control task, transparently and independently of the control function, as described in Section 5.
4.4. Control Function
The user-written control function, depicted as a gray block in Figure 2, is responsible for implementing the C phase of the cyclic executive, as well as handling all sporadic events generated by other parts of the firmware. As such, A pointer to the The current cycle number, which gives the control function information about elapsed time with a granularity of the cyclic executive period. Since this data item has limited width (32 bits in the current implementation), The event type that triggered the current invocation. The first and most important information that the control function can derive from this argument is whether it should perform a time-triggered C phase or handle a sporadic event. In the second case, it conveys more information about the event itself. A pointer to a user-defined data structure, which the user communicates to
As it executes, the control function has access to the PI variables stored in memory area [A] through data flow ➁ in Figure 2, as well as two other memory areas, called input and output shared memories [B] and [C], through data flows ➂ and ➅. Those are used to share part of the real-time control state with the UI and proxies, as described in Section 4.5.
4.5. User Interface and Proxy Access
Memory areas [B] and [C] of Figure 2 provide support for data sharing between the real-time algorithms and other parts of the system, namely, UI and proxy tasks. Being shared between multiple groups of tasks, these memory areas must be protected against concurrent access by means of mutual exclusion locks with definite timeouts on the real-time side. The choice of having two memory areas, each supporting unidirectional data flows ➂–➃ and ➄–➅, respectively, is useful to reduce lock contention. At the same time, keeping memory [A] disjoint from [B] and [C] also provides a safeguard against unintentional or unauthorized access to PI variables by non-real-time tasks, on systems equipped with a Memory Protection Unit (MPU) or similar memory protection mechanisms.
Data transfer to and from these shared memory areas may be performed explicitly by the control function on the real-time side and by UI and proxy tasks on the other side. This approach is convenient when some processing is required besides the transfer. Alternatively, when a mere copy is sufficient,
A typical UI consists of multiple UI tasks, which are completely user-written and are outside the scope of
Internet communication can be based upon a variety of protocols and corresponds to data flow ➉ in Figure 2. Currently,
5. Event-Driven Programming
Event-driven programming relies on the timely reaction of the embedded system to external events, typically detected by sensors connected to remote I/O cards. In this case, the challenge was to design an event management system that provided a timely reaction to events and adequate overload protection while staying within the computing and memory constraints of typical IoT systems and allowing it to coexist with the time-driven part of the framework. This goal was achieved by means of a single, dedicated event management task, a couple of semaphores, and a timer. In fact, on the controller card used for the experimental evaluation, the event-to-input and event-to-output reaction times commented in Section 8 are I/O-bound rather than CPU-bound. Moreover, the event-management system represents a modest 6% of the
As shown in Figure 4, the event management task waits for events coming from one of the
As shown in Figure 4, when an event arrives, the task first applies the hold-off algorithm to be discussed in Section 5.1 to aggregate events as necessary and avoid overloading the control task by sending it events too closely in time. Then, if the hold-off mechanism permits, it sends an event notification, which may contain multiple aggregated events, to the control task. Finally, the control task calls the control function, surrounded by the selective I/O procedure discussed in Section 5.2, to update PI variables before and after the call. When the control task has finished servicing the event, it must provide feedback to the event management task so that it can update the hold-off algorithm state and, possibly, deliver a new event notification to the control task.
While handling an event, the control task may query which remote I/O cards must be serviced during the current activation to properly drive selective I/O and minimize the number of I/O operations it performs. The control function, instead, has a more abstract view of the situation and is informed of which PI variables need to be serviced because the remote I/O card they come from has generated an event. After working on them, the control function gets the opportunity to inform the control task of which other PI variables it has updated, again, with the purpose of optimizing selective I/O.
5.1. Hold-Off Interval and Overload Avoidance
The purpose of the hold-off mechanism is to force the minimum interval between events delivered to the control task to be at least , while guaranteeing a bounded maximum event delivery latency, regardless of the rate at which incoming events arrive from remote I/O cards. In the simplest scenario, it operates as depicted in the topmost diagram of Figure 5. Namely, we have the following: At any time the event management task can be in one of two possible states, denoted as idle and hold-off in the figure. The task starts in the idle state. When idle, the task immediately sends an event notification to the control task when it receives an event from an I/O card and enters the hold-off state. As an example, the figure shows the arrival of an event from I/O card 1 and its delivery to the control task. The notification sent to the control task contains a set of events that has 1 as its only element. The hold-off period lasts for , a configurable parameter with a 1 ms granularity. If the event management task receives no further events during the hold-off period, it returns to the idle state without carrying out any further action.
Hold-off and hold-off extension intervals in event management. The numbers 1, 3, and 5 represent slaves and the events they generate.
[Figure omitted. See PDF]
On the contrary, if the task receives one or more events during the hold-off period, as depicted in the middle diagram of Figure 5, it does not immediately send any additional event notification to the control task. Instead, it aggregates all incoming events into a single notification and sends it at the end of the hold-off interval. Then, it starts the hold-off interval again, thus repeating the process. For instance, if events originating from slaves 1, 3, and 5 arrive during a hold-off interval, the event management task will send a single notification to the control module at the end of the interval. The notification will contain the set of events .
Overall, the hold-off mechanism guarantees that events arriving while the task is idle reach the control task as soon as possible. At the same time, it also guarantees that events arriving during a hold-off interval are serviced after at most , while keeping the minimum interval between consecutive control task activations also at . To do this, the hold-off mechanism breaks the one-to-one relationship between events received from the I/O cards and notifications sent to the control task. Namely, multiple events arriving in quick succession will be gathered and result in a single notification being sent.
Moreover, an overload avoidance mechanism, also implemented by the event management task, may delay the generation of further notification events towards the control task, by extending the hold-off interval, if the control task has not completely processed the previous event yet. An example of this mechanism is illustrated in the bottom diagram of Figure 5. It shows how, after initially delivering event set to the control task, the event management task kept extending the hold-off interval by until it received an end-of-service notification from the control task. During a hold-off extension, the event management task handles incoming events as in a normal hold-off interval. Like , is a configurable
5.2. Selective I/O and Event Processing
When it receives an event notification, the control task surrounds the control function invocation with a special version of the I/O operations shown in Figure 3, modified for better I/O bus utilization. More specifically, before invoking the control function, it refreshes the PI input variables of the remote cards indicated by the event notification by means of a sequence of input transactions. The other input variables keep the value they assumed in the previous time-driven cycle. The rationale behind this approach is that while the control function is reacting to external events, it is crucial for it to operate on the most recent version of the PI input variables coming from the cards that generated them. On the contrary, the other input variables have not changed significantly because the corresponding remote I/O cards did not generate any event, and hence, their immediate refresh is unnecessary.
During execution, the control function will likely update some PI output variables to react to the event. It can signal these changes by invoking the macro
6. System Configuration
System configuration lets users customize most
6.1. Board Instantiation and PI Variable Mapping
The I/O configuration file contains a sequence of macro invocations that determine which local or remote I/O devices or boards, are expected to be present in the system. Boards are instantiated from a board database that specifies the capabilities of each class of boards in terms of physical inputs and outputs. It will not be further discussed in this paper for conciseness. For example, an invocation of the macro The name of the class of boards it belongs to. This name must match one of the board classes defined in the database just mentioned. The name of the board instance being configured, which must be unique in the whole system and is used to resolve any ambiguity among boards belonging to the same class. The list of Modbus addresses the board may appear at, given as an argument to the A sequence of macro invocations that map a subset of the physical inputs and outputs available on the board being configured to the corresponding PI variables.
Example of Modbus board instantiation and PI variables mapping.
[Figure omitted. See PDF]
Each mapping macro invocation (within the fourth argument above) requires five arguments to fully specify a mapping: The name of one of the physical inputs or outputs mentioned in the board database for this class of boards. The data type of the PI variable that corresponds to it. The name of the PI variable. This is an ordinary C-language identifier that the control function can use to refer to the variable. The name of a conversion function, to convert the variable from its device-specific representation into a format suitable for the control function (for inputs) and vice versa (for outputs). A pointer to additional arguments specific to the conversion functions.
Therefore, the I/O configuration file excerpt shown in Figure 6 declares that board
6.2. Data Structure Synthesis
As mentioned previously,
The need for a second pass stems from the fact that the C macro preprocessor does not allow a macro to be defined during the expansion of a macro body [20]. On the contrary, when parsing configuration files,
To circumvent this issue, the body of the macros that need to define other macros introduce those definitions with the special token
Figure 7 contains a simplified view of the data structures that
Referring back to the PI variable descriptor, other pointers locate the converter function that
The choice of adopting a tree-like data structure in which the various nodes are linked by means of pointers instead of a monolithic structure has two distinct advantages: It becomes possible to save memory by sharing common information. For instance, all variable descriptors pertaining to variables whose value originates from the same board point to the same board descriptor. Most data can be stored in read-only Flash memory, reserving RAM (that is often a precious resource in low-cost embedded systems) for the actual read–write portions of the data structure. Referring back to Figure 7, the only read–write structures—to be stored in RAM—are the dark-gray-colored ones.
As shown in the figure, there are three main kinds of RAM-based information: The value of PI variables, Status information about them, for instance, the outcome of the last I/O operation involving them. Status information about boards as a whole, for instance, the actual Modbus address of a board that has more than one possible configured address.
6.3. Shared Memory Configuration
Shared memory configuration is performed in a very similar way. Another configuration file must contain two macro invocations, one for output shared memory [B], the other for input shared memory [C]. Figure 8 shows an example of the first kind of configuration. The outer macro argument contains a sequence of invocations of the macro The data type and the name of the variable; An indication of whether any update to the variable should trigger a sporadic event directed to the control task; The mirroring configuration.
Example of (output) shared memory configuration.
[Figure omitted. See PDF]
For instance, the first configuration item shown in Figure 8 states that the output shared memory shall contain a variable
6.4. Proxy Access
The last configuration file to be discussed is the one used to configure proxy access. As described in Section 4.5, proxy tasks may be granted access to a subset of the contents of shared memories [B] and [C]. Access configuration, exemplified in Figure 9, consists of one invocation of the macro The first step determines whether or not a shared variable is accessible to proxy tasks in general. More specifically, only variables mentioned as a first argument of a The second step specifies which proxy tasks get access, and provides additional mapping and conversion information specific to each access method. Namely, the second argument of
Example of proxy access configuration.
[Figure omitted. See PDF]
For Modbus-CAN and Modbus-TCP the mapping macro is named
7. Internet Access
7.1. Requirements
As shown in Figure 1, modern embedded systems ought to be connected to the Internet to support a wide range of services, such as remote configuration, monitoring, diagnostics, and troubleshooting, also according to the industrial IoT paradigm [53]. Hence, it becomes necessary to grant the Internet-based management software (IMS) access to a portion of the embedded system state without disrupting real-time execution. In the case of
Within the controller card, introducing a clear separation of duties between the real-time and Internet-access parts of the system alleviates security concerns and makes the system more modular. At the same time, the assignment of appropriate priorities to the proxy tasks in charge of Internet access prevents them from interfering with real-time performance and timings. In addition, all peculiarities of the Internet access method chosen for a given system—for instance, wired versus WiFi network access, or specific data encryption and authentication protocols—can easily be confined to the proxy. As an example, Figure 2 shows how a proxy can grant access to part of the system state by means of an Ethernet-based Modbus-TCP connection through path ➉.
Under this premise, the main design problem to be solved is how to do so by means of abstract, symbolic variable names, while keeping the access mechanism as simple and efficient as possible. When symbolic names are known at compile time, they can be represented as values of an enumerated data type. On the contrary, names known only at run time are usually represented as variable-length strings of characters. The support for symbolic names is a key point to decouple the IMS—typically not developed by means of
7.2. Design and Implementation
The remote access method proposed in this paper is based on a two-step translation process relying on the collaboration between the controller card and the IMS, enabling them to share the workload. Even more importantly, the method has been designed so that at least part of the required computations can be performed at compile time. More specifically, the translation proceeds as follows: The controller card and the IMS identify shared variables by means of unique values of an enumerated data type. When necessary, the IMS resolves symbolic names represented as variable-length strings of characters into the corresponding enumerated values.
An additional upside of this approach is that when multiple controller cards are present, the IMS can act as a centralized mapping point for all of them. Furthermore, shifting the workload towards the Internet node on which the IMS runs can be considered an advantage as well, because these nodes typically have more processing power than controller cards.
7.2.1. Shared Variable Enumeration
Regarding the first translation step, the underlying idea is that the controller card and the IMS have access to the shared variables configuration file described in Section 6 at compile time. From it, they can both generate an identical enumerated data type definition, together with the enumerated values associated with it, by means of the code listed in Figure 10. The code relies on techniques backed by the C language standard [20] and widely supported by C compilers like
With this approach, the enumerated values corresponding to the shared variable names are mentioned in the type definition in the same order as they appear in the configuration file when the C pre-processor scans the file. This is the same order followed when generating the input shared memory table for the controller card firmware. Considering that enumerated values are represented as integers by the compiler, and both enumerated values and array indexes start at zero, they can be used as an unambiguous index in the input shared memory table by both the controller card and the IMS.
For conciseness, the example code only shows how to generate the aforementioned data type definition from the declaration of input shared variables, but the same method is also appropriate for outputs. A finer-granularity, variable-by-variable approach is possible as well, such as the one shown for user interfaces and proxies in Section 4.5, at the expense of a higher complexity of the generation macros. However, this is not a concern because, being expanded at compile time, they do not introduce any runtime overhead.
For the same reason, the example generates a data type with a fixed name,
7.2.2. Symbolic Name Translation
Moving on to the second translation step, a variety of well-known techniques are appropriate, also because this function is carried out by the IMS, where plenty of processing power is available. For instance, a hash function can be applied to the character string that holds the symbolic name to derive the index of the corresponding entry in a hash table. An advantage of this approach is that it is quite straightforward and intuitive. However, it also has several downsides typical of hash tables: The hash function may lead to a hash value that is quite large. Since this value indicates the position of a symbolic name in the hash table, the table itself may use a large amount of memory space, although only a small portion of its elements are filled with real data. On the other hand, a hash function with a smaller range incurs in a higher probability of collisions, thus reducing access efficiency. Even though the probability may be low, a hash conflict, which arises when multiple symbolic names are associated with the same hash value, cannot be ruled out. In this case, further checks and the overhead associated with them are needed to avoid operating on the wrong variable.
Regardless of the implementation technique, the macro substitution technique illustrated previously is still useful for generating most of the required data structures and code at compile time. As an example, Figure 11 shows how to synthesize a comparison function that takes as argument a character string and resolves it into an enumerated value. The synthesis is performed completely at compile time and relies on compiler optimizations to enhance code performance and reduce footprint. It is suitable to handle a relatively small number of symbolic names efficiently, without resorting to memory-hungry data structures and complex algorithms at run time. If the input-dependent execution time of the function is a concern, it is possible to work around it by always performing the comparison of the input argument against all the symbolic names before returning the result to the caller.
7.3. Comparison with Single-Step Translation
With respect to single-step translation methods, such as the aforementioned hashing performed directly on the controller card, the two-step approach just discussed offers distinct advantages.
Firstly, the maintenance effort of the two-step approach is not significantly higher than the other. Indeed, the only requirement is that the IMS has access to a copy of the shared memory configuration files pertaining to all controller cards it is meant to communicate with at compile time. Considering that this configuration information is determined very early in the design and development process and is unlikely to change during firmware lifetime, the maintenance effort related to those configuration files can be kept at a reasonable level.
Furthermore, the method is bandwidth friendly because only enumerated values—represented as small, fixed-length integers in
Should a further consistency check between the view on shared variables of a controller card and the IMS become necessary, the controller card can still include the symbolic name (generated according to its own mapping) in its reply to an IMS request. This can be done with negligible interference with other, real-time activities because the extra processing it requires is limited. Even more importantly, since the controller card has full control on all the tasks running on it, as well as on how the real-time bus is utilized, it can choose to send back the reply at the most appropriate moment from both the processor and bus scheduling perspectives.
8. Performance Evaluation and Analysis
This part of the paper studies the overhead of
During the experiments, which were conducted in a lab setting, no communication errors were detected. The effect of communication errors on
Memory footprint evaluation has been performed statically, instead, on
8.1. Time-Driven Execution Performance
The time-driven execution performance of
The topmost layer is the
The control task performs most of the cyclic activities of
Therefore, the measurements in the third layer are the total output time and the total input time . Each of them consists of local and Modbus communication. Then, Modbus communication time was further split up to evaluate the data gathering/scattering times, called and , respectively, as well as the output and input bus transaction times and . Local I/O time was not singled out because it was found to be negligible with respect to Modbus communication time.
Data gathering and scattering are an essential part of the Modbus I/O process because, for better efficiency,
The main conclusion that can be drawn from those results is that the overhead is dominated by Modbus CAN I/O time rather than
(1)
and its average in the experiments was . In contrast, the average Modbus CAN I/O time , expressed by(2)
was . Therefore, represents less than 6% of the total overhead even when it is maximized by reducing the I/O time to the minimum (1 input and 1 output 16-bit I/O point). Another important aspect is the extremely low standard deviation of , which stayed consistently below what could be measured during the experiment. This confirms the suitability ofThe second part of the evaluation focused on the behavior of and as a function of the number of 16-bit I/O points. The results are shown in Table 2. The maximum number of I/O points considered in the experiments was 8 because Modbus I/O boards typically have between 2 and 8 analog inputs or outputs, each accessed by means of a 16-bit register [55]. The number of digital I/Os may be larger, but up to 16 of them are normally packed into the same I/O register. Besides confirming the expected direct dependency of and from the number of I/O points, the additional measurements confirm that the combined input and output standard deviation does not increase significantly and stays below 6 µs in all considered scenarios. The extra jitter incurred by when the number of I/O points exceeds two can be attributed to additional interference from the 1 ms RTOS tick handler that overlaps with the I phase of the control cycle in those cases, as also depicted in Figure 12.
8.2. Event-Driven Reactivity
The reaction time of A remote Modbus I/O card generates an event and sends an asynchronous event notification message ➀ to the controller card via a real-time bus. The controller card firmware reacts by activating the event handling task and then the control task ➁. The control task performs a selective input operation ➂, activates the control function to handle the event ➃, and performs a selective output operation ➄.
Framework timing diagram, event-driven execution. Bus traffic not shown for clarity.
[Figure omitted. See PDF]
The input and output operations that the controller card performs are seen by remote I/O cards as a sequence of Modbus register read and write operations, respectively. For writes, the timestamping point has been placed after the remote I/O card received the Modbus request from the controller card and the data to be written, but before it sent the corresponding acknowledgment. For reads, the timestamping point has been placed as soon as the remote I/O card becomes aware of the request. Therefore, represents the total reaction time of the controller card to a remote event, measured from event generation to the time at which the reaction becomes externally observable as a change of state of some of its outputs. Time , instead, is the earliest point in time when the remote I/O card that generated the event becomes aware that event handling has started.
Table 3 lists experimental results, as before, as a function of the number of 16-bit I/O points. The interval between consecutive remote event generations was set to a value greater than for the experiment to avoid triggering the activation of event gathering and hold-off interval extension. Moreover, care has been taken to avoid any interference from time-driven activities while handling an event. As in the previous set of experiments, the control function content was kept to a minimum.
Barring measurement noise, remained constant as the number of I/O points varied. This was to be expected because a Modbus register read request has a fixed length, regardless of the number of registers to be read. Instead, depends on the number of I/O points because their values are transferred together with the Modbus register write request. What is more important though, is that remained below 1.3 ms, even in the worst case, with a standard deviation below 4 µs, thus confirming that
8.3. Memory Footprint
Table 4 contains information about the The base modules of the framework, comprising its real-time tasks (Section 4.1) and configuration data structures (Section 6). The Modbus and local real-time I/O modules. The Modbus RTU, CAN, and TCP proxies (Section 4.5). The shared memory management modules, including mirroring. Additional utilities, mainly consisting of functions to dump framework data structures in a human-readable format as a high-level debugging aid. The main program of the application firmware, which initializes
Memory footprint divided by category.
| Category | Text + RO Data (B) | RW Data (B) | BSS (B) |
|---|---|---|---|
| 5257 | 0 | 136 | |
| Event management | 1536 | 0 | 0 |
| I/O modules | 5384 | 0 | 0 |
| Proxies | 3112 | 0 | 40 |
| Shared memory management | 868 | 0 | 56 |
| Utilities | 6879 | 0 | 0 |
| Main program | 1481 | 0 | 2272 |
| Total | 24,517 | 0 | 2504 |
The footprint measurement confirmed that
Besides
8.4. Comparison with Other Frameworks
The framework was compared with two other approaches among the ones discussed in Section 2. Namely, CPAL was selected among higher-level, MBD frameworks because it has successfully been used for practical cyber-physical and embedded applications. Moreover, it supports both interpreted and compiled execution, which provided further insights for the comparison. Arduino was chosen as a representative of lower-level, C++-based frameworks due to its popularity and availability on a variety of hardware platforms. In both cases, the hardware platform used for the comparison was the one closest to the
The comparison was carried out according to the following metrics: (a) minimum sustainable time-driven cycle time without incurring systematic timing errors; (b) total (code+data+BSS) footprint of the framework, as determined by the
All frameworks but interpreted CPAL were able to achieve a cycle time of 1 ms and were classified as “+” in the corresponding column of Table 7. Interpreted CPAL was classified as “−” instead.
9. Conclusions
This paper described how
The execution time overhead and memory footprint of a prototype implementation of
All in all, results show that the higher-level programming paradigm supported by
The original contributions presented in this study are included in the article. Further inquiries can be directed to the corresponding author.
The author declares no conflicts of interest.
Footnotes
Disclaimer/Publisher’s Note: The statements, opinions and data contained in all publications are solely those of the individual author(s) and contributor(s) and not of MDPI and/or the editor(s). MDPI and/or the editor(s) disclaim responsibility for any injury to people or property resulting from any ideas, methods, instructions or products referred to in the content.
Figure 1 Architecture of a system using an
Figure 2 Structure of the core framework components.
Figure 4 Relationship between the event management task and other
Figure 7
Figure 10 Generation of the enumerated data type for Internet access to shared (input) variables.
Figure 11 Direct code generation for resolving symbolic names into symbolic values.
Figure 12 Framework timing diagram, time-driven execution.
Measurement of the delays shown in
| Operation | Delay (μs) | ||||
|---|---|---|---|---|---|
| μ | | Min | Max | ||
| Local Operations | |||||
| | (timer task activation) | 3.46 | 0.00 | 3.46 | 3.46 |
| | (control function activation) | 18.75 | 0.06 | 18.69 | 18.89 |
| Output Operations, 1 16-bit I/O point | |||||
| 11.61 | 0.00 | 11.61 | 11.61 | ||
| 398.58 | 0.83 | 396.81 | 400.82 | ||
| | (Total) | 410.19 | 0.83 | 408.42 | 412.43 |
| Input Operations, 1 16-bit I/O point | |||||
| 276.96 | 1.09 | 274.80 | 279.90 | ||
| 3.59 | 0.00 | 3.59 | 3.59 | ||
| | (Total) | 280.55 | 1.09 | 278.39 | 283.49 |
Behavior of
| Number of Outputs | Total Delay | |||
|---|---|---|---|---|
| μ | σ | Min | Max | |
| 1 | 410.19 | 0.83 | 408.42 | 412.43 |
| 2 | 428.00 | 0.64 | 426.56 | 430.15 |
| 4 | 524.22 | 0.62 | 522.87 | 525.78 |
| 8 | 663.05 | 1.45 | 660.05 | 665.68 |
| Number of Inputs | Total Delay | |||
| μ | σ | Min | Max | |
| 1 | 280.55 | 1.09 | 278.39 | 283.49 |
| 2 | 360.54 | 1.59 | 357.83 | 367.03 |
| 4 | 405.67 | 3.41 | 398.87 | 415.32 |
| 8 | 544.20 | 3.91 | 536.81 | 557.93 |
Event-driven reactivity,
| Number of I/O Points | Event to Input | Event to Output | ||||||
|---|---|---|---|---|---|---|---|---|
| μ | σ | Min | Max | μ | σ | Min | Max | |
| 1 | 315.19 | 0.67 | 313.75 | 316.77 | 709.32 | 1.15 | 706.86 | 713.53 |
| 2 | 314.12 | 0.72 | 312.72 | 315.71 | 811.35 | 2.24 | 807.33 | 818.12 |
| 4 | 316.20 | 0.65 | 314.69 | 317.74 | 953.94 | 2.73 | 948.61 | 961.69 |
| 8 | 318.46 | 1.36 | 316.69 | 322.67 | 1241.20 | 3.93 | 1232.23 | 1255.63 |
Frameworks and platforms selected for the comparison. All cores but one have been disabled on multi-core processors; the BCM2837 has been forced to operate at its minimum clock speed.
| Framework | OS | Processor | CPU | Cores @ Freq. | |
|---|---|---|---|---|---|
| CPAL 1.27 | (interpreted) | Linux | BCM2837 | Cortex-A53 | 4 @ 600 MHz |
| CPAL 1.24 | (compiled) | Linux | BCM2837 | Cortex-A53 | 4 @ 600 MHz |
| Arduino 2.3.6 | (compiled) | FreeRTOS | ESP32-WROOM-32E | LX6 | 2 @ 240 MHz |
| | (compiled) | FreeRTOS | LPC1768 | Cortex-M3 | 1 @ 100 MHz |
Minimum cycle time and footprint of the selected frameworks.
| Framework | Min. Cycle Time c (ms) | Mem. Footprint (B) | |
|---|---|---|---|
| CPAL 1.27 | (interpreted) | | 679,357 |
| CPAL 1.24 | (compiled) | | 1600,623 |
| Arduino 2.3.6 | (compiled) | | 298,099 |
| | (compiled) | | 146,632 |
Semi-quantitative comparison among the selected frameworks.
| Framework | Level of Abstraction | Min. Cycle Time | Mem. Footprint | |
|---|---|---|---|---|
| CPAL 1.27 | (interpreted) | + | − | − |
| CPAL 1.24 | (compiled) | + | + | − |
| Arduino 2.3.6 | (compiled) | − | + | ∘ |
| | (compiled) | ∘ | + | + |
1. Bigler, T.; Gaderer, G.; Loschmidt, P.; Sauter, T. SmartFridge: Demand Side Management for the device level. Proceedings of the 16th IEEE Conference on Emerging Technologies and Factory Automation (ETFA); Toulouse, France, 5–9 September 2011; pp. 1-8. [DOI: https://dx.doi.org/10.1109/ETFA.2011.6059105]
2. De Silva, L.C.; Morikawa, C.; Petra, I.M. State of the art of smart homes. Eng. Appl. Artif. Intell.; 2012; 25, pp. 1313-1321. [DOI: https://dx.doi.org/10.1016/j.engappai.2012.05.002]
3. Lobaccaro, G.; Carlucci, S.; Löfström, E. A Review of Systems and Technologies for Smart Homes and Smart Grids. Energies; 2016; 9, 348. [DOI: https://dx.doi.org/10.3390/en9050348]
4. Choudhary, G.; Jain, A.K. Internet of Things: A survey on architecture, technologies, protocols and challenges. Proceedings of the International Conference on Recent Advances and Innovations in Engineering (ICRAIE); Jaipur, India, 23–25 December 2016; pp. 1-8. [DOI: https://dx.doi.org/10.1109/ICRAIE.2016.7939537]
5. Aouedi, O.; Vu, T.H.; Sacco, A.; Nguyen, D.C.; Piamrat, K.; Marchetto, G.; Pham, Q.V. A Survey on Intelligent Internet of Things: Applications, Security, Privacy, and Future Directions. IEEE Commun. Surv. Tutor.; 2024; 27, pp. 1238-1292. [DOI: https://dx.doi.org/10.1109/COMST.2024.3430368]
6. Hakiri, A.; Gokhale, A.; Yahia, S.B.; Mellouli, N. A comprehensive survey on digital twin for future networks and emerging Internet of Things industry. Comput. Netw.; 2024; 244, 110350. [DOI: https://dx.doi.org/10.1016/j.comnet.2024.110350]
7. Robinsha, S.D.; Amutha, B. Transportation networks that leverage internet of things architectures: A review. AIP Conf. Proc.; 2025; 3162, 020114. [DOI: https://dx.doi.org/10.1063/5.0241650]
8. Fariha, A.; Alwidian, S.; Azim, A. A Systematic Literature Review on Requirements Engineering and Maintenance for Embedded Software. IEEE Access; 2024; 12, pp. 114263-114279. [DOI: https://dx.doi.org/10.1109/ACCESS.2024.3443271]
9. Cibrario Bertolotti, I.; Hu, T.; Ghafour Zadeh Kashani, G. A Low-Overhead Framework for Inexpensive Embedded Control Systems. Proceedings of the 12th International Conference on Digital Telecommunications (ICDT); Venice, Italy, 23–27 April 2017; pp. 7-12.
10. Neumann, P. Communication in industrial automation—What is going on?. Control Eng. Pract.; 2007; 15, pp. 1332-1347. [DOI: https://dx.doi.org/10.1016/j.conengprac.2006.10.004]
11. Przybył, A. Hard real-time communication solution for mechatronic systems. Robot.-Comput.-Integr. Manuf.; 2018; 49, pp. 309-316. [DOI: https://dx.doi.org/10.1016/j.rcim.2017.08.001]
12. Thondalapally, K.R. Event-Driven Architectures: The Foundation of Modern Distributed Systems. Int. J. Sci. Technol.; 2025; 16, pp. 1-13. [DOI: https://dx.doi.org/10.71097/IJSAT.v16.i1.2907]
13. Mok, W.Y. A Conceptual Model Based Design Methodology for MongoDB Databases. Proceedings of the 2024 7th International Conference on Information and Computer Technologies (ICICT); Honolulu, HI, USA, 15–17 March 2024; pp. 151-159. [DOI: https://dx.doi.org/10.1109/ICICT62343.2024.00030]
14. Umbarkar, S.; Admane, S. Advanced Embedded Software and Systems using MBD for Electrical Grid Stability. Proceedings of the 2025 IEEE 14th International Conference on Communication Systems and Network Technologies (CSNT); Bhopal, India, 7–9 March 2025; pp. 1277-1280. [DOI: https://dx.doi.org/10.1109/CSNT64827.2025.10967990]
15. Benveniste, A.; Caspi, P.; Edwards, S.A.; Halbwachs, N.; Guernic, P.L.; de Simone, R. The synchronous languages 12 years later. Proc. IEEE; 2003; 91, pp. 64-83. [DOI: https://dx.doi.org/10.1109/JPROC.2002.805826]
16. Chen, J.; de Mendonça, J.L.V.; Ayele, B.S.; Bekele, B.N.; Jalili, S.; Sharma, P.; Wohlfeil, N.; Zhang, Y.; Jeannin, J.B. Synchronous Programming with Refinement Types. Proc. ACM Program. Lang.; 2024; 8, 268. [DOI: https://dx.doi.org/10.1145/3674657]
17. Samek, M. Practical UML Statecharts in C/C++; 2nd ed. Newnes: Oxford, UK, 2008.
18. Rempillo, C.; Mustafiz, S. STL4IoT: A statechart template library for IoT system design. Simulation; 2025; 101, pp. 213-239. [DOI: https://dx.doi.org/10.1177/00375497241290369] [PubMed: https://www.ncbi.nlm.nih.gov/pubmed/40046903]
19. Navet, N.; Fejoz, L. CPAL: High-level Abstractions for Safe Embedded Systems. Proceedings of the ACM International Workshop on Domain-Specific Modeling (DSM); Amsterdam, The Netherlands, 30 October 2016; pp. 35-41. [DOI: https://dx.doi.org/10.1145/3023147.3023153]
20.
21. Cibrario Bertolotti, I.; Hu, T.; Navet, N. Model-based design languages: A case study. Proceedings of the 13th IEEE International Workshop on Factory Communication Systems (WFCS); Trondheim, Norway, 31 May–2 June 2017; pp. 1-6. [DOI: https://dx.doi.org/10.1109/WFCS.2017.7991964]
22. Hu, T.; Cibrario Bertolotti, I.; Navet, N. Towards Seamless Integration of N-Version Programming in Model-Based Design. Proceedings of the 22nd IEEE International Conference on Emerging Technologies and Factory Automation (ETFA); Limassol, Cyprus, 13–15 September 2017; pp. 1-8.
23. Altmeyer, S.; André, É.; Dal Zilio, S.; Fejoz, L.; Harbour, M.G.; Graf, S.; Gutiérrez, J.J.; Henia, R.; Le Botlan, D.; Lipari, G.
24. Bolton, W. Programmable Logic Controllers; 6th ed. Newnes: Oxford, UK, 2015.
25. CODESYS. Industrial IEC 61131-3 PLC Programming. 2018; Available online: https://www.codesys.com (accessed on 16 June 2025).
26. Strasser, T.; Rooker, M.; Ebenhofer, G.; Zoitl, A.; Sunder, C.; Valentini, A.; Martel, A. Framework for Distributed Industrial Automation and Control (4DIAC). Proceedings of the 6th IEEE International Conference on Industrial Informatics (INDIN); Daejeon, Republic of Korea, 13–16 July 2008; pp. 283-288. [DOI: https://dx.doi.org/10.1109/INDIN.2008.4618110]
27. Fu, Y.; Gui, W.; Song, H. Smart Factory Design Based on CoDeSys. Proceedings of the 2023 6th International Conference on Information Communication and Signal Processing (ICICSP); Xi’an, China, 23–25 September 2023; pp. 860-865. [DOI: https://dx.doi.org/10.1109/ICICSP59554.2023.10390674]
28. Pinto, G.; Nunes, A.; Silva, L.; Pinto, R.; Pinheiro, J.; Ribeiro, A. Digital Factory: An Industrial Case Study for Function Block-Oriented Development. Proceedings of the 2023 IEEE 9th World Forum on Internet of Things (WF-IoT); Aveiro, Portugal, 12-–27 October 2023; pp. 1-6. [DOI: https://dx.doi.org/10.1109/WF-IoT58464.2023.10539486]
29.
30. Arduino, A.G. Arduino IDE. 2018; Available online: https://www.arduino.cc (accessed on 16 June 2025).
31. Ávila, B.Y.L.; Vázquez, C.A.G.; Baluja, O.P.; Alexandru, M.; Cotfas, D.T.; Cotfas, P.A.; Domínguez, L.A.Q. Protothread and Cooperative Multitasking Scheduler on the Arduino Framework. Proceedings of the 2024 International Conference on Applied and Theoretical Electricity (ICATE); Craiova, Romania, 24–26 October 2024; pp. 1-5. [DOI: https://dx.doi.org/10.1109/ICATE62934.2024.10749444]
32. Buonocunto, P.; Biondi, A.; Lorefice, P. Real-time multitasking in Arduino. Proceedings of the 9th IEEE International Symposium on Industrial Embedded Systems (SIES); Pisa, Italy, 18–20 June 2014; pp. 1-4. [DOI: https://dx.doi.org/10.1109/SIES.2014.7087331]
33. Restuccia, F.; Pagani, M.; Mascitti, A.; Barrow, M.; Marinoni, M.; Biondi, A.; Buttazzo, G.; Kastner, R. ARTe: Providing real-time multitasking to Arduino. J. Syst. Softw.; 2022; 186, 111185. [DOI: https://dx.doi.org/10.1016/j.jss.2021.111185]
34. Cibrario Bertolotti, I.; Hu, T. Modular design of an open-source, networked embedded system. Comput. Stand. Interfaces; 2015; 37, pp. 41-52. [DOI: https://dx.doi.org/10.1016/j.csi.2014.05.004]
35. Farina, M.D.O.; Pohren, D.H.; Roque, A.d.S.; Silva, A.; da Costa, J.P.J.; Fontoura, L.M.; Anjos, J.C.S.d.; Freitas, E.P.d. Hardware-Independent Embedded Firmware Architecture Framework. J. Internet Serv. Appl.; 2024; 15, pp. 14-24. [DOI: https://dx.doi.org/10.5753/jisa.2024.3634]
36. Barry, R. Using the FreeRTOS Real Time Kernel—Standard Edition; 1st ed. Lulu Press: Raleigh, NC, USA, 2010.
37. ChaN. FatFs Generic FAT File System Module. 2018; Available online: http://elm-chan.org/fsw/ff/00index_e.html (accessed on 16 June 2025).
38. Dunkels, A. lwIP—A Lightweight TCP/IP Stack. 2018; Available online: http://savannah.nongnu.org/projects/lwip/ (accessed on 16 June 2025).
39.
40. Pontarolli, R.P.; Bigheti, J.A.; Domingues, F.O.; de Sá, L.B.; Godoy, E.P. Distributed I/O as a service: A data acquisition solution to Industry 4.0. HardwareX; 2022; 12, e00355. [DOI: https://dx.doi.org/10.1016/j.ohx.2022.e00355] [PubMed: https://www.ncbi.nlm.nih.gov/pubmed/36110159]
41. Cena, G.; Cibrario Bertolotti, I.; Hu, T.; Valenzano, A. Design, verification, and performance of a MODBUS-CAN adaptation layer. Proceedings of the 10th IEEE International Workshop on Factory Communication Systems (WFCS); Toulouse, France, 5–7 May 2014; pp. 1-10. [DOI: https://dx.doi.org/10.1109/WFCS.2014.6837605]
42. CiA. CiA 301 V4.2.0 – CANopen Application Layer and Communication Profile; CAN in Automation e.V.: Nuremberg, Germany, 2011.
43. Modbus-IDA. MODBUS Messaging on TCP/IP Implementation Guide V1.0b; Modbus Organization, Inc.: Westford, MA, USA, 2006; Available online: http://www.modbus-ida.org/ (accessed on 19 May 2025).
44. Modbus-IDA. MODBUS over Serial Line Specification and Implementation Guide V1.02; Modbus Organization, Inc.: Westford, MA, USA, 2006; Available online: http://www.modbus-ida.org/ (accessed on 16 June 2025).
45. Walter, C. FreeMODBUS—A Modbus ASCII/RTU and TCP Implementation. Available online: http://freemodbus.berlios.de/ (accessed on 16 June 2025).
46. Embedded Solutions. Modbus Master. Available online: http://www.embedded-solutions.at/ (accessed on 19 May 2025).
47. Tisserant, E.; Dupin, F. Free Software CANopen Framework. Available online: https://canfestival.org/ (accessed on 19 May 2025).
48.
49. Baker, T.P.; Shaw, A. The cyclic executive model and Ada. Proceedings of the IEEE Real-Time Systems Symposium (RTSS); Huntsville, AL, USA, 6–8 December 1988; pp. 120-129. [DOI: https://dx.doi.org/10.1109/REAL.1988.51108]
50. Caccamo, M.; Baker, T.; Burns, A.; Buttazzo, G.; Sha, L. Real-Time Scheduling for Embedded Systems. Handbook of Networked and Embedded Control Systems; Hristu-Varsakelis, D.; Levine, W.S. Birkhäuser Boston: Cambridge, MA, USA, 2005; pp. 173-195.
51. Modbus-IDA. MODBUS Application Protocol Specification V1.1b; Modbus Organization, Inc.: Westford, MA, USA, 2006; Available online: http://www.modbus-ida.org/ (accessed on 16 June 2025).
52. Locke, C.D. Software architecture for hard real-time applications: Cyclic executives vs. fixed priority executives. Real-Time Syst.; 1992; 4, pp. 37-53. [DOI: https://dx.doi.org/10.1007/BF00365463]
53. Bloom, G.; Alsulami, B.; Nwafor, E.; Cibrario Bertolotti, I. Design patterns for the industrial Internet of Things. Proceedings of the 14th IEEE International Workshop on Factory Communication Systems (WFCS); Imperia, Italy, 13–15 June 2018; pp. 1-10. [DOI: https://dx.doi.org/10.1109/WFCS.2018.8402353]
54. NXP B.V. LPC1769/68/67/66/65/64/63 Product Data Sheet, Rev. 6. 2010; Available online: http://www.nxp.com/ (accessed on 16 June 2025).
55. Moxa Inc. Modular I/O Product Series. 2018; Available online: https://www.moxa.com/product/Modular_IO.htm (accessed on 16 June 2025).
56. Chamberlain, S.; Pesch, R. Red Hat Support Johnston, J. The Red Hat Newlib C Library, Libc 2.2.0; Red Hat Inc.: Raleigh, NC, USA, 2014.
57. Cibrario Bertolotti, I. RTOS Support in C-Language Toolchains. Proceedings of the 18th IEEE International Conference on Industrial Technology (ICIT); Toronto, ON, Canada, 22–25 March 2017; pp. 1328-1333. [DOI: https://dx.doi.org/10.1109/ICIT.2017.7915556]
© 2025 by the author. Licensee MDPI, Basel, Switzerland. This article is an open access article distributed under the terms and conditions of the Creative Commons Attribution (CC BY) license (https://creativecommons.org/licenses/by/4.0/). Notwithstanding the ProQuest Terms and Conditions, you may use this content in accordance with the terms of the License.