rabbit-slide-hasumikin-RubyConf2019 2019.11.18.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rabbit +1 -0
- data/README.rd +24 -0
- data/Rakefile +17 -0
- data/config.yaml +24 -0
- data/images/IDE.png +0 -0
- data/images/Powerpoint Content Slide.png +0 -0
- data/images/Powerpoint Hold Slide.png +0 -0
- data/images/asahi-1.jpg +0 -0
- data/images/asahi-2.jpg +0 -0
- data/images/asahi-3.jpg +0 -0
- data/images/bytecode.png +0 -0
- data/images/co2.png +0 -0
- data/images/co2_demo.png +0 -0
- data/images/collage01.jpg +0 -0
- data/images/esp32.jpg +0 -0
- data/images/fuzz.png +0 -0
- data/images/hasumi.jpg +0 -0
- data/images/how-mrubyc-test-works.png +0 -0
- data/images/juji-asahi.jpg +0 -0
- data/images/kamos.jpg +0 -0
- data/images/mark32.png +0 -0
- data/images/mark48.png +0 -0
- data/images/mark64.png +0 -0
- data/images/mobile.png +0 -0
- data/images/monstarlab.png +0 -0
- data/images/monstarlab_webpage.png +0 -0
- data/images/mruby_and_mrubyc-mruby.png +0 -0
- data/images/mruby_and_mrubyc-mrubyc.png +0 -0
- data/images/mruby_and_mrubyc.png +0 -0
- data/images/psoc5lp_chip.jpg +0 -0
- data/images/raspberrypi.jpg +0 -0
- data/images/rubykaigi2020.png +0 -0
- data/images/rubylabel.jpg +0 -0
- data/images/rubylabeljujiasahi.jpg +0 -0
- data/images/unsoldered-2.png +0 -0
- data/images/unsoldered.jpg +0 -0
- data/images//346/235/276/346/261/237/345/237/216_Matsue.rb.jpg +0 -0
- data/mrubyc-Running-on-Less-Than-64KB-RAM-Microcontroller.rab +720 -0
- data/pdf/RubyConf2019-mrubyc-Running-on-Less-Than-64KB-RAM-Microcontroller.pdf +0 -0
- data/theme.rb +118 -0
- metadata +97 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7d313e1ad0aef139cb1993d6641f9f054542121a09d0f5a88f1b18dc544871cf
|
4
|
+
data.tar.gz: 85b7b21fa455a01dfc22108f822e4dd433fe96d603a282ddcfa2949cd72dc293
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a95f09ae99c0b83eac872d3b8af4a09c819e163708ebf79e4232bf4f296948f06e987d6b2d4c7ed63e0440149fca2c83bfad80a08eced711a8870c30ab564bdd
|
7
|
+
data.tar.gz: 075c61a9408b085f1e22aeedebf0aac3bdd608b334af8039c4b09328ee3fd680766c4483eaf5a91efc137ee741d5ee1bd649053f20edef7c8ba799621dc986d2
|
data/.rabbit
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
mrubyc-Running-on-Less-Than-64KB-RAM-Microcontroller.rab
|
data/README.rd
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
= mruby/c: Running on Less Than 64KB RAM Microcontroller
|
2
|
+
|
3
|
+
A presentation slide for RubyConf 2019 at JW Marriott Nashville on Nov 18, 2019
|
4
|
+
|
5
|
+
== 作者向け
|
6
|
+
|
7
|
+
=== 表示
|
8
|
+
|
9
|
+
rake
|
10
|
+
|
11
|
+
=== 公開
|
12
|
+
|
13
|
+
rake publish
|
14
|
+
|
15
|
+
== 閲覧者向け
|
16
|
+
|
17
|
+
=== インストール
|
18
|
+
|
19
|
+
gem install rabbit-slide-hasumikin-RubyConf2019
|
20
|
+
|
21
|
+
=== 表示
|
22
|
+
|
23
|
+
rabbit rabbit-slide-hasumikin-RubyConf2019.gem
|
24
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "rabbit/task/slide"
|
2
|
+
|
3
|
+
# Edit ./config.yaml to customize meta data
|
4
|
+
|
5
|
+
spec = nil
|
6
|
+
Rabbit::Task::Slide.new do |task|
|
7
|
+
spec = task.spec
|
8
|
+
# spec.files += Dir.glob("doc/**/*.*")
|
9
|
+
# spec.files -= Dir.glob("private/**/*.*")
|
10
|
+
# spec.add_runtime_dependency("rabbit-theme-YOUR-THEME")
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Tag #{spec.version}"
|
14
|
+
task :tag do
|
15
|
+
sh("git", "tag", "-a", spec.version.to_s, "-m", "Publish #{spec.version}")
|
16
|
+
sh("git", "push", "--tags")
|
17
|
+
end
|
data/config.yaml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
---
|
2
|
+
id: RubyConf2019
|
3
|
+
base_name: mrubyc-Running-on-Less-Than-64KB-RAM-Microcontroller
|
4
|
+
tags:
|
5
|
+
- mruby/c
|
6
|
+
- Sake
|
7
|
+
- IoT
|
8
|
+
presentation_date: '2019-11-18'
|
9
|
+
presentation_start_time:
|
10
|
+
presentation_end_time:
|
11
|
+
version: 2019.11.18.0
|
12
|
+
licenses: []
|
13
|
+
slideshare_id:
|
14
|
+
speaker_deck_id:
|
15
|
+
ustream_id:
|
16
|
+
vimeo_id:
|
17
|
+
youtube_id:
|
18
|
+
author:
|
19
|
+
markup_language: :rd
|
20
|
+
name: HASUMI Hitoshi
|
21
|
+
email: hasumikin@gmail.com
|
22
|
+
rubygems_user: hasumikin
|
23
|
+
slideshare_user:
|
24
|
+
speaker_deck_user:
|
data/images/IDE.png
ADDED
Binary file
|
Binary file
|
Binary file
|
data/images/asahi-1.jpg
ADDED
Binary file
|
data/images/asahi-2.jpg
ADDED
Binary file
|
data/images/asahi-3.jpg
ADDED
Binary file
|
data/images/bytecode.png
ADDED
Binary file
|
data/images/co2.png
ADDED
Binary file
|
data/images/co2_demo.png
ADDED
Binary file
|
Binary file
|
data/images/esp32.jpg
ADDED
Binary file
|
data/images/fuzz.png
ADDED
Binary file
|
data/images/hasumi.jpg
ADDED
Binary file
|
Binary file
|
Binary file
|
data/images/kamos.jpg
ADDED
Binary file
|
data/images/mark32.png
ADDED
Binary file
|
data/images/mark48.png
ADDED
Binary file
|
data/images/mark64.png
ADDED
Binary file
|
data/images/mobile.png
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,720 @@
|
|
1
|
+
= mruby/c: Running on Less Than 64KB RAM Microcontroller
|
2
|
+
|
3
|
+
# : subtitle
|
4
|
+
# サブタイトル
|
5
|
+
: author
|
6
|
+
HASUMI Hitoshi @hasumikin
|
7
|
+
# : institution
|
8
|
+
# 所属
|
9
|
+
# : content-source
|
10
|
+
# イベント名
|
11
|
+
# : date
|
12
|
+
# November 18, 2019
|
13
|
+
: allotted-time
|
14
|
+
38m
|
15
|
+
: theme
|
16
|
+
theme
|
17
|
+
|
18
|
+
= Me
|
19
|
+
* HASUMI Hitoshi\n@hasumikin
|
20
|
+
* Live in Matsue city,\na holy place of Ruby
|
21
|
+
* Sake 🍶\nSoba 🍜\nCoffee ☕
|
22
|
+
# image
|
23
|
+
# src = images/hasumi.jpg
|
24
|
+
# align = right
|
25
|
+
# relative-height = 80
|
26
|
+
# relative_margin_left = 25
|
27
|
+
|
28
|
+
= Me
|
29
|
+
# image
|
30
|
+
# src = images/monstarlab.png
|
31
|
+
# relative_width = 104
|
32
|
+
# relative_margin_top = -1
|
33
|
+
|
34
|
+
= Me
|
35
|
+
# image
|
36
|
+
# src = images/monstarlab_webpage.png
|
37
|
+
# relative_width = 104
|
38
|
+
# relative_margin_top = -2
|
39
|
+
== prop
|
40
|
+
: hide-title
|
41
|
+
true
|
42
|
+
|
43
|
+
= FUZZ
|
44
|
+
# image
|
45
|
+
# src = images/fuzz.png
|
46
|
+
# relative_width = 105
|
47
|
+
# relative_margin_top = -1
|
48
|
+
|
49
|
+
= Me
|
50
|
+
# image
|
51
|
+
# src = images/松江城_Matsue.rb.jpg
|
52
|
+
# relative_width = 105
|
53
|
+
# relative_margin_top = -7
|
54
|
+
== prop
|
55
|
+
: hide-title
|
56
|
+
true
|
57
|
+
|
58
|
+
= hide title
|
59
|
+
(('tag:center'))\n\n\n
|
60
|
+
(('tag:small:Chapter 1'))\n
|
61
|
+
(('tag:xx-large:Introduction'))
|
62
|
+
== prop
|
63
|
+
: hide-title
|
64
|
+
true
|
65
|
+
|
66
|
+
= Terminology
|
67
|
+
* mruby/c
|
68
|
+
* A language implementation I will talk about today
|
69
|
+
* I say mrubyc since ((*/c*)) [slˈæʃ síː] is hard to pronounce
|
70
|
+
* Microcontroller
|
71
|
+
* Small computer contains CPU, memory and programmable I/O peripherals
|
72
|
+
|
73
|
+
= Terminology
|
74
|
+
* RTOS
|
75
|
+
* Real-time OS. Usually used for microcontroller
|
76
|
+
* Task
|
77
|
+
* Almost equivalent to `Thread` in Linux. We say `Task` in microcontroller world
|
78
|
+
|
79
|
+
= Terminology
|
80
|
+
* 旭日酒造 (Asahi-Shuzo)
|
81
|
+
* Shuzo means `Sake brewery`
|
82
|
+
* One of the best Japanese Sake brewery
|
83
|
+
* FYI, Asahi Breweries (famous for SUPER DRY) has no concern with Asahi-Shuzo
|
84
|
+
* Asahi-Shuzo and I make an IoT system using mruby/c
|
85
|
+
|
86
|
+
= Why microcontroller?
|
87
|
+
* I don't use single board computer like Raspberry Pi for production environment.
|
88
|
+
* I use microcontroller, instead
|
89
|
+
* It starts immediately right after plugged in
|
90
|
+
* End-users, brewery workers in my case, can use it simply like home electical appliance
|
91
|
+
|
92
|
+
= Why microcontroller?
|
93
|
+
* Microcontroller can run without OS
|
94
|
+
* So-called `Bare Metal`
|
95
|
+
* You can narrow security issue list
|
96
|
+
* Many a malware aims at Linux or Windows platform as a target
|
97
|
+
* You don't need to consider unnecessary deamon
|
98
|
+
* You don't need to do `apt upgrade`
|
99
|
+
* (RasPi can be bare metal device if you want)
|
100
|
+
|
101
|
+
= Why microcontroller?
|
102
|
+
* Low energy
|
103
|
+
* Rarely overheated
|
104
|
+
* Many choices of power supply
|
105
|
+
* Mass production
|
106
|
+
* You can choose appropriate chipset (number of GPIO, memory size, etc.) for your application
|
107
|
+
* Cost advantage for parts supply and subcontractor manufacturing
|
108
|
+
|
109
|
+
= Which microcontroller?
|
110
|
+
|
111
|
+
= Which microcontroller?
|
112
|
+
# image
|
113
|
+
# src = images/psoc5lp_chip.jpg
|
114
|
+
# align = center
|
115
|
+
# relative-height = 45
|
116
|
+
* e.g. CYPRESS PSoC5LP
|
117
|
+
* 32 bit Arm Cortex-M3 CPU
|
118
|
+
* Flash: 256KB
|
119
|
+
* SRAM: 64KB (target size of mruby/c)
|
120
|
+
|
121
|
+
= Which microcontroller?
|
122
|
+
# image
|
123
|
+
# src = images/esp32.jpg
|
124
|
+
# align = center
|
125
|
+
# relative-height = 50
|
126
|
+
* e.g. Espressif ESP-WROOM-32 (ESP32)
|
127
|
+
* 32 bit dual core LX6 CPU
|
128
|
+
* Flash: 4MB
|
129
|
+
* SRAM: 520KB
|
130
|
+
|
131
|
+
= My IoT project
|
132
|
+
|
133
|
+
= My IoT project
|
134
|
+
* IoT system for Sake brewing
|
135
|
+
* PSoC5LP
|
136
|
+
* Delivered to actual brew work in January 2018
|
137
|
+
* Devices post temperature of Sake ingredient in brewing, surrounding temperature and humidity to server
|
138
|
+
* Data is displayed on mobile app
|
139
|
+
|
140
|
+
= photo
|
141
|
+
# image
|
142
|
+
# src = images/asahi-2.jpg
|
143
|
+
# relative_width = 105
|
144
|
+
# relative_margin_top = -3
|
145
|
+
== prop
|
146
|
+
: hide-title
|
147
|
+
true
|
148
|
+
|
149
|
+
= photo
|
150
|
+
# image
|
151
|
+
# src = images/asahi-3.jpg
|
152
|
+
# relative_height = 110
|
153
|
+
# relative_margin_top = -3
|
154
|
+
== prop
|
155
|
+
: hide-title
|
156
|
+
true
|
157
|
+
|
158
|
+
= photo
|
159
|
+
# image
|
160
|
+
# src = images/asahi-1.jpg
|
161
|
+
# relative_height = 110
|
162
|
+
# relative_margin_top = -3
|
163
|
+
== prop
|
164
|
+
: hide-title
|
165
|
+
true
|
166
|
+
|
167
|
+
= My IoT project
|
168
|
+
# image
|
169
|
+
# src = images/kamos.jpg
|
170
|
+
# align = center
|
171
|
+
# relative-height = 100
|
172
|
+
|
173
|
+
= My IoT project
|
174
|
+
# image
|
175
|
+
# src = images/collage01.jpg
|
176
|
+
# align = center
|
177
|
+
# relative-height = 100
|
178
|
+
|
179
|
+
= My IoT project
|
180
|
+
# image
|
181
|
+
# src = images/mobile.png
|
182
|
+
# align = center
|
183
|
+
# relative-height = 100
|
184
|
+
|
185
|
+
= IoT in field makes you hurry
|
186
|
+
* Imagine,
|
187
|
+
* You have to go back and forth between dark 5℃ (=41°F) storage cellar and humid 35℃ (=95°F) rice mold room
|
188
|
+
* Brewery workers run around
|
189
|
+
* You have to amend your firmware with your small laptop in 10 minutes
|
190
|
+
* You will thank Ruby's descriptiveness and agility
|
191
|
+
|
192
|
+
= photo
|
193
|
+
# image
|
194
|
+
# src = images/rubylabeljujiasahi.jpg
|
195
|
+
# relative_width = 105
|
196
|
+
# relative_margin_top = -7
|
197
|
+
== prop
|
198
|
+
: hide-title
|
199
|
+
true
|
200
|
+
|
201
|
+
= photo
|
202
|
+
# image
|
203
|
+
# src = images/rubykaigi2020.png
|
204
|
+
# relative_width = 105
|
205
|
+
# relative_margin_top = -1
|
206
|
+
== prop
|
207
|
+
: hide-title
|
208
|
+
true
|
209
|
+
|
210
|
+
= Demo
|
211
|
+
* CO(('sub:2')) concentration
|
212
|
+
* 400ppm : Atmospheric
|
213
|
+
* 1000ppm : Your programming speed decreases
|
214
|
+
* 1500ppm : FYI, tomatoes ((*🍅*)) may grow well
|
215
|
+
* > 2000ppm : Sleepiness, headache
|
216
|
+
* > 40000ppm : 💀
|
217
|
+
* (Please look at the screen)
|
218
|
+
|
219
|
+
= Demo
|
220
|
+
* My device is taking CO(('sub:2')) concentration
|
221
|
+
* CO(('sub:2')) may increase because of your breathing
|
222
|
+
|
223
|
+
= Demo
|
224
|
+
* My device is taking CO(('sub:2')) concentration
|
225
|
+
* CO(('sub:2')) may increase because of your breathing
|
226
|
+
* I will prove that it is due to CO(('sub:2')) if you fell asleep while I was speaking
|
227
|
+
|
228
|
+
(('tag:center'))\n
|
229
|
+
(('tag:xx-large:😴'))
|
230
|
+
|
231
|
+
= Bugaboos in IoT 👻
|
232
|
+
|
233
|
+
= Bugaboos in IoT 👻
|
234
|
+
* Peripheral equipments ...★
|
235
|
+
* Circuit, wiring and housing
|
236
|
+
* Printed circuit board = PCB
|
237
|
+
* Soldering ...★
|
238
|
+
* Firmware with C, mruby and mruby/c ...★
|
239
|
+
* Network, TCP/IP, Bluetooth, etc.
|
240
|
+
(('tag:right'))
|
241
|
+
★...I will cover these topics today
|
242
|
+
|
243
|
+
= Peripheral equipments
|
244
|
+
|
245
|
+
= Peripheral equipments
|
246
|
+
* Very important to check the part before writing application code
|
247
|
+
* Do equipments like sensor or communication module work as its spec sheets?
|
248
|
+
* Whether or not the equipment is broken (sometimes broken by soldering heat 😭)
|
249
|
+
* Combining parts is unrevertable
|
250
|
+
* We don't have a Git for hardware.
|
251
|
+
|
252
|
+
= Peripheral equipments
|
253
|
+
# image
|
254
|
+
# src = images/raspberrypi.jpg
|
255
|
+
# relative-height = 55
|
256
|
+
|
257
|
+
* Raspberry Pi & CRuby are great for pre-prototyping
|
258
|
+
* Use breadboard or make PCB for experiment
|
259
|
+
|
260
|
+
= CRuby and serial port
|
261
|
+
# enscript ruby
|
262
|
+
# Notice: This is CRuby for RasPi
|
263
|
+
require "rubyserial"
|
264
|
+
require "timeout"
|
265
|
+
sp = Serial.new "/dev/serial0", 9600, 8
|
266
|
+
loop do
|
267
|
+
puts "[command]"
|
268
|
+
command = gets
|
269
|
+
sp.write command.sub("\n", "\r") # replace LF if needed
|
270
|
+
sleep 0.1
|
271
|
+
result = ""
|
272
|
+
begin
|
273
|
+
Timeout.timeout(10) do
|
274
|
+
loop do
|
275
|
+
line = sp.read(128)
|
276
|
+
break if line == "" && result != ""
|
277
|
+
result << line
|
278
|
+
sleep 0.1
|
279
|
+
end
|
280
|
+
puts "=> " + result
|
281
|
+
end
|
282
|
+
rescue Timeout::Error
|
283
|
+
|
284
|
+
= CRuby and serial port
|
285
|
+
# enscript bash
|
286
|
+
$ serial_communication_test.rb
|
287
|
+
[command]
|
288
|
+
AT # command
|
289
|
+
=> OK # response
|
290
|
+
[command]
|
291
|
+
AT+CIMI # command
|
292
|
+
=> 123456789012 # response
|
293
|
+
[command]
|
294
|
+
AT+XXX # command
|
295
|
+
=> error # response
|
296
|
+
|
297
|
+
= Soldering
|
298
|
+
|
299
|
+
= Soldering
|
300
|
+
# image
|
301
|
+
# src = images/unsoldered.jpg
|
302
|
+
# relative-width = 30
|
303
|
+
|
304
|
+
* It often works even if you leave a pin unsoldered on surface mounting
|
305
|
+
* Because the pin touches circuit's plate
|
306
|
+
* Then, it will come not to work one day
|
307
|
+
|
308
|
+
= Soldering
|
309
|
+
# image
|
310
|
+
# src = images/unsoldered-2.png
|
311
|
+
# relative-width = 30
|
312
|
+
|
313
|
+
* Discovering this kind of bug is much more difficult than software bug
|
314
|
+
* My teacher said "All the cause of failure, it is ((*impatience*))"
|
315
|
+
|
316
|
+
= hide title
|
317
|
+
(('tag:center'))\n\n\n
|
318
|
+
(('tag:small:Chapter 2'))\n
|
319
|
+
(('tag:xx-large:mruby/c'))
|
320
|
+
== prop
|
321
|
+
: hide-title
|
322
|
+
true
|
323
|
+
|
324
|
+
= What is mruby?
|
325
|
+
|
326
|
+
= What is mruby?
|
327
|
+
* github.com/mruby/mruby
|
328
|
+
* Another implemantation of Ruby for general embedded usage
|
329
|
+
* Easily combined with system programming like C/C++
|
330
|
+
* e.g. ngx_mruby is a popular product of mruby
|
331
|
+
* Good for making command line tool as one-binary executable
|
332
|
+
|
333
|
+
= What is mruby((*/c*))?
|
334
|
+
|
335
|
+
= What is mruby((*/c*))?
|
336
|
+
* github.com/mrubyc/mrubyc
|
337
|
+
* Yet another implementation of mruby
|
338
|
+
* `/c` symbolizes compact, concurrent and capability
|
339
|
+
* Especially dedicated to one-chip microcontroller
|
340
|
+
|
341
|
+
= Bytecode is a common stuff
|
342
|
+
* They are compiled by `mrbc` (mruby compiler) and each VM execute bytecode
|
343
|
+
# image
|
344
|
+
# src = images/mruby_and_mrubyc.png
|
345
|
+
# align = center
|
346
|
+
# relative-height = 100
|
347
|
+
|
348
|
+
= Bytecode?
|
349
|
+
* A kind of intermediate representation
|
350
|
+
* mruby bytecode is designed for mruby VM
|
351
|
+
* mruby VM dynamically interprets the bytecode and processes the application
|
352
|
+
|
353
|
+
= HEX dump of bytecode
|
354
|
+
(('tag:center'))\n
|
355
|
+
Looks like this if you compile\n`puts "Hello World!"`
|
356
|
+
\n
|
357
|
+
|
358
|
+
# enscript C
|
359
|
+
5249 5445 3030 3036 9a78 0000 0062 4d41 RITE0006.x...bMA
|
360
|
+
545a 3030 3030 4952 4550 0000 0044 3030 TZ0000IREP...D00
|
361
|
+
3032 0000 0060 0001 0004 0000 0000 000c 02...`..........
|
362
|
+
1001 4f02 002e 0100 0137 0167 0000 0001 ..O......7.g....
|
363
|
+
0000 0c48 656c 6c6f 2057 6f72 6c64 2100 ...Hello World!.
|
364
|
+
0000 0100 0470 7574 7300 454e 4400 0000 .....puts.END...
|
365
|
+
0008 ..
|
366
|
+
|
367
|
+
= mruby on microcontroller
|
368
|
+
* RTOS (Real-Time OS) manages mruby VMs in order to realize multi tasking
|
369
|
+
# image
|
370
|
+
# src = images/mruby_and_mrubyc-mruby.png
|
371
|
+
# align = center
|
372
|
+
# relative-height = 100
|
373
|
+
|
374
|
+
= mruby/c on microcontroller
|
375
|
+
* mruby/c has its own mechanism to manage multi tasks: ((*rrt0*))
|
376
|
+
# image
|
377
|
+
# src = images/mruby_and_mrubyc-mrubyc.png
|
378
|
+
# align = center
|
379
|
+
# relative-height = 100
|
380
|
+
|
381
|
+
= mruby and mruby/c
|
382
|
+
# RT
|
383
|
+
|
384
|
+
mruby, mruby/c
|
385
|
+
|
386
|
+
v1.0.0 in Jan 2014, v1.0 in Jan 2017
|
387
|
+
for general embedded software, for one-chip microcontroller
|
388
|
+
mrbgems, no package manager
|
389
|
+
RAM < 200KB ...(*), RAM < 40KB ...(*)
|
390
|
+
|
391
|
+
|
392
|
+
(('tag:center'))\n
|
393
|
+
(('tag:xx-small:(*)...It depends on the situation'))
|
394
|
+
|
395
|
+
= mruby/c's Virtual Machine
|
396
|
+
* Much smaller than mruby's one
|
397
|
+
* That's why mruby/c runs on smaller RAM
|
398
|
+
* Accordingly, mruby/c has ((*less*)) functionality than mruby and CRuby
|
399
|
+
|
400
|
+
= How ((*less*))?
|
401
|
+
|
402
|
+
= How ((*less*))? - For example
|
403
|
+
* mruby/c doesn't have module, hence there is no Kernel module
|
404
|
+
* Then you must wonder how can you `#puts`?
|
405
|
+
* In mruby/c, `#puts` is implemented in Object class
|
406
|
+
* mruby/c doesn't have #send, #eval, and #method_missing, etc.
|
407
|
+
|
408
|
+
= How ((*less*))? - For example
|
409
|
+
* The full list of mruby/c's classes
|
410
|
+
* Array, FalseClass, Fixnum, Float, Hash, Math, Mutex, NilClass, Numeric, Object, Proc, Range, String, Symbol, TrueClass, VM
|
411
|
+
|
412
|
+
= Despite the fact,
|
413
|
+
* No problem in practical usage of microcontroller
|
414
|
+
* As far as IoT goes, mruby/c is enough Ruby
|
415
|
+
* We can fully develop firmwares with these features of mruby/c
|
416
|
+
|
417
|
+
= How does mruby/c work
|
418
|
+
# enscript bash
|
419
|
+
~/project/sample_project
|
420
|
+
├─ main.c
|
421
|
+
├─ mrblib
|
422
|
+
│ ├─ task_1.rb
|
423
|
+
│ └─ task_2.rb
|
424
|
+
└─ src
|
425
|
+
├─ task_1.c
|
426
|
+
└─ task_2.c
|
427
|
+
|
428
|
+
* task_*.c is compliled bytecode from task_*.rb
|
429
|
+
|
430
|
+
= How does mruby/c work
|
431
|
+
# enscript c
|
432
|
+
/* main.c */
|
433
|
+
#include "src/task_1.c"
|
434
|
+
#include "src/task_2.c"
|
435
|
+
// using 40KB RAM for VM heap in this case
|
436
|
+
#define MEMORY_SIZE (1024 * 40)
|
437
|
+
static uint8_t memory_pool[MEMORY_SIZE];
|
438
|
+
int main(void) {
|
439
|
+
mrbc_init(memory_pool, MEMORY_SIZE);
|
440
|
+
mrbc_create_task(task_1, 0);
|
441
|
+
mrbc_create_task(task_2, 0);
|
442
|
+
mrbc_run(); // 2 tasks run concurrently!
|
443
|
+
return 0;
|
444
|
+
}
|
445
|
+
|
446
|
+
= How does mruby/c work
|
447
|
+
* We can run easily multiple VMs with ((*concurrency*)) feature of ((*rrt0*))
|
448
|
+
* You might be disappointed to know you have to write C
|
449
|
+
* Yes, we have to write ((*main.c*))
|
450
|
+
* Don't worry, it's almost boilerplate code
|
451
|
+
|
452
|
+
= hide title
|
453
|
+
(('tag:center'))\n\n
|
454
|
+
(('tag:small:Chapter 3'))\n
|
455
|
+
(('tag:xx-large:Application code'))\n(('tag:xx-large:and tools'))
|
456
|
+
== prop
|
457
|
+
: hide-title
|
458
|
+
true
|
459
|
+
|
460
|
+
= Application code
|
461
|
+
(('tag:center'))\n\n\n\n
|
462
|
+
github.com/hasumikin/co2_demo
|
463
|
+
|
464
|
+
= Application code
|
465
|
+
# enscript bash
|
466
|
+
~/project/co2_demo
|
467
|
+
├─ main.c
|
468
|
+
└─ mrblib
|
469
|
+
├─ loops
|
470
|
+
│ ├─ primary.rb
|
471
|
+
│ └─ secondary.rb
|
472
|
+
└─ models
|
473
|
+
├─ co2.rb
|
474
|
+
├─ led.rb
|
475
|
+
└─ thermistor.rb
|
476
|
+
|
477
|
+
= Application code
|
478
|
+
# enscript ruby
|
479
|
+
# loops/primary.rb
|
480
|
+
$co2 = Co2.new # Makes it global so that secondary task can use it
|
481
|
+
$thermistor = $thermistor.new
|
482
|
+
led = Led.new(19) # 19 is a pin number which LED connects
|
483
|
+
while true
|
484
|
+
co2 = $co2.concentrate
|
485
|
+
if co2 > 2000 # When CO2 reaches fatal level
|
486
|
+
5.times do # Turning LED on and off
|
487
|
+
led.turn_on
|
488
|
+
sleep 0.1
|
489
|
+
led.turn_off
|
490
|
+
sleep 0.1
|
491
|
+
end
|
492
|
+
else # Safe level
|
493
|
+
led.turn_off # Turns off
|
494
|
+
sleep 1
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
= Application code
|
499
|
+
(('tag:center'))\n\n\n\n
|
500
|
+
How does ((*Led#trun_on*)) work?
|
501
|
+
|
502
|
+
= Application code
|
503
|
+
# enscript ruby
|
504
|
+
# models/led.rb
|
505
|
+
class Led
|
506
|
+
def initialize(pin)
|
507
|
+
@pin = pin
|
508
|
+
gpio_init_output(@pin)
|
509
|
+
turn_off
|
510
|
+
end
|
511
|
+
def turn_on
|
512
|
+
gpio_set_level(@pin, 1) # high
|
513
|
+
end
|
514
|
+
def turn_off
|
515
|
+
gpio_set_level(@pin, 0) # low
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
= Application code
|
520
|
+
# enscript c
|
521
|
+
/* a part of main.c */
|
522
|
+
#include "models/led.c"
|
523
|
+
static void c_gpio_init_output(mrbc_vm *vm, mrbc_value *v, int argc) {
|
524
|
+
int pin = GET_INT_ARG(1);
|
525
|
+
// Function of microcontroller's library
|
526
|
+
gpio_set_direction(pin, GPIO_MODE_OUTPUT);
|
527
|
+
}
|
528
|
+
static void c_gpio_set_level(mrbc_vm *vm, mrbc_value *v, int argc){
|
529
|
+
int pin = GET_INT_ARG(1);
|
530
|
+
int level = GET_INT_ARG(2);
|
531
|
+
gpio_set_level(pin, level); // Function of microcontroller's library
|
532
|
+
}
|
533
|
+
int main(void){
|
534
|
+
...
|
535
|
+
mrbc_define_method(0, mrbc_class_object, "gpio_init_output",
|
536
|
+
c_gpio_init_output);
|
537
|
+
mrbc_define_method(0, mrbc_class_object, "gpio_set_level",
|
538
|
+
c_gpio_set_level);
|
539
|
+
...
|
540
|
+
}
|
541
|
+
|
542
|
+
= Application code
|
543
|
+
# enscript c
|
544
|
+
/* a part of main.c */
|
545
|
+
#include "models/co2.c"
|
546
|
+
static void c_get_co2(struct VM *vm, mrbc_value v[], int argc){
|
547
|
+
uint8_t command[] = { // Command to take CO2
|
548
|
+
0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79
|
549
|
+
};
|
550
|
+
uart_write_bytes(uart_num, (const char*)command, 9);
|
551
|
+
// ↑Write then ↓Read data
|
552
|
+
uint8_t data[10];
|
553
|
+
int length = 0;
|
554
|
+
length = uart_read_bytes(uart_num, data, length, 10);
|
555
|
+
mrbc_value array = mrbc_array_new( vm, 9 ); // mrubyc's variable
|
556
|
+
for( int i = 0; i < 9; i++ ) {
|
557
|
+
mrbc_value value = mrbc_fixnum_value(data[i]);
|
558
|
+
mrbc_array_set( &array, i, &value ); // Adding a value to array
|
559
|
+
}
|
560
|
+
SET_RETURN(array); // Returning the array object to mruby
|
561
|
+
}
|
562
|
+
int main(void){
|
563
|
+
...
|
564
|
+
mrbc_define_method(0, mrbc_class_object, "get_co2", c_get_co2);
|
565
|
+
...
|
566
|
+
}
|
567
|
+
|
568
|
+
= Application code
|
569
|
+
# enscript ruby
|
570
|
+
# models/co2.rb
|
571
|
+
class Co2
|
572
|
+
def concentrate
|
573
|
+
res = get_co2
|
574
|
+
# checks if the sensor works
|
575
|
+
if res[0] == 255 && res[1] == 134
|
576
|
+
res[2] * 256 + res[3]
|
577
|
+
else
|
578
|
+
0
|
579
|
+
end
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
= Application code
|
584
|
+
* Trivial tip to reduce memory usage
|
585
|
+
* C function can return String instead of Array
|
586
|
+
* `mrbc_array_new` will allocate larger memory than `mrbc_string_new`
|
587
|
+
* So, you can use String instead of Array if memory becomes short
|
588
|
+
* Remember STRING of C is just an array of char and '\0'
|
589
|
+
|
590
|
+
= Application code
|
591
|
+
# enscript ruby
|
592
|
+
# loops/secondary.rb
|
593
|
+
http_client = HttpClient.new("http://data.server")
|
594
|
+
while true
|
595
|
+
co2 = $co2.concentrate
|
596
|
+
temperature = $thermistor.temperature
|
597
|
+
if co2 > 0 # No trouble
|
598
|
+
data = "co2=#{co2}&temperature=#{temperature}"
|
599
|
+
http_client.post(data)
|
600
|
+
sleep 180
|
601
|
+
else # A trouble happens?
|
602
|
+
sleep 3 # Or you can retry
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
606
|
+
= Dev tools for mruby/c
|
607
|
+
|
608
|
+
= Dev tools for mruby/c
|
609
|
+
* mrubyc-utils
|
610
|
+
* mrubyc-test
|
611
|
+
* mrubyc-debugger
|
612
|
+
|
613
|
+
= Dev tools for mruby/c
|
614
|
+
(('tag:center'))\n\n\n
|
615
|
+
I am trying to make mruby/c development ((*Rubyish*))
|
616
|
+
|
617
|
+
= Rubyish? - IMHO
|
618
|
+
* Unix/Linux
|
619
|
+
* Command line
|
620
|
+
* No-IDE (as far as possible)
|
621
|
+
|
622
|
+
= Rubyish? - IMHO
|
623
|
+
* Unix/Linux
|
624
|
+
* Command line
|
625
|
+
* No-IDE (as far as possible)
|
626
|
+
|
627
|
+
(('tag:center'))\n
|
628
|
+
Taking full advantage of\nour Laptop and Ruby World
|
629
|
+
|
630
|
+
= mrubyc-utils
|
631
|
+
* github.com/hasumikin/mrubyc-utils
|
632
|
+
* One-binary tool made with mruby
|
633
|
+
* Helps to install boilerplate of application
|
634
|
+
* Utility subcommands like...
|
635
|
+
|
636
|
+
= mrubyc-utils
|
637
|
+
$ mrubyc-utils classes
|
638
|
+
- Array
|
639
|
+
- FalseClass
|
640
|
+
- Fixnum
|
641
|
+
- Float
|
642
|
+
- Hash
|
643
|
+
- Math
|
644
|
+
- Mutex
|
645
|
+
- NilClass
|
646
|
+
- Numeric
|
647
|
+
- Object
|
648
|
+
- Proc
|
649
|
+
- Range
|
650
|
+
- String
|
651
|
+
- Symbol
|
652
|
+
- TrueClass
|
653
|
+
- VM
|
654
|
+
|
655
|
+
= mrubyc-utils
|
656
|
+
$ mrubyc-utils methods --class=array
|
657
|
+
Array
|
658
|
+
- + - inspect
|
659
|
+
- << - join
|
660
|
+
- [] - last
|
661
|
+
- []= - length
|
662
|
+
- at - max
|
663
|
+
- clear - min
|
664
|
+
- collect - minmax
|
665
|
+
- collect! - new
|
666
|
+
- count - pop
|
667
|
+
- delete_at - push
|
668
|
+
- dup - shift
|
669
|
+
- each - size
|
670
|
+
- each_index - to_s
|
671
|
+
- each_with_index - unshift
|
672
|
+
- empty? < Object
|
673
|
+
- first - !
|
674
|
+
- index ...
|
675
|
+
|
676
|
+
= mrubyc-test
|
677
|
+
* github.com/mrubyc/mrubyc-test
|
678
|
+
* Unit testing framework
|
679
|
+
* A RubyGem implemented with CRuby
|
680
|
+
* Supports stub and mock
|
681
|
+
* Official test tool of mruby/c dev team
|
682
|
+
|
683
|
+
= mrubyc-test
|
684
|
+
* Gathers information from app and test code
|
685
|
+
* Internally generates stub and mock methods
|
686
|
+
* Makes all-in-one script: ((*test.rb*))
|
687
|
+
# image
|
688
|
+
# src = images/how-mrubyc-test-works.png
|
689
|
+
# align = center
|
690
|
+
# relative-width = 100
|
691
|
+
|
692
|
+
= mrubyc-debugger
|
693
|
+
* github.com/hasumikin/mrubyc-debugger
|
694
|
+
* Debugger for mutiple infinite loops
|
695
|
+
|
696
|
+
= DEMO
|
697
|
+
(('tag:center'))\n\n\n\n
|
698
|
+
github.com/hasumikin/\nmrubyc-debugger
|
699
|
+
|
700
|
+
= DEMO
|
701
|
+
(('tag:center'))\n\n\n\n
|
702
|
+
How is CO(('sub:2')) going?
|
703
|
+
|
704
|
+
= DEMO (added after the Conf)
|
705
|
+
# image
|
706
|
+
# src = images/co2.png
|
707
|
+
# align = center
|
708
|
+
# relative-width = 100
|
709
|
+
|
710
|
+
= Conclusion
|
711
|
+
|
712
|
+
= Conclusion
|
713
|
+
(('tag:center'))\n\n
|
714
|
+
(('tag:xx-large:You should refresh air 💨'))
|
715
|
+
|
716
|
+
= Thank you!
|
717
|
+
# image
|
718
|
+
# src = images/rubylabel.jpg
|
719
|
+
# align = center
|
720
|
+
# relative-height = 110
|
data/theme.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# puts font_families.sort
|
2
|
+
@xx_large_font_size = screen_size(12 * Pango::SCALE)
|
3
|
+
@x_large_font_size = screen_size(8 * Pango::SCALE)
|
4
|
+
@large_font_size = screen_size(7 * Pango::SCALE)
|
5
|
+
@normal_font_size = screen_size(4.5 * Pango::SCALE)
|
6
|
+
@small_font_size = screen_size(4 * Pango::SCALE)
|
7
|
+
@x_small_font_size = screen_size(3.5 * Pango::SCALE)
|
8
|
+
@xx_small_font_size = screen_size(3 * Pango::SCALE)
|
9
|
+
|
10
|
+
@font_family = find_font_family('Roboto Slab')
|
11
|
+
@monospace_font_family = 'Ricty Discord'
|
12
|
+
|
13
|
+
@default_headline_line_color = '#FFB400'
|
14
|
+
@default_headline_line_width = 8
|
15
|
+
@default_headline_line_expand = false
|
16
|
+
|
17
|
+
set_graffiti_color "#FF2B22"
|
18
|
+
set_graffiti_line_width 10
|
19
|
+
|
20
|
+
#@table_frame_color = "#ffffff"
|
21
|
+
#@table_fill_color = "#0f0428"
|
22
|
+
#@table_body_frame_color = "#ffffff"
|
23
|
+
#@table_body_fill_color = "#3f3468"
|
24
|
+
#@table_head_frame_color = "#ffffff"
|
25
|
+
#@table_head_fill_color = "#rf0428"
|
26
|
+
|
27
|
+
#@preformatted_fill_color = '#000000'
|
28
|
+
# @preformatted_centering = true
|
29
|
+
@space = screen_y(1)
|
30
|
+
|
31
|
+
@margin_left = 300
|
32
|
+
|
33
|
+
@image_slide_number_start_flag_color = "#FFB400"
|
34
|
+
@image_slide_number_goal_flag_color = "#FF2B22"
|
35
|
+
|
36
|
+
include_theme('default')
|
37
|
+
|
38
|
+
match(Slide, HeadLine) do |heads|
|
39
|
+
heads.prop_set("size", @large_font_size)
|
40
|
+
heads.prop_set("weight", "normal")
|
41
|
+
set_font_family(heads)
|
42
|
+
end
|
43
|
+
match(Slide) do |slides|
|
44
|
+
#slides.prop_set("foreground", "#FF2B22")
|
45
|
+
slides.prop_set("foreground", "black")
|
46
|
+
end
|
47
|
+
|
48
|
+
@slide_headline_hide = true
|
49
|
+
match TitleSlide do |slides|
|
50
|
+
slides.margin_left = @margin_right
|
51
|
+
end
|
52
|
+
match TitleSlide, Title do |titles|
|
53
|
+
#titles.prop_set "foreground", "#FF2B22"
|
54
|
+
titles.prop_set "foreground", "#FFB400"
|
55
|
+
titles.margin_top = -80
|
56
|
+
end
|
57
|
+
match TitleSlide, Author do |authors|
|
58
|
+
#authors.prop_set "foreground", "white"
|
59
|
+
authors.prop_set "foreground", "#FFB400"
|
60
|
+
authors.margin_top = 540
|
61
|
+
end
|
62
|
+
|
63
|
+
@title_slide_background_image = 'images/Powerpoint Hold Slide.png'
|
64
|
+
include_theme("title-slide-background-image")
|
65
|
+
|
66
|
+
@slide_background_image = 'images/Powerpoint Content Slide.png'
|
67
|
+
include_theme("slide-background-image")
|
68
|
+
|
69
|
+
#@slide_logo_image = 'images/mark48.png'
|
70
|
+
#include_theme('slide-logo')
|
71
|
+
|
72
|
+
@item_image = 'images/mark48.png'
|
73
|
+
|
74
|
+
include_theme("default-item-mark")
|
75
|
+
|
76
|
+
add_image_path("rabbit-images")
|
77
|
+
|
78
|
+
slide_body = [Slide, Body]
|
79
|
+
item_list_item = [ItemList, ItemListItem]
|
80
|
+
|
81
|
+
indent = 70
|
82
|
+
|
83
|
+
match(*(slide_body + (item_list_item * 1))) do |items|
|
84
|
+
name = "item1"
|
85
|
+
items.delete_pre_draw_proc_by_name(name)
|
86
|
+
items.delete_post_draw_proc_by_name(name)
|
87
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
88
|
+
end
|
89
|
+
|
90
|
+
match(*(slide_body + (item_list_item * 2))) do |items|
|
91
|
+
name = "item2"
|
92
|
+
items.delete_pre_draw_proc_by_name(name)
|
93
|
+
items.delete_post_draw_proc_by_name(name)
|
94
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
95
|
+
end
|
96
|
+
|
97
|
+
match(*(slide_body + (item_list_item * 3))) do |items|
|
98
|
+
name = "item3"
|
99
|
+
items.delete_pre_draw_proc_by_name(name)
|
100
|
+
items.delete_post_draw_proc_by_name(name)
|
101
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
102
|
+
end
|
103
|
+
|
104
|
+
enum_list_item = [EnumList, EnumListItem]
|
105
|
+
|
106
|
+
match(*(slide_body + enum_list_item + item_list_item)) do |items|
|
107
|
+
name = "enum-item1"
|
108
|
+
items.delete_pre_draw_proc_by_name(name)
|
109
|
+
items.delete_post_draw_proc_by_name(name)
|
110
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
111
|
+
end
|
112
|
+
|
113
|
+
match(*(slide_body + enum_list_item + (item_list_item * 2))) do |items|
|
114
|
+
name = "enum-item2"
|
115
|
+
items.delete_pre_draw_proc_by_name(name)
|
116
|
+
items.delete_post_draw_proc_by_name(name)
|
117
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
118
|
+
end
|
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rabbit-slide-hasumikin-RubyConf2019
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2019.11.18.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- HASUMI Hitoshi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-11-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rabbit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.0.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.0.2
|
27
|
+
description: A presentation slide for RubyConf 2019 at JW Marriott Nashville on Nov
|
28
|
+
18, 2019
|
29
|
+
email:
|
30
|
+
- hasumikin@gmail.com
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ".rabbit"
|
36
|
+
- README.rd
|
37
|
+
- Rakefile
|
38
|
+
- config.yaml
|
39
|
+
- images/IDE.png
|
40
|
+
- images/Powerpoint Content Slide.png
|
41
|
+
- images/Powerpoint Hold Slide.png
|
42
|
+
- images/asahi-1.jpg
|
43
|
+
- images/asahi-2.jpg
|
44
|
+
- images/asahi-3.jpg
|
45
|
+
- images/bytecode.png
|
46
|
+
- images/co2.png
|
47
|
+
- images/co2_demo.png
|
48
|
+
- images/collage01.jpg
|
49
|
+
- images/esp32.jpg
|
50
|
+
- images/fuzz.png
|
51
|
+
- images/hasumi.jpg
|
52
|
+
- images/how-mrubyc-test-works.png
|
53
|
+
- images/juji-asahi.jpg
|
54
|
+
- images/kamos.jpg
|
55
|
+
- images/mark32.png
|
56
|
+
- images/mark48.png
|
57
|
+
- images/mark64.png
|
58
|
+
- images/mobile.png
|
59
|
+
- images/monstarlab.png
|
60
|
+
- images/monstarlab_webpage.png
|
61
|
+
- images/mruby_and_mrubyc-mruby.png
|
62
|
+
- images/mruby_and_mrubyc-mrubyc.png
|
63
|
+
- images/mruby_and_mrubyc.png
|
64
|
+
- images/psoc5lp_chip.jpg
|
65
|
+
- images/raspberrypi.jpg
|
66
|
+
- images/rubykaigi2020.png
|
67
|
+
- images/rubylabel.jpg
|
68
|
+
- images/rubylabeljujiasahi.jpg
|
69
|
+
- images/unsoldered-2.png
|
70
|
+
- images/unsoldered.jpg
|
71
|
+
- images/松江城_Matsue.rb.jpg
|
72
|
+
- mrubyc-Running-on-Less-Than-64KB-RAM-Microcontroller.rab
|
73
|
+
- pdf/RubyConf2019-mrubyc-Running-on-Less-Than-64KB-RAM-Microcontroller.pdf
|
74
|
+
- theme.rb
|
75
|
+
homepage: https://slide.rabbit-shocker.org/authors/hasumikin/RubyConf2019/
|
76
|
+
licenses: []
|
77
|
+
metadata: {}
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
requirements: []
|
93
|
+
rubygems_version: 3.0.3
|
94
|
+
signing_key:
|
95
|
+
specification_version: 4
|
96
|
+
summary: 'mruby/c: Running on Less Than 64KB RAM Microcontroller'
|
97
|
+
test_files: []
|