00:00:00.060
Hello, everybody. Almost all the people listening to our talk today are interested in our specification story or CSV story. Thank you for participating! My name is Hitoshi Hasumi, and my talk is titled 'Practical mruby/c Firmware Development with CRuby.'
00:00:08.490
This is my IoT system for a sake brewery. The temperature sensor is connected to these boxes, which send data such as temperature and humidity to a server. I am using mruby/c for these devices. This box is a prototype. The first prototype I talked about last year at RubyKaigi looked very, very basic. This year I made it a little smarter, but its function is essentially the same as the first unit. I am using mruby/c as well.
00:00:34.350
First, I will give a short explanation of what mruby/c is. I will refer to it as mrbc for simplicity. So, what is mruby/c? It's one of the mruby family. The last letter 'C' symbolizes compact, concurrent, and capability. It is especially dedicated to one-chip microcontrollers.
00:01:01.590
A microcontroller is a monolithic integrated circuit that consists of a CPU, memory, and general-purpose I/O pins. You can regard it as a tiny computer. This is a comparison table of mruby and mruby/c. As you see, mruby is three years behind the Ruby version released in 2017.
00:01:20.450
mruby is designed for general embedded software. On the other hand, mruby/c is tailored for one-chip microcontrollers. It is assumed that the RAM is less than 400 kilobytes for mruby, while mruby/c assumes that the RAM is around 40 kilobytes, which is ten times less than mruby.
00:01:39.900
This diagram shows the basic components when they run on a microcontroller. Both mruby and mruby/c utilize the same bytecode compiled by a mruby compiler. The green colors indicate that each byte is exactly the same, while the blue areas are different.
00:02:02.759
Now, let’s provide an elementary explanation of bytecode. Bytecode is a kind of intermediate representation. A virtual machine (VM) then interprets the bytecode and processes the program. The red circles represent theory, while the black circle represents your Ruby script. Your Ruby script will be tokenized and compiled into bytecode, which the VM can execute.
00:02:14.440
The lower part shows that the mruby family and mruby/c share the same compilation process. However, mruby requires an RTOS to run on microcontrollers, while mruby/c does not need any OS for multitasking. This is because it employs a long-neck mechanism for multitasking named RT0 Ruby.
00:02:35.250
I believe that mruby's VM is much smaller than that of mruby, so mruby/c runs on smaller RAM. However, mruby/c has less functionality than mruby. For instance, mruby/c supports modules but does not support kernel modules.
00:02:55.710
You may wonder how you can test mruby/c. For example, mruby/c does not have an evil machine (error machine). Furthermore, it lacks certain features that might be favorites to some developers, such as refinements. That's problematic. Developers have only these classes available, and if you try to leverage unsupported features, the mruby/c VM will fail to process it even if your compilation went well.
00:03:41.470
Despite these limitations, mruby/c can handle embedded systems well, meaning we can fully develop applications using only the features available in mruby/c. Today's agenda will cover these topics.
00:04:09.900
Let's take a short break. Remember, there is a special place in Ruby and sake you should visit. The castle near me was built in 1611.
00:04:36.790
Now, let’s get back to the main topic. Developing firmware is made up of three parts: a peripheral API wrapper and main logic. The peripheral API acts like hardware control. Most of you might be familiar with Rails, so you may understand if I say it’s like a model in a business logic context.
00:05:07.920
This can make our development situation difficult, as the business logic needs our peripheral connections to function properly. If there is a deep dependency between the business logic and the peripheral, it can complicate development significantly.
00:05:33.080
So, how do we make them slightly coupled? Otherwise, we can easily find ourselves stuck in a situation where any modification to the code may require substantial reinstallation of the program on the microcontroller.
00:06:04.260
The first part is the peripheral API, which we can call layer C or a natural technical layer. It is almost entirely in C language, but I won’t delve into that today.
00:06:32.880
Last year, I talked about how to write the API wrapper in Ruby. I explained how to start programming with Ruby and provided tips for handling hardware for software programmers like us. I also explained why I chose a microcontroller instead of a single-board computer, like a Raspberry Pi, so feel free to check the material if you're interested.
00:07:02.440
Now let's move on to the next part, the business logic. This is another way of explaining the three components. Look at the upper left, which shows the business logic, while the right and bottom show the API wrapper written in Ruby. The infinite loop monitors values like sensors, switches, Bluetooth, Wi-Fi, etc.
00:07:34.360
The infinite loop continuously checks the sensors. When it detects a change, it interacts with the business logic, which in turn calls the appropriate Peripheral API functions. If your library is implemented, it should also be shipped with the microcontroller as a framework. By following the documentation, we should be able to implement correctly.
00:08:08.520
Now, let's talk about stubbing. What do you think about this? Yes, of course, I'm talking about methods that are not implemented. Often, we end up writing business logic without hitting the peripherals because it can be costly.
00:08:30.900
In some cases, the design of peripheral details might not even be finalized. In this situation, what can we expect? Stubbing is the answer—test-driven development (TDD) helps to ensure we can write tests even without peripheral implementations.
00:09:01.460
Does anyone here have experience with TDD for embedded Ruby? No? From now on, you can call me 'Professor.' Let’s proceed to a demonstration.
00:09:25.890
This is a test case for the string class in mruby/c. You can find many assertions. Note that test classes should inherit from mruby/c test case. I will explain it later. Let's run this test.
00:09:48.110
First, the test tool creates a test routine that identifies whether the test entity can be compiled into an executable binary. Then we execute the test to see the results.
00:10:08.950
The results show success after success, meaning all tests have passed, with various operations and assertions being validated.
00:10:30.330
When I started using mruby/c, there were no testing tools available. Debugging was challenging.
00:10:48.310
So, why did I use mruby/c? I realized it was essential, so I started creating the mruby/c test gem. This gem is the first testing framework I created specifically for mruby/c.
00:11:13.250
However, mruby/c initially lacked the features needed for building a comprehensive testing tool. Therefore, I designed it as a Ruby gem, implemented using mruby's API, so it could support mocking.
00:11:35.400
Now, you can write tests for your business logic without needing to implement peripheral functions. This is an example of how that can work in practice.
00:11:57.440
The upper part is responsible for your business logic. Let’s say a sample has a method named 'do_something,' and this method will call another not yet defined method. The test will inherit the mruby/c test case class.
00:12:19.450
As you create stubbed methods for unimplemented features, the assertions will pass successfully. If you don’t have defined methods, it’s similarly straightforward to implement stubs and mocks.
00:12:40.630
From the start, my personal tool was to address the lack of testing mechanisms in mruby/c. The official version has now accepted contributions from various developers.
00:13:02.620
Thanks to the MRuby/c test gem, it is now officially part of the mruby/c ecosystem, allowing you to send pull requests confidently.
00:13:23.530
Here is a diagram that shows how mruby/c tests work. It indicates that tests are created with various components, delivering results accurately.
00:13:50.660
Now, we can discuss how to make the tests efficient. I learned a lot about utilizing test cases and how they gather various assertions. With this setup, local variables can be changed dynamically.
00:14:15.960
In this segment with a generated stub, you can see how integration works with assertions. It creates methods that return expected values, similar to how we see in Ruby.
00:14:37.810
Next, let’s take a break before diving into the final part of my talk about loops written in mruby/c.
00:15:03.720
This segment contains an infinite loop while true. Programming often consists of threading, especially when configurations for concurrent applications are involved.
00:15:31.700
Applications typically monitor user inputs, sensor values, and Bluetooth or Wi-Fi messages all at once to ensure seamless status reporting.
00:15:55.890
Now let’s focus on creating threads, especially emphasizing how easy it is to write applications for multitasking.
00:16:21.470
This is a practical example of creating threads, using native threading for operations similar to Ruby threading.
00:16:50.130
In the debugging section, we can see our business logic class named 'MyClass,' which we've developed with quite a few methods.
00:17:14.270
We have an example of how to set breakpoints effectively with the current code structure.
00:17:39.310
When a condition is met, we can interact with the debug window to determine the current state of the application.
00:18:06.870
This involves checking local variables, understanding their values during execution, and observing how our conditions evolve.
00:18:29.060
We can utilize Ruby's debugging mechanisms to introspect our programs and understand the flow in live applications.
00:18:54.200
This gives us the ability to control the execution while it’s running. Additionally, we can move cursors during these sleep states, offering vital flexibility.
00:19:21.600
This summarizes mruby/c testing and debugging mechanisms. It signifies the beginning of a new ecosystem.
00:19:44.310
It reveals the opportunities offered by concurrent tasks to maximize our capabilities while working with mruby/c.
00:20:07.020
While developing in mruby/c appears restrictive due to its limitations, it ultimately allows for effective utilization of resources.
00:20:25.240
Terminal-based development can be fun and engaging.
00:20:39.720
My name is Hitoshi Hasumi, and I'm known as Hasumi-kun or simply Hitoshi.
00:21:01.000
I enjoy soccer, sake, and coffee. Thank you for your attention!