At the beginning of this thesis project, Bern RTOS consisted of a preemptive Round-Robin scheduler. The only way for threads to communicate was through a few synchronization primitives. During this project, the process and thread model was introduced. In this model, multiple threads share a common memory section. This approach was chosen as a compromise because the memory protection hardware on Armv7E-M CPUs is restricted to $2^n$ bytes region size. This proved to be insufficient for thread-level protection. The advantage of a process is that the threads can communicate promptly without kernel interaction. Still missing is a defined behavior when a thread of a process crashes. It might be necessary to restart the entire process affected because message passing usually binds threads tightly together.
Besides a change in the memory model, the kernel was extended in various directions. Kernel objects are now allocated so that there are fewer parameters (e.g. max number of events) to adjust as a user. The user also has access to a process allocator. Multiple allocation methods were implemented. Although, the allocator cannot be selected at the moment. The heap algorithm currently has an issue that leads to immediate memory fragmentation. New forms of inter-process communication have been added as well. Most prominently, the kernel supports message passing (message queues). Still missing are event flags or support for a thread to wait for more than one event simultaneously. Usability has been improved with system logs and tracing. Especially tracing the threads and events has proven helpful when debugging RTOS applications.
The goal of the espresso machine application was to test the kernel on a real-world application. As expected some issues with the kernel emerged. For example does the kernel not support cache maintenance which lead to a corrupted cache due to thread switching. In addition, there seems to be an ongoing issue with variable placement in release build mode. This leads to threads being terminated on the basis of memory violations. Overall development was progressing well. In a multithreaded context application debugging became increasingly frustrating due to lacking support for Bern RTOS in the debugger (no stack traces per thread). This emphasized the importance of RTOS tracing once more.
The first few firmware revision let the espresso machine crash from time to time. Upon investigation, it was either the stack that was too small or an error in the kernel. However, the business logic written in Rust was never the issue. The strict compiler caught all critical bugs at compile time. Additionally, Rusts modern syntax and abstractions lead to efficient development and reusable code. The binary size of the firmware is comparable to an implementation in the C language. The limiting factor with embedded Rust is the small number of libraries and hardware support. However, existing C code can be used together with Rust to overcome this issue.
The testing strategy on system level was changed from white-box to a black-box approach. Now only external signals are measured. The results on system level showed that Bern RTOS can compete with existing RTOS in terms of latency. However, the test cases do not cover all the requirements defined beforehand. The aim was to develop a testing method and to implement tests for the crucial parts of the kernel. Most tests on the hardware integration-level focus on memory protection rules. These tests prove that the most integral part of the kernel works correctly.
In conclusion, Rust is suitable for embedded software applications and Bern RTOS now provides a solid foundation for real-time applications.